p12e.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:59k
源码类别:

CA认证

开发平台:

WINDOWS

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