| 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 "p12t.h" |
| 6 #include "p12.h" |
| 7 #include "plarena.h" |
| 8 #include "secitem.h" |
| 9 #include "secoid.h" |
| 10 #include "seccomon.h" |
| 11 #include "secport.h" |
| 12 #include "cert.h" |
| 13 #include "secpkcs7.h" |
| 14 #include "secasn1.h" |
| 15 #include "secerr.h" |
| 16 #include "pk11func.h" |
| 17 #include "p12plcy.h" |
| 18 #include "p12local.h" |
| 19 #include "prcpucfg.h" |
| 20 |
| 21 extern const int NSS_PBE_DEFAULT_ITERATION_COUNT; /* defined in p7create.c */ |
| 22 |
| 23 /* |
| 24 ** This PKCS12 file encoder uses numerous nested ASN.1 and PKCS7 encoder |
| 25 ** contexts. It can be difficult to keep straight. Here's a picture: |
| 26 ** |
| 27 ** "outer" ASN.1 encoder. The output goes to the library caller's CB. |
| 28 ** "middle" PKCS7 encoder. Feeds the "outer" ASN.1 encoder. |
| 29 ** "middle" ASN1 encoder. Encodes the encrypted aSafes. |
| 30 ** Feeds the "middle" P7 encoder above. |
| 31 ** "inner" PKCS7 encoder. Encrypts the "authenticated Safes" (aSafes) |
| 32 ** Feeds the "middle" ASN.1 encoder above. |
| 33 ** "inner" ASN.1 encoder. Encodes the unencrypted aSafes. |
| 34 ** Feeds the "inner" P7 enocder above. |
| 35 ** |
| 36 ** Buffering has been added at each point where the output of an ASN.1 |
| 37 ** encoder feeds the input of a PKCS7 encoder. |
| 38 */ |
| 39 |
| 40 /********************************* |
| 41 * Output buffer object, used to buffer output from ASN.1 encoder |
| 42 * before passing data on down to the next PKCS7 encoder. |
| 43 *********************************/ |
| 44 |
| 45 #define PK12_OUTPUT_BUFFER_SIZE 8192 |
| 46 |
| 47 struct sec_pkcs12OutputBufferStr { |
| 48 SEC_PKCS7EncoderContext * p7eCx; |
| 49 PK11Context * hmacCx; |
| 50 unsigned int numBytes; |
| 51 unsigned int bufBytes; |
| 52 char buf[PK12_OUTPUT_BUFFER_SIZE]; |
| 53 }; |
| 54 typedef struct sec_pkcs12OutputBufferStr sec_pkcs12OutputBuffer; |
| 55 |
| 56 /********************************* |
| 57 * Structures used in exporting the PKCS 12 blob |
| 58 *********************************/ |
| 59 |
| 60 /* A SafeInfo is used for each ContentInfo which makes up the |
| 61 * sequence of safes in the AuthenticatedSafe portion of the |
| 62 * PFX structure. |
| 63 */ |
| 64 struct SEC_PKCS12SafeInfoStr { |
| 65 PLArenaPool *arena; |
| 66 |
| 67 /* information for setting up password encryption */ |
| 68 SECItem pwitem; |
| 69 SECOidTag algorithm; |
| 70 PK11SymKey *encryptionKey; |
| 71 |
| 72 /* how many items have been stored in this safe, |
| 73 * we will skip any safe which does not contain any |
| 74 * items |
| 75 */ |
| 76 unsigned int itemCount; |
| 77 |
| 78 /* the content info for the safe */ |
| 79 SEC_PKCS7ContentInfo *cinfo; |
| 80 |
| 81 sec_PKCS12SafeContents *safe; |
| 82 }; |
| 83 |
| 84 /* An opaque structure which contains information needed for exporting |
| 85 * certificates and keys through PKCS 12. |
| 86 */ |
| 87 struct SEC_PKCS12ExportContextStr { |
| 88 PLArenaPool *arena; |
| 89 PK11SlotInfo *slot; |
| 90 void *wincx; |
| 91 |
| 92 /* integrity information */ |
| 93 PRBool integrityEnabled; |
| 94 PRBool pwdIntegrity; |
| 95 union { |
| 96 struct sec_PKCS12PasswordModeInfo pwdInfo; |
| 97 struct sec_PKCS12PublicKeyModeInfo pubkeyInfo; |
| 98 } integrityInfo; |
| 99 |
| 100 /* helper functions */ |
| 101 /* retrieve the password call back */ |
| 102 SECKEYGetPasswordKey pwfn; |
| 103 void *pwfnarg; |
| 104 |
| 105 /* safe contents bags */ |
| 106 SEC_PKCS12SafeInfo **safeInfos; |
| 107 unsigned int safeInfoCount; |
| 108 |
| 109 /* the sequence of safes */ |
| 110 sec_PKCS12AuthenticatedSafe authSafe; |
| 111 |
| 112 /* information needing deletion */ |
| 113 CERTCertificate **certList; |
| 114 }; |
| 115 |
| 116 /* structures for passing information to encoder callbacks when processing |
| 117 * data through the ASN1 engine. |
| 118 */ |
| 119 struct sec_pkcs12_encoder_output { |
| 120 SEC_PKCS12EncoderOutputCallback outputfn; |
| 121 void *outputarg; |
| 122 }; |
| 123 |
| 124 struct sec_pkcs12_hmac_and_output_info { |
| 125 void *arg; |
| 126 struct sec_pkcs12_encoder_output output; |
| 127 }; |
| 128 |
| 129 /* An encoder context which is used for the actual encoding |
| 130 * portion of PKCS 12. |
| 131 */ |
| 132 typedef struct sec_PKCS12EncoderContextStr { |
| 133 PLArenaPool *arena; |
| 134 SEC_PKCS12ExportContext *p12exp; |
| 135 |
| 136 /* encoder information - this is set up based on whether |
| 137 * password based or public key pased privacy is being used |
| 138 */ |
| 139 SEC_ASN1EncoderContext *outerA1ecx; |
| 140 union { |
| 141 struct sec_pkcs12_hmac_and_output_info hmacAndOutputInfo; |
| 142 struct sec_pkcs12_encoder_output encOutput; |
| 143 } output; |
| 144 |
| 145 /* structures for encoding of PFX and MAC */ |
| 146 sec_PKCS12PFXItem pfx; |
| 147 sec_PKCS12MacData mac; |
| 148 |
| 149 /* authenticated safe encoding tracking information */ |
| 150 SEC_PKCS7ContentInfo *aSafeCinfo; |
| 151 SEC_PKCS7EncoderContext *middleP7ecx; |
| 152 SEC_ASN1EncoderContext *middleA1ecx; |
| 153 unsigned int currentSafe; |
| 154 |
| 155 /* hmac context */ |
| 156 PK11Context *hmacCx; |
| 157 |
| 158 /* output buffers */ |
| 159 sec_pkcs12OutputBuffer middleBuf; |
| 160 sec_pkcs12OutputBuffer innerBuf; |
| 161 |
| 162 } sec_PKCS12EncoderContext; |
| 163 |
| 164 |
| 165 /********************************* |
| 166 * Export setup routines |
| 167 *********************************/ |
| 168 |
| 169 /* SEC_PKCS12CreateExportContext |
| 170 * Creates an export context and sets the unicode and password retrieval |
| 171 * callbacks. This is the first call which must be made when exporting |
| 172 * a PKCS 12 blob. |
| 173 * |
| 174 * pwfn, pwfnarg - password retrieval callback and argument. these are |
| 175 * required for password-authentication mode. |
| 176 */ |
| 177 SEC_PKCS12ExportContext * |
| 178 SEC_PKCS12CreateExportContext(SECKEYGetPasswordKey pwfn, void *pwfnarg, |
| 179 PK11SlotInfo *slot, void *wincx) |
| 180 { |
| 181 PLArenaPool *arena = NULL; |
| 182 SEC_PKCS12ExportContext *p12ctxt = NULL; |
| 183 |
| 184 /* allocate the arena and create the context */ |
| 185 arena = PORT_NewArena(4096); |
| 186 if(!arena) { |
| 187 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 188 return NULL; |
| 189 } |
| 190 |
| 191 p12ctxt = (SEC_PKCS12ExportContext *)PORT_ArenaZAlloc(arena, |
| 192 sizeof(SEC_PKCS12ExportContext)); |
| 193 if(!p12ctxt) { |
| 194 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 195 goto loser; |
| 196 } |
| 197 |
| 198 /* password callback for key retrieval */ |
| 199 p12ctxt->pwfn = pwfn; |
| 200 p12ctxt->pwfnarg = pwfnarg; |
| 201 |
| 202 p12ctxt->integrityEnabled = PR_FALSE; |
| 203 p12ctxt->arena = arena; |
| 204 p12ctxt->wincx = wincx; |
| 205 p12ctxt->slot = (slot) ? PK11_ReferenceSlot(slot) : PK11_GetInternalSlot(); |
| 206 |
| 207 return p12ctxt; |
| 208 |
| 209 loser: |
| 210 if(arena) { |
| 211 PORT_FreeArena(arena, PR_TRUE); |
| 212 } |
| 213 |
| 214 return NULL; |
| 215 } |
| 216 |
| 217 /* |
| 218 * Adding integrity mode |
| 219 */ |
| 220 |
| 221 /* SEC_PKCS12AddPasswordIntegrity |
| 222 * Add password integrity to the exported data. If an integrity method |
| 223 * has already been set, then return an error. |
| 224 * |
| 225 * p12ctxt - the export context |
| 226 * pwitem - the password for integrity mode |
| 227 * integAlg - the integrity algorithm to use for authentication. |
| 228 */ |
| 229 SECStatus |
| 230 SEC_PKCS12AddPasswordIntegrity(SEC_PKCS12ExportContext *p12ctxt, |
| 231 SECItem *pwitem, SECOidTag integAlg) |
| 232 { |
| 233 if(!p12ctxt || p12ctxt->integrityEnabled) { |
| 234 return SECFailure; |
| 235 } |
| 236 |
| 237 /* set up integrity information */ |
| 238 p12ctxt->pwdIntegrity = PR_TRUE; |
| 239 p12ctxt->integrityInfo.pwdInfo.password = |
| 240 (SECItem*)PORT_ArenaZAlloc(p12ctxt->arena, sizeof(SECItem)); |
| 241 if(!p12ctxt->integrityInfo.pwdInfo.password) { |
| 242 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 243 return SECFailure; |
| 244 } |
| 245 if(SECITEM_CopyItem(p12ctxt->arena, |
| 246 p12ctxt->integrityInfo.pwdInfo.password, pwitem) |
| 247 != SECSuccess) { |
| 248 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 249 return SECFailure; |
| 250 } |
| 251 p12ctxt->integrityInfo.pwdInfo.algorithm = integAlg; |
| 252 p12ctxt->integrityEnabled = PR_TRUE; |
| 253 |
| 254 return SECSuccess; |
| 255 } |
| 256 |
| 257 /* SEC_PKCS12AddPublicKeyIntegrity |
| 258 * Add public key integrity to the exported data. If an integrity method |
| 259 * has already been set, then return an error. The certificate must be |
| 260 * allowed to be used as a signing cert. |
| 261 * |
| 262 * p12ctxt - the export context |
| 263 * cert - signer certificate |
| 264 * certDb - the certificate database |
| 265 * algorithm - signing algorithm |
| 266 * keySize - size of the signing key (?) |
| 267 */ |
| 268 SECStatus |
| 269 SEC_PKCS12AddPublicKeyIntegrity(SEC_PKCS12ExportContext *p12ctxt, |
| 270 CERTCertificate *cert, CERTCertDBHandle *certDb, |
| 271 SECOidTag algorithm, int keySize) |
| 272 { |
| 273 if(!p12ctxt) { |
| 274 return SECFailure; |
| 275 } |
| 276 |
| 277 p12ctxt->integrityInfo.pubkeyInfo.cert = cert; |
| 278 p12ctxt->integrityInfo.pubkeyInfo.certDb = certDb; |
| 279 p12ctxt->integrityInfo.pubkeyInfo.algorithm = algorithm; |
| 280 p12ctxt->integrityInfo.pubkeyInfo.keySize = keySize; |
| 281 p12ctxt->integrityEnabled = PR_TRUE; |
| 282 |
| 283 return SECSuccess; |
| 284 } |
| 285 |
| 286 |
| 287 /* |
| 288 * Adding safes - encrypted (password/public key) or unencrypted |
| 289 * Each of the safe creation routines return an opaque pointer which |
| 290 * are later passed into the routines for exporting certificates and |
| 291 * keys. |
| 292 */ |
| 293 |
| 294 /* append the newly created safeInfo to list of safeInfos in the export |
| 295 * context. |
| 296 */ |
| 297 static SECStatus |
| 298 sec_pkcs12_append_safe_info(SEC_PKCS12ExportContext *p12ctxt, SEC_PKCS12SafeInfo
*info) |
| 299 { |
| 300 void *mark = NULL, *dummy1 = NULL, *dummy2 = NULL; |
| 301 |
| 302 if(!p12ctxt || !info) { |
| 303 return SECFailure; |
| 304 } |
| 305 |
| 306 mark = PORT_ArenaMark(p12ctxt->arena); |
| 307 |
| 308 /* if no safeInfos have been set, create the list, otherwise expand it. */ |
| 309 if(!p12ctxt->safeInfoCount) { |
| 310 p12ctxt->safeInfos = (SEC_PKCS12SafeInfo **)PORT_ArenaZAlloc(p12ctxt->ar
ena, |
| 311 2 * sizeof(SEC_PKCS12SafeInfo *)); |
| 312 dummy1 = p12ctxt->safeInfos; |
| 313 p12ctxt->authSafe.encodedSafes = (SECItem **)PORT_ArenaZAlloc(p12ctxt->a
rena, |
| 314 2 * sizeof(SECItem *)); |
| 315 dummy2 = p12ctxt->authSafe.encodedSafes; |
| 316 } else { |
| 317 dummy1 = PORT_ArenaGrow(p12ctxt->arena, p12ctxt->safeInfos, |
| 318 (p12ctxt->safeInfoCount + 1) * sizeof(SEC_PKCS12S
afeInfo *), |
| 319 (p12ctxt->safeInfoCount + 2) * sizeof(SEC_PKCS12S
afeInfo *)); |
| 320 p12ctxt->safeInfos = (SEC_PKCS12SafeInfo **)dummy1; |
| 321 dummy2 = PORT_ArenaGrow(p12ctxt->arena, p12ctxt->authSafe.encodedSafes, |
| 322 (p12ctxt->authSafe.safeCount + 1) * sizeof(SECIte
m *), |
| 323 (p12ctxt->authSafe.safeCount + 2) * sizeof(SECIte
m *)); |
| 324 p12ctxt->authSafe.encodedSafes = (SECItem**)dummy2; |
| 325 } |
| 326 if(!dummy1 || !dummy2) { |
| 327 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 328 goto loser; |
| 329 } |
| 330 |
| 331 /* append the new safeInfo and null terminate the list */ |
| 332 p12ctxt->safeInfos[p12ctxt->safeInfoCount] = info; |
| 333 p12ctxt->safeInfos[++p12ctxt->safeInfoCount] = NULL; |
| 334 p12ctxt->authSafe.encodedSafes[p12ctxt->authSafe.safeCount] = |
| 335 (SECItem*)PORT_ArenaZAlloc(p12ctxt->arena, sizeof(SECItem)); |
| 336 if(!p12ctxt->authSafe.encodedSafes[p12ctxt->authSafe.safeCount]) { |
| 337 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 338 goto loser; |
| 339 } |
| 340 p12ctxt->authSafe.encodedSafes[++p12ctxt->authSafe.safeCount] = NULL; |
| 341 |
| 342 PORT_ArenaUnmark(p12ctxt->arena, mark); |
| 343 return SECSuccess; |
| 344 |
| 345 loser: |
| 346 PORT_ArenaRelease(p12ctxt->arena, mark); |
| 347 return SECFailure; |
| 348 } |
| 349 |
| 350 /* SEC_PKCS12CreatePasswordPrivSafe |
| 351 * Create a password privacy safe to store exported information in. |
| 352 * |
| 353 * p12ctxt - export context |
| 354 * pwitem - password for encryption |
| 355 * privAlg - pbe algorithm through which encryption is done. |
| 356 */ |
| 357 SEC_PKCS12SafeInfo * |
| 358 SEC_PKCS12CreatePasswordPrivSafe(SEC_PKCS12ExportContext *p12ctxt, |
| 359 SECItem *pwitem, SECOidTag privAlg) |
| 360 { |
| 361 SEC_PKCS12SafeInfo *safeInfo = NULL; |
| 362 void *mark = NULL; |
| 363 PK11SlotInfo *slot = NULL; |
| 364 SECAlgorithmID *algId; |
| 365 SECItem uniPwitem = {siBuffer, NULL, 0}; |
| 366 |
| 367 if(!p12ctxt) { |
| 368 return NULL; |
| 369 } |
| 370 |
| 371 /* allocate the safe info */ |
| 372 mark = PORT_ArenaMark(p12ctxt->arena); |
| 373 safeInfo = (SEC_PKCS12SafeInfo *)PORT_ArenaZAlloc(p12ctxt->arena, |
| 374 sizeof(SEC_PKCS12SafeInfo)); |
| 375 if(!safeInfo) { |
| 376 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 377 PORT_ArenaRelease(p12ctxt->arena, mark); |
| 378 return NULL; |
| 379 } |
| 380 |
| 381 safeInfo->itemCount = 0; |
| 382 |
| 383 /* create the encrypted safe */ |
| 384 safeInfo->cinfo = SEC_PKCS7CreateEncryptedData(privAlg, 0, p12ctxt->pwfn, |
| 385 p12ctxt->pwfnarg); |
| 386 if(!safeInfo->cinfo) { |
| 387 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 388 goto loser; |
| 389 } |
| 390 safeInfo->arena = p12ctxt->arena; |
| 391 |
| 392 /* convert the password to unicode */ |
| 393 if(!sec_pkcs12_convert_item_to_unicode(NULL, &uniPwitem, pwitem, |
| 394 PR_TRUE, PR_TRUE, PR_TRUE)) { |
| 395 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 396 goto loser; |
| 397 } |
| 398 if(SECITEM_CopyItem(p12ctxt->arena, &safeInfo->pwitem, &uniPwitem) != SECSuc
cess) { |
| 399 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 400 goto loser; |
| 401 } |
| 402 |
| 403 /* generate the encryption key */ |
| 404 slot = PK11_ReferenceSlot(p12ctxt->slot); |
| 405 if(!slot) { |
| 406 slot = PK11_GetInternalKeySlot(); |
| 407 if(!slot) { |
| 408 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 409 goto loser; |
| 410 } |
| 411 } |
| 412 |
| 413 algId = SEC_PKCS7GetEncryptionAlgorithm(safeInfo->cinfo); |
| 414 safeInfo->encryptionKey = PK11_PBEKeyGen(slot, algId, &uniPwitem, |
| 415 PR_FALSE, p12ctxt->wincx); |
| 416 if(!safeInfo->encryptionKey) { |
| 417 goto loser; |
| 418 } |
| 419 |
| 420 safeInfo->arena = p12ctxt->arena; |
| 421 safeInfo->safe = NULL; |
| 422 if(sec_pkcs12_append_safe_info(p12ctxt, safeInfo) != SECSuccess) { |
| 423 goto loser; |
| 424 } |
| 425 |
| 426 if(uniPwitem.data) { |
| 427 SECITEM_ZfreeItem(&uniPwitem, PR_FALSE); |
| 428 } |
| 429 PORT_ArenaUnmark(p12ctxt->arena, mark); |
| 430 |
| 431 if (slot) { |
| 432 PK11_FreeSlot(slot); |
| 433 } |
| 434 return safeInfo; |
| 435 |
| 436 loser: |
| 437 if (slot) { |
| 438 PK11_FreeSlot(slot); |
| 439 } |
| 440 if(safeInfo->cinfo) { |
| 441 SEC_PKCS7DestroyContentInfo(safeInfo->cinfo); |
| 442 } |
| 443 |
| 444 if(uniPwitem.data) { |
| 445 SECITEM_ZfreeItem(&uniPwitem, PR_FALSE); |
| 446 } |
| 447 |
| 448 PORT_ArenaRelease(p12ctxt->arena, mark); |
| 449 return NULL; |
| 450 } |
| 451 |
| 452 /* SEC_PKCS12CreateUnencryptedSafe |
| 453 * Creates an unencrypted safe within the export context. |
| 454 * |
| 455 * p12ctxt - the export context |
| 456 */ |
| 457 SEC_PKCS12SafeInfo * |
| 458 SEC_PKCS12CreateUnencryptedSafe(SEC_PKCS12ExportContext *p12ctxt) |
| 459 { |
| 460 SEC_PKCS12SafeInfo *safeInfo = NULL; |
| 461 void *mark = NULL; |
| 462 |
| 463 if(!p12ctxt) { |
| 464 return NULL; |
| 465 } |
| 466 |
| 467 /* create the safe info */ |
| 468 mark = PORT_ArenaMark(p12ctxt->arena); |
| 469 safeInfo = (SEC_PKCS12SafeInfo *)PORT_ArenaZAlloc(p12ctxt->arena, |
| 470 sizeof(SEC_PKCS12SafeInfo)); |
| 471 if(!safeInfo) { |
| 472 PORT_ArenaRelease(p12ctxt->arena, mark); |
| 473 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 474 return NULL; |
| 475 } |
| 476 |
| 477 safeInfo->itemCount = 0; |
| 478 |
| 479 /* create the safe content */ |
| 480 safeInfo->cinfo = SEC_PKCS7CreateData(); |
| 481 if(!safeInfo->cinfo) { |
| 482 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 483 goto loser; |
| 484 } |
| 485 |
| 486 if(sec_pkcs12_append_safe_info(p12ctxt, safeInfo) != SECSuccess) { |
| 487 goto loser; |
| 488 } |
| 489 |
| 490 PORT_ArenaUnmark(p12ctxt->arena, mark); |
| 491 return safeInfo; |
| 492 |
| 493 loser: |
| 494 if(safeInfo->cinfo) { |
| 495 SEC_PKCS7DestroyContentInfo(safeInfo->cinfo); |
| 496 } |
| 497 |
| 498 PORT_ArenaRelease(p12ctxt->arena, mark); |
| 499 return NULL; |
| 500 } |
| 501 |
| 502 /* SEC_PKCS12CreatePubKeyEncryptedSafe |
| 503 * Creates a safe which is protected by public key encryption. |
| 504 * |
| 505 * p12ctxt - the export context |
| 506 * certDb - the certificate database |
| 507 * signer - the signer's certificate |
| 508 * recipients - the list of recipient certificates. |
| 509 * algorithm - the encryption algorithm to use |
| 510 * keysize - the algorithms key size (?) |
| 511 */ |
| 512 SEC_PKCS12SafeInfo * |
| 513 SEC_PKCS12CreatePubKeyEncryptedSafe(SEC_PKCS12ExportContext *p12ctxt, |
| 514 CERTCertDBHandle *certDb, |
| 515 CERTCertificate *signer, |
| 516 CERTCertificate **recipients, |
| 517 SECOidTag algorithm, int keysize) |
| 518 { |
| 519 SEC_PKCS12SafeInfo *safeInfo = NULL; |
| 520 void *mark = NULL; |
| 521 |
| 522 if(!p12ctxt || !signer || !recipients || !(*recipients)) { |
| 523 return NULL; |
| 524 } |
| 525 |
| 526 /* allocate the safeInfo */ |
| 527 mark = PORT_ArenaMark(p12ctxt->arena); |
| 528 safeInfo = (SEC_PKCS12SafeInfo *)PORT_ArenaZAlloc(p12ctxt->arena, |
| 529 sizeof(SEC_PKCS12SafeInfo)
); |
| 530 if(!safeInfo) { |
| 531 PORT_ArenaRelease(p12ctxt->arena, mark); |
| 532 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 533 return NULL; |
| 534 } |
| 535 |
| 536 safeInfo->itemCount = 0; |
| 537 safeInfo->arena = p12ctxt->arena; |
| 538 |
| 539 /* create the enveloped content info using certUsageEmailSigner currently. |
| 540 * XXX We need to eventually use something other than certUsageEmailSigner |
| 541 */ |
| 542 safeInfo->cinfo = SEC_PKCS7CreateEnvelopedData(signer, certUsageEmailSigner, |
| 543 certDb, algorithm, keysize, |
| 544 p12ctxt->pwfn, p12ctxt->pwfnarg); |
| 545 if(!safeInfo->cinfo) { |
| 546 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 547 goto loser; |
| 548 } |
| 549 |
| 550 /* add recipients */ |
| 551 if(recipients) { |
| 552 unsigned int i = 0; |
| 553 while(recipients[i] != NULL) { |
| 554 SECStatus rv = SEC_PKCS7AddRecipient(safeInfo->cinfo, recipients[i], |
| 555 certUsageEmailRecipient, certDb); |
| 556 if(rv != SECSuccess) { |
| 557 goto loser; |
| 558 } |
| 559 i++; |
| 560 } |
| 561 } |
| 562 |
| 563 if(sec_pkcs12_append_safe_info(p12ctxt, safeInfo) != SECSuccess) { |
| 564 goto loser; |
| 565 } |
| 566 |
| 567 PORT_ArenaUnmark(p12ctxt->arena, mark); |
| 568 return safeInfo; |
| 569 |
| 570 loser: |
| 571 if(safeInfo->cinfo) { |
| 572 SEC_PKCS7DestroyContentInfo(safeInfo->cinfo); |
| 573 safeInfo->cinfo = NULL; |
| 574 } |
| 575 |
| 576 PORT_ArenaRelease(p12ctxt->arena, mark); |
| 577 return NULL; |
| 578 } |
| 579 |
| 580 /********************************* |
| 581 * Routines to handle the exporting of the keys and certificates |
| 582 *********************************/ |
| 583 |
| 584 /* creates a safe contents which safeBags will be appended to */ |
| 585 sec_PKCS12SafeContents * |
| 586 sec_PKCS12CreateSafeContents(PLArenaPool *arena) |
| 587 { |
| 588 sec_PKCS12SafeContents *safeContents; |
| 589 |
| 590 if(arena == NULL) { |
| 591 return NULL; |
| 592 } |
| 593 |
| 594 /* create the safe contents */ |
| 595 safeContents = (sec_PKCS12SafeContents *)PORT_ArenaZAlloc(arena, |
| 596 sizeof(sec_PKCS12SafeContents)); |
| 597 if(!safeContents) { |
| 598 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 599 goto loser; |
| 600 } |
| 601 |
| 602 /* set up the internal contents info */ |
| 603 safeContents->safeBags = NULL; |
| 604 safeContents->arena = arena; |
| 605 safeContents->bagCount = 0; |
| 606 |
| 607 return safeContents; |
| 608 |
| 609 loser: |
| 610 return NULL; |
| 611 } |
| 612 |
| 613 /* appends a safe bag to a safeContents using the specified arena. |
| 614 */ |
| 615 SECStatus |
| 616 sec_pkcs12_append_bag_to_safe_contents(PLArenaPool *arena, |
| 617 sec_PKCS12SafeContents *safeContents, |
| 618 sec_PKCS12SafeBag *safeBag) |
| 619 { |
| 620 void *mark = NULL, *dummy = NULL; |
| 621 |
| 622 if(!arena || !safeBag || !safeContents) { |
| 623 return SECFailure; |
| 624 } |
| 625 |
| 626 mark = PORT_ArenaMark(arena); |
| 627 if(!mark) { |
| 628 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 629 return SECFailure; |
| 630 } |
| 631 |
| 632 /* allocate space for the list, or reallocate to increase space */ |
| 633 if(!safeContents->safeBags) { |
| 634 safeContents->safeBags = (sec_PKCS12SafeBag **)PORT_ArenaZAlloc(arena, |
| 635 (2 * sizeof(sec_PKCS12SafeBag *)
)); |
| 636 dummy = safeContents->safeBags; |
| 637 safeContents->bagCount = 0; |
| 638 } else { |
| 639 dummy = PORT_ArenaGrow(arena, safeContents->safeBags, |
| 640 (safeContents->bagCount + 1) * sizeof(sec_PKCS12SafeBag
*), |
| 641 (safeContents->bagCount + 2) * sizeof(sec_PKCS12SafeBag
*)); |
| 642 safeContents->safeBags = (sec_PKCS12SafeBag **)dummy; |
| 643 } |
| 644 |
| 645 if(!dummy) { |
| 646 PORT_ArenaRelease(arena, mark); |
| 647 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 648 return SECFailure; |
| 649 } |
| 650 |
| 651 /* append the bag at the end and null terminate the list */ |
| 652 safeContents->safeBags[safeContents->bagCount++] = safeBag; |
| 653 safeContents->safeBags[safeContents->bagCount] = NULL; |
| 654 |
| 655 PORT_ArenaUnmark(arena, mark); |
| 656 |
| 657 return SECSuccess; |
| 658 } |
| 659 |
| 660 /* appends a safeBag to a specific safeInfo. |
| 661 */ |
| 662 SECStatus |
| 663 sec_pkcs12_append_bag(SEC_PKCS12ExportContext *p12ctxt, |
| 664 SEC_PKCS12SafeInfo *safeInfo, sec_PKCS12SafeBag *safeBag) |
| 665 { |
| 666 sec_PKCS12SafeContents *dest; |
| 667 SECStatus rv = SECFailure; |
| 668 |
| 669 if(!p12ctxt || !safeBag || !safeInfo) { |
| 670 return SECFailure; |
| 671 } |
| 672 |
| 673 if(!safeInfo->safe) { |
| 674 safeInfo->safe = sec_PKCS12CreateSafeContents(p12ctxt->arena); |
| 675 if(!safeInfo->safe) { |
| 676 return SECFailure; |
| 677 } |
| 678 } |
| 679 |
| 680 dest = safeInfo->safe; |
| 681 rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena, dest, safeBag); |
| 682 if(rv == SECSuccess) { |
| 683 safeInfo->itemCount++; |
| 684 } |
| 685 |
| 686 return rv; |
| 687 } |
| 688 |
| 689 /* Creates a safeBag of the specified type, and if bagData is specified, |
| 690 * the contents are set. The contents could be set later by the calling |
| 691 * routine. |
| 692 */ |
| 693 sec_PKCS12SafeBag * |
| 694 sec_PKCS12CreateSafeBag(SEC_PKCS12ExportContext *p12ctxt, SECOidTag bagType, |
| 695 void *bagData) |
| 696 { |
| 697 sec_PKCS12SafeBag *safeBag; |
| 698 PRBool setName = PR_TRUE; |
| 699 void *mark = NULL; |
| 700 SECStatus rv = SECSuccess; |
| 701 SECOidData *oidData = NULL; |
| 702 |
| 703 if(!p12ctxt) { |
| 704 return NULL; |
| 705 } |
| 706 |
| 707 mark = PORT_ArenaMark(p12ctxt->arena); |
| 708 if(!mark) { |
| 709 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 710 return NULL; |
| 711 } |
| 712 |
| 713 safeBag = (sec_PKCS12SafeBag *)PORT_ArenaZAlloc(p12ctxt->arena, |
| 714 sizeof(sec_PKCS12SafeBag)); |
| 715 if(!safeBag) { |
| 716 PORT_ArenaRelease(p12ctxt->arena, mark); |
| 717 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 718 return NULL; |
| 719 } |
| 720 |
| 721 /* set the bags content based upon bag type */ |
| 722 switch(bagType) { |
| 723 case SEC_OID_PKCS12_V1_KEY_BAG_ID: |
| 724 safeBag->safeBagContent.pkcs8KeyBag = |
| 725 (SECKEYPrivateKeyInfo *)bagData; |
| 726 break; |
| 727 case SEC_OID_PKCS12_V1_CERT_BAG_ID: |
| 728 safeBag->safeBagContent.certBag = (sec_PKCS12CertBag *)bagData; |
| 729 break; |
| 730 case SEC_OID_PKCS12_V1_CRL_BAG_ID: |
| 731 safeBag->safeBagContent.crlBag = (sec_PKCS12CRLBag *)bagData; |
| 732 break; |
| 733 case SEC_OID_PKCS12_V1_SECRET_BAG_ID: |
| 734 safeBag->safeBagContent.secretBag = (sec_PKCS12SecretBag *)bagData; |
| 735 break; |
| 736 case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID: |
| 737 safeBag->safeBagContent.pkcs8ShroudedKeyBag = |
| 738 (SECKEYEncryptedPrivateKeyInfo *)bagData; |
| 739 break; |
| 740 case SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID: |
| 741 safeBag->safeBagContent.safeContents = |
| 742 (sec_PKCS12SafeContents *)bagData; |
| 743 setName = PR_FALSE; |
| 744 break; |
| 745 default: |
| 746 goto loser; |
| 747 } |
| 748 |
| 749 oidData = SECOID_FindOIDByTag(bagType); |
| 750 if(oidData) { |
| 751 rv = SECITEM_CopyItem(p12ctxt->arena, &safeBag->safeBagType, &oidData->o
id); |
| 752 if(rv != SECSuccess) { |
| 753 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 754 goto loser; |
| 755 } |
| 756 } else { |
| 757 goto loser; |
| 758 } |
| 759 |
| 760 safeBag->arena = p12ctxt->arena; |
| 761 PORT_ArenaUnmark(p12ctxt->arena, mark); |
| 762 |
| 763 return safeBag; |
| 764 |
| 765 loser: |
| 766 if(mark) { |
| 767 PORT_ArenaRelease(p12ctxt->arena, mark); |
| 768 } |
| 769 |
| 770 return NULL; |
| 771 } |
| 772 |
| 773 /* Creates a new certificate bag and returns a pointer to it. If an error |
| 774 * occurs NULL is returned. |
| 775 */ |
| 776 sec_PKCS12CertBag * |
| 777 sec_PKCS12NewCertBag(PLArenaPool *arena, SECOidTag certType) |
| 778 { |
| 779 sec_PKCS12CertBag *certBag = NULL; |
| 780 SECOidData *bagType = NULL; |
| 781 SECStatus rv; |
| 782 void *mark = NULL; |
| 783 |
| 784 if(!arena) { |
| 785 return NULL; |
| 786 } |
| 787 |
| 788 mark = PORT_ArenaMark(arena); |
| 789 certBag = (sec_PKCS12CertBag *)PORT_ArenaZAlloc(arena, |
| 790 sizeof(sec_PKCS12CertBag)); |
| 791 if(!certBag) { |
| 792 PORT_ArenaRelease(arena, mark); |
| 793 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 794 return NULL; |
| 795 } |
| 796 |
| 797 bagType = SECOID_FindOIDByTag(certType); |
| 798 if(!bagType) { |
| 799 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 800 goto loser; |
| 801 } |
| 802 |
| 803 rv = SECITEM_CopyItem(arena, &certBag->bagID, &bagType->oid); |
| 804 if(rv != SECSuccess) { |
| 805 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 806 goto loser; |
| 807 } |
| 808 |
| 809 PORT_ArenaUnmark(arena, mark); |
| 810 return certBag; |
| 811 |
| 812 loser: |
| 813 PORT_ArenaRelease(arena, mark); |
| 814 return NULL; |
| 815 } |
| 816 |
| 817 /* Creates a new CRL bag and returns a pointer to it. If an error |
| 818 * occurs NULL is returned. |
| 819 */ |
| 820 sec_PKCS12CRLBag * |
| 821 sec_PKCS12NewCRLBag(PLArenaPool *arena, SECOidTag crlType) |
| 822 { |
| 823 sec_PKCS12CRLBag *crlBag = NULL; |
| 824 SECOidData *bagType = NULL; |
| 825 SECStatus rv; |
| 826 void *mark = NULL; |
| 827 |
| 828 if(!arena) { |
| 829 return NULL; |
| 830 } |
| 831 |
| 832 mark = PORT_ArenaMark(arena); |
| 833 crlBag = (sec_PKCS12CRLBag *)PORT_ArenaZAlloc(arena, |
| 834 sizeof(sec_PKCS12CRLBag)); |
| 835 if(!crlBag) { |
| 836 PORT_ArenaRelease(arena, mark); |
| 837 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 838 return NULL; |
| 839 } |
| 840 |
| 841 bagType = SECOID_FindOIDByTag(crlType); |
| 842 if(!bagType) { |
| 843 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 844 goto loser; |
| 845 } |
| 846 |
| 847 rv = SECITEM_CopyItem(arena, &crlBag->bagID, &bagType->oid); |
| 848 if(rv != SECSuccess) { |
| 849 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 850 goto loser; |
| 851 } |
| 852 |
| 853 PORT_ArenaUnmark(arena, mark); |
| 854 return crlBag; |
| 855 |
| 856 loser: |
| 857 PORT_ArenaRelease(arena, mark); |
| 858 return NULL; |
| 859 } |
| 860 |
| 861 /* sec_PKCS12AddAttributeToBag |
| 862 * adds an attribute to a safeBag. currently, the only attributes supported |
| 863 * are those which are specified within PKCS 12. |
| 864 * |
| 865 * p12ctxt - the export context |
| 866 * safeBag - the safeBag to which attributes are appended |
| 867 * attrType - the attribute type |
| 868 * attrData - the attribute data |
| 869 */ |
| 870 SECStatus |
| 871 sec_PKCS12AddAttributeToBag(SEC_PKCS12ExportContext *p12ctxt, |
| 872 sec_PKCS12SafeBag *safeBag, SECOidTag attrType, |
| 873 SECItem *attrData) |
| 874 { |
| 875 sec_PKCS12Attribute *attribute; |
| 876 void *mark = NULL, *dummy = NULL; |
| 877 SECOidData *oiddata = NULL; |
| 878 SECItem unicodeName = { siBuffer, NULL, 0}; |
| 879 void *src = NULL; |
| 880 unsigned int nItems = 0; |
| 881 SECStatus rv; |
| 882 |
| 883 if(!safeBag || !p12ctxt) { |
| 884 return SECFailure; |
| 885 } |
| 886 |
| 887 mark = PORT_ArenaMark(safeBag->arena); |
| 888 |
| 889 /* allocate the attribute */ |
| 890 attribute = (sec_PKCS12Attribute *)PORT_ArenaZAlloc(safeBag->arena, |
| 891 sizeof(sec_PKCS12Attribute)); |
| 892 if(!attribute) { |
| 893 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 894 goto loser; |
| 895 } |
| 896 |
| 897 /* set up the attribute */ |
| 898 oiddata = SECOID_FindOIDByTag(attrType); |
| 899 if(!oiddata) { |
| 900 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 901 goto loser; |
| 902 } |
| 903 if(SECITEM_CopyItem(p12ctxt->arena, &attribute->attrType, &oiddata->oid) != |
| 904 SECSuccess) { |
| 905 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 906 goto loser; |
| 907 } |
| 908 |
| 909 nItems = 1; |
| 910 switch(attrType) { |
| 911 case SEC_OID_PKCS9_LOCAL_KEY_ID: |
| 912 { |
| 913 src = attrData; |
| 914 break; |
| 915 } |
| 916 case SEC_OID_PKCS9_FRIENDLY_NAME: |
| 917 { |
| 918 if(!sec_pkcs12_convert_item_to_unicode(p12ctxt->arena, |
| 919 &unicodeName, attrData, PR_FALSE, |
| 920 PR_FALSE, PR_TRUE)) { |
| 921 goto loser; |
| 922 } |
| 923 src = &unicodeName; |
| 924 break; |
| 925 } |
| 926 default: |
| 927 goto loser; |
| 928 } |
| 929 |
| 930 /* append the attribute to the attribute value list */ |
| 931 attribute->attrValue = (SECItem **)PORT_ArenaZAlloc(p12ctxt->arena, |
| 932 ((nItems + 1) * sizeof(SECItem *))); |
| 933 if(!attribute->attrValue) { |
| 934 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 935 goto loser; |
| 936 } |
| 937 |
| 938 /* XXX this will need to be changed if attributes requiring more than |
| 939 * one element are ever used. |
| 940 */ |
| 941 attribute->attrValue[0] = (SECItem *)PORT_ArenaZAlloc(p12ctxt->arena, |
| 942 sizeof(SECItem)); |
| 943 if(!attribute->attrValue[0]) { |
| 944 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 945 goto loser; |
| 946 } |
| 947 attribute->attrValue[1] = NULL; |
| 948 |
| 949 rv = SECITEM_CopyItem(p12ctxt->arena, attribute->attrValue[0], |
| 950 (SECItem*)src); |
| 951 if(rv != SECSuccess) { |
| 952 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 953 goto loser; |
| 954 } |
| 955 |
| 956 /* append the attribute to the safeBag attributes */ |
| 957 if(safeBag->nAttribs) { |
| 958 dummy = PORT_ArenaGrow(p12ctxt->arena, safeBag->attribs, |
| 959 ((safeBag->nAttribs + 1) * sizeof(sec_PKCS12Attribute *)
), |
| 960 ((safeBag->nAttribs + 2) * sizeof(sec_PKCS12Attribute *)
)); |
| 961 safeBag->attribs = (sec_PKCS12Attribute **)dummy; |
| 962 } else { |
| 963 safeBag->attribs = (sec_PKCS12Attribute **)PORT_ArenaZAlloc(p12ctxt->are
na, |
| 964 2 * sizeof(sec_PKCS12Attribute *
)); |
| 965 dummy = safeBag->attribs; |
| 966 } |
| 967 if(!dummy) { |
| 968 goto loser; |
| 969 } |
| 970 |
| 971 safeBag->attribs[safeBag->nAttribs] = attribute; |
| 972 safeBag->attribs[++safeBag->nAttribs] = NULL; |
| 973 |
| 974 PORT_ArenaUnmark(p12ctxt->arena, mark); |
| 975 return SECSuccess; |
| 976 |
| 977 loser: |
| 978 if(mark) { |
| 979 PORT_ArenaRelease(p12ctxt->arena, mark); |
| 980 } |
| 981 |
| 982 return SECFailure; |
| 983 } |
| 984 |
| 985 /* SEC_PKCS12AddCert |
| 986 * Adds a certificate to the data being exported. |
| 987 * |
| 988 * p12ctxt - the export context |
| 989 * safe - the safeInfo to which the certificate is placed |
| 990 * nestedDest - if the cert is to be placed within a nested safeContents th
en, |
| 991 * this value is to be specified with the destination |
| 992 * cert - the cert to export |
| 993 * certDb - the certificate database handle |
| 994 * keyId - a unique identifier to associate a certificate/key pair |
| 995 * includeCertChain - PR_TRUE if the certificate chain is to be included. |
| 996 */ |
| 997 SECStatus |
| 998 SEC_PKCS12AddCert(SEC_PKCS12ExportContext *p12ctxt, SEC_PKCS12SafeInfo *safe, |
| 999 void *nestedDest, CERTCertificate *cert, |
| 1000 CERTCertDBHandle *certDb, SECItem *keyId, |
| 1001 PRBool includeCertChain) |
| 1002 { |
| 1003 sec_PKCS12CertBag *certBag; |
| 1004 sec_PKCS12SafeBag *safeBag; |
| 1005 void *mark; |
| 1006 SECStatus rv; |
| 1007 SECItem nick = {siBuffer, NULL,0}; |
| 1008 |
| 1009 if(!p12ctxt || !cert) { |
| 1010 return SECFailure; |
| 1011 } |
| 1012 mark = PORT_ArenaMark(p12ctxt->arena); |
| 1013 |
| 1014 /* allocate the cert bag */ |
| 1015 certBag = sec_PKCS12NewCertBag(p12ctxt->arena, |
| 1016 SEC_OID_PKCS9_X509_CERT); |
| 1017 if(!certBag) { |
| 1018 goto loser; |
| 1019 } |
| 1020 |
| 1021 if(SECITEM_CopyItem(p12ctxt->arena, &certBag->value.x509Cert, |
| 1022 &cert->derCert) != SECSuccess) { |
| 1023 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 1024 goto loser; |
| 1025 } |
| 1026 |
| 1027 /* if the cert chain is to be included, we should only be exporting |
| 1028 * the cert from our internal database. |
| 1029 */ |
| 1030 if(includeCertChain) { |
| 1031 CERTCertificateList *certList = CERT_CertChainFromCert(cert, |
| 1032 certUsageSSLClien
t, |
| 1033 PR_TRUE); |
| 1034 unsigned int count = 0; |
| 1035 if(!certList) { |
| 1036 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 1037 goto loser; |
| 1038 } |
| 1039 |
| 1040 /* add cert chain */ |
| 1041 for(count = 0; count < (unsigned int)certList->len; count++) { |
| 1042 if(SECITEM_CompareItem(&certList->certs[count], &cert->derCert) |
| 1043 != SECEqual) { |
| 1044 CERTCertificate *tempCert; |
| 1045 |
| 1046 /* decode the certificate */ |
| 1047 /* XXX |
| 1048 * This was rather silly. The chain is constructed above |
| 1049 * by finding all of the CERTCertificate's in the database. |
| 1050 * Then the chain is put into a CERTCertificateList, which only |
| 1051 * contains the DER. Finally, the DER was decoded, and the |
| 1052 * decoded cert was sent recursively back to this function. |
| 1053 * Beyond being inefficent, this causes data loss (specifically, |
| 1054 * the nickname). Instead, for 3.4, we'll do a lookup by the |
| 1055 * DER, which should return the cached entry. |
| 1056 */ |
| 1057 tempCert = CERT_FindCertByDERCert(CERT_GetDefaultCertDB(), |
| 1058 &certList->certs[count]); |
| 1059 if(!tempCert) { |
| 1060 CERT_DestroyCertificateList(certList); |
| 1061 goto loser; |
| 1062 } |
| 1063 |
| 1064 /* add the certificate */ |
| 1065 if(SEC_PKCS12AddCert(p12ctxt, safe, nestedDest, tempCert, |
| 1066 certDb, NULL, PR_FALSE) != SECSuccess) { |
| 1067 CERT_DestroyCertificate(tempCert); |
| 1068 CERT_DestroyCertificateList(certList); |
| 1069 goto loser; |
| 1070 } |
| 1071 CERT_DestroyCertificate(tempCert); |
| 1072 } |
| 1073 } |
| 1074 CERT_DestroyCertificateList(certList); |
| 1075 } |
| 1076 |
| 1077 /* if the certificate has a nickname, we will set the friendly name |
| 1078 * to that. |
| 1079 */ |
| 1080 if(cert->nickname) { |
| 1081 if (cert->slot && !PK11_IsInternal(cert->slot)) { |
| 1082 /* |
| 1083 * The cert is coming off of an external token, |
| 1084 * let's strip the token name from the nickname |
| 1085 * and only add what comes after the colon as the |
| 1086 * nickname. -javi |
| 1087 */ |
| 1088 char *delimit; |
| 1089 |
| 1090 delimit = PORT_Strchr(cert->nickname,':'); |
| 1091 if (delimit == NULL) { |
| 1092 nick.data = (unsigned char *)cert->nickname; |
| 1093 nick.len = PORT_Strlen(cert->nickname); |
| 1094 } else { |
| 1095 delimit++; |
| 1096 nick.data = (unsigned char *)PORT_ArenaStrdup(p12ctxt->arena, |
| 1097 delimit); |
| 1098 nick.len = PORT_Strlen(delimit); |
| 1099 } |
| 1100 } else { |
| 1101 nick.data = (unsigned char *)cert->nickname; |
| 1102 nick.len = PORT_Strlen(cert->nickname); |
| 1103 } |
| 1104 } |
| 1105 |
| 1106 safeBag = sec_PKCS12CreateSafeBag(p12ctxt, SEC_OID_PKCS12_V1_CERT_BAG_ID, |
| 1107 certBag); |
| 1108 if(!safeBag) { |
| 1109 goto loser; |
| 1110 } |
| 1111 |
| 1112 /* add the friendly name and keyId attributes, if necessary */ |
| 1113 if(nick.data) { |
| 1114 if(sec_PKCS12AddAttributeToBag(p12ctxt, safeBag, |
| 1115 SEC_OID_PKCS9_FRIENDLY_NAME, &nick) |
| 1116 != SECSuccess) { |
| 1117 goto loser; |
| 1118 } |
| 1119 } |
| 1120 |
| 1121 if(keyId) { |
| 1122 if(sec_PKCS12AddAttributeToBag(p12ctxt, safeBag, SEC_OID_PKCS9_LOCAL_KEY
_ID, |
| 1123 keyId) != SECSuccess) { |
| 1124 goto loser; |
| 1125 } |
| 1126 } |
| 1127 |
| 1128 /* append the cert safeBag */ |
| 1129 if(nestedDest) { |
| 1130 rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena, |
| 1131 (sec_PKCS12SafeContents*)nestedDest, |
| 1132 safeBag); |
| 1133 } else { |
| 1134 rv = sec_pkcs12_append_bag(p12ctxt, safe, safeBag); |
| 1135 } |
| 1136 |
| 1137 if(rv != SECSuccess) { |
| 1138 goto loser; |
| 1139 } |
| 1140 |
| 1141 PORT_ArenaUnmark(p12ctxt->arena, mark); |
| 1142 return SECSuccess; |
| 1143 |
| 1144 loser: |
| 1145 if(mark) { |
| 1146 PORT_ArenaRelease(p12ctxt->arena, mark); |
| 1147 } |
| 1148 |
| 1149 return SECFailure; |
| 1150 } |
| 1151 |
| 1152 /* SEC_PKCS12AddKeyForCert |
| 1153 * Extracts the key associated with a particular certificate and exports |
| 1154 * it. |
| 1155 * |
| 1156 * p12ctxt - the export context |
| 1157 * safe - the safeInfo to place the key in |
| 1158 * nestedDest - the nested safeContents to place a key |
| 1159 * cert - the certificate which the key belongs to |
| 1160 * shroudKey - encrypt the private key for export. This value should |
| 1161 * always be true. lower level code will not allow the export |
| 1162 * of unencrypted private keys. |
| 1163 * algorithm - the algorithm with which to encrypt the private key |
| 1164 * pwitem - the password to encrypt the private key with |
| 1165 * keyId - the keyID attribute |
| 1166 * nickName - the nickname attribute |
| 1167 */ |
| 1168 SECStatus |
| 1169 SEC_PKCS12AddKeyForCert(SEC_PKCS12ExportContext *p12ctxt, SEC_PKCS12SafeInfo *sa
fe, |
| 1170 void *nestedDest, CERTCertificate *cert, |
| 1171 PRBool shroudKey, SECOidTag algorithm, SECItem *pwitem, |
| 1172 SECItem *keyId, SECItem *nickName) |
| 1173 { |
| 1174 void *mark; |
| 1175 void *keyItem; |
| 1176 SECOidTag keyType; |
| 1177 SECStatus rv = SECFailure; |
| 1178 SECItem nickname = {siBuffer,NULL,0}, uniPwitem = {siBuffer, NULL, 0}; |
| 1179 sec_PKCS12SafeBag *returnBag; |
| 1180 |
| 1181 if(!p12ctxt || !cert || !safe) { |
| 1182 return SECFailure; |
| 1183 } |
| 1184 |
| 1185 mark = PORT_ArenaMark(p12ctxt->arena); |
| 1186 |
| 1187 /* retrieve the key based upon the type that it is and |
| 1188 * specify the type of safeBag to store the key in |
| 1189 */ |
| 1190 if(!shroudKey) { |
| 1191 |
| 1192 /* extract the key unencrypted. this will most likely go away */ |
| 1193 SECKEYPrivateKeyInfo *pki = PK11_ExportPrivateKeyInfo(cert, |
| 1194 p12ctxt->wincx); |
| 1195 if(!pki) { |
| 1196 PORT_ArenaRelease(p12ctxt->arena, mark); |
| 1197 PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY); |
| 1198 return SECFailure; |
| 1199 } |
| 1200 keyItem = PORT_ArenaZAlloc(p12ctxt->arena, sizeof(SECKEYPrivateKeyInfo))
; |
| 1201 if(!keyItem) { |
| 1202 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 1203 goto loser; |
| 1204 } |
| 1205 rv = SECKEY_CopyPrivateKeyInfo(p12ctxt->arena, |
| 1206 (SECKEYPrivateKeyInfo *)keyItem, pki); |
| 1207 keyType = SEC_OID_PKCS12_V1_KEY_BAG_ID; |
| 1208 SECKEY_DestroyPrivateKeyInfo(pki, PR_TRUE); |
| 1209 } else { |
| 1210 |
| 1211 /* extract the key encrypted */ |
| 1212 SECKEYEncryptedPrivateKeyInfo *epki = NULL; |
| 1213 PK11SlotInfo *slot = NULL; |
| 1214 |
| 1215 if(!sec_pkcs12_convert_item_to_unicode(p12ctxt->arena, &uniPwitem, |
| 1216 pwitem, PR_TRUE, PR_TRUE, PR_TRUE)) { |
| 1217 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 1218 goto loser; |
| 1219 } |
| 1220 |
| 1221 /* we want to make sure to take the key out of the key slot */ |
| 1222 if(PK11_IsInternal(p12ctxt->slot)) { |
| 1223 slot = PK11_GetInternalKeySlot(); |
| 1224 } else { |
| 1225 slot = PK11_ReferenceSlot(p12ctxt->slot); |
| 1226 } |
| 1227 |
| 1228 epki = PK11_ExportEncryptedPrivateKeyInfo(slot, algorithm, |
| 1229 &uniPwitem, cert, |
| 1230 NSS_PBE_DEFAULT_ITERATION_COUNT, |
| 1231 p12ctxt->wincx); |
| 1232 PK11_FreeSlot(slot); |
| 1233 if(!epki) { |
| 1234 PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY); |
| 1235 goto loser; |
| 1236 } |
| 1237 |
| 1238 keyItem = PORT_ArenaZAlloc(p12ctxt->arena, |
| 1239 sizeof(SECKEYEncryptedPrivateKeyInfo)); |
| 1240 if(!keyItem) { |
| 1241 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 1242 goto loser; |
| 1243 } |
| 1244 rv = SECKEY_CopyEncryptedPrivateKeyInfo(p12ctxt->arena, |
| 1245 (SECKEYEncryptedPrivateKeyInfo *)keyItem
, |
| 1246 epki); |
| 1247 keyType = SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID; |
| 1248 SECKEY_DestroyEncryptedPrivateKeyInfo(epki, PR_TRUE); |
| 1249 } |
| 1250 |
| 1251 if(rv != SECSuccess) { |
| 1252 goto loser; |
| 1253 } |
| 1254 |
| 1255 /* if no nickname specified, let's see if the certificate has a |
| 1256 * nickname. |
| 1257 */ |
| 1258 if(!nickName) { |
| 1259 if(cert->nickname) { |
| 1260 nickname.data = (unsigned char *)cert->nickname; |
| 1261 nickname.len = PORT_Strlen(cert->nickname); |
| 1262 nickName = &nickname; |
| 1263 } |
| 1264 } |
| 1265 |
| 1266 /* create the safe bag and set any attributes */ |
| 1267 returnBag = sec_PKCS12CreateSafeBag(p12ctxt, keyType, keyItem); |
| 1268 if(!returnBag) { |
| 1269 rv = SECFailure; |
| 1270 goto loser; |
| 1271 } |
| 1272 |
| 1273 if(nickName) { |
| 1274 if(sec_PKCS12AddAttributeToBag(p12ctxt, returnBag, |
| 1275 SEC_OID_PKCS9_FRIENDLY_NAME, nickName) |
| 1276 != SECSuccess) { |
| 1277 goto loser; |
| 1278 } |
| 1279 } |
| 1280 |
| 1281 if(keyId) { |
| 1282 if(sec_PKCS12AddAttributeToBag(p12ctxt, returnBag, SEC_OID_PKCS9_LOCAL_K
EY_ID, |
| 1283 keyId) != SECSuccess) { |
| 1284 goto loser; |
| 1285 } |
| 1286 } |
| 1287 |
| 1288 if(nestedDest) { |
| 1289 rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena, |
| 1290 (sec_PKCS12SafeContents*)nestedDest, |
| 1291 returnBag); |
| 1292 } else { |
| 1293 rv = sec_pkcs12_append_bag(p12ctxt, safe, returnBag); |
| 1294 } |
| 1295 |
| 1296 loser: |
| 1297 |
| 1298 if (rv != SECSuccess) { |
| 1299 PORT_ArenaRelease(p12ctxt->arena, mark); |
| 1300 } else { |
| 1301 PORT_ArenaUnmark(p12ctxt->arena, mark); |
| 1302 } |
| 1303 |
| 1304 return rv; |
| 1305 } |
| 1306 |
| 1307 /* SEC_PKCS12AddCertOrChainAndKey |
| 1308 * Add a certificate and key pair to be exported. |
| 1309 * |
| 1310 * p12ctxt - the export context |
| 1311 * certSafe - the safeInfo where the cert is stored |
| 1312 * certNestedDest - the nested safeContents to store the cert |
| 1313 * keySafe - the safeInfo where the key is stored |
| 1314 * keyNestedDest - the nested safeContents to store the key |
| 1315 * shroudKey - extract the private key encrypted? |
| 1316 * pwitem - the password with which the key is encrypted |
| 1317 * algorithm - the algorithm with which the key is encrypted |
| 1318 * includeCertChain - also add certs from chain to bag. |
| 1319 */ |
| 1320 SECStatus |
| 1321 SEC_PKCS12AddCertOrChainAndKey(SEC_PKCS12ExportContext *p12ctxt, |
| 1322 void *certSafe, void *certNestedDest, |
| 1323 CERTCertificate *cert, CERTCertDBHandle *certDb, |
| 1324 void *keySafe, void *keyNestedDest, |
| 1325 PRBool shroudKey, SECItem *pwitem, |
| 1326 SECOidTag algorithm, PRBool includeCertChain) |
| 1327 { |
| 1328 SECStatus rv = SECFailure; |
| 1329 SGNDigestInfo *digest = NULL; |
| 1330 void *mark = NULL; |
| 1331 |
| 1332 if(!p12ctxt || !certSafe || !keySafe || !cert) { |
| 1333 return SECFailure; |
| 1334 } |
| 1335 |
| 1336 mark = PORT_ArenaMark(p12ctxt->arena); |
| 1337 |
| 1338 /* generate the thumbprint of the cert to use as a keyId */ |
| 1339 digest = sec_pkcs12_compute_thumbprint(&cert->derCert); |
| 1340 if(!digest) { |
| 1341 PORT_ArenaRelease(p12ctxt->arena, mark); |
| 1342 return SECFailure; |
| 1343 } |
| 1344 |
| 1345 /* add the certificate */ |
| 1346 rv = SEC_PKCS12AddCert(p12ctxt, (SEC_PKCS12SafeInfo*)certSafe, |
| 1347 (SEC_PKCS12SafeInfo*)certNestedDest, cert, certDb, |
| 1348 &digest->digest, includeCertChain); |
| 1349 if(rv != SECSuccess) { |
| 1350 goto loser; |
| 1351 } |
| 1352 |
| 1353 /* add the key */ |
| 1354 rv = SEC_PKCS12AddKeyForCert(p12ctxt, (SEC_PKCS12SafeInfo*)keySafe, |
| 1355 keyNestedDest, cert, |
| 1356 shroudKey, algorithm, pwitem, |
| 1357 &digest->digest, NULL ); |
| 1358 if(rv != SECSuccess) { |
| 1359 goto loser; |
| 1360 } |
| 1361 |
| 1362 SGN_DestroyDigestInfo(digest); |
| 1363 |
| 1364 PORT_ArenaUnmark(p12ctxt->arena, mark); |
| 1365 return SECSuccess; |
| 1366 |
| 1367 loser: |
| 1368 SGN_DestroyDigestInfo(digest); |
| 1369 PORT_ArenaRelease(p12ctxt->arena, mark); |
| 1370 |
| 1371 return SECFailure; |
| 1372 } |
| 1373 |
| 1374 /* like SEC_PKCS12AddCertOrChainAndKey, but always adds cert chain */ |
| 1375 SECStatus |
| 1376 SEC_PKCS12AddCertAndKey(SEC_PKCS12ExportContext *p12ctxt, |
| 1377 void *certSafe, void *certNestedDest, |
| 1378 CERTCertificate *cert, CERTCertDBHandle *certDb, |
| 1379 void *keySafe, void *keyNestedDest, |
| 1380 PRBool shroudKey, SECItem *pwItem, SECOidTag algorithm) |
| 1381 { |
| 1382 return SEC_PKCS12AddCertOrChainAndKey(p12ctxt, certSafe, certNestedDest, |
| 1383 cert, certDb, keySafe, keyNestedDest, shroudKey, pwItem, |
| 1384 algorithm, PR_TRUE); |
| 1385 } |
| 1386 |
| 1387 |
| 1388 /* SEC_PKCS12CreateNestedSafeContents |
| 1389 * Allows nesting of safe contents to be implemented. No limit imposed on |
| 1390 * depth. |
| 1391 * |
| 1392 * p12ctxt - the export context |
| 1393 * baseSafe - the base safeInfo |
| 1394 * nestedDest - a parent safeContents (?) |
| 1395 */ |
| 1396 void * |
| 1397 SEC_PKCS12CreateNestedSafeContents(SEC_PKCS12ExportContext *p12ctxt, |
| 1398 void *baseSafe, void *nestedDest) |
| 1399 { |
| 1400 sec_PKCS12SafeContents *newSafe; |
| 1401 sec_PKCS12SafeBag *safeContentsBag; |
| 1402 void *mark; |
| 1403 SECStatus rv; |
| 1404 |
| 1405 if(!p12ctxt || !baseSafe) { |
| 1406 return NULL; |
| 1407 } |
| 1408 |
| 1409 mark = PORT_ArenaMark(p12ctxt->arena); |
| 1410 |
| 1411 newSafe = sec_PKCS12CreateSafeContents(p12ctxt->arena); |
| 1412 if(!newSafe) { |
| 1413 PORT_ArenaRelease(p12ctxt->arena, mark); |
| 1414 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 1415 return NULL; |
| 1416 } |
| 1417 |
| 1418 /* create the safeContents safeBag */ |
| 1419 safeContentsBag = sec_PKCS12CreateSafeBag(p12ctxt, |
| 1420 SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID, |
| 1421 newSafe); |
| 1422 if(!safeContentsBag) { |
| 1423 goto loser; |
| 1424 } |
| 1425 |
| 1426 /* append the safeContents to the appropriate area */ |
| 1427 if(nestedDest) { |
| 1428 rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena, |
| 1429 (sec_PKCS12SafeContents*)nestedDest, |
| 1430 safeContentsBag); |
| 1431 } else { |
| 1432 rv = sec_pkcs12_append_bag(p12ctxt, (SEC_PKCS12SafeInfo*)baseSafe, |
| 1433 safeContentsBag); |
| 1434 } |
| 1435 if(rv != SECSuccess) { |
| 1436 goto loser; |
| 1437 } |
| 1438 |
| 1439 PORT_ArenaUnmark(p12ctxt->arena, mark); |
| 1440 return newSafe; |
| 1441 |
| 1442 loser: |
| 1443 PORT_ArenaRelease(p12ctxt->arena, mark); |
| 1444 return NULL; |
| 1445 } |
| 1446 |
| 1447 /********************************* |
| 1448 * Encoding routines |
| 1449 *********************************/ |
| 1450 |
| 1451 /* Clean up the resources allocated by a sec_PKCS12EncoderContext. */ |
| 1452 static void |
| 1453 sec_pkcs12_encoder_destroy_context(sec_PKCS12EncoderContext *p12enc) |
| 1454 { |
| 1455 if(p12enc) { |
| 1456 if(p12enc->outerA1ecx) { |
| 1457 SEC_ASN1EncoderFinish(p12enc->outerA1ecx); |
| 1458 p12enc->outerA1ecx = NULL; |
| 1459 } |
| 1460 if(p12enc->aSafeCinfo) { |
| 1461 SEC_PKCS7DestroyContentInfo(p12enc->aSafeCinfo); |
| 1462 p12enc->aSafeCinfo = NULL; |
| 1463 } |
| 1464 if(p12enc->middleP7ecx) { |
| 1465 SEC_PKCS7EncoderFinish(p12enc->middleP7ecx, p12enc->p12exp->pwfn, |
| 1466 p12enc->p12exp->pwfnarg); |
| 1467 p12enc->middleP7ecx = NULL; |
| 1468 } |
| 1469 if(p12enc->middleA1ecx) { |
| 1470 SEC_ASN1EncoderFinish(p12enc->middleA1ecx); |
| 1471 p12enc->middleA1ecx = NULL; |
| 1472 } |
| 1473 if(p12enc->hmacCx) { |
| 1474 PK11_DestroyContext(p12enc->hmacCx, PR_TRUE); |
| 1475 p12enc->hmacCx = NULL; |
| 1476 } |
| 1477 } |
| 1478 } |
| 1479 |
| 1480 /* set up the encoder context based on information in the export context |
| 1481 * and return the newly allocated enocoder context. A return of NULL |
| 1482 * indicates an error occurred. |
| 1483 */ |
| 1484 static sec_PKCS12EncoderContext * |
| 1485 sec_pkcs12_encoder_start_context(SEC_PKCS12ExportContext *p12exp) |
| 1486 { |
| 1487 sec_PKCS12EncoderContext *p12enc = NULL; |
| 1488 unsigned int i, nonEmptyCnt; |
| 1489 SECStatus rv; |
| 1490 SECItem ignore = {0}; |
| 1491 void *mark; |
| 1492 |
| 1493 if(!p12exp || !p12exp->safeInfos) { |
| 1494 return NULL; |
| 1495 } |
| 1496 |
| 1497 /* check for any empty safes and skip them */ |
| 1498 i = nonEmptyCnt = 0; |
| 1499 while(p12exp->safeInfos[i]) { |
| 1500 if(p12exp->safeInfos[i]->itemCount) { |
| 1501 nonEmptyCnt++; |
| 1502 } |
| 1503 i++; |
| 1504 } |
| 1505 if(nonEmptyCnt == 0) { |
| 1506 return NULL; |
| 1507 } |
| 1508 p12exp->authSafe.encodedSafes[nonEmptyCnt] = NULL; |
| 1509 |
| 1510 /* allocate the encoder context */ |
| 1511 mark = PORT_ArenaMark(p12exp->arena); |
| 1512 p12enc = PORT_ArenaZNew(p12exp->arena, sec_PKCS12EncoderContext); |
| 1513 if(!p12enc) { |
| 1514 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 1515 return NULL; |
| 1516 } |
| 1517 |
| 1518 p12enc->arena = p12exp->arena; |
| 1519 p12enc->p12exp = p12exp; |
| 1520 |
| 1521 /* set up the PFX version and information */ |
| 1522 PORT_Memset(&p12enc->pfx, 0, sizeof(sec_PKCS12PFXItem)); |
| 1523 if(!SEC_ASN1EncodeInteger(p12exp->arena, &(p12enc->pfx.version), |
| 1524 SEC_PKCS12_VERSION) ) { |
| 1525 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 1526 goto loser; |
| 1527 } |
| 1528 |
| 1529 /* set up the authenticated safe content info based on the |
| 1530 * type of integrity being used. this should be changed to |
| 1531 * enforce integrity mode, but will not be implemented until |
| 1532 * it is confirmed that integrity must be in place |
| 1533 */ |
| 1534 if(p12exp->integrityEnabled && !p12exp->pwdIntegrity) { |
| 1535 SECStatus rv; |
| 1536 |
| 1537 /* create public key integrity mode */ |
| 1538 p12enc->aSafeCinfo = SEC_PKCS7CreateSignedData( |
| 1539 p12exp->integrityInfo.pubkeyInfo.cert, |
| 1540 certUsageEmailSigner, |
| 1541 p12exp->integrityInfo.pubkeyInfo.certDb, |
| 1542 p12exp->integrityInfo.pubkeyInfo.algorithm, |
| 1543 NULL, |
| 1544 p12exp->pwfn, |
| 1545 p12exp->pwfnarg); |
| 1546 if(!p12enc->aSafeCinfo) { |
| 1547 goto loser; |
| 1548 } |
| 1549 if(SEC_PKCS7IncludeCertChain(p12enc->aSafeCinfo,NULL) != SECSuccess) { |
| 1550 goto loser; |
| 1551 } |
| 1552 rv = SEC_PKCS7AddSigningTime(p12enc->aSafeCinfo); |
| 1553 PORT_Assert(rv == SECSuccess); |
| 1554 } else { |
| 1555 p12enc->aSafeCinfo = SEC_PKCS7CreateData(); |
| 1556 |
| 1557 /* init password pased integrity mode */ |
| 1558 if(p12exp->integrityEnabled) { |
| 1559 SECItem pwd = {siBuffer,NULL, 0}; |
| 1560 SECItem *salt = sec_pkcs12_generate_salt(); |
| 1561 PK11SymKey *symKey; |
| 1562 SECItem *params; |
| 1563 CK_MECHANISM_TYPE integrityMechType; |
| 1564 CK_MECHANISM_TYPE hmacMechType; |
| 1565 |
| 1566 /* zero out macData and set values */ |
| 1567 PORT_Memset(&p12enc->mac, 0, sizeof(sec_PKCS12MacData)); |
| 1568 |
| 1569 if(!salt) { |
| 1570 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 1571 goto loser; |
| 1572 } |
| 1573 if(SECITEM_CopyItem(p12exp->arena, &(p12enc->mac.macSalt), salt) |
| 1574 != SECSuccess) { |
| 1575 /* XXX salt is leaked */ |
| 1576 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 1577 goto loser; |
| 1578 } |
| 1579 if (!SEC_ASN1EncodeInteger(p12exp->arena, &(p12enc->mac.iter), |
| 1580 NSS_PBE_DEFAULT_ITERATION_COUNT)) { |
| 1581 /* XXX salt is leaked */ |
| 1582 goto loser; |
| 1583 } |
| 1584 |
| 1585 /* generate HMAC key */ |
| 1586 if(!sec_pkcs12_convert_item_to_unicode(NULL, &pwd, |
| 1587 p12exp->integrityInfo.pwdInfo.password, PR_TRUE, |
| 1588 PR_TRUE, PR_TRUE)) { |
| 1589 /* XXX salt is leaked */ |
| 1590 goto loser; |
| 1591 } |
| 1592 /* |
| 1593 * This code only works with PKCS #12 Mac using PKCS #5 v1 |
| 1594 * PBA keygens. PKCS #5 v2 support will require a change to |
| 1595 * the PKCS #12 spec. |
| 1596 */ |
| 1597 params = PK11_CreatePBEParams(salt, &pwd, |
| 1598 NSS_PBE_DEFAULT_ITERATION_COUNT); |
| 1599 SECITEM_ZfreeItem(salt, PR_TRUE); |
| 1600 SECITEM_ZfreeItem(&pwd, PR_FALSE); |
| 1601 |
| 1602 /* get the PBA Mechanism to generate the key */ |
| 1603 switch (p12exp->integrityInfo.pwdInfo.algorithm) { |
| 1604 case SEC_OID_SHA1: |
| 1605 integrityMechType = CKM_PBA_SHA1_WITH_SHA1_HMAC; break; |
| 1606 case SEC_OID_MD5: |
| 1607 integrityMechType = CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN; break; |
| 1608 case SEC_OID_MD2: |
| 1609 integrityMechType = CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN; break; |
| 1610 default: |
| 1611 /* XXX params is leaked */ |
| 1612 goto loser; |
| 1613 } |
| 1614 |
| 1615 /* generate the key */ |
| 1616 symKey = PK11_KeyGen(NULL, integrityMechType, params, 20, NULL); |
| 1617 PK11_DestroyPBEParams(params); |
| 1618 if(!symKey) { |
| 1619 goto loser; |
| 1620 } |
| 1621 |
| 1622 /* initialize HMAC */ |
| 1623 /* Get the HMAC mechanism from the hash OID */ |
| 1624 hmacMechType= sec_pkcs12_algtag_to_mech( |
| 1625 p12exp->integrityInfo.pwdInfo.algorithm); |
| 1626 |
| 1627 p12enc->hmacCx = PK11_CreateContextBySymKey( hmacMechType, |
| 1628 CKA_SIGN, symKey, &ignore); |
| 1629 |
| 1630 PK11_FreeSymKey(symKey); |
| 1631 if(!p12enc->hmacCx) { |
| 1632 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 1633 goto loser; |
| 1634 } |
| 1635 rv = PK11_DigestBegin(p12enc->hmacCx); |
| 1636 if (rv != SECSuccess) |
| 1637 goto loser; |
| 1638 } |
| 1639 } |
| 1640 |
| 1641 if(!p12enc->aSafeCinfo) { |
| 1642 goto loser; |
| 1643 } |
| 1644 |
| 1645 PORT_ArenaUnmark(p12exp->arena, mark); |
| 1646 |
| 1647 return p12enc; |
| 1648 |
| 1649 loser: |
| 1650 sec_pkcs12_encoder_destroy_context(p12enc); |
| 1651 if (p12exp->arena != NULL) |
| 1652 PORT_ArenaRelease(p12exp->arena, mark); |
| 1653 |
| 1654 return NULL; |
| 1655 } |
| 1656 |
| 1657 /* The outermost ASN.1 encoder calls this function for output. |
| 1658 ** This function calls back to the library caller's output routine, |
| 1659 ** which typically writes to a PKCS12 file. |
| 1660 */ |
| 1661 static void |
| 1662 sec_P12A1OutputCB_Outer(void *arg, const char *buf, unsigned long len, |
| 1663 int depth, SEC_ASN1EncodingPart data_kind) |
| 1664 { |
| 1665 struct sec_pkcs12_encoder_output *output; |
| 1666 |
| 1667 output = (struct sec_pkcs12_encoder_output*)arg; |
| 1668 (* output->outputfn)(output->outputarg, buf, len); |
| 1669 } |
| 1670 |
| 1671 /* The "middle" and "inner" ASN.1 encoders call this function to output. |
| 1672 ** This function does HMACing, if appropriate, and then buffers the data. |
| 1673 ** The buffered data is eventually passed down to the underlying PKCS7 encoder. |
| 1674 */ |
| 1675 static void |
| 1676 sec_P12A1OutputCB_HmacP7Update(void *arg, const char *buf, |
| 1677 unsigned long len, |
| 1678 int depth, |
| 1679 SEC_ASN1EncodingPart data_kind) |
| 1680 { |
| 1681 sec_pkcs12OutputBuffer * bufcx = (sec_pkcs12OutputBuffer *)arg; |
| 1682 |
| 1683 if(!buf || !len) |
| 1684 return; |
| 1685 |
| 1686 if (bufcx->hmacCx) { |
| 1687 PK11_DigestOp(bufcx->hmacCx, (unsigned char *)buf, len); |
| 1688 } |
| 1689 |
| 1690 /* buffer */ |
| 1691 if (bufcx->numBytes > 0) { |
| 1692 int toCopy; |
| 1693 if (len + bufcx->numBytes <= bufcx->bufBytes) { |
| 1694 memcpy(bufcx->buf + bufcx->numBytes, buf, len); |
| 1695 bufcx->numBytes += len; |
| 1696 if (bufcx->numBytes < bufcx->bufBytes) |
| 1697 return; |
| 1698 SEC_PKCS7EncoderUpdate(bufcx->p7eCx, bufcx->buf, bufcx->bufBytes); |
| 1699 bufcx->numBytes = 0; |
| 1700 return; |
| 1701 } |
| 1702 toCopy = bufcx->bufBytes - bufcx->numBytes; |
| 1703 memcpy(bufcx->buf + bufcx->numBytes, buf, toCopy); |
| 1704 SEC_PKCS7EncoderUpdate(bufcx->p7eCx, bufcx->buf, bufcx->bufBytes); |
| 1705 bufcx->numBytes = 0; |
| 1706 len -= toCopy; |
| 1707 buf += toCopy; |
| 1708 } |
| 1709 /* buffer is presently empty */ |
| 1710 if (len >= bufcx->bufBytes) { |
| 1711 /* Just pass it through */ |
| 1712 SEC_PKCS7EncoderUpdate(bufcx->p7eCx, buf, len); |
| 1713 } else { |
| 1714 /* copy it all into the buffer, and return */ |
| 1715 memcpy(bufcx->buf, buf, len); |
| 1716 bufcx->numBytes = len; |
| 1717 } |
| 1718 } |
| 1719 |
| 1720 void |
| 1721 sec_FlushPkcs12OutputBuffer( sec_pkcs12OutputBuffer * bufcx) |
| 1722 { |
| 1723 if (bufcx->numBytes > 0) { |
| 1724 SEC_PKCS7EncoderUpdate(bufcx->p7eCx, bufcx->buf, bufcx->numBytes); |
| 1725 bufcx->numBytes = 0; |
| 1726 } |
| 1727 } |
| 1728 |
| 1729 /* Feeds the output of a PKCS7 encoder into the next outward ASN.1 encoder. |
| 1730 ** This function is used by both the inner and middle PCS7 encoders. |
| 1731 */ |
| 1732 static void |
| 1733 sec_P12P7OutputCB_CallA1Update(void *arg, const char *buf, unsigned long len) |
| 1734 { |
| 1735 SEC_ASN1EncoderContext *cx = (SEC_ASN1EncoderContext*)arg; |
| 1736 |
| 1737 if (!buf || !len) |
| 1738 return; |
| 1739 |
| 1740 SEC_ASN1EncoderUpdate(cx, buf, len); |
| 1741 } |
| 1742 |
| 1743 |
| 1744 /* this function encodes content infos which are part of the |
| 1745 * sequence of content infos labeled AuthenticatedSafes |
| 1746 */ |
| 1747 static SECStatus |
| 1748 sec_pkcs12_encoder_asafe_process(sec_PKCS12EncoderContext *p12ecx) |
| 1749 { |
| 1750 SEC_PKCS7EncoderContext *innerP7ecx; |
| 1751 SEC_PKCS7ContentInfo *cinfo; |
| 1752 PK11SymKey *bulkKey = NULL; |
| 1753 SEC_ASN1EncoderContext *innerA1ecx = NULL; |
| 1754 SECStatus rv = SECSuccess; |
| 1755 |
| 1756 if(p12ecx->currentSafe < p12ecx->p12exp->authSafe.safeCount) { |
| 1757 SEC_PKCS12SafeInfo *safeInfo; |
| 1758 SECOidTag cinfoType; |
| 1759 |
| 1760 safeInfo = p12ecx->p12exp->safeInfos[p12ecx->currentSafe]; |
| 1761 |
| 1762 /* skip empty safes */ |
| 1763 if(safeInfo->itemCount == 0) { |
| 1764 return SECSuccess; |
| 1765 } |
| 1766 |
| 1767 cinfo = safeInfo->cinfo; |
| 1768 cinfoType = SEC_PKCS7ContentType(cinfo); |
| 1769 |
| 1770 /* determine the safe type and set the appropriate argument */ |
| 1771 switch(cinfoType) { |
| 1772 case SEC_OID_PKCS7_DATA: |
| 1773 case SEC_OID_PKCS7_ENVELOPED_DATA: |
| 1774 break; |
| 1775 case SEC_OID_PKCS7_ENCRYPTED_DATA: |
| 1776 bulkKey = safeInfo->encryptionKey; |
| 1777 PK11_SetSymKeyUserData(bulkKey, &safeInfo->pwitem, NULL); |
| 1778 break; |
| 1779 default: |
| 1780 return SECFailure; |
| 1781 |
| 1782 } |
| 1783 |
| 1784 /* start the PKCS7 encoder */ |
| 1785 innerP7ecx = SEC_PKCS7EncoderStart(cinfo, |
| 1786 sec_P12P7OutputCB_CallA1Update, |
| 1787 p12ecx->middleA1ecx, bulkKey); |
| 1788 if(!innerP7ecx) { |
| 1789 goto loser; |
| 1790 } |
| 1791 |
| 1792 /* encode safe contents */ |
| 1793 p12ecx->innerBuf.p7eCx = innerP7ecx; |
| 1794 p12ecx->innerBuf.hmacCx = NULL; |
| 1795 p12ecx->innerBuf.numBytes = 0; |
| 1796 p12ecx->innerBuf.bufBytes = sizeof p12ecx->innerBuf.buf; |
| 1797 |
| 1798 innerA1ecx = SEC_ASN1EncoderStart(safeInfo->safe, |
| 1799 sec_PKCS12SafeContentsTemplate, |
| 1800 sec_P12A1OutputCB_HmacP7Update, |
| 1801 &p12ecx->innerBuf); |
| 1802 if(!innerA1ecx) { |
| 1803 goto loser; |
| 1804 } |
| 1805 rv = SEC_ASN1EncoderUpdate(innerA1ecx, NULL, 0); |
| 1806 SEC_ASN1EncoderFinish(innerA1ecx); |
| 1807 sec_FlushPkcs12OutputBuffer( &p12ecx->innerBuf); |
| 1808 innerA1ecx = NULL; |
| 1809 if(rv != SECSuccess) { |
| 1810 goto loser; |
| 1811 } |
| 1812 |
| 1813 |
| 1814 /* finish up safe content info */ |
| 1815 rv = SEC_PKCS7EncoderFinish(innerP7ecx, p12ecx->p12exp->pwfn, |
| 1816 p12ecx->p12exp->pwfnarg); |
| 1817 } |
| 1818 memset(&p12ecx->innerBuf, 0, sizeof p12ecx->innerBuf); |
| 1819 return SECSuccess; |
| 1820 |
| 1821 loser: |
| 1822 if(innerP7ecx) { |
| 1823 SEC_PKCS7EncoderFinish(innerP7ecx, p12ecx->p12exp->pwfn, |
| 1824 p12ecx->p12exp->pwfnarg); |
| 1825 } |
| 1826 |
| 1827 if(innerA1ecx) { |
| 1828 SEC_ASN1EncoderFinish(innerA1ecx); |
| 1829 } |
| 1830 memset(&p12ecx->innerBuf, 0, sizeof p12ecx->innerBuf); |
| 1831 return SECFailure; |
| 1832 } |
| 1833 |
| 1834 /* finish the HMAC and encode the macData so that it can be |
| 1835 * encoded. |
| 1836 */ |
| 1837 static SECStatus |
| 1838 sec_Pkcs12FinishMac(sec_PKCS12EncoderContext *p12ecx) |
| 1839 { |
| 1840 SECItem hmac = { siBuffer, NULL, 0 }; |
| 1841 SECStatus rv; |
| 1842 SGNDigestInfo *di = NULL; |
| 1843 void *dummy; |
| 1844 |
| 1845 if(!p12ecx) { |
| 1846 return SECFailure; |
| 1847 } |
| 1848 |
| 1849 /* make sure we are using password integrity mode */ |
| 1850 if(!p12ecx->p12exp->integrityEnabled) { |
| 1851 return SECSuccess; |
| 1852 } |
| 1853 |
| 1854 if(!p12ecx->p12exp->pwdIntegrity) { |
| 1855 return SECSuccess; |
| 1856 } |
| 1857 |
| 1858 /* finish the hmac */ |
| 1859 hmac.data = (unsigned char *)PORT_ZAlloc(SHA1_LENGTH); |
| 1860 if(!hmac.data) { |
| 1861 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 1862 return SECFailure; |
| 1863 } |
| 1864 |
| 1865 rv = PK11_DigestFinal(p12ecx->hmacCx, hmac.data, &hmac.len, SHA1_LENGTH); |
| 1866 |
| 1867 if(rv != SECSuccess) { |
| 1868 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 1869 goto loser; |
| 1870 } |
| 1871 |
| 1872 /* create the digest info */ |
| 1873 di = SGN_CreateDigestInfo(p12ecx->p12exp->integrityInfo.pwdInfo.algorithm, |
| 1874 hmac.data, hmac.len); |
| 1875 if(!di) { |
| 1876 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 1877 rv = SECFailure; |
| 1878 goto loser; |
| 1879 } |
| 1880 |
| 1881 rv = SGN_CopyDigestInfo(p12ecx->arena, &p12ecx->mac.safeMac, di); |
| 1882 if(rv != SECSuccess) { |
| 1883 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 1884 goto loser; |
| 1885 } |
| 1886 |
| 1887 /* encode the mac data */ |
| 1888 dummy = SEC_ASN1EncodeItem(p12ecx->arena, &p12ecx->pfx.encodedMacData, |
| 1889 &p12ecx->mac, sec_PKCS12MacDataTemplate); |
| 1890 if(!dummy) { |
| 1891 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 1892 rv = SECFailure; |
| 1893 } |
| 1894 |
| 1895 loser: |
| 1896 if(di) { |
| 1897 SGN_DestroyDigestInfo(di); |
| 1898 } |
| 1899 if(hmac.data) { |
| 1900 SECITEM_ZfreeItem(&hmac, PR_FALSE); |
| 1901 } |
| 1902 PK11_DestroyContext(p12ecx->hmacCx, PR_TRUE); |
| 1903 p12ecx->hmacCx = NULL; |
| 1904 |
| 1905 return rv; |
| 1906 } |
| 1907 |
| 1908 /* pfx notify function for ASN1 encoder. |
| 1909 * We want to stop encoding once we reach the authenticated safe. |
| 1910 * At that point, the encoder will be updated via streaming |
| 1911 * as the authenticated safe is encoded. |
| 1912 */ |
| 1913 static void |
| 1914 sec_pkcs12_encoder_pfx_notify(void *arg, PRBool before, void *dest, int real_dep
th) |
| 1915 { |
| 1916 sec_PKCS12EncoderContext *p12ecx; |
| 1917 |
| 1918 if(!before) { |
| 1919 return; |
| 1920 } |
| 1921 |
| 1922 /* look for authenticated safe */ |
| 1923 p12ecx = (sec_PKCS12EncoderContext*)arg; |
| 1924 if(dest != &p12ecx->pfx.encodedAuthSafe) { |
| 1925 return; |
| 1926 } |
| 1927 |
| 1928 SEC_ASN1EncoderSetTakeFromBuf(p12ecx->outerA1ecx); |
| 1929 SEC_ASN1EncoderSetStreaming(p12ecx->outerA1ecx); |
| 1930 SEC_ASN1EncoderClearNotifyProc(p12ecx->outerA1ecx); |
| 1931 } |
| 1932 |
| 1933 /* SEC_PKCS12Encode |
| 1934 * Encodes the PFX item and returns it to the output function, via |
| 1935 * callback. the output function must be capable of multiple updates. |
| 1936 * |
| 1937 * p12exp - the export context |
| 1938 * output - the output function callback, will be called more than once, |
| 1939 * must be able to accept streaming data. |
| 1940 * outputarg - argument for the output callback. |
| 1941 */ |
| 1942 SECStatus |
| 1943 SEC_PKCS12Encode(SEC_PKCS12ExportContext *p12exp, |
| 1944 SEC_PKCS12EncoderOutputCallback output, void *outputarg) |
| 1945 { |
| 1946 sec_PKCS12EncoderContext *p12enc; |
| 1947 struct sec_pkcs12_encoder_output outInfo; |
| 1948 SECStatus rv; |
| 1949 |
| 1950 if(!p12exp || !output) { |
| 1951 return SECFailure; |
| 1952 } |
| 1953 |
| 1954 /* get the encoder context */ |
| 1955 p12enc = sec_pkcs12_encoder_start_context(p12exp); |
| 1956 if(!p12enc) { |
| 1957 return SECFailure; |
| 1958 } |
| 1959 |
| 1960 outInfo.outputfn = output; |
| 1961 outInfo.outputarg = outputarg; |
| 1962 |
| 1963 /* set up PFX encoder, the "outer" encoder. Set it for streaming */ |
| 1964 p12enc->outerA1ecx = SEC_ASN1EncoderStart(&p12enc->pfx, |
| 1965 sec_PKCS12PFXItemTemplate, |
| 1966 sec_P12A1OutputCB_Outer, |
| 1967 &outInfo); |
| 1968 if(!p12enc->outerA1ecx) { |
| 1969 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 1970 rv = SECFailure; |
| 1971 goto loser; |
| 1972 } |
| 1973 SEC_ASN1EncoderSetStreaming(p12enc->outerA1ecx); |
| 1974 SEC_ASN1EncoderSetNotifyProc(p12enc->outerA1ecx, |
| 1975 sec_pkcs12_encoder_pfx_notify, p12enc); |
| 1976 rv = SEC_ASN1EncoderUpdate(p12enc->outerA1ecx, NULL, 0); |
| 1977 if(rv != SECSuccess) { |
| 1978 rv = SECFailure; |
| 1979 goto loser; |
| 1980 } |
| 1981 |
| 1982 /* set up asafe cinfo - the output of the encoder feeds the PFX encoder */ |
| 1983 p12enc->middleP7ecx = SEC_PKCS7EncoderStart(p12enc->aSafeCinfo, |
| 1984 sec_P12P7OutputCB_CallA1Update, |
| 1985 p12enc->outerA1ecx, NULL); |
| 1986 if(!p12enc->middleP7ecx) { |
| 1987 rv = SECFailure; |
| 1988 goto loser; |
| 1989 } |
| 1990 |
| 1991 /* encode asafe */ |
| 1992 p12enc->middleBuf.p7eCx = p12enc->middleP7ecx; |
| 1993 p12enc->middleBuf.hmacCx = NULL; |
| 1994 p12enc->middleBuf.numBytes = 0; |
| 1995 p12enc->middleBuf.bufBytes = sizeof p12enc->middleBuf.buf; |
| 1996 |
| 1997 /* Setup the "inner ASN.1 encoder for Authenticated Safes. */ |
| 1998 if(p12enc->p12exp->integrityEnabled && |
| 1999 p12enc->p12exp->pwdIntegrity) { |
| 2000 p12enc->middleBuf.hmacCx = p12enc->hmacCx; |
| 2001 } |
| 2002 p12enc->middleA1ecx = SEC_ASN1EncoderStart(&p12enc->p12exp->authSafe, |
| 2003 sec_PKCS12AuthenticatedSafeTemplate, |
| 2004 sec_P12A1OutputCB_HmacP7Update, |
| 2005 &p12enc->middleBuf); |
| 2006 if(!p12enc->middleA1ecx) { |
| 2007 rv = SECFailure; |
| 2008 goto loser; |
| 2009 } |
| 2010 SEC_ASN1EncoderSetStreaming(p12enc->middleA1ecx); |
| 2011 SEC_ASN1EncoderSetTakeFromBuf(p12enc->middleA1ecx); |
| 2012 |
| 2013 /* encode each of the safes */ |
| 2014 while(p12enc->currentSafe != p12enc->p12exp->safeInfoCount) { |
| 2015 sec_pkcs12_encoder_asafe_process(p12enc); |
| 2016 p12enc->currentSafe++; |
| 2017 } |
| 2018 SEC_ASN1EncoderClearTakeFromBuf(p12enc->middleA1ecx); |
| 2019 SEC_ASN1EncoderClearStreaming(p12enc->middleA1ecx); |
| 2020 SEC_ASN1EncoderUpdate(p12enc->middleA1ecx, NULL, 0); |
| 2021 SEC_ASN1EncoderFinish(p12enc->middleA1ecx); |
| 2022 p12enc->middleA1ecx = NULL; |
| 2023 |
| 2024 sec_FlushPkcs12OutputBuffer( &p12enc->middleBuf); |
| 2025 |
| 2026 /* finish the encoding of the authenticated safes */ |
| 2027 rv = SEC_PKCS7EncoderFinish(p12enc->middleP7ecx, p12exp->pwfn, |
| 2028 p12exp->pwfnarg); |
| 2029 p12enc->middleP7ecx = NULL; |
| 2030 if(rv != SECSuccess) { |
| 2031 goto loser; |
| 2032 } |
| 2033 |
| 2034 SEC_ASN1EncoderClearTakeFromBuf(p12enc->outerA1ecx); |
| 2035 SEC_ASN1EncoderClearStreaming(p12enc->outerA1ecx); |
| 2036 |
| 2037 /* update the mac, if necessary */ |
| 2038 rv = sec_Pkcs12FinishMac(p12enc); |
| 2039 if(rv != SECSuccess) { |
| 2040 goto loser; |
| 2041 } |
| 2042 |
| 2043 /* finish encoding the pfx */ |
| 2044 rv = SEC_ASN1EncoderUpdate(p12enc->outerA1ecx, NULL, 0); |
| 2045 |
| 2046 SEC_ASN1EncoderFinish(p12enc->outerA1ecx); |
| 2047 p12enc->outerA1ecx = NULL; |
| 2048 |
| 2049 loser: |
| 2050 sec_pkcs12_encoder_destroy_context(p12enc); |
| 2051 return rv; |
| 2052 } |
| 2053 |
| 2054 void |
| 2055 SEC_PKCS12DestroyExportContext(SEC_PKCS12ExportContext *p12ecx) |
| 2056 { |
| 2057 int i = 0; |
| 2058 |
| 2059 if(!p12ecx) { |
| 2060 return; |
| 2061 } |
| 2062 |
| 2063 if(p12ecx->safeInfos) { |
| 2064 i = 0; |
| 2065 while(p12ecx->safeInfos[i] != NULL) { |
| 2066 if(p12ecx->safeInfos[i]->encryptionKey) { |
| 2067 PK11_FreeSymKey(p12ecx->safeInfos[i]->encryptionKey); |
| 2068 } |
| 2069 if(p12ecx->safeInfos[i]->cinfo) { |
| 2070 SEC_PKCS7DestroyContentInfo(p12ecx->safeInfos[i]->cinfo); |
| 2071 } |
| 2072 i++; |
| 2073 } |
| 2074 } |
| 2075 |
| 2076 PK11_FreeSlot(p12ecx->slot); |
| 2077 |
| 2078 PORT_FreeArena(p12ecx->arena, PR_TRUE); |
| 2079 } |
| OLD | NEW |