security/nss/lib/pkcs12/p12e.c

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

     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/. */
     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"
    21 extern const int NSS_PBE_DEFAULT_ITERATION_COUNT; /* defined in p7create.c */
    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 */
    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  *********************************/
    45 #define PK12_OUTPUT_BUFFER_SIZE  8192
    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;
    56 /*********************************
    57  * Structures used in exporting the PKCS 12 blob
    58  *********************************/
    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;
    67     /* information for setting up password encryption */
    68     SECItem pwitem;
    69     SECOidTag algorithm;
    70     PK11SymKey *encryptionKey;
    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;
    78     /* the content info for the safe */
    79     SEC_PKCS7ContentInfo *cinfo;
    81     sec_PKCS12SafeContents *safe;
    82 };
    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;
    92     /* integrity information */
    93     PRBool integrityEnabled;
    94     PRBool	pwdIntegrity;
    95     union {
    96 	struct sec_PKCS12PasswordModeInfo pwdInfo;
    97 	struct sec_PKCS12PublicKeyModeInfo pubkeyInfo;
    98     } integrityInfo; 
   100     /* helper functions */
   101     /* retrieve the password call back */
   102     SECKEYGetPasswordKey pwfn;
   103     void *pwfnarg;
   105     /* safe contents bags */
   106     SEC_PKCS12SafeInfo **safeInfos;
   107     unsigned int safeInfoCount;
   109     /* the sequence of safes */
   110     sec_PKCS12AuthenticatedSafe authSafe;
   112     /* information needing deletion */
   113     CERTCertificate **certList;
   114 };
   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 };
   124 struct sec_pkcs12_hmac_and_output_info {
   125     void *arg;
   126     struct sec_pkcs12_encoder_output output;
   127 };
   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;
   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;
   145     /* structures for encoding of PFX and MAC */
   146     sec_PKCS12PFXItem        pfx;
   147     sec_PKCS12MacData        mac;
   149     /* authenticated safe encoding tracking information */
   150     SEC_PKCS7ContentInfo    *aSafeCinfo;
   151     SEC_PKCS7EncoderContext *middleP7ecx;
   152     SEC_ASN1EncoderContext  *middleA1ecx;
   153     unsigned int             currentSafe;
   155     /* hmac context */
   156     PK11Context             *hmacCx;
   158     /* output buffers */
   159     sec_pkcs12OutputBuffer  middleBuf;
   160     sec_pkcs12OutputBuffer  innerBuf;
   162 } sec_PKCS12EncoderContext;
   165 /*********************************
   166  * Export setup routines
   167  *********************************/
   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;
   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     }
   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     }
   198     /* password callback for key retrieval */
   199     p12ctxt->pwfn = pwfn;
   200     p12ctxt->pwfnarg = pwfnarg;
   202     p12ctxt->integrityEnabled = PR_FALSE;
   203     p12ctxt->arena = arena;
   204     p12ctxt->wincx = wincx;
   205     p12ctxt->slot = (slot) ? PK11_ReferenceSlot(slot) : PK11_GetInternalSlot();
   207     return p12ctxt;
   209 loser:
   210     if(arena) {
   211 	PORT_FreeArena(arena, PR_TRUE);
   212     }
   214     return NULL;
   215 }
   217 /* 
   218  * Adding integrity mode
   219  */
   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     }
   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;
   254     return SECSuccess;
   255 }
   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     }
   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;
   283     return SECSuccess;
   284 }
   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  */
   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;
   302     if(!p12ctxt || !info) {
   303 	return SECFailure;
   304     }
   306     mark = PORT_ArenaMark(p12ctxt->arena);
   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->arena, 
   311 					      2 * sizeof(SEC_PKCS12SafeInfo *));
   312 	dummy1 = p12ctxt->safeInfos;
   313 	p12ctxt->authSafe.encodedSafes = (SECItem **)PORT_ArenaZAlloc(p12ctxt->arena, 
   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_PKCS12SafeInfo *),
   319 			       (p12ctxt->safeInfoCount + 2) * sizeof(SEC_PKCS12SafeInfo *));
   320 	p12ctxt->safeInfos = (SEC_PKCS12SafeInfo **)dummy1;
   321 	dummy2 = PORT_ArenaGrow(p12ctxt->arena, p12ctxt->authSafe.encodedSafes, 
   322 			       (p12ctxt->authSafe.safeCount + 1) * sizeof(SECItem *),
   323 			       (p12ctxt->authSafe.safeCount + 2) * sizeof(SECItem *));
   324 	p12ctxt->authSafe.encodedSafes = (SECItem**)dummy2;
   325     }
   326     if(!dummy1 || !dummy2) {
   327 	PORT_SetError(SEC_ERROR_NO_MEMORY);
   328 	goto loser;
   329     }
   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;
   342     PORT_ArenaUnmark(p12ctxt->arena, mark);
   343     return SECSuccess;
   345 loser:
   346     PORT_ArenaRelease(p12ctxt->arena, mark);
   347     return SECFailure;
   348 }
   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};
   367     if(!p12ctxt) {
   368 	return NULL;
   369     }
   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     }
   381     safeInfo->itemCount = 0;
   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;
   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) != SECSuccess) {
   399 	PORT_SetError(SEC_ERROR_NO_MEMORY);
   400 	goto loser;
   401     }
   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     }
   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     }
   420     safeInfo->arena = p12ctxt->arena;
   421     safeInfo->safe = NULL;
   422     if(sec_pkcs12_append_safe_info(p12ctxt, safeInfo) != SECSuccess) {
   423 	goto loser;
   424     }
   426     if(uniPwitem.data) {
   427 	SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);
   428     }
   429     PORT_ArenaUnmark(p12ctxt->arena, mark);
   431     if (slot) {
   432 	PK11_FreeSlot(slot);
   433     }
   434     return safeInfo;
   436 loser:
   437     if (slot) {
   438 	PK11_FreeSlot(slot);
   439     }
   440     if(safeInfo->cinfo) {
   441 	SEC_PKCS7DestroyContentInfo(safeInfo->cinfo);
   442     }
   444     if(uniPwitem.data) {
   445 	SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);
   446     }
   448     PORT_ArenaRelease(p12ctxt->arena, mark);
   449     return NULL;
   450 }
   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;
   463     if(!p12ctxt) {
   464 	return NULL;
   465     }
   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     }
   477     safeInfo->itemCount = 0;
   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     }
   486     if(sec_pkcs12_append_safe_info(p12ctxt, safeInfo) != SECSuccess) {
   487 	goto loser;
   488     }
   490     PORT_ArenaUnmark(p12ctxt->arena, mark);
   491     return safeInfo;
   493 loser:
   494     if(safeInfo->cinfo) {
   495 	SEC_PKCS7DestroyContentInfo(safeInfo->cinfo);
   496     }
   498     PORT_ArenaRelease(p12ctxt->arena, mark);
   499     return NULL;
   500 }
   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;
   522     if(!p12ctxt || !signer || !recipients || !(*recipients)) {
   523 	return NULL;
   524     }
   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     }
   536     safeInfo->itemCount = 0;
   537     safeInfo->arena = p12ctxt->arena;
   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     }
   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     }
   563     if(sec_pkcs12_append_safe_info(p12ctxt, safeInfo) != SECSuccess) {
   564 	goto loser;
   565     }
   567     PORT_ArenaUnmark(p12ctxt->arena, mark);
   568     return safeInfo;
   570 loser:
   571     if(safeInfo->cinfo) {
   572 	SEC_PKCS7DestroyContentInfo(safeInfo->cinfo);
   573 	safeInfo->cinfo = NULL;
   574     }
   576     PORT_ArenaRelease(p12ctxt->arena, mark);
   577     return NULL;
   578 } 
   580 /*********************************
   581  * Routines to handle the exporting of the keys and certificates
   582  *********************************/
   584 /* creates a safe contents which safeBags will be appended to */
   585 sec_PKCS12SafeContents *
   586 sec_PKCS12CreateSafeContents(PLArenaPool *arena)
   587 {
   588     sec_PKCS12SafeContents *safeContents;
   590     if(arena == NULL) {
   591 	return NULL; 
   592     }
   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     }
   602     /* set up the internal contents info */
   603     safeContents->safeBags = NULL;
   604     safeContents->arena = arena;
   605     safeContents->bagCount = 0;
   607     return safeContents;
   609 loser:
   610     return NULL;
   611 }   
   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;
   622     if(!arena || !safeBag || !safeContents) {
   623 	return SECFailure;
   624     }
   626     mark = PORT_ArenaMark(arena);
   627     if(!mark) {
   628 	PORT_SetError(SEC_ERROR_NO_MEMORY);
   629 	return SECFailure;
   630     }
   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     }
   645     if(!dummy) {
   646 	PORT_ArenaRelease(arena, mark);
   647 	PORT_SetError(SEC_ERROR_NO_MEMORY);
   648 	return SECFailure;
   649     }
   651     /* append the bag at the end and null terminate the list */
   652     safeContents->safeBags[safeContents->bagCount++] = safeBag;
   653     safeContents->safeBags[safeContents->bagCount] = NULL;
   655     PORT_ArenaUnmark(arena, mark);
   657     return SECSuccess;
   658 }
   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;
   669     if(!p12ctxt || !safeBag || !safeInfo) {
   670 	return SECFailure;
   671     }
   673     if(!safeInfo->safe) {
   674 	safeInfo->safe = sec_PKCS12CreateSafeContents(p12ctxt->arena);
   675 	if(!safeInfo->safe) {
   676 	    return SECFailure;
   677 	}
   678     }
   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     }
   686     return rv;
   687 } 
   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;
   703     if(!p12ctxt) {
   704 	return NULL;
   705     }
   707     mark = PORT_ArenaMark(p12ctxt->arena);
   708     if(!mark) {
   709 	PORT_SetError(SEC_ERROR_NO_MEMORY);
   710 	return NULL;
   711     }
   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     }
   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     }
   749     oidData = SECOID_FindOIDByTag(bagType);
   750     if(oidData) {
   751 	rv = SECITEM_CopyItem(p12ctxt->arena, &safeBag->safeBagType, &oidData->oid);
   752 	if(rv != SECSuccess) {
   753 	    PORT_SetError(SEC_ERROR_NO_MEMORY);
   754 	    goto loser;
   755 	}
   756     } else {
   757 	goto loser;
   758     }
   760     safeBag->arena = p12ctxt->arena;
   761     PORT_ArenaUnmark(p12ctxt->arena, mark);
   763     return safeBag;
   765 loser:
   766     if(mark) {
   767 	PORT_ArenaRelease(p12ctxt->arena, mark);
   768     }
   770     return NULL;
   771 }
   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;
   784     if(!arena) {
   785 	return NULL;
   786     }
   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     }
   797     bagType = SECOID_FindOIDByTag(certType);
   798     if(!bagType) {
   799 	PORT_SetError(SEC_ERROR_NO_MEMORY);
   800 	goto loser;
   801     }
   803     rv = SECITEM_CopyItem(arena, &certBag->bagID, &bagType->oid);
   804     if(rv != SECSuccess) {
   805 	PORT_SetError(SEC_ERROR_NO_MEMORY);
   806 	goto loser;
   807     }
   809     PORT_ArenaUnmark(arena, mark);
   810     return certBag;
   812 loser:
   813     PORT_ArenaRelease(arena, mark);
   814     return NULL;
   815 }
   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;
   828     if(!arena) {
   829 	return NULL;
   830     }
   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     }
   841     bagType = SECOID_FindOIDByTag(crlType);
   842     if(!bagType) {
   843 	PORT_SetError(SEC_ERROR_NO_MEMORY);
   844 	goto loser;
   845     }
   847     rv = SECITEM_CopyItem(arena, &crlBag->bagID, &bagType->oid);
   848     if(rv != SECSuccess) {
   849 	PORT_SetError(SEC_ERROR_NO_MEMORY);
   850 	goto loser;
   851     }
   853     PORT_ArenaUnmark(arena, mark);
   854     return crlBag;
   856 loser:
   857     PORT_ArenaRelease(arena, mark);
   858     return NULL;
   859 }
   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;
   883     if(!safeBag || !p12ctxt) {
   884 	return SECFailure;
   885     }
   887     mark = PORT_ArenaMark(safeBag->arena);
   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     }
   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     }
   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     }
   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     }
   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;
   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     }
   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->arena, 
   964 						2 * sizeof(sec_PKCS12Attribute *));
   965 	dummy = safeBag->attribs;
   966     }
   967     if(!dummy) {
   968 	goto loser;
   969     }
   971     safeBag->attribs[safeBag->nAttribs] = attribute;
   972     safeBag->attribs[++safeBag->nAttribs] = NULL;
   974     PORT_ArenaUnmark(p12ctxt->arena, mark);
   975     return SECSuccess;
   977 loser:
   978     if(mark) {
   979 	PORT_ArenaRelease(p12ctxt->arena, mark);
   980     }
   982     return SECFailure;
   983 }
   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 then,
   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)
  1003     sec_PKCS12CertBag *certBag;
  1004     sec_PKCS12SafeBag *safeBag;
  1005     void *mark;
  1006     SECStatus rv;
  1007     SECItem nick = {siBuffer, NULL,0};
  1009     if(!p12ctxt || !cert) {
  1010 	return SECFailure;
  1012     mark = PORT_ArenaMark(p12ctxt->arena);
  1014     /* allocate the cert bag */
  1015     certBag = sec_PKCS12NewCertBag(p12ctxt->arena, 
  1016     				   SEC_OID_PKCS9_X509_CERT);
  1017     if(!certBag) {
  1018 	goto loser;
  1021     if(SECITEM_CopyItem(p12ctxt->arena, &certBag->value.x509Cert, 
  1022     			&cert->derCert) != SECSuccess) {
  1023 	PORT_SetError(SEC_ERROR_NO_MEMORY);
  1024 	goto loser;
  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 							       certUsageSSLClient,
  1033 							       PR_TRUE);
  1034 	unsigned int count = 0;
  1035 	if(!certList) {
  1036 	    PORT_SetError(SEC_ERROR_NO_MEMORY);
  1037 	    goto loser;
  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;
  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;
  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;
  1071 		CERT_DestroyCertificate(tempCert);
  1074 	CERT_DestroyCertificateList(certList);
  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;
  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);
  1100 	} else {
  1101 	    nick.data = (unsigned char *)cert->nickname;
  1102 	    nick.len = PORT_Strlen(cert->nickname);
  1106     safeBag = sec_PKCS12CreateSafeBag(p12ctxt, SEC_OID_PKCS12_V1_CERT_BAG_ID, 
  1107     				      certBag);
  1108     if(!safeBag) {
  1109 	goto loser;
  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;
  1121     if(keyId) {
  1122 	if(sec_PKCS12AddAttributeToBag(p12ctxt, safeBag, SEC_OID_PKCS9_LOCAL_KEY_ID,
  1123 				       keyId) != SECSuccess) {
  1124 	    goto loser;
  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);
  1137     if(rv != SECSuccess) {
  1138 	goto loser;
  1141     PORT_ArenaUnmark(p12ctxt->arena, mark);
  1142     return SECSuccess;
  1144 loser:
  1145     if(mark) {
  1146 	PORT_ArenaRelease(p12ctxt->arena, mark);
  1149     return SECFailure;
  1152 /* SEC_PKCS12AddKeyForCert
  1153  *	Extracts the key associated with a particular certificate and exports
  1154  *	it.
  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 *safe, 
  1170 			void *nestedDest, CERTCertificate *cert,
  1171 			PRBool shroudKey, SECOidTag algorithm, SECItem *pwitem,
  1172 			SECItem *keyId, SECItem *nickName)
  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;
  1181     if(!p12ctxt || !cert || !safe) {
  1182 	return SECFailure;
  1185     mark = PORT_ArenaMark(p12ctxt->arena);
  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) {
  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;
  1200 	keyItem = PORT_ArenaZAlloc(p12ctxt->arena, sizeof(SECKEYPrivateKeyInfo));
  1201 	if(!keyItem) {
  1202 	    PORT_SetError(SEC_ERROR_NO_MEMORY);
  1203 	    goto loser;
  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 {
  1211 	/* extract the key encrypted */
  1212 	SECKEYEncryptedPrivateKeyInfo *epki = NULL;
  1213 	PK11SlotInfo *slot = NULL;
  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;
  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);
  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;
  1238 	keyItem = PORT_ArenaZAlloc(p12ctxt->arena, 
  1239 				  sizeof(SECKEYEncryptedPrivateKeyInfo));
  1240 	if(!keyItem) {
  1241 	    PORT_SetError(SEC_ERROR_NO_MEMORY);
  1242 	    goto loser;
  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);
  1251     if(rv != SECSuccess) {
  1252 	goto loser;
  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;
  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;
  1273     if(nickName) {
  1274 	if(sec_PKCS12AddAttributeToBag(p12ctxt, returnBag, 
  1275 				       SEC_OID_PKCS9_FRIENDLY_NAME, nickName) 
  1276 				       != SECSuccess) {
  1277 	    goto loser;
  1281     if(keyId) {
  1282 	if(sec_PKCS12AddAttributeToBag(p12ctxt, returnBag, SEC_OID_PKCS9_LOCAL_KEY_ID,
  1283 				       keyId) != SECSuccess) {
  1284 	    goto loser;
  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);
  1296 loser:
  1298     if (rv != SECSuccess) {
  1299 	PORT_ArenaRelease(p12ctxt->arena, mark);
  1300     } else {
  1301 	PORT_ArenaUnmark(p12ctxt->arena, mark);
  1304     return rv;
  1307 /* SEC_PKCS12AddCertOrChainAndKey
  1308  *	Add a certificate and key pair to be exported.
  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)
  1328     SECStatus rv = SECFailure;
  1329     SGNDigestInfo *digest = NULL;
  1330     void *mark = NULL;
  1332     if(!p12ctxt || !certSafe || !keySafe || !cert) {
  1333 	return SECFailure;
  1336     mark = PORT_ArenaMark(p12ctxt->arena);
  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;
  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;
  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;
  1362     SGN_DestroyDigestInfo(digest);
  1364     PORT_ArenaUnmark(p12ctxt->arena, mark);
  1365     return SECSuccess;
  1367 loser:
  1368     SGN_DestroyDigestInfo(digest);
  1369     PORT_ArenaRelease(p12ctxt->arena, mark);
  1371     return SECFailure; 
  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)
  1382     return SEC_PKCS12AddCertOrChainAndKey(p12ctxt, certSafe, certNestedDest,
  1383     		cert, certDb, keySafe, keyNestedDest, shroudKey, pwItem, 
  1384 		algorithm, PR_TRUE);
  1388 /* SEC_PKCS12CreateNestedSafeContents
  1389  * 	Allows nesting of safe contents to be implemented.  No limit imposed on 
  1390  *	depth.  
  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)
  1400     sec_PKCS12SafeContents *newSafe;
  1401     sec_PKCS12SafeBag *safeContentsBag;
  1402     void *mark;
  1403     SECStatus rv;
  1405     if(!p12ctxt || !baseSafe) {
  1406 	return NULL;
  1409     mark = PORT_ArenaMark(p12ctxt->arena);
  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;
  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;
  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);
  1435     if(rv != SECSuccess) {
  1436 	goto loser;
  1439     PORT_ArenaUnmark(p12ctxt->arena, mark);
  1440     return newSafe;
  1442 loser:
  1443     PORT_ArenaRelease(p12ctxt->arena, mark);
  1444     return NULL;
  1447 /*********************************
  1448  * Encoding routines
  1449  *********************************/
  1451 /* Clean up the resources allocated by a sec_PKCS12EncoderContext. */
  1452 static void
  1453 sec_pkcs12_encoder_destroy_context(sec_PKCS12EncoderContext *p12enc)
  1455     if(p12enc) {
  1456 	if(p12enc->outerA1ecx) {
  1457 	    SEC_ASN1EncoderFinish(p12enc->outerA1ecx);
  1458 	    p12enc->outerA1ecx = NULL;
  1460 	if(p12enc->aSafeCinfo) {
  1461 	    SEC_PKCS7DestroyContentInfo(p12enc->aSafeCinfo);
  1462 	    p12enc->aSafeCinfo = NULL;
  1464 	if(p12enc->middleP7ecx) {
  1465 	    SEC_PKCS7EncoderFinish(p12enc->middleP7ecx, p12enc->p12exp->pwfn,
  1466 				   p12enc->p12exp->pwfnarg);
  1467 	    p12enc->middleP7ecx = NULL;
  1469 	if(p12enc->middleA1ecx) {
  1470 	    SEC_ASN1EncoderFinish(p12enc->middleA1ecx);
  1471 	    p12enc->middleA1ecx = NULL;
  1473 	if(p12enc->hmacCx) {
  1474 	    PK11_DestroyContext(p12enc->hmacCx, PR_TRUE);
  1475 	    p12enc->hmacCx = NULL;
  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)
  1487     sec_PKCS12EncoderContext *p12enc = NULL;
  1488     unsigned int i, nonEmptyCnt;
  1489     SECStatus rv;
  1490     SECItem ignore = {0};
  1491     void *mark;
  1493     if(!p12exp || !p12exp->safeInfos) {
  1494 	return NULL;
  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++;
  1503 	i++;
  1505     if(nonEmptyCnt == 0) {
  1506 	return NULL;
  1508     p12exp->authSafe.encodedSafes[nonEmptyCnt] = NULL;
  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;
  1518     p12enc->arena = p12exp->arena;
  1519     p12enc->p12exp = p12exp;
  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;
  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;
  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;
  1549 	if(SEC_PKCS7IncludeCertChain(p12enc->aSafeCinfo,NULL) != SECSuccess) {
  1550 	    goto loser;
  1552 	rv = SEC_PKCS7AddSigningTime(p12enc->aSafeCinfo);
  1553 	PORT_Assert(rv == SECSuccess);
  1554     } else {
  1555 	p12enc->aSafeCinfo = SEC_PKCS7CreateData();
  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;
  1566 	    /* zero out macData and set values */
  1567 	    PORT_Memset(&p12enc->mac, 0, sizeof(sec_PKCS12MacData));
  1569 	    if(!salt) {
  1570 		PORT_SetError(SEC_ERROR_NO_MEMORY);
  1571 		goto loser;
  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;
  1579 	    if (!SEC_ASN1EncodeInteger(p12exp->arena, &(p12enc->mac.iter),
  1580 				       NSS_PBE_DEFAULT_ITERATION_COUNT)) {
  1581 		/* XXX salt is leaked */
  1582 		goto loser;
  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;
  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);
  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;
  1615 	    /* generate the key */
  1616 	    symKey = PK11_KeyGen(NULL, integrityMechType, params, 20, NULL);
  1617 	    PK11_DestroyPBEParams(params);
  1618 	    if(!symKey) {
  1619 		goto loser;
  1622 	    /* initialize HMAC */
  1623 	    /* Get the HMAC mechanism from the hash OID */
  1624 	    hmacMechType=  sec_pkcs12_algtag_to_mech( 
  1625 	                              p12exp->integrityInfo.pwdInfo.algorithm);
  1627 	    p12enc->hmacCx = PK11_CreateContextBySymKey( hmacMechType,
  1628 						 CKA_SIGN, symKey, &ignore);
  1630 	    PK11_FreeSymKey(symKey);
  1631 	    if(!p12enc->hmacCx) {
  1632 		PORT_SetError(SEC_ERROR_NO_MEMORY);
  1633 		goto loser;
  1635 	    rv = PK11_DigestBegin(p12enc->hmacCx);
  1636 	    if (rv != SECSuccess)
  1637 		goto loser;
  1641     if(!p12enc->aSafeCinfo) {
  1642 	goto loser;
  1645     PORT_ArenaUnmark(p12exp->arena, mark);
  1647     return p12enc;
  1649 loser:
  1650     sec_pkcs12_encoder_destroy_context(p12enc);
  1651     if (p12exp->arena != NULL)
  1652 	PORT_ArenaRelease(p12exp->arena, mark);
  1654     return NULL;
  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)
  1665     struct sec_pkcs12_encoder_output *output;
  1667     output = (struct sec_pkcs12_encoder_output*)arg;
  1668     (* output->outputfn)(output->outputarg, buf, len);
  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)
  1681     sec_pkcs12OutputBuffer *  bufcx = (sec_pkcs12OutputBuffer *)arg;
  1683     if(!buf || !len) 
  1684 	return;
  1686     if (bufcx->hmacCx) {
  1687 	PK11_DigestOp(bufcx->hmacCx, (unsigned char *)buf, len);
  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;
  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;
  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;
  1720 void
  1721 sec_FlushPkcs12OutputBuffer( sec_pkcs12OutputBuffer *  bufcx)
  1723     if (bufcx->numBytes > 0) {
  1724 	SEC_PKCS7EncoderUpdate(bufcx->p7eCx, bufcx->buf, bufcx->numBytes);
  1725 	bufcx->numBytes = 0;
  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)
  1735     SEC_ASN1EncoderContext *cx = (SEC_ASN1EncoderContext*)arg;
  1737     if (!buf || !len) 
  1738     	return;
  1740     SEC_ASN1EncoderUpdate(cx, buf, len);
  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)
  1750     SEC_PKCS7EncoderContext *innerP7ecx;
  1751     SEC_PKCS7ContentInfo    *cinfo;
  1752     PK11SymKey              *bulkKey      = NULL;
  1753     SEC_ASN1EncoderContext  *innerA1ecx   = NULL;
  1754     SECStatus                rv           = SECSuccess;
  1756     if(p12ecx->currentSafe < p12ecx->p12exp->authSafe.safeCount) {
  1757 	SEC_PKCS12SafeInfo *safeInfo;
  1758 	SECOidTag cinfoType;
  1760 	safeInfo = p12ecx->p12exp->safeInfos[p12ecx->currentSafe];
  1762 	/* skip empty safes */
  1763 	if(safeInfo->itemCount == 0) {
  1764 	    return SECSuccess;
  1767 	cinfo = safeInfo->cinfo;
  1768 	cinfoType = SEC_PKCS7ContentType(cinfo);
  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;
  1784 	/* start the PKCS7 encoder */
  1785 	innerP7ecx = SEC_PKCS7EncoderStart(cinfo, 
  1786 				  sec_P12P7OutputCB_CallA1Update,
  1787 				  p12ecx->middleA1ecx, bulkKey);
  1788 	if(!innerP7ecx) {
  1789 	    goto loser;
  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;
  1798 	innerA1ecx = SEC_ASN1EncoderStart(safeInfo->safe, 
  1799 	                           sec_PKCS12SafeContentsTemplate,
  1800 				   sec_P12A1OutputCB_HmacP7Update, 
  1801 				   &p12ecx->innerBuf);
  1802 	if(!innerA1ecx) {
  1803 	    goto loser;
  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;
  1814 	/* finish up safe content info */
  1815 	rv = SEC_PKCS7EncoderFinish(innerP7ecx, p12ecx->p12exp->pwfn, 
  1816 				    p12ecx->p12exp->pwfnarg);
  1818     memset(&p12ecx->innerBuf, 0, sizeof p12ecx->innerBuf);
  1819     return SECSuccess;
  1821 loser:
  1822     if(innerP7ecx) {
  1823 	SEC_PKCS7EncoderFinish(innerP7ecx, p12ecx->p12exp->pwfn, 
  1824 			       p12ecx->p12exp->pwfnarg);
  1827     if(innerA1ecx) {
  1828 	SEC_ASN1EncoderFinish(innerA1ecx);
  1830     memset(&p12ecx->innerBuf, 0, sizeof p12ecx->innerBuf);
  1831     return SECFailure;
  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)
  1840     SECItem hmac = { siBuffer, NULL, 0 };
  1841     SECStatus rv;
  1842     SGNDigestInfo *di = NULL;
  1843     void *dummy;
  1845     if(!p12ecx) {
  1846 	return SECFailure;
  1849     /* make sure we are using password integrity mode */
  1850     if(!p12ecx->p12exp->integrityEnabled) {
  1851 	return SECSuccess;
  1854     if(!p12ecx->p12exp->pwdIntegrity) {
  1855 	return SECSuccess;
  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;
  1865     rv = PK11_DigestFinal(p12ecx->hmacCx, hmac.data, &hmac.len, SHA1_LENGTH);
  1867     if(rv != SECSuccess) {
  1868 	PORT_SetError(SEC_ERROR_NO_MEMORY);
  1869 	goto loser;
  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;
  1881     rv = SGN_CopyDigestInfo(p12ecx->arena, &p12ecx->mac.safeMac, di);
  1882     if(rv != SECSuccess) {
  1883 	PORT_SetError(SEC_ERROR_NO_MEMORY);
  1884 	goto loser;
  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;
  1895 loser:
  1896     if(di) {
  1897 	SGN_DestroyDigestInfo(di);
  1899     if(hmac.data) {
  1900 	SECITEM_ZfreeItem(&hmac, PR_FALSE);
  1902     PK11_DestroyContext(p12ecx->hmacCx, PR_TRUE);
  1903     p12ecx->hmacCx = NULL;
  1905     return rv;
  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_depth)
  1916     sec_PKCS12EncoderContext *p12ecx;
  1918     if(!before) {
  1919 	return;
  1922     /* look for authenticated safe */
  1923     p12ecx = (sec_PKCS12EncoderContext*)arg;
  1924     if(dest != &p12ecx->pfx.encodedAuthSafe) {
  1925 	return;
  1928     SEC_ASN1EncoderSetTakeFromBuf(p12ecx->outerA1ecx);
  1929     SEC_ASN1EncoderSetStreaming(p12ecx->outerA1ecx);
  1930     SEC_ASN1EncoderClearNotifyProc(p12ecx->outerA1ecx);
  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.
  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)
  1946     sec_PKCS12EncoderContext *p12enc;
  1947     struct sec_pkcs12_encoder_output outInfo;
  1948     SECStatus rv;
  1950     if(!p12exp || !output) {
  1951 	return SECFailure;
  1954     /* get the encoder context */
  1955     p12enc = sec_pkcs12_encoder_start_context(p12exp);
  1956     if(!p12enc) {
  1957 	return SECFailure;
  1960     outInfo.outputfn = output;
  1961     outInfo.outputarg = outputarg;
  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;
  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;
  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;
  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;
  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;
  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;
  2010     SEC_ASN1EncoderSetStreaming(p12enc->middleA1ecx);
  2011     SEC_ASN1EncoderSetTakeFromBuf(p12enc->middleA1ecx); 
  2013     /* encode each of the safes */			 
  2014     while(p12enc->currentSafe != p12enc->p12exp->safeInfoCount) {
  2015 	sec_pkcs12_encoder_asafe_process(p12enc);
  2016 	p12enc->currentSafe++;
  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;
  2024     sec_FlushPkcs12OutputBuffer( &p12enc->middleBuf);
  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;
  2034     SEC_ASN1EncoderClearTakeFromBuf(p12enc->outerA1ecx);
  2035     SEC_ASN1EncoderClearStreaming(p12enc->outerA1ecx);
  2037     /* update the mac, if necessary */
  2038     rv = sec_Pkcs12FinishMac(p12enc);
  2039     if(rv != SECSuccess) {
  2040 	goto loser;
  2043     /* finish encoding the pfx */ 
  2044     rv = SEC_ASN1EncoderUpdate(p12enc->outerA1ecx, NULL, 0);
  2046     SEC_ASN1EncoderFinish(p12enc->outerA1ecx);
  2047     p12enc->outerA1ecx = NULL;
  2049 loser:
  2050     sec_pkcs12_encoder_destroy_context(p12enc);
  2051     return rv;
  2054 void
  2055 SEC_PKCS12DestroyExportContext(SEC_PKCS12ExportContext *p12ecx)
  2057     int i = 0;
  2059     if(!p12ecx) {
  2060 	return;
  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);
  2069 	    if(p12ecx->safeInfos[i]->cinfo) {
  2070 		SEC_PKCS7DestroyContentInfo(p12ecx->safeInfos[i]->cinfo);
  2072 	    i++;
  2076     PK11_FreeSlot(p12ecx->slot);
  2078     PORT_FreeArena(p12ecx->arena, PR_TRUE);

mercurial