LCOV - code coverage report
Current view: directory - security/manager/ssl/src - nsPKCS12Blob.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 333 0 0.0 %
Date: 2012-06-02 Functions: 22 0 0.0 %

       1                 : /* ***** BEGIN LICENSE BLOCK *****
       2                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       3                 :  *
       4                 :  * The contents of this file are subject to the Mozilla Public License Version
       5                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       6                 :  * the License. You may obtain a copy of the License at
       7                 :  * http://www.mozilla.org/MPL/
       8                 :  *
       9                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      10                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      11                 :  * for the specific language governing rights and limitations under the
      12                 :  * License.
      13                 :  *
      14                 :  * The Original Code is the Netscape security libraries.
      15                 :  *
      16                 :  * The Initial Developer of the Original Code is
      17                 :  * Netscape Communications Corporation.
      18                 :  * Portions created by the Initial Developer are Copyright (C) 2000
      19                 :  * the Initial Developer. All Rights Reserved.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *   Ian McGreer <mcgreer@netscape.com>
      23                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      26                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      28                 :  * of those above. If you wish to allow use of your version of this file only
      29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      30                 :  * use your version of this file under the terms of the MPL, indicate your
      31                 :  * decision by deleting the provisions above and replace them with the notice
      32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      33                 :  * the provisions above, a recipient may use your version of this file under
      34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      35                 :  *
      36                 :  * ***** END LICENSE BLOCK ***** */
      37                 : /* $Id: nsPKCS12Blob.cpp,v 1.49 2007/09/05 07:13:46 jwalden%mit.edu Exp $ */
      38                 : 
      39                 : #include "prmem.h"
      40                 : #include "prprf.h"
      41                 : 
      42                 : #include "nsISupportsArray.h"
      43                 : #include "nsIFile.h"
      44                 : #include "nsNetUtil.h"
      45                 : #include "nsILocalFile.h"
      46                 : #include "nsIDirectoryService.h"
      47                 : #include "nsThreadUtils.h"
      48                 : 
      49                 : #include "nsNSSComponent.h"
      50                 : #include "nsNSSHelper.h"
      51                 : #include "nsPKCS12Blob.h"
      52                 : #include "nsString.h"
      53                 : #include "nsReadableUtils.h"
      54                 : #include "nsXPIDLString.h"
      55                 : #include "nsDirectoryServiceDefs.h"
      56                 : #include "nsNSSHelper.h"
      57                 : #include "nsNSSCertificate.h"
      58                 : #include "nsKeygenHandler.h" //For GetSlotWithMechanism
      59                 : #include "nsPK11TokenDB.h"
      60                 : #include "nsICertificateDialogs.h"
      61                 : #include "nsNSSShutDown.h"
      62                 : #include "nsCRT.h"
      63                 : #include "pk11func.h"
      64                 : #include "secerr.h"
      65                 : 
      66                 : #ifdef PR_LOGGING
      67                 : extern PRLogModuleInfo* gPIPNSSLog;
      68                 : #endif
      69                 : 
      70                 : #include "nsNSSCleaner.h"
      71               0 : NSSCleanupAutoPtrClass(CERTCertificate, CERT_DestroyCertificate)
      72                 : 
      73                 : static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
      74                 : 
      75                 : #define PIP_PKCS12_TMPFILENAME   NS_LITERAL_CSTRING(".pip_p12tmp")
      76                 : #define PIP_PKCS12_BUFFER_SIZE   2048
      77                 : #define PIP_PKCS12_RESTORE_OK          1
      78                 : #define PIP_PKCS12_BACKUP_OK           2
      79                 : #define PIP_PKCS12_USER_CANCELED       3
      80                 : #define PIP_PKCS12_NOSMARTCARD_EXPORT  4
      81                 : #define PIP_PKCS12_RESTORE_FAILED      5
      82                 : #define PIP_PKCS12_BACKUP_FAILED       6
      83                 : #define PIP_PKCS12_NSS_ERROR           7
      84                 : 
      85                 : // constructor
      86               0 : nsPKCS12Blob::nsPKCS12Blob():mCertArray(0),
      87                 :                              mTmpFile(nsnull),
      88                 :                              mTmpFilePath(nsnull),
      89                 :                              mDigest(nsnull),
      90                 :                              mDigestIterator(nsnull),
      91               0 :                              mTokenSet(false)
      92                 : {
      93               0 :   mUIContext = new PipUIContext();
      94               0 : }
      95                 : 
      96                 : // destructor
      97               0 : nsPKCS12Blob::~nsPKCS12Blob()
      98                 : {
      99               0 :   delete mDigestIterator;
     100               0 :   delete mDigest;
     101               0 : }
     102                 : 
     103                 : // nsPKCS12Blob::SetToken
     104                 : //
     105                 : // Set the token to use for import/export
     106                 : nsresult
     107               0 : nsPKCS12Blob::SetToken(nsIPK11Token *token)
     108                 : {
     109               0 :  nsNSSShutDownPreventionLock locker;
     110               0 :  nsresult rv = NS_OK;
     111               0 :  if (token) {
     112               0 :    mToken = token;
     113                 :  } else {
     114                 :    PK11SlotInfo *slot;
     115               0 :    rv = GetSlotWithMechanism(CKM_RSA_PKCS, mUIContext,&slot);
     116               0 :    if (NS_FAILED(rv)) {
     117               0 :       mToken = 0;  
     118                 :    } else {
     119               0 :      mToken = new nsPK11Token(slot);
     120               0 :      PK11_FreeSlot(slot);
     121                 :    }
     122                 :  }
     123               0 :  mTokenSet = true;
     124               0 :  return rv;
     125                 : }
     126                 : 
     127                 : // nsPKCS12Blob::ImportFromFile
     128                 : //
     129                 : // Given a file handle, read a PKCS#12 blob from that file, decode it,
     130                 : // and import the results into the token.
     131                 : nsresult
     132               0 : nsPKCS12Blob::ImportFromFile(nsILocalFile *file)
     133                 : {
     134               0 :   nsNSSShutDownPreventionLock locker;
     135               0 :   nsresult rv = NS_OK;
     136                 : 
     137               0 :   if (!mToken) {
     138               0 :     if (!mTokenSet) {
     139               0 :       rv = SetToken(NULL); // Ask the user to pick a slot
     140               0 :       if (NS_FAILED(rv)) {
     141               0 :         handleError(PIP_PKCS12_USER_CANCELED);
     142               0 :         return rv;
     143                 :       }
     144                 :     }
     145                 :   }
     146                 : 
     147               0 :   if (!mToken) {
     148               0 :     handleError(PIP_PKCS12_RESTORE_FAILED);
     149               0 :     return NS_ERROR_NOT_AVAILABLE;
     150                 :   }
     151                 : 
     152                 :   // init slot
     153               0 :   rv = mToken->Login(true);
     154               0 :   if (NS_FAILED(rv)) return rv;
     155                 :   
     156                 :   RetryReason wantRetry;
     157                 :   
     158               0 :   do {
     159               0 :     rv = ImportFromFileHelper(file, im_standard_prompt, wantRetry);
     160                 :     
     161               0 :     if (NS_SUCCEEDED(rv) && wantRetry == rr_auto_retry_empty_password_flavors)
     162                 :     {
     163               0 :       rv = ImportFromFileHelper(file, im_try_zero_length_secitem, wantRetry);
     164                 :     }
     165                 :   }
     166               0 :   while (NS_SUCCEEDED(rv) && (wantRetry != rr_do_not_retry));
     167                 :   
     168               0 :   return rv;
     169                 : }
     170                 : 
     171                 : nsresult
     172               0 : nsPKCS12Blob::ImportFromFileHelper(nsILocalFile *file, 
     173                 :                                    nsPKCS12Blob::ImportMode aImportMode,
     174                 :                                    nsPKCS12Blob::RetryReason &aWantRetry)
     175                 : {
     176               0 :   nsNSSShutDownPreventionLock locker;
     177                 :   nsresult rv;
     178               0 :   SECStatus srv = SECSuccess;
     179               0 :   SEC_PKCS12DecoderContext *dcx = NULL;
     180                 :   SECItem unicodePw;
     181                 : 
     182               0 :   PK11SlotInfo *slot=nsnull;
     183               0 :   nsXPIDLString tokenName;
     184               0 :   unicodePw.data = NULL;
     185                 :   
     186               0 :   aWantRetry = rr_do_not_retry;
     187                 : 
     188               0 :   if (aImportMode == im_try_zero_length_secitem)
     189                 :   {
     190               0 :     unicodePw.len = 0;
     191                 :   }
     192                 :   else
     193                 :   {
     194                 :     // get file password (unicode)
     195               0 :     rv = getPKCS12FilePassword(&unicodePw);
     196               0 :     if (NS_FAILED(rv)) goto finish;
     197               0 :     if (unicodePw.data == NULL) {
     198               0 :       handleError(PIP_PKCS12_USER_CANCELED);
     199               0 :       return NS_OK;
     200                 :     }
     201                 :   }
     202                 :   
     203               0 :   mToken->GetTokenName(getter_Copies(tokenName));
     204                 :   {
     205               0 :     NS_ConvertUTF16toUTF8 tokenNameCString(tokenName);
     206               0 :     slot = PK11_FindSlotByName(tokenNameCString.get());
     207                 :   }
     208               0 :   if (!slot) {
     209               0 :     srv = SECFailure;
     210               0 :     goto finish;
     211                 :   }
     212                 : 
     213                 :   // initialize the decoder
     214                 :   dcx = SEC_PKCS12DecoderStart(&unicodePw, slot, NULL,
     215                 :                                digest_open, digest_close,
     216                 :                                digest_read, digest_write,
     217               0 :                                this);
     218               0 :   if (!dcx) {
     219               0 :     srv = SECFailure;
     220               0 :     goto finish;
     221                 :   }
     222                 :   // read input file and feed it to the decoder
     223               0 :   rv = inputToDecoder(dcx, file);
     224               0 :   if (NS_FAILED(rv)) {
     225               0 :     if (NS_ERROR_ABORT == rv) {
     226                 :       // inputToDecoder indicated a NSS error
     227               0 :       srv = SECFailure;
     228                 :     }
     229               0 :     goto finish;
     230                 :   }
     231                 :   // verify the blob
     232               0 :   srv = SEC_PKCS12DecoderVerify(dcx);
     233               0 :   if (srv) goto finish;
     234                 :   // validate bags
     235               0 :   srv = SEC_PKCS12DecoderValidateBags(dcx, nickname_collision);
     236               0 :   if (srv) goto finish;
     237                 :   // import cert and key
     238               0 :   srv = SEC_PKCS12DecoderImportBags(dcx);
     239               0 :   if (srv) goto finish;
     240                 :   // Later - check to see if this should become default email cert
     241               0 :   handleError(PIP_PKCS12_RESTORE_OK);
     242                 : finish:
     243                 :   // If srv != SECSuccess, NSS probably set a specific error code.
     244                 :   // We should use that error code instead of inventing a new one
     245                 :   // for every error possible.
     246               0 :   if (srv != SECSuccess) {
     247               0 :     if (SEC_ERROR_BAD_PASSWORD == PORT_GetError()) {
     248               0 :       if (unicodePw.len == sizeof(PRUnichar))
     249                 :       {
     250                 :         // no password chars available, 
     251                 :         // unicodeToItem allocated space for the trailing zero character only.
     252               0 :         aWantRetry = rr_auto_retry_empty_password_flavors;
     253                 :       }
     254                 :       else
     255                 :       {
     256               0 :         aWantRetry = rr_bad_password;
     257               0 :         handleError(PIP_PKCS12_NSS_ERROR);
     258                 :       }
     259                 :     }
     260                 :     else
     261                 :     {
     262               0 :       handleError(PIP_PKCS12_NSS_ERROR);
     263                 :     }
     264               0 :   } else if (NS_FAILED(rv)) { 
     265               0 :     handleError(PIP_PKCS12_RESTORE_FAILED);
     266                 :   }
     267               0 :   if (slot)
     268               0 :     PK11_FreeSlot(slot);
     269                 :   // finish the decoder
     270               0 :   if (dcx)
     271               0 :     SEC_PKCS12DecoderFinish(dcx);
     272               0 :   SECITEM_ZfreeItem(&unicodePw, false);
     273               0 :   return NS_OK;
     274                 : }
     275                 : 
     276                 : #if 0
     277                 : // nsPKCS12Blob::LoadCerts
     278                 : //
     279                 : // Given an array of certificate nicknames, load the corresponding
     280                 : // certificates into a local array.
     281                 : nsresult
     282                 : nsPKCS12Blob::LoadCerts(const PRUnichar **certNames, int numCerts)
     283                 : {
     284                 :   nsresult rv;
     285                 :   char namecpy[256];
     286                 :   /* Create the local array if needed */
     287                 :   if (!mCertArray) {
     288                 :     rv = NS_NewISupportsArray(getter_AddRefs(mCertArray));
     289                 :     if (NS_FAILED(rv)) {
     290                 :       if (!handleError())
     291                 :         return NS_ERROR_OUT_OF_MEMORY;
     292                 :     }
     293                 :   }
     294                 :   /* Add the certs */
     295                 :   for (int i=0; i<numCerts; i++) {
     296                 :     strcpy(namecpy, NS_ConvertUTF16toUTF8(certNames[i]));
     297                 :     CERTCertificate *nssCert = PK11_FindCertFromNickname(namecpy, NULL);
     298                 :     if (!nssCert) {
     299                 :       if (!handleError())
     300                 :         return NS_ERROR_FAILURE;
     301                 :       else continue; /* user may request to keep going */
     302                 :     }
     303                 :     nsCOMPtr<nsIX509Cert> cert = nsNSSCertificate::Create(nssCert);
     304                 :     CERT_DestroyCertificate(nssCert);
     305                 :     if (!cert) {
     306                 :       if (!handleError())
     307                 :         return NS_ERROR_OUT_OF_MEMORY;
     308                 :     } else {
     309                 :       mCertArray->AppendElement(cert);
     310                 :     }
     311                 :   }
     312                 :   return NS_OK;
     313                 : }
     314                 : #endif
     315                 : 
     316                 : static bool
     317               0 : isExtractable(SECKEYPrivateKey *privKey)
     318                 : {
     319                 :   SECItem value;
     320               0 :   bool    isExtractable = false;
     321                 :   SECStatus rv;
     322                 : 
     323               0 :   rv=PK11_ReadRawAttribute(PK11_TypePrivKey, privKey, CKA_EXTRACTABLE, &value);
     324               0 :   if (rv != SECSuccess) {
     325               0 :     return false;
     326                 :   }
     327               0 :   if ((value.len == 1) && (value.data != NULL)) {
     328               0 :     isExtractable = !!(*(CK_BBOOL*)value.data);
     329                 :   }
     330               0 :   SECITEM_FreeItem(&value, false);
     331               0 :   return isExtractable;
     332                 : }
     333                 :   
     334                 : // nsPKCS12Blob::ExportToFile
     335                 : //
     336                 : // Having already loaded the certs, form them into a blob (loading the keys
     337                 : // also), encode the blob, and stuff it into the file.
     338                 : //
     339                 : // TODO: handle slots correctly
     340                 : //       mirror "slotToUse" behavior from PSM 1.x
     341                 : //       verify the cert array to start off with?
     342                 : //       open output file as nsIFileStream object?
     343                 : //       set appropriate error codes
     344                 : nsresult
     345               0 : nsPKCS12Blob::ExportToFile(nsILocalFile *file, 
     346                 :                            nsIX509Cert **certs, int numCerts)
     347                 : {
     348               0 :   nsNSSShutDownPreventionLock locker;
     349                 :   nsresult rv;
     350               0 :   SECStatus srv = SECSuccess;
     351               0 :   SEC_PKCS12ExportContext *ecx = NULL;
     352               0 :   SEC_PKCS12SafeInfo *certSafe = NULL, *keySafe = NULL;
     353                 :   SECItem unicodePw;
     354               0 :   nsAutoString filePath;
     355                 :   int i;
     356               0 :   nsCOMPtr<nsILocalFile> localFileRef;
     357               0 :   NS_ASSERTION(mToken, "Need to set the token before exporting");
     358                 :   // init slot
     359                 : 
     360               0 :   bool InformedUserNoSmartcardBackup = false;
     361               0 :   int numCertsExported = 0;
     362                 : 
     363               0 :   rv = mToken->Login(true);
     364               0 :   if (NS_FAILED(rv)) goto finish;
     365                 :   // get file password (unicode)
     366               0 :   unicodePw.data = NULL;
     367               0 :   rv = newPKCS12FilePassword(&unicodePw);
     368               0 :   if (NS_FAILED(rv)) goto finish;
     369               0 :   if (unicodePw.data == NULL) {
     370               0 :     handleError(PIP_PKCS12_USER_CANCELED);
     371               0 :     return NS_OK;
     372                 :   }
     373                 :   // what about slotToUse in psm 1.x ???
     374                 :   // create export context
     375               0 :   ecx = SEC_PKCS12CreateExportContext(NULL, NULL, NULL /*slot*/, NULL);
     376               0 :   if (!ecx) {
     377               0 :     srv = SECFailure;
     378               0 :     goto finish;
     379                 :   }
     380                 :   // add password integrity
     381               0 :   srv = SEC_PKCS12AddPasswordIntegrity(ecx, &unicodePw, SEC_OID_SHA1);
     382               0 :   if (srv) goto finish;
     383                 : #if 0
     384                 :   // count the number of certs to export
     385                 :   nrv = mCertArray->Count(&numCerts);
     386                 :   if (NS_FAILED(nrv)) goto finish;
     387                 :   // loop over the certs
     388                 :   for (i=0; i<numCerts; i++) {
     389                 :     nsCOMPtr<nsIX509Cert> cert;
     390                 :     nrv = mCertArray->GetElementAt(i, getter_AddRefs(cert));
     391                 :     if (NS_FAILED(nrv)) goto finish;
     392                 : #endif
     393               0 :   for (i=0; i<numCerts; i++) {
     394                 : //    nsNSSCertificate *cert = reinterpret_cast<nsNSSCertificate *>(certs[i]);
     395               0 :     nsNSSCertificate *cert = (nsNSSCertificate *)certs[i];
     396                 :     // get it as a CERTCertificate XXX
     397               0 :     CERTCertificate *nssCert = NULL;
     398               0 :     CERTCertificateCleaner nssCertCleaner(nssCert);
     399               0 :     nssCert = cert->GetCert();
     400               0 :     if (!nssCert) {
     401               0 :       rv = NS_ERROR_FAILURE;
     402                 :       goto finish;
     403                 :     }
     404                 :     // We can only successfully export certs that are on 
     405                 :     // internal token.  Most, if not all, smart card vendors
     406                 :     // won't let you extract the private key (in any way
     407                 :     // shape or form) from the card.  So let's punt if 
     408                 :     // the cert is not in the internal db.
     409               0 :     if (nssCert->slot && !PK11_IsInternal(nssCert->slot)) {
     410                 :       // we aren't the internal token, see if the key is extractable.
     411                 :       SECKEYPrivateKey *privKey=PK11_FindKeyByDERCert(nssCert->slot,
     412               0 :                                                       nssCert, this);
     413                 : 
     414               0 :       if (privKey) {
     415               0 :         bool privKeyIsExtractable = isExtractable(privKey);
     416                 : 
     417               0 :         SECKEY_DestroyPrivateKey(privKey);
     418                 : 
     419               0 :         if (!privKeyIsExtractable) {
     420               0 :           if (!InformedUserNoSmartcardBackup) {
     421               0 :             InformedUserNoSmartcardBackup = true;
     422               0 :             handleError(PIP_PKCS12_NOSMARTCARD_EXPORT);
     423                 :           }
     424               0 :           continue;
     425                 :         }
     426                 :       }
     427                 :     }
     428                 : 
     429                 :     // XXX this is why, to verify the slot is the same
     430                 :     // PK11_FindObjectForCert(nssCert, NULL, slot);
     431                 :     // create the cert and key safes
     432               0 :     keySafe = SEC_PKCS12CreateUnencryptedSafe(ecx);
     433               0 :     if (!SEC_PKCS12IsEncryptionAllowed() || PK11_IsFIPS()) {
     434               0 :       certSafe = keySafe;
     435                 :     } else {
     436                 :       certSafe = SEC_PKCS12CreatePasswordPrivSafe(ecx, &unicodePw,
     437               0 :                            SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC);
     438                 :     }
     439               0 :     if (!certSafe || !keySafe) {
     440               0 :       rv = NS_ERROR_FAILURE;
     441                 :       goto finish;
     442                 :     }
     443                 :     // add the cert and key to the blob
     444                 :     srv = SEC_PKCS12AddCertAndKey(ecx, certSafe, NULL, nssCert,
     445                 :                                   CERT_GetDefaultCertDB(), // XXX
     446                 :                                   keySafe, NULL, true, &unicodePw,
     447               0 :                       SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC);
     448               0 :     if (srv) goto finish;
     449                 :     // cert was dup'ed, so release it
     450               0 :     ++numCertsExported;
     451                 :   }
     452                 :   
     453               0 :   if (!numCertsExported) goto finish;
     454                 :   
     455                 :   // prepare the instance to write to an export file
     456               0 :   this->mTmpFile = NULL;
     457               0 :   file->GetPath(filePath);
     458                 :   // Use the nsCOMPtr var localFileRef so that
     459                 :   // the reference to the nsILocalFile we create gets released as soon as
     460                 :   // we're out of scope, ie when this function exits.
     461               0 :   if (filePath.RFind(".p12", true, -1, 4) < 0) {
     462                 :     // We're going to add the .p12 extension to the file name just like
     463                 :     // Communicator used to.  We create a new nsILocalFile and initialize
     464                 :     // it with the new patch.
     465               0 :     filePath.AppendLiteral(".p12");
     466               0 :     localFileRef = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
     467               0 :     if (NS_FAILED(rv)) goto finish;
     468               0 :     localFileRef->InitWithPath(filePath);
     469               0 :     file = localFileRef;
     470                 :   }
     471                 :   rv = file->OpenNSPRFileDesc(PR_RDWR|PR_CREATE_FILE|PR_TRUNCATE, 0664, 
     472               0 :                               &mTmpFile);
     473               0 :   if (NS_FAILED(rv) || !this->mTmpFile) goto finish;
     474                 :   // encode and write
     475               0 :   srv = SEC_PKCS12Encode(ecx, write_export_file, this);
     476               0 :   if (srv) goto finish;
     477               0 :   handleError(PIP_PKCS12_BACKUP_OK);
     478                 : finish:
     479               0 :   if (NS_FAILED(rv) || srv != SECSuccess) {
     480               0 :     handleError(PIP_PKCS12_BACKUP_FAILED);
     481                 :   }
     482               0 :   if (ecx)
     483               0 :     SEC_PKCS12DestroyExportContext(ecx);
     484               0 :   if (this->mTmpFile) {
     485               0 :     PR_Close(this->mTmpFile);
     486               0 :     this->mTmpFile = NULL;
     487                 :   }
     488               0 :   SECITEM_ZfreeItem(&unicodePw, false);
     489               0 :   return rv;
     490                 : }
     491                 : 
     492                 : ///////////////////////////////////////////////////////////////////////
     493                 : //
     494                 : //  private members
     495                 : //
     496                 : ///////////////////////////////////////////////////////////////////////
     497                 : 
     498                 : // unicodeToItem
     499                 : //
     500                 : // For the NSS PKCS#12 library, must convert PRUnichars (shorts) to
     501                 : // a buffer of octets.  Must handle byte order correctly.
     502                 : // TODO: Is there a mozilla way to do this?  In the string lib?
     503                 : void
     504               0 : nsPKCS12Blob::unicodeToItem(const PRUnichar *uni, SECItem *item)
     505                 : {
     506               0 :   int len = 0;
     507               0 :   while (uni[len++] != 0);
     508               0 :   SECITEM_AllocItem(NULL, item, sizeof(PRUnichar) * len);
     509                 : #ifdef IS_LITTLE_ENDIAN
     510               0 :   int i = 0;
     511               0 :   for (i=0; i<len; i++) {
     512               0 :     item->data[2*i  ] = (unsigned char )(uni[i] << 8);
     513               0 :     item->data[2*i+1] = (unsigned char )(uni[i]);
     514                 :   }
     515                 : #else
     516                 :   memcpy(item->data, uni, item->len);
     517                 : #endif
     518               0 : }
     519                 : 
     520                 : // newPKCS12FilePassword
     521                 : //
     522                 : // Launch a dialog requesting the user for a new PKCS#12 file passowrd.
     523                 : // Handle user canceled by returning null password (caller must catch).
     524                 : nsresult
     525               0 : nsPKCS12Blob::newPKCS12FilePassword(SECItem *unicodePw)
     526                 : {
     527               0 :   nsresult rv = NS_OK;
     528               0 :   nsAutoString password;
     529               0 :   nsCOMPtr<nsICertificateDialogs> certDialogs;
     530               0 :   rv = ::getNSSDialogs(getter_AddRefs(certDialogs), 
     531                 :                        NS_GET_IID(nsICertificateDialogs),
     532               0 :                        NS_CERTIFICATEDIALOGS_CONTRACTID);
     533               0 :   if (NS_FAILED(rv)) return rv;
     534                 :   bool pressedOK;
     535                 :   {
     536               0 :     nsPSMUITracker tracker;
     537               0 :     if (tracker.isUIForbidden()) {
     538               0 :       rv = NS_ERROR_NOT_AVAILABLE;
     539                 :     }
     540                 :     else {
     541               0 :       rv = certDialogs->SetPKCS12FilePassword(mUIContext, password, &pressedOK);
     542                 :     }
     543                 :   }
     544               0 :   if (NS_FAILED(rv) || !pressedOK) return rv;
     545               0 :   unicodeToItem(password.get(), unicodePw);
     546               0 :   return NS_OK;
     547                 : }
     548                 : 
     549                 : // getPKCS12FilePassword
     550                 : //
     551                 : // Launch a dialog requesting the user for the password to a PKCS#12 file.
     552                 : // Handle user canceled by returning null password (caller must catch).
     553                 : nsresult
     554               0 : nsPKCS12Blob::getPKCS12FilePassword(SECItem *unicodePw)
     555                 : {
     556               0 :   nsresult rv = NS_OK;
     557               0 :   nsAutoString password;
     558               0 :   nsCOMPtr<nsICertificateDialogs> certDialogs;
     559               0 :   rv = ::getNSSDialogs(getter_AddRefs(certDialogs), 
     560                 :                        NS_GET_IID(nsICertificateDialogs),
     561               0 :                        NS_CERTIFICATEDIALOGS_CONTRACTID);
     562               0 :   if (NS_FAILED(rv)) return rv;
     563                 :   bool pressedOK;
     564                 :   {
     565               0 :     nsPSMUITracker tracker;
     566               0 :     if (tracker.isUIForbidden()) {
     567               0 :       rv = NS_ERROR_NOT_AVAILABLE;
     568                 :     }
     569                 :     else {
     570               0 :       rv = certDialogs->GetPKCS12FilePassword(mUIContext, password, &pressedOK);
     571                 :     }
     572                 :   }
     573               0 :   if (NS_FAILED(rv) || !pressedOK) return rv;
     574               0 :   unicodeToItem(password.get(), unicodePw);
     575               0 :   return NS_OK;
     576                 : }
     577                 : 
     578                 : // inputToDecoder
     579                 : //
     580                 : // Given a decoder, read bytes from file and input them to the decoder.
     581                 : nsresult
     582               0 : nsPKCS12Blob::inputToDecoder(SEC_PKCS12DecoderContext *dcx, nsILocalFile *file)
     583                 : {
     584               0 :   nsNSSShutDownPreventionLock locker;
     585                 :   nsresult rv;
     586                 :   SECStatus srv;
     587                 :   PRUint32 amount;
     588                 :   char buf[PIP_PKCS12_BUFFER_SIZE];
     589                 : 
     590               0 :   nsCOMPtr<nsIInputStream> fileStream;
     591               0 :   rv = NS_NewLocalFileInputStream(getter_AddRefs(fileStream), file);
     592                 :   
     593               0 :   if (NS_FAILED(rv)) {
     594               0 :     return rv;
     595                 :   }
     596                 : 
     597               0 :   while (true) {
     598               0 :     rv = fileStream->Read(buf, PIP_PKCS12_BUFFER_SIZE, &amount);
     599               0 :     if (NS_FAILED(rv)) {
     600               0 :       return rv;
     601                 :     }
     602                 :     // feed the file data into the decoder
     603                 :     srv = SEC_PKCS12DecoderUpdate(dcx, 
     604                 :                                   (unsigned char*) buf, 
     605               0 :                                   amount);
     606               0 :     if (srv) {
     607                 :       // don't allow the close call to overwrite our precious error code
     608               0 :       int pr_err = PORT_GetError();
     609               0 :       PORT_SetError(pr_err);
     610               0 :       return NS_ERROR_ABORT;
     611                 :     }
     612               0 :     if (amount < PIP_PKCS12_BUFFER_SIZE)
     613                 :       break;
     614                 :   }
     615               0 :   return NS_OK;
     616                 : }
     617                 : 
     618                 : #ifdef XP_MAC
     619                 : 
     620                 : OSErr ConvertMacPathToUnixPath(const char *macPath, char **unixPath)
     621                 : {
     622                 :   PRIntn len;
     623                 :   char *cursor;
     624                 :   
     625                 :   len = PL_strlen(macPath);
     626                 :   cursor = (char*)PR_Malloc(len+2);
     627                 :   if (!cursor)
     628                 :     return memFullErr;
     629                 :     
     630                 :   memcpy(cursor+1, macPath, len+1);
     631                 :   *unixPath = cursor;
     632                 :   *cursor = '/';
     633                 :   while ((cursor = PL_strchr(cursor, ':')) != NULL) {
     634                 :     *cursor = '/';
     635                 :     cursor++;
     636                 :   }
     637                 :   return noErr;
     638                 : }
     639                 : #endif
     640                 : 
     641                 : //
     642                 : // C callback methods
     643                 : //
     644                 : 
     645                 : // digest_open
     646                 : // prepare a memory buffer for reading/writing digests
     647                 : SECStatus PR_CALLBACK
     648               0 : nsPKCS12Blob::digest_open(void *arg, PRBool reading)
     649                 : {
     650               0 :   nsPKCS12Blob *cx = reinterpret_cast<nsPKCS12Blob *>(arg);
     651               0 :   NS_ENSURE_TRUE(cx, SECFailure);
     652                 :   
     653               0 :   if (reading) {
     654               0 :     NS_ENSURE_TRUE(cx->mDigest, SECFailure);
     655                 : 
     656               0 :     delete cx->mDigestIterator;
     657               0 :     cx->mDigestIterator = new nsCString::const_iterator;
     658                 : 
     659               0 :     if (!cx->mDigestIterator) {
     660               0 :       PORT_SetError(SEC_ERROR_NO_MEMORY);
     661               0 :       return SECFailure;
     662                 :     }
     663                 : 
     664               0 :     cx->mDigest->BeginReading(*cx->mDigestIterator);
     665                 :   }
     666                 :   else {
     667               0 :     delete cx->mDigest;
     668               0 :     cx->mDigest = new nsCString;
     669                 : 
     670               0 :     if (!cx->mDigest) {
     671               0 :       PORT_SetError(SEC_ERROR_NO_MEMORY);
     672               0 :       return SECFailure;
     673                 :     }
     674                 :   }
     675                 : 
     676               0 :   return SECSuccess;
     677                 : }
     678                 : 
     679                 : // digest_close
     680                 : // destroy a possibly active iterator
     681                 : // remove the data buffer if requested
     682                 : SECStatus PR_CALLBACK
     683               0 : nsPKCS12Blob::digest_close(void *arg, PRBool remove_it)
     684                 : {
     685               0 :   nsPKCS12Blob *cx = reinterpret_cast<nsPKCS12Blob *>(arg);
     686               0 :   NS_ENSURE_TRUE(cx, SECFailure);
     687                 : 
     688               0 :   delete cx->mDigestIterator;
     689               0 :   cx->mDigestIterator = nsnull;
     690                 : 
     691               0 :   if (remove_it) {  
     692               0 :     delete cx->mDigest;
     693               0 :     cx->mDigest = nsnull;
     694                 :   }
     695                 :   
     696               0 :   return SECSuccess;
     697                 : }
     698                 : 
     699                 : // digest_read
     700                 : // read bytes from the memory buffer
     701                 : int PR_CALLBACK
     702               0 : nsPKCS12Blob::digest_read(void *arg, unsigned char *buf, unsigned long len)
     703                 : {
     704               0 :   nsPKCS12Blob *cx = reinterpret_cast<nsPKCS12Blob *>(arg);
     705               0 :   NS_ENSURE_TRUE(cx, SECFailure);
     706               0 :   NS_ENSURE_TRUE(cx->mDigest, SECFailure);
     707                 : 
     708                 :   // iterator object must exist when digest has been opened in read mode
     709               0 :   NS_ENSURE_TRUE(cx->mDigestIterator, SECFailure);
     710                 : 
     711               0 :   unsigned long available = cx->mDigestIterator->size_forward();
     712                 :   
     713               0 :   if (len > available)
     714               0 :     len = available;
     715                 : 
     716               0 :   memcpy(buf, cx->mDigestIterator->get(), len);
     717               0 :   cx->mDigestIterator->advance(len);
     718                 :   
     719               0 :   return len;
     720                 : }
     721                 : 
     722                 : // digest_write
     723                 : // append bytes to the memory buffer
     724                 : int PR_CALLBACK
     725               0 : nsPKCS12Blob::digest_write(void *arg, unsigned char *buf, unsigned long len)
     726                 : {
     727               0 :   nsPKCS12Blob *cx = reinterpret_cast<nsPKCS12Blob *>(arg);
     728               0 :   NS_ENSURE_TRUE(cx, SECFailure);
     729               0 :   NS_ENSURE_TRUE(cx->mDigest, SECFailure);
     730                 : 
     731                 :   // make sure we are in write mode, read iterator has not yet been allocated
     732               0 :   NS_ENSURE_FALSE(cx->mDigestIterator, SECFailure);
     733                 :   
     734                 :   cx->mDigest->Append(reinterpret_cast<char *>(buf),
     735               0 :                      static_cast<PRUint32>(len));
     736                 :   
     737               0 :   return len;
     738                 : }
     739                 : 
     740                 : // nickname_collision
     741                 : // what to do when the nickname collides with one already in the db.
     742                 : // TODO: not handled, throw a dialog allowing the nick to be changed?
     743                 : SECItem * PR_CALLBACK
     744               0 : nsPKCS12Blob::nickname_collision(SECItem *oldNick, PRBool *cancel, void *wincx)
     745                 : {
     746               0 :   nsNSSShutDownPreventionLock locker;
     747               0 :   *cancel = false;
     748                 :   nsresult rv;
     749               0 :   nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
     750               0 :   if (NS_FAILED(rv)) return nsnull;
     751               0 :   int count = 1;
     752               0 :   nsCString nickname;
     753               0 :   nsAutoString nickFromProp;
     754               0 :   nssComponent->GetPIPNSSBundleString("P12DefaultNickname", nickFromProp);
     755               0 :   NS_ConvertUTF16toUTF8 nickFromPropC(nickFromProp);
     756                 :   // The user is trying to import a PKCS#12 file that doesn't have the
     757                 :   // attribute we use to set the nickname.  So in order to reduce the
     758                 :   // number of interactions we require with the user, we'll build a nickname
     759                 :   // for the user.  The nickname isn't prominently displayed in the UI, 
     760                 :   // so it's OK if we generate one on our own here.
     761                 :   //   XXX If the NSS API were smarter and actually passed a pointer to
     762                 :   //       the CERTCertificate* we're importing we could actually just
     763                 :   //       call default_nickname (which is what the issuance code path
     764                 :   //       does) and come up with a reasonable nickname.  Alas, the NSS
     765                 :   //       API limits our ability to produce a useful nickname without
     766                 :   //       bugging the user.  :(
     767               0 :   while (1) {
     768                 :     // If we've gotten this far, that means there isn't a certificate
     769                 :     // in the database that has the same subject name as the cert we're
     770                 :     // trying to import.  So we need to come up with a "nickname" to 
     771                 :     // satisfy the NSS requirement or fail in trying to import.  
     772                 :     // Basically we use a default nickname from a properties file and 
     773                 :     // see if a certificate exists with that nickname.  If there isn't, then
     774                 :     // create update the count by one and append the string '#1' Or 
     775                 :     // whatever the count currently is, and look for a cert with 
     776                 :     // that nickname.  Keep updating the count until we find a nickname
     777                 :     // without a corresponding cert.
     778                 :     //  XXX If a user imports *many* certs without the 'friendly name'
     779                 :     //      attribute, then this may take a long time.  :(
     780               0 :     if (count > 1) {
     781               0 :       nickname.Adopt(PR_smprintf("%s #%d", nickFromPropC.get(), count));
     782                 :     } else {
     783               0 :       nickname = nickFromPropC;
     784                 :     }
     785                 :     CERTCertificate *cert = CERT_FindCertByNickname(CERT_GetDefaultCertDB(),
     786               0 :                                            const_cast<char*>(nickname.get()));
     787               0 :     if (!cert) {
     788                 :       break;
     789                 :     }
     790               0 :     CERT_DestroyCertificate(cert);
     791               0 :     count++;
     792                 :   }
     793               0 :   SECItem *newNick = new SECItem;
     794               0 :   if (!newNick)
     795               0 :     return nsnull;
     796                 : 
     797               0 :   newNick->type = siAsciiString;
     798               0 :   newNick->data = (unsigned char*) nsCRT::strdup(nickname.get());
     799               0 :   newNick->len  = strlen((char*)newNick->data);
     800               0 :   return newNick;
     801                 : }
     802                 : 
     803                 : // write_export_file
     804                 : // write bytes to the exported PKCS#12 file
     805                 : void PR_CALLBACK
     806               0 : nsPKCS12Blob::write_export_file(void *arg, const char *buf, unsigned long len)
     807                 : {
     808               0 :   nsPKCS12Blob *cx = (nsPKCS12Blob *)arg;
     809               0 :   PR_Write(cx->mTmpFile, buf, len);
     810               0 : }
     811                 : 
     812                 : // pip_ucs2_ascii_conversion_fn
     813                 : // required to be set by NSS (to do PKCS#12), but since we've already got
     814                 : // unicode make this a no-op.
     815                 : PRBool
     816               0 : pip_ucs2_ascii_conversion_fn(PRBool toUnicode,
     817                 :                              unsigned char *inBuf,
     818                 :                              unsigned int inBufLen,
     819                 :                              unsigned char *outBuf,
     820                 :                              unsigned int maxOutBufLen,
     821                 :                              unsigned int *outBufLen,
     822                 :                              PRBool swapBytes)
     823                 : {
     824                 :   // do a no-op, since I've already got unicode.  Hah!
     825               0 :   *outBufLen = inBufLen;
     826               0 :   memcpy(outBuf, inBuf, inBufLen);
     827               0 :   return true;
     828                 : }
     829                 : 
     830                 : void
     831               0 : nsPKCS12Blob::handleError(int myerr)
     832                 : {
     833               0 :   if (!NS_IsMainThread()) {
     834               0 :     NS_ERROR("nsPKCS12Blob::handleError called off the mai nthread.");
     835               0 :     return;
     836                 :   }
     837                 : 
     838               0 :   int prerr = PORT_GetError();
     839               0 :   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("PKCS12: NSS/NSPR error(%d)", prerr));
     840               0 :   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("PKCS12: I called(%d)", myerr));
     841                 : 
     842               0 :   const char * msgID = nsnull;
     843                 : 
     844               0 :   switch (myerr) {
     845               0 :   case PIP_PKCS12_RESTORE_OK:       msgID = "SuccessfulP12Restore"; break;
     846               0 :   case PIP_PKCS12_BACKUP_OK:        msgID = "SuccessfulP12Backup";  break;
     847                 :   case PIP_PKCS12_USER_CANCELED:
     848               0 :     return;  /* Just ignore it for now */
     849               0 :   case PIP_PKCS12_NOSMARTCARD_EXPORT: msgID = "PKCS12InfoNoSmartcardBackup"; break;
     850               0 :   case PIP_PKCS12_RESTORE_FAILED:   msgID = "PKCS12UnknownErrRestore"; break;
     851               0 :   case PIP_PKCS12_BACKUP_FAILED:    msgID = "PKCS12UnknownErrBackup"; break;
     852                 :   case PIP_PKCS12_NSS_ERROR:
     853               0 :     switch (prerr) {
     854                 :     // The following errors have the potential to be "handled", by asking
     855                 :     // the user (via a dialog) whether s/he wishes to continue
     856               0 :     case 0: break;
     857                 :     case SEC_ERROR_PKCS12_CERT_COLLISION:
     858                 :       /* pop a dialog saying the cert is already in the database */
     859                 :       /* ask to keep going?  what happens if one collision but others ok? */
     860                 :       // The following errors cannot be "handled", notify the user (via an alert)
     861                 :       // that the operation failed.
     862                 : #if 0
     863                 :       // XXX a boy can dream...
     864                 :       //     but the PKCS12 lib never throws this error
     865                 :       //     but then again, how would it?  anyway, convey the info below
     866                 :     case SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT:
     867                 :       msgID = "PKCS12PasswordInvalid";
     868                 :       break;
     869                 : #endif
     870                 : 
     871               0 :     case SEC_ERROR_BAD_PASSWORD: msgID = "PK11BadPassword"; break;
     872                 : 
     873                 :     case SEC_ERROR_BAD_DER:
     874                 :     case SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE:
     875                 :     case SEC_ERROR_PKCS12_INVALID_MAC:
     876               0 :       msgID = "PKCS12DecodeErr";
     877               0 :       break;
     878                 : 
     879               0 :     case SEC_ERROR_PKCS12_DUPLICATE_DATA: msgID = "PKCS12DupData"; break;
     880                 :     }
     881               0 :     break;
     882                 :   }
     883                 : 
     884               0 :   if (!msgID)
     885               0 :     msgID = "PKCS12UnknownErr";
     886                 : 
     887                 :   nsresult rv;
     888               0 :   nsCOMPtr<nsINSSComponent> nssComponent = do_GetService(kNSSComponentCID, &rv);
     889               0 :   if (NS_SUCCEEDED(rv))
     890               0 :     (void) nssComponent->ShowAlertFromStringBundle(msgID);
     891                 : }
     892                 : 

Generated by: LCOV version 1.7