.. _mozilla_projects_nss_nss_sample_code_enc_dec_mac_using_key_wrap_certreq_pkcs10_csr:

Enc Dec MAC Using Key Wrap CertReq PKCS10 CSR
=============================================

.. _nss_sample_code_6_encryptiondecryption_and_mac_and_output_public_as_a_pkcs_11_csr.:

`NSS Sample Code 6: Encryption/Decryption and MAC and output Public as a PKCS 11 CSR. <#nss_sample_code_6_encryptiondecryption_and_mac_and_output_public_as_a_pkcs_11_csr.>`__
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

.. container::

   Generates encryption/mac keys and outputs public key as pkcs11 certificate signing request

   .. code:: brush:

       /* This Source Code Form is subject to the terms of the Mozilla Public
        * License, v. 2.0. If a copy of the MPL was not distributed with this
        * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

      /* NSPR Headers */
       #include <prthread.h>
       #include <plgetopt.h>
       #include <prerror.h>
       #include <prinit.h>
       #include <prlog.h>
       #include <prtypes.h>
       #include <plstr.h>

      /* NSS headers */
       #include <keyhi.h>
       #include <pk11priv.h>

      /* our samples utilities */
       #include "util.h"

      /* Constants */
       #define BLOCKSIZE             32
       #define MODBLOCKSIZE          128
       #define DEFAULT_KEY_BITS      1024

      /* Header file Constants */
       #define ENCKEY_HEADER         "-----BEGIN WRAPPED ENCKEY-----"
       #define ENCKEY_TRAILER        "-----END WRAPPED ENCKEY-----"
       #define MACKEY_HEADER         "-----BEGIN WRAPPED MACKEY-----"
       #define MACKEY_TRAILER        "-----END WRAPPED MACKEY-----"
       #define IV_HEADER             "-----BEGIN IV-----"
       #define IV_TRAILER            "-----END IV-----"
       #define MAC_HEADER            "-----BEGIN MAC-----"
       #define MAC_TRAILER           "-----END MAC-----"
       #define PAD_HEADER            "-----BEGIN PAD-----"
       #define PAD_TRAILER           "-----END PAD-----"
       #define LAB_HEADER            "-----BEGIN KEY LABEL-----"
       #define LAB_TRAILER           "-----END KEY LABEL-----"
       #define PUBKEY_HEADER         "-----BEGIN PUB KEY -----"
       #define PUBKEY_TRAILER        "-----END PUB KEY -----"
       #define NS_CERTREQ_HEADER     "-----BEGIN NEW CERTIFICATE REQUEST-----"
       #define NS_CERTREQ_TRAILER    "-----END NEW CERTIFICATE REQUEST-----"
       #define NS_CERT_ENC_HEADER    "-----BEGIN CERTIFICATE FOR ENCRYPTION-----"
       #define NS_CERT_ENC_TRAILER   "-----END CERTIFICATE FOR ENCRYPTION-----"
       #define NS_CERT_VFY_HEADER    "-----BEGIN CERTIFICATE FOR SIGNATURE VERIFICATION-----"
       #define NS_CERT_VFY_TRAILER   "-----END CERTIFICATE FOR SIGNATURE VERIFICATION-----"
       #define NS_SIG_HEADER         "-----BEGIN SIGNATURE-----"
       #define NS_SIG_TRAILER        "-----END SIGNATURE-----"
       #define NS_CERT_HEADER        "-----BEGIN CERTIFICATE-----"
       #define NS_CERT_TRAILER       "-----END CERTIFICATE-----"

      /* sample 6 commands */
       typedef enum {
           GENERATE_CSR,
           ADD_CERT_TO_DB,
           SAVE_CERT_TO_HEADER,
           ENCRYPT,
           DECRYPT,
           SIGN,
           VERIFY,
           UNKNOWN
       } CommandType;

      typedef enum {
          SYMKEY = 0,
          MACKEY = 1,
          IV     = 2,
          MAC    = 3,
          PAD    = 4,
          PUBKEY = 5,
          LAB    = 6,
          CERTENC= 7,
          CERTVFY= 8,
          SIG    = 9
       } HeaderType;


       /*
        * Print usage message and exit
        */
       static void
       Usage(const char *progName)
       {
           fprintf(stderr, "\nUsage:  %s %s %s %s %s %s %s %s %s %s\n\n",
                   progName,
                   " -<G|A|H|E|DS|V> -d <dbdirpath> ",
                   "[-p <dbpwd> | -f <dbpwdfile>] [-z <noisefilename>] [-a <\"\">]",
                   "-s <subject> -r <csr> | ",
                   "-n <nickName> -t <trust> -c <cert> [ -r <csr> -u <issuerNickname> [-x <\"\">] -m <serialNumber> ] | ",
                   "-n <nickName> -b <headerfilename> | ",
                   "-b <headerfilename> -i <ipfilename> -e <encryptfilename> | ",
                   "-b <headerfilename> -i <ipfilename> | ",
                   "-b <headerfilename> -i <ipfilename> | ",
                   "-b <headerfilename> -e <encryptfilename> -o <opfilename> \n");
           fprintf(stderr, "commands:\n\n");
           fprintf(stderr, "%s %s\n --for generating cert request (for CA also)\n\n",
                    progName, "-G -s <subject> -r <csr>");
           fprintf(stderr, "%s %s\n --to input and store cert (for CA also)\n\n",
                    progName, "-A -n <nickName> -t <trust> -c <cert> [ -r <csr> -u <issuerNickname> [-x <\"\">] -m <serialNumber> ]");
           fprintf(stderr, "%s %s\n --to put cert in header\n\n",
                    progName, "-H -n <nickname> -b <headerfilename> [-v <\"\">]");
           fprintf(stderr, "%s %s\n --to find public key from cert in header and encrypt\n\n",
                    progName, "-E -b <headerfilename> -i <ipfilename> -e <encryptfilename> ");
           fprintf(stderr, "%s %s\n --decrypt using corresponding private key \n\n",
                    progName, "-D -b <headerfilename> -e <encryptfilename> -o <opfilename>");
           fprintf(stderr, "%s %s\n --Sign using private key \n\n",
                    progName, "-S -b <headerfilename> -i <infilename> ");
           fprintf(stderr, "%s %s\n --Verify using public key \n\n",
                    progName, "-V -b <headerfilename> -i <ipfilename> ");
           fprintf(stderr, "options:\n\n");
           fprintf(stderr, "%-30s - db directory path\n\n",
                    "-d <dbdirpath>");
           fprintf(stderr, "%-30s - db password [optional]\n\n",
                    "-p <dbpwd>");
           fprintf(stderr, "%-30s - db password file [optional]\n\n",
                    "-f <dbpwdfile>");
           fprintf(stderr, "%-30s - noise file name [optional]\n\n",
                    "-z <noisefilename>");
           fprintf(stderr, "%-30s - input file name\n\n",
                    "-i <ipfilename>");
           fprintf(stderr, "%-30s - header file name\n\n",
                    "-b <headerfilename>");
           fprintf(stderr, "%-30s - encrypt file name\n\n",
                    "-e <encryptfilename>");
           fprintf(stderr, "%-30s - output file name\n\n",
                    "-o <opfilename>");
           fprintf(stderr, "%-30s - certificate serial number\n\n",
                    "-m <serialNumber>");
           fprintf(stderr, "%-30s - certificate nickname\n\n",
                    "-n <nickname>");
           fprintf(stderr, "%-30s - certificate trust\n\n",
                    "-t <trustargs>");
           fprintf(stderr, "%-30s - certificate issuer nickname\n\n",
                    "-u <issuerNickname>");
           fprintf(stderr, "%-30s - certificate signing request \n\n",
                    "-r <csr>");
           fprintf(stderr, "%-30s - generate a self-signed cert [optional]\n\n",
                    "-x");
           fprintf(stderr, "%-30s - to enable ascii [optional]\n\n",
                    "-a");
           fprintf(stderr, "%-30s - to save certificate to header file as sig verification [optional]\n\n",
                    "-v");
           exit(-1);
       }

      /*
        * Validate the options used for Generate CSR command
        */
       static void
       ValidateGenerateCSRCommand(const char *progName,
                                  const char *dbdir,
                                  CERTName   *subject,
                                  const char *subjectStr,
                                  const char *certReqFileName)
       {
           PRBool validationFailed = PR_FALSE;
           if (!subject) {
               PR_fprintf(PR_STDERR, "%s -G -d %s -s: improperly formatted name: \"%s\"\n",
                          progName, dbdir, subjectStr);
               validationFailed = PR_TRUE;
           }
           if (!certReqFileName) {
               PR_fprintf(PR_STDERR, "%s -G -d %s -s %s -r: certificate request file name not found\n",
                          progName, dbdir, subjectStr);
               validationFailed = PR_TRUE;
           }
           if (validationFailed) {
               fprintf(stderr, "\nUsage:  %s %s \n\n", progName,
                       "-G -d <dbdirpath> -s <subject> -r <csr> \n");
               exit(-1);
           }
       }

      /*
        * Validate the options used for Add Cert to DB command
        */
       static void
       ValidateAddCertToDBCommand(const char *progName,
                                  const char *dbdir,
                                  const char *nickNameStr,
                                  const char *trustStr,
                                  const char *certFileName,
                                  const char *certReqFileName,
                                  const char *issuerNameStr,
                                  const char *serialNumberStr,
                                  PRBool      selfsign)
       {
           PRBool validationFailed = PR_FALSE;
           if (!nickNameStr) {
               PR_fprintf(PR_STDERR, "%s -A -d %s -n : nick name is missing\n",
                          progName, dbdir);
               validationFailed = PR_TRUE;
           }
           if (!trustStr) {
               PR_fprintf(PR_STDERR, "%s -A -d %s -n %s -t: trust flag is missing\n",
                          progName, dbdir, nickNameStr);
               validationFailed = PR_TRUE;
           }
           if (!certFileName) {
               PR_fprintf(PR_STDERR, "%s -A -d %s -n %s -t %s -c: certificate file name not found\n",
                          progName, dbdir, nickNameStr, trustStr, serialNumberStr, certReqFileName);
               validationFailed = PR_TRUE;
           }
           if (PR_Access(certFileName, PR_ACCESS_EXISTS) == PR_FAILURE) {
               if (!certReqFileName) {
                   PR_fprintf(PR_STDERR, "%s -A -d %s -n %s -t %s -c %s -r: certificate file or certificate request file is not found\n",
                              progName, dbdir, nickNameStr, trustStr, certFileName);
                   validationFailed = PR_TRUE;
               }
               if (!selfsign && !issuerNameStr) {
                   PR_fprintf(PR_STDERR, "%s -A -d %s -n %s -t %s -c %s -r %s -u : issuer name is missing\n",
                              progName, dbdir, nickNameStr, trustStr, certFileName, certReqFileName);
                   validationFailed = PR_TRUE;
               }
               if (!serialNumberStr) {
                   PR_fprintf(PR_STDERR, "%s -A -d %s -n %s -t %s -c %s -r %s -u %s -m : serial number is missing\n",
                              progName, dbdir, nickNameStr, trustStr, certFileName, certReqFileName, issuerNameStr);
                   validationFailed = PR_TRUE;
               }
           }
           if (validationFailed) {
               fprintf(stderr, "\nUsage:  %s %s \n\n", progName,
                       " -A -d <dbdirpath> -n <nickName> -t <trust> -c <cert> \n");
               fprintf(stderr, "     OR\n");
               fprintf(stderr, "\nUsage:  %s %s \n\n", progName,
                       "-A -d <dbdirpath> -n <nickName> -t <trust> -c <cert> -r <csr> -u <issuerNickname> -m <serialNumber> [-x <\"\">] \n");
               exit(-1);
           }
       }

      /*
        * Validate the options used for Save Cert To Header command
        */
       static void
       ValidateSaveCertToHeaderCommand(const char *progName,
                                       const char *dbdir,
                                       const char *nickNameStr,
                                       const char *headerFileName)
       {
           PRBool validationFailed = PR_FALSE;
           if (!nickNameStr) {
               PR_fprintf(PR_STDERR, "%s -S -d %s -n : nick name is missing\n",
                          progName, dbdir);
               validationFailed = PR_TRUE;
           }
           if (!headerFileName) {
               PR_fprintf(PR_STDERR, "%s -S -d %s -n %s -b : header file name is not found\n",
                          progName, dbdir, nickNameStr);
               validationFailed = PR_TRUE;
           }
           if (validationFailed) {
               fprintf(stderr, "\nUsage:  %s %s \n\n", progName,
                       "-S -d <dbdirpath> -n <nickname> -b <headerfilename> [-v <\"\">]\n");
               exit(-1);
           }
       }

      /*
        * Validate the options used for Encrypt command
        */
       static void
       ValidateEncryptCommand(const char *progName,
                              const char *dbdir,
                              const char *nickNameStr,
                              const char *headerFileName,
                              const char *inFileName,
                              const char *encryptedFileName)
       {
           PRBool validationFailed = PR_FALSE;
           if (!nickNameStr) {
               PR_fprintf(PR_STDERR, "%s -E -d %s -n : nick name is missing\n",
                          progName, dbdir);
               validationFailed = PR_TRUE;
           }
           if (!headerFileName) {
               PR_fprintf(PR_STDERR, "%s -E -d %s -n %s -b : header file name is not found\n",
                          progName, dbdir, nickNameStr);
               validationFailed = PR_TRUE;
           }
           if (!inFileName) {
               PR_fprintf(PR_STDERR, "%s -E -d %s -n %s -b %s -i : input file name is not found\n",
                          progName, dbdir, nickNameStr, headerFileName);
               validationFailed = PR_TRUE;
           }
           if (!encryptedFileName) {
               PR_fprintf(PR_STDERR, "%s -E -d %s -n %s -b %s -i %s -e : encrypt file name is not found\n",
                          progName, dbdir, nickNameStr, headerFileName, inFileName);
               validationFailed = PR_TRUE;
           }
           if (validationFailed) {
               fprintf(stderr, "\nUsage:  %s %s \n\n", progName,
                       "-E -d <dbdirpath> -b <headerfilename> -i <ipfilename> -e <encryptfilename> -n <nickname> \n");
               exit(-1);
           }
       }

      /*
        * Validate the options used for Sign command
        */
       static void
       ValidateSignCommand(const char *progName,
                              const char *dbdir,
                              const char *nickNameStr,
                              const char *headerFileName,
                              const char *inFileName)
       {
           PRBool validationFailed = PR_FALSE;
           if (!nickNameStr) {
               PR_fprintf(PR_STDERR, "%s -I -d %s -n : nick name is missing\n",
                          progName, dbdir);
               validationFailed = PR_TRUE;
           }
           if (!headerFileName) {
               PR_fprintf(PR_STDERR, "%s -I -d %s -n %s -b : header file name is not found\n",
                          progName, dbdir, nickNameStr);
               validationFailed = PR_TRUE;
           }
           if (!inFileName) {
               PR_fprintf(PR_STDERR, "%s -I -d %s -n %s -b %s -i : input file name is not found\n",
                          progName, dbdir, nickNameStr, headerFileName);
               validationFailed = PR_TRUE;
           }
           if (validationFailed) {
               fprintf(stderr, "\nUsage:  %s %s \n\n", progName,
                       "-I -d <dbdirpath> -b <headerfilename> -i <ipfilename> -n <nickname> \n");
               exit(-1);
           }
       }

      /*
        * Validate the options used for verify command
        */
       static void
       ValidateVerifyCommand(const char *progName,
                              const char *dbdir,
                              const char *headerFileName,
                              const char *inFileName)
       {
           PRBool validationFailed = PR_FALSE;
           if (!headerFileName) {
               PR_fprintf(PR_STDERR, "%s -V -d %s -b : header file name is not found\n",
                          progName, dbdir);
               validationFailed = PR_TRUE;
           }
           if (!inFileName) {
               PR_fprintf(PR_STDERR, "%s -I -d %s -b %s -i : input file name is not found\n",
                          progName, dbdir, headerFileName);
               validationFailed = PR_TRUE;
           }
           if (validationFailed) {
               fprintf(stderr, "\nUsage:  %s %s \n\n", progName,
                       "-I -d <dbdirpath> -b <headerfilename> -i <ipfilename> \n");
               exit(-1);
           }
       }

      /*
        * Validate the options used for Decrypt command
        */
       static void
       ValidateDecryptCommand(const char *progName,
                              const char *dbdir,
                              const char *headerFileName,
                              const char *encryptedFileName,
                              const char *outFileName)
       {
           PRBool validationFailed = PR_FALSE;
           if (!headerFileName) {
               PR_fprintf(PR_STDERR, "%s -D -d %s -b : header file name is not found\n",
                          progName, dbdir);
               validationFailed = PR_TRUE;
           }
           if (!encryptedFileName) {
               PR_fprintf(PR_STDERR, "%s -D -d %s -b %s -e : encrypt file name is not found\n",
                          progName, dbdir, headerFileName);
               validationFailed = PR_TRUE;
           }
           if (!outFileName) {
               PR_fprintf(PR_STDERR, "%s -D -d %s -b %s -e %s -o : output file name is not found\n",
                          progName, dbdir, headerFileName, encryptedFileName);
               validationFailed = PR_TRUE;
           }
           if (validationFailed) {
               fprintf(stderr, "\nUsage:  %s %s \n\n", progName,
                       "-D -d <dbdirpath> -b <headerfilename> -e <encryptfilename> -o <opfilename>\n");
               exit(-1);
           }
       }

      /*
        * Sign the contents of input file using private key and
        * return result as SECItem
        */
       SECStatus
       SignData(const char *inFileName, SECKEYPrivateKey *pk, SECItem *res)
       {
           SECStatus     rv         = SECFailure;
           unsigned int  nb;
           unsigned char ibuf[4096];
           PRFileDesc   *inFile     = NULL;
           SGNContext   *sgn        = NULL;

          /*  Open the input file for reading */
           inFile = PR_Open(inFileName, PR_RDONLY, 0);
           if (!inFile) {
               PR_fprintf(PR_STDERR, "Unable to open \"%s\" for reading.\n",
                          inFileName);
               rv = SECFailure;
               goto cleanup;
           }

          /* Sign using private key */

          sgn = SGN_NewContext(SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION, pk);
           if (!sgn) {
               PR_fprintf(PR_STDERR, "unable to create context for signing\n");
               rv = SECFailure;
               goto cleanup;
           }

          rv = SGN_Begin(sgn);
           if (rv != SECSuccess) {
               PR_fprintf(PR_STDERR, "problem while SGN_Begin\n");
               goto cleanup;
           }
           while ((nb = PR_Read(inFile, ibuf, sizeof(ibuf))) > 0) {
               rv = SGN_Update(sgn, ibuf, nb);
               if (rv != SECSuccess) {
                   PR_fprintf(PR_STDERR, "problem while SGN_Update\n");
                   goto cleanup;
               }
           }
           rv = SGN_End(sgn, res);
           if (rv != SECSuccess) {
               PR_fprintf(PR_STDERR, "problem while SGN_End\n");
               goto cleanup;
           }
       cleanup:
           if (inFile) {
               PR_Close(inFile);
           }
           if (sgn) {
               SGN_DestroyContext(sgn, PR_TRUE);
           }
           return rv;
       }

      /*
        * Verify the signature using public key
        */
       SECStatus
       VerifyData(const char *inFileName, SECKEYPublicKey *pk,
                  SECItem *sigItem, secuPWData *pwdata)
       {
           unsigned int  nb;
           unsigned char ibuf[4096];
           SECStatus     rv     = SECFailure;
           VFYContext   *vfy    = NULL;
           PRFileDesc   *inFile = NULL;

          /*  Open the input file for reading */
           inFile = PR_Open(inFileName, PR_RDONLY, 0);
           if (!inFile) {
               PR_fprintf(PR_STDERR, "Unable to open \"%s\" for reading.\n",
                          inFileName);
               rv = SECFailure;
               goto cleanup;
           }

          vfy = VFY_CreateContext(pk,
                                  sigItem,
                                  SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION,
                                  pwdata);
           if (!vfy) {
               PR_fprintf(PR_STDERR, "unable to create context for verifying signature\n");
               rv = SECFailure;
               goto cleanup;
           }
           rv = VFY_Begin(vfy);
           if (rv != SECSuccess) {
               PR_fprintf(PR_STDERR, "problem while VFY_Begin\n");
               goto cleanup;
           }
           while ((nb = PR_Read(inFile, ibuf, sizeof(ibuf))) > 0) {
               rv = VFY_Update(vfy, ibuf, nb);
               if (rv != SECSuccess) {
                   PR_fprintf(PR_STDERR, "problem while VFY_Update\n");
                   goto cleanup;
               }
           }
           rv = VFY_End(vfy);
           if (rv != SECSuccess) {
               PR_fprintf(PR_STDERR, "problem while VFY_End\n");
               goto cleanup;
           }

      cleanup:
           if (inFile) {
               PR_Close(inFile);
           }
           if (vfy) {
               VFY_DestroyContext(vfy, PR_TRUE);
           }
           return rv;
       }

      /*
        * Write Cryptographic parameters to header file
        */
       SECStatus
       WriteToHeaderFile(const char *buf, unsigned int len, HeaderType type,
                         PRFileDesc *outFile)
       {
           SECStatus      rv;
           const char    *header;
           const char    *trailer;

          switch (type) {
           case SYMKEY:
               header = ENCKEY_HEADER;
               trailer = ENCKEY_TRAILER;
               break;
           case MACKEY:
               header =  MACKEY_HEADER;
               trailer = MACKEY_TRAILER;
               break;
           case IV:
               header = IV_HEADER;
               trailer = IV_TRAILER;
               break;
           case MAC:
               header = MAC_HEADER;
               trailer = MAC_TRAILER;
               break;
           case PAD:
               header = PAD_HEADER;
               trailer = PAD_TRAILER;
               break;
           case PUBKEY:
               header = PUBKEY_HEADER;
               trailer = PUBKEY_TRAILER;
               break;
           case CERTENC:
               header  = NS_CERT_ENC_HEADER;
               trailer = NS_CERT_ENC_TRAILER;
               break;
           case CERTVFY:
               header  = NS_CERT_VFY_HEADER;
               trailer = NS_CERT_VFY_TRAILER;
               break;
           case SIG:
               header  = NS_SIG_HEADER;
               trailer = NS_SIG_TRAILER;
               break;
           case LAB:
               header = LAB_HEADER;
               trailer = LAB_TRAILER;
               PR_fprintf(outFile, "%s\n", header);
               PR_fprintf(outFile, "%s\n", buf);
               PR_fprintf(outFile, "%s\n\n", trailer);
               return SECSuccess;
               break;
           default:
               return SECFailure;
           }

          PR_fprintf(outFile, "%s\n", header);
           PrintAsHex(outFile, buf, len);
           PR_fprintf(outFile, "%s\n\n", trailer);
           return SECSuccess;
       }

      /*
        * Read cryptographic parameters from the header file
        */
       SECStatus
       ReadFromHeaderFile(const char *fileName, HeaderType type,
                          SECItem *item, PRBool isHexData)
       {
           SECStatus      rv = SECSuccess;
           PRFileDesc*    file = NULL;
           SECItem        filedata;
           SECItem        outbuf;
           unsigned char *nonbody;
           unsigned char *body;
           char          *header;
           char          *trailer;

          outbuf.type = siBuffer;
           file = PR_Open(fileName, PR_RDONLY, 0);
           if (!file) {
               PR_fprintf(PR_STDERR, "Failed to open %s\n", fileName);
               rv = SECFailure;
               goto cleanup;
           }
           switch (type) {
           case PUBKEY:
               header = PUBKEY_HEADER;
               trailer = PUBKEY_TRAILER;
               break;
           case SYMKEY:
               header = ENCKEY_HEADER;
               trailer = ENCKEY_TRAILER;
               break;
           case MACKEY:
               header = MACKEY_HEADER;
               trailer = MACKEY_TRAILER;
               break;
           case IV:
               header = IV_HEADER;
               trailer = IV_TRAILER;
               break;
           case MAC:
               header = MAC_HEADER;
               trailer = MAC_TRAILER;
               break;
           case PAD:
               header = PAD_HEADER;
               trailer = PAD_TRAILER;
               break;
           case LAB:
               header = LAB_HEADER;
               trailer = LAB_TRAILER;
               break;
           case CERTENC:
               header  = NS_CERT_ENC_HEADER;
               trailer = NS_CERT_ENC_TRAILER;
               break;
           case CERTVFY:
               header  = NS_CERT_VFY_HEADER;
               trailer = NS_CERT_VFY_TRAILER;
               break;
           case SIG:
               header  = NS_SIG_HEADER;
               trailer = NS_SIG_TRAILER;
               break;
           default:
               rv = SECFailure;
               goto cleanup;
           }

          rv = FileToItem(&filedata, file);
           nonbody = (char *)filedata.data;
           if (!nonbody) {
               PR_fprintf(PR_STDERR, "unable to read data from input file\n");
               rv = SECFailure;
               goto cleanup;
           }

          /* check for headers and trailers and remove them */
           if ((body = strstr(nonbody, header)) != NULL) {
               char *trail = NULL;
               nonbody = body;
               body = PORT_Strchr(body, '\n');
               if (!body)
                   body = PORT_Strchr(nonbody, '\r'); /* maybe this is a MAC file */
               if (body)
                   trail = strstr(++body, trailer);
               if (trail != NULL) {
                   *trail = '\0';
               } else {
                   PR_fprintf(PR_STDERR,  "input has header but no trailer\n");
                   PORT_Free(filedata.data);
                   rv = SECFailure;
                   goto cleanup;
               }
           } else {
               /* headers didn't exist */
               char *trail = NULL;
               body = nonbody;
               if (body) {
                   trail = strstr(++body, trailer);
                   if (trail != NULL) {
                       PR_fprintf(PR_STDERR,  "input has no header but has trailer\n");
                       PORT_Free(filedata.data);
                       rv = SECFailure;
                       goto cleanup;
                   }
               }
           }
           HexToBuf(body, item, isHexData);
       cleanup:
           if (file) {
               PR_Close(file);
           }
           return rv;
       }

      /*
        * Generate the private key   
        */
       SECKEYPrivateKey *
       GeneratePrivateKey(KeyType keytype, PK11SlotInfo *slot, int size,
                          int publicExponent, const char *noise,
                          SECKEYPublicKey **pubkeyp, const char *pqgFile,
                          secuPWData *pwdata)
       {
           CK_MECHANISM_TYPE  mechanism;
           SECOidTag          algtag;
           PK11RSAGenParams   rsaparams;
           void              *params;
           SECKEYPrivateKey  *privKey    = NULL;
           SECStatus          rv;
           unsigned char      randbuf[BLOCKSIZE + 1];

          rv = GenerateRandom(randbuf, BLOCKSIZE);
           if (rv != SECSuccess) {
               fprintf(stderr, "Error while generating the random numbers : %s\n",
                       PORT_ErrorToString(rv));
               goto cleanup;
           }
           PK11_RandomUpdate(randbuf, BLOCKSIZE);
           switch (keytype) {
               case rsaKey:
                   rsaparams.keySizeInBits = size;
                   rsaparams.pe            = publicExponent;
                   mechanism               = CKM_RSA_PKCS_KEY_PAIR_GEN;
                   algtag                  = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION;
                   params                  = &rsaparams;
                   break;
               default:
                   goto cleanup;
           }
           fprintf(stderr, "\n\n");
           fprintf(stderr, "Generating key.  This may take a few moments...\n\n");
           privKey = PK11_GenerateKeyPair(slot, mechanism, params, pubkeyp,
                                              PR_TRUE /*isPerm*/, PR_TRUE /*isSensitive*/,
                                              pwdata);
       cleanup:
           return privKey;
       }

      /*
        * Get the certificate request from CSR
        */
       static CERTCertificateRequest *
       GetCertRequest(char *inFileName, PRBool ascii)
       {
           CERTSignedData signedData;
           SECItem reqDER;
           CERTCertificateRequest *certReq = NULL;
           SECStatus rv                    = SECSuccess;
           PRArenaPool *arena              = NULL;

          reqDER.data = NULL;
           arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
           if (arena == NULL) {
               rv = SECFailure;
               goto cleanup;
           }

          rv = ReadDERFromFile(&reqDER, inFileName, ascii);
           if (rv) {
               rv = SECFailure;
               goto cleanup;
           }
           certReq = (CERTCertificateRequest*) PORT_ArenaZAlloc
                      (arena, sizeof(CERTCertificateRequest));
           if (!certReq) {
               rv = SECFailure;
               goto cleanup;
           }
           certReq->arena = arena;

          /* Since cert request is a signed data, must decode to get the inner data */
           PORT_Memset(&signedData, 0, sizeof(signedData));
           rv = SEC_ASN1DecodeItem(arena, &signedData,
                                   SEC_ASN1_GET(CERT_SignedDataTemplate), &reqDER);
           if (rv) {
               rv = SECFailure;
               goto cleanup;
           }
           rv = SEC_ASN1DecodeItem(arena, certReq,
                                   SEC_ASN1_GET(CERT_CertificateRequestTemplate), &signedData.data);
           if (rv) {
               rv = SECFailure;
               goto cleanup;
           }
           rv = CERT_VerifySignedDataWithPublicKeyInfo(&signedData,
                       &certReq->subjectPublicKeyInfo, NULL /* wincx */);
           if (reqDER.data) {
               SECITEM_FreeItem(&reqDER, PR_FALSE);
           }

      cleanup:
           if (rv) {
               PR_fprintf(PR_STDERR, "bad certificate request\n");
               if (arena) {
                   PORT_FreeArena(arena, PR_FALSE);
               }
               certReq = NULL;
           }
           return certReq;
       }

      /*
        * Sign Cert
        */
       static SECItem *
       SignCert(CERTCertDBHandle *handle, CERTCertificate *cert,
                PRBool selfsign, SECOidTag hashAlgTag,
                SECKEYPrivateKey *privKey, char *issuerNickName, void *pwarg)
       {
           SECItem der;
           SECStatus rv;
           SECOidTag algID;
           void *dummy;
           PRArenaPool *arena             = NULL;
           SECItem *result                = NULL;
           SECKEYPrivateKey *caPrivateKey = NULL;

          if (!selfsign) {
               CERTCertificate *issuer = PK11_FindCertFromNickname(issuerNickName, pwarg);
               if ((CERTCertificate *)NULL == issuer) {
                   PR_fprintf(PR_STDERR, "unable to find issuer with nickname %s\n",
                              issuerNickName);
                   goto cleanup;
               }
               privKey = caPrivateKey = PK11_FindKeyByAnyCert(issuer, pwarg);
               CERT_DestroyCertificate(issuer);
               if (caPrivateKey == NULL) {
                   PR_fprintf(PR_STDERR, "unable to retrieve key  %s\n",
                              issuerNickName);
                   goto cleanup;
               }
           }
           arena = cert->arena;
           algID = SEC_GetSignatureAlgorithmOidTag(privKey->keyType, hashAlgTag);
           if (algID == SEC_OID_UNKNOWN) {
               PR_fprintf(PR_STDERR, "Unknown key or hash type for issuer.\n");
               goto cleanup;
           }
           rv = SECOID_SetAlgorithmID(arena, &cert->signature, algID, 0);
           if (rv != SECSuccess) {
               PR_fprintf(PR_STDERR, "Could not set signature algorithm id.\n%s\n",
                          PORT_ErrorToString(rv));
               goto cleanup;
           }

          /* we only deal with cert v3 here */
           *(cert->version.data) = 2;
           cert->version.len = 1;

          der.len = 0;
           der.data = NULL;
           dummy = SEC_ASN1EncodeItem (arena, &der, cert,
                                       SEC_ASN1_GET(CERT_CertificateTemplate));
           if (!dummy) {
               PR_fprintf(PR_STDERR, "Could not encode certificate.\n");
               goto cleanup;
           }

          result = (SECItem *) PORT_ArenaZAlloc (arena, sizeof (SECItem));
           if (result == NULL) {
               PR_fprintf(PR_STDERR, "Could not allocate item for certificate data.\n");
               goto cleanup;
           }

          rv = SEC_DerSignData(arena, result, der.data, der.len, privKey, algID);
           if (rv != SECSuccess) {
               PR_fprintf(PR_STDERR, "Could not sign encoded certificate data : %s\n",
                          PORT_ErrorToString(rv));
               /* result allocated out of the arena, it will be freed
                * when the arena is freed */
               result = NULL;
               goto cleanup;
           }
           cert->derCert = *result;
       cleanup:
           if (caPrivateKey) {
               SECKEY_DestroyPrivateKey(caPrivateKey);
           }
           return result;
       }

      /*
        * MakeV1Cert
        */
       static CERTCertificate *
       MakeV1Cert(CERTCertDBHandle       *handle,
                  CERTCertificateRequest *req,
                  char *                  issuerNickName,
                  PRBool                  selfsign,
                  unsigned int            serialNumber,
                  int                     warpmonths,
                  int                     validityMonths)
       {
           PRExplodedTime  printableTime;
           PRTime          now;
           PRTime          after;
           CERTValidity    *validity   = NULL;
           CERTCertificate *issuerCert = NULL;
           CERTCertificate *cert       = NULL;

          if ( !selfsign ) {
               issuerCert = CERT_FindCertByNicknameOrEmailAddr(handle, issuerNickName);
               if (!issuerCert) {
                   PR_fprintf(PR_STDERR, "could not find certificate named %s\n",
                              issuerNickName);
                   goto cleanup;
               }
           }

          now = PR_Now();
           PR_ExplodeTime (now, PR_GMTParameters, &printableTime);
           if ( warpmonths ) {
               printableTime.tm_month += warpmonths;
               now = PR_ImplodeTime (&printableTime);
               PR_ExplodeTime (now, PR_GMTParameters, &printableTime);
           }
           printableTime.tm_month += validityMonths;
           after = PR_ImplodeTime (&printableTime);

          /* note that the time is now in micro-second unit */
           validity = CERT_CreateValidity (now, after);
           if (validity) {
               cert = CERT_CreateCertificate(serialNumber,
                            (selfsign ? &req->subject : &issuerCert->subject),
                            validity, req);

              CERT_DestroyValidity(validity);
           }
       cleanup:
           if ( issuerCert ) {
               CERT_DestroyCertificate (issuerCert);
           }
           return cert;
       }

      /*
        * Add a certificate to the nss database
        */
       SECStatus
       AddCert(PK11SlotInfo *slot, CERTCertDBHandle *handle,
               const char *name, char *trusts, char *inFileName,
               PRBool ascii, PRBool emailcert, void *pwdata)
       {
           SECItem         certDER;
           SECStatus       rv;
           CERTCertTrust   *trust = NULL;
           CERTCertificate *cert = NULL;

          certDER.data = NULL;

          /* Read in the entire file specified with the -i argument */
           rv = ReadDERFromFile(&certDER, inFileName, ascii);
           if (rv != SECSuccess) {
               PR_fprintf(PR_STDERR, "unable to read input file %s : %s\n",
                          inFileName, PORT_ErrorToString(rv));
               goto cleanup;
           }

          /* Read in an ASCII cert and return a CERTCertificate */
           cert = CERT_DecodeCertFromPackage((char *)certDER.data, certDER.len);
           if (!cert) {
               PR_fprintf(PR_STDERR, "could not obtain certificate from file\n");
               rv = SECFailure;
               goto cleanup;
           }

          /* Create a cert trust */
           trust = (CERTCertTrust *)PORT_ZAlloc(sizeof(CERTCertTrust));
           if (!trust) {
               PR_fprintf(PR_STDERR, "unable to allocate cert trust\n");
               rv = SECFailure;
               goto cleanup;
           }

          rv = CERT_DecodeTrustString(trust, trusts);
           if (rv) {
               PR_fprintf(PR_STDERR, "unable to decode trust string\n");
               rv = SECFailure;
               goto cleanup;
           }

          rv =  PK11_ImportCert(slot, cert, CK_INVALID_HANDLE, name, PR_FALSE);
           if (rv != SECSuccess) {
               /* sigh, PK11_Import Cert and CERT_ChangeCertTrust should have
                * been coded to take a password arg. */
               if (PORT_GetError() == SEC_ERROR_TOKEN_NOT_LOGGED_IN) {
                   rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
                   if (rv != SECSuccess) {
                       PR_fprintf(PR_STDERR, "could not authenticate to token  %s : %s\n",
                                  PK11_GetTokenName(slot), PORT_ErrorToString(rv));
                       rv = SECFailure;
                       goto cleanup;
                   }
                   rv = PK11_ImportCert(slot, cert, CK_INVALID_HANDLE,
                                        name, PR_FALSE);
               }
               if (rv != SECSuccess) {
                   PR_fprintf(PR_STDERR,
                              "could not add certificate to token or database : %s\n",
                              PORT_ErrorToString(rv));
                   rv = SECFailure;
                   goto cleanup;
               }
           }
           rv = CERT_ChangeCertTrust(handle, cert, trust);
           if (rv != SECSuccess) {
               if (PORT_GetError() == SEC_ERROR_TOKEN_NOT_LOGGED_IN) {
                   rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
                   if (rv != SECSuccess) {
                       PR_fprintf(PR_STDERR, "could not authenticate to token  %s : %s\n",
                                  PK11_GetTokenName(slot), PORT_ErrorToString(rv));
                       rv = SECFailure;
                       goto cleanup;
                   }
                   rv = CERT_ChangeCertTrust(handle, cert, trust);
               }
               if (rv != SECSuccess) {
                   PR_fprintf(PR_STDERR, "could not change trust on certificate : %s\n",
                              PORT_ErrorToString(rv));
                   rv = SECFailure;
                   goto cleanup;
               }
           }

          if (emailcert) {
               CERT_SaveSMimeProfile(cert, NULL, pwdata);
           }

      cleanup:
           if (cert) {
               CERT_DestroyCertificate (cert);
           }
           if (trust) {
               PORT_Free(trust);
           }
           if (certDER.data) {
               PORT_Free(certDER.data);
           }
           return rv;
       }

      /*
        * Create a certificate
        */
       static SECStatus
       CreateCert(
               CERTCertDBHandle *handle,
               PK11SlotInfo *slot,
               char *  issuerNickName,
               char *inFileName,
               char *outFileName,
               SECKEYPrivateKey **selfsignprivkey,
               void    *pwarg,
               SECOidTag hashAlgTag,
               unsigned int serialNumber,
               int     warpmonths,
               int     validityMonths,
               const char *dnsNames,
               PRBool  ascii,
               PRBool  selfsign)
       {
           void                   *extHandle;
           SECItem                reqDER;
           CERTCertExtension      **CRexts;
           SECStatus              rv               = SECSuccess;
           CERTCertificate        *subjectCert     = NULL;
           CERTCertificateRequest *certReq         = NULL;
           PRFileDesc             *outFile         = NULL;
           SECItem                *certDER         = NULL;

          reqDER.data = NULL;
           outFile = PR_Open(outFileName,
                             PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, 00660);

          /* Create a cert request object from the input cert request der */
           certReq = GetCertRequest(inFileName, ascii);
           if (certReq == NULL) {
               rv = SECFailure;
               goto cleanup;
           }
           subjectCert = MakeV1Cert(handle, certReq, issuerNickName, selfsign,
                                    serialNumber, warpmonths, validityMonths);
           if (subjectCert == NULL) {
               rv = SECFailure;
               goto cleanup;
           }

          extHandle = CERT_StartCertExtensions (subjectCert);
           if (extHandle == NULL) {
               rv = SECFailure;
               goto cleanup;
           }

          if (certReq->attributes != NULL &&
               certReq->attributes[0] != NULL &&
               certReq->attributes[0]->attrType.data != NULL &&
               certReq->attributes[0]->attrType.len   > 0    &&
               SECOID_FindOIDTag(&certReq->attributes[0]->attrType)
                       == SEC_OID_PKCS9_EXTENSION_REQUEST) {
               rv = CERT_GetCertificateRequestExtensions(certReq, &CRexts);
               if (rv != SECSuccess) {
                   PR_fprintf(PR_STDERR, "%s\n", PORT_ErrorToString(rv));
                   goto cleanup;
               }
               rv = CERT_MergeExtensions(extHandle, CRexts);
               if (rv != SECSuccess) {
                   PR_fprintf(PR_STDERR, "%s\n", PORT_ErrorToString(rv));
                   goto cleanup;
               }
           }

          CERT_FinishExtensions(extHandle);

          /* self-signing a cert request, find the private key */
           if (*selfsignprivkey == NULL) {
               *selfsignprivkey = PK11_FindKeyByDERCert(slot, subjectCert, pwarg);
               if (!*selfsignprivkey) {
                   PR_fprintf(PR_STDERR, "Failed to locate private key.\n");
                   rv = SECFailure;
                   goto cleanup;
               }
           }

          certDER = SignCert(handle, subjectCert, selfsign, hashAlgTag,
                              *selfsignprivkey, issuerNickName,pwarg);
           if (certDER) {
               if (ascii) {
                   PR_fprintf(outFile, "%s\n%s\n%s\n", NS_CERT_HEADER,
                              BTOA_DataToAscii(certDER->data, certDER->len),
                              NS_CERT_TRAILER);
               } else {
                   PR_Write(outFile, certDER->data, certDER->len);
               }
           }
           if (rv != SECSuccess) {
               PRErrorCode  perr = PR_GetError();
               PR_fprintf(PR_STDERR, "unable to create cert %s\n",
                          perr);
           }
       cleanup:
           if (outFile) {
               PR_Close(outFile);
           }
           if (*selfsignprivkey) {
               SECKEY_DestroyPrivateKey(*selfsignprivkey);
           }
           if (certReq) {
               CERT_DestroyCertificateRequest(certReq);
           }
           if (subjectCert) {
               CERT_DestroyCertificate(subjectCert);
           }
           return rv;
       }

      /*
        *  Generate the certificate request with subject
        */
       static SECStatus
       CertReq(SECKEYPrivateKey *privk, SECKEYPublicKey *pubk, KeyType keyType,
               SECOidTag hashAlgTag, CERTName *subject, PRBool ascii,
               const char *certReqFileName)
       {
           SECOidTag                 signAlgTag;
           SECItem                   result;
           PRInt32                   numBytes;
           SECStatus                 rv            = SECSuccess;
           PRArenaPool              *arena         = NULL;
           void                     *extHandle     = NULL;
           PRFileDesc               *outFile       = NULL;
           CERTSubjectPublicKeyInfo *spki          = NULL;
           CERTCertificateRequest   *cr            = NULL;
           SECItem                  *encoding      = NULL;

          /* If the certificate request file already exists, delete it */
           if (PR_Access(certReqFileName, PR_ACCESS_EXISTS) == PR_SUCCESS) {
               PR_Delete(certReqFileName);
           }
           /*  Open the certificate request file to write */
           outFile = PR_Open(certReqFileName, PR_CREATE_FILE | PR_RDWR | PR_TRUNCATE, 00660);
           if (!outFile) {
               PR_fprintf(PR_STDERR,
                          "unable to open \"%s\" for writing (%ld, %ld).\n",
                          certReqFileName, PR_GetError(), PR_GetOSError());
               goto cleanup;
           }
           /* Create info about public key */
           spki = SECKEY_CreateSubjectPublicKeyInfo(pubk);
           if (!spki) {
               PR_fprintf(PR_STDERR, "unable to create subject public key\n");
               rv = SECFailure;
               goto cleanup;
           }

          /* Generate certificate request */
           cr = CERT_CreateCertificateRequest(subject, spki, NULL);
           if (!cr) {
               PR_fprintf(PR_STDERR, "unable to make certificate request\n");
               rv = SECFailure;
               goto cleanup;
           }
          
           arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
           if (!arena) {
               fprintf(stderr, "out of memory");
               rv = SECFailure;
               goto cleanup;
           }

          extHandle = CERT_StartCertificateRequestAttributes(cr);
           if (extHandle == NULL) {
               PORT_FreeArena (arena, PR_FALSE);
               rv = SECFailure;
               goto cleanup;
           }

          CERT_FinishExtensions(extHandle);
           CERT_FinishCertificateRequestAttributes(cr);
           
           /* Der encode the request */
           encoding = SEC_ASN1EncodeItem(arena, NULL, cr,
                                         SEC_ASN1_GET(CERT_CertificateRequestTemplate));
           if (encoding == NULL) {
               PR_fprintf(PR_STDERR, "der encoding of request failed\n");
               rv = SECFailure;
               goto cleanup;
           }

          /* Sign the request */
           signAlgTag = SEC_GetSignatureAlgorithmOidTag(keyType, hashAlgTag);
           if (signAlgTag == SEC_OID_UNKNOWN) {
               PR_fprintf(PR_STDERR, "unknown Key or Hash type\n");
               rv = SECFailure;
           goto cleanup;
           }
           rv = SEC_DerSignData(arena, &result, encoding->data, encoding->len,
                                privk, signAlgTag);
           if (rv) {
               PR_fprintf(PR_STDERR, "signing of data failed\n");
               rv = SECFailure;
               goto cleanup;
           }

          /* Encode request in specified format */
           if (ascii) {
               char *obuf;
               char *name, *email, *org, *state, *country;
               SECItem *it;
               int total;

              it = &result;

              obuf = BTOA_ConvertItemToAscii(it);
               total = PL_strlen(obuf);

              name = CERT_GetCommonName(subject);
               if (!name) {
                   name = strdup("(not specified)");
               }

              email = CERT_GetCertEmailAddress(subject);
               if (!email)
                   email = strdup("(not specified)");

              org = CERT_GetOrgName(subject);
               if (!org)
                   org = strdup("(not specified)");

              state = CERT_GetStateName(subject);
               if (!state)
                   state = strdup("(not specified)");

              country = CERT_GetCountryName(subject);
               if (!country)
                   country = strdup("(not specified)");

              PR_fprintf(outFile,
                          "\nCertificate request generated by Netscape certutil\n");
               PR_fprintf(outFile, "Common Name: %s\n", name);
               PR_fprintf(outFile, "Email: %s\n", email);
               PR_fprintf(outFile, "Organization: %s\n", org);
               PR_fprintf(outFile, "State: %s\n", state);
               PR_fprintf(outFile, "Country: %s\n\n", country);

              PR_fprintf(outFile, "%s\n", NS_CERTREQ_HEADER);
               numBytes = PR_Write(outFile, obuf, total);
               if (numBytes != total) {
                   PR_fprintf(PR_STDERR, "write error\n");
                   return SECFailure;
               }
               PR_fprintf(outFile, "\n%s\n", NS_CERTREQ_TRAILER);
           } else {
               numBytes = PR_Write(outFile, result.data, result.len);
               if (numBytes != (int)result.len) {
                   PR_fprintf(PR_STDERR, "write error\n");
                   rv = SECFailure;
                   goto cleanup;
               }
           }
       cleanup:
           if (outFile) {
               PR_Close(outFile);
           }
           if (privk) {
               SECKEY_DestroyPrivateKey(privk);
           }
           if (pubk) {
               SECKEY_DestroyPublicKey(pubk);
           }
           return rv;
       }

      /*
        * Create certificate request with subject
        */
       SECStatus CreateCertRequest(PK11SlotInfo *slot,
           secuPWData   *pwdata,
           CERTName     *subject,
           char   *certReqFileName,
           PRBool       ascii)
       {
           SECStatus rv;
           SECKEYPrivateKey    *privkey         = NULL;
           SECKEYPublicKey     *pubkey          = NULL;
           KeyType             keytype          = rsaKey;
           int                 keysize          = DEFAULT_KEY_BITS;
           int                 publicExponent   = 0x010001;
           SECOidTag           hashAlgTag       = SEC_OID_UNKNOWN;

          privkey = GeneratePrivateKey(keytype, slot, keysize,
                                        publicExponent, NULL,
                                        &pubkey, NULL, pwdata);
           if (privkey == NULL) {
               PR_fprintf(PR_STDERR, "unable to generate key(s)\n");
               rv = SECFailure;
               goto cleanup;
           }
           privkey->wincx = pwdata;
           PORT_Assert(pubkey != NULL);
           rv = CertReq(privkey, pubkey, keytype, hashAlgTag, subject,
                        ascii, certReqFileName);
           
           if (rv != SECSuccess) {
               PR_fprintf(PR_STDERR, "Failed to create Certificate Request\n");
           }
       cleanup:
           return rv;
       }

      /*
        * Creates the certificate using CSR and adds the certificate to DB
        */
       SECStatus AddCertificateToDB(PK11SlotInfo     *slot,
                                    secuPWData       *pwdata,
                                    char             *certReqFileName,
                                    char             *certFileName,
                                    char             *issuerNameStr,
                                    CERTCertDBHandle *certHandle,
                                    const char       *nickNameStr,
                                    char             *trustStr,
                                    unsigned int     serialNumber,
                                    PRBool           selfsign,
                                    PRBool           ascii)
       {
           SECStatus rv;
           SECKEYPrivateKey    *privkey         = NULL;
           SECKEYPublicKey     *pubkey          = NULL;
           SECOidTag           hashAlgTag       = SEC_OID_UNKNOWN;

          if (PR_Access(certFileName, PR_ACCESS_EXISTS) == PR_FAILURE) {
               rv = CreateCert(certHandle, slot, issuerNameStr,
                               certReqFileName, certFileName, &privkey, &pwdata, hashAlgTag,
                               serialNumber, 0, 3, NULL, ascii, selfsign);
               if (rv != SECSuccess) {
                   PR_fprintf(PR_STDERR, "Failed to create Certificate\n");
                   goto cleanup;
               }
           }
           rv = AddCert(slot, certHandle, nickNameStr,
                        trustStr, certFileName, ascii, 0, &pwdata);
           if (rv != SECSuccess) {
               PR_fprintf(PR_STDERR, "Failed to add Certificate\n");
           }
       cleanup:
           return rv;
       }

      /*
        * Finds the certificate using nickname and saves it to the header file
        */
       SECStatus AddCertificateToHeader(PK11SlotInfo     *slot,
                                        secuPWData       *pwdata,
                                        const char       *headerFileName,
                                        CERTCertDBHandle *certHandle,
                                        const char       *nickNameStr,
                                        PRBool           sigVerify)
                       
       {
           SECStatus            rv              = SECSuccess;
           PRFileDesc          *headerFile      = NULL;
           CERTCertificate     *cert            = NULL;
           HeaderType           hType           = CERTENC;

          /* If the intermediate header file already exists, delete it */
           if (PR_Access(headerFileName, PR_ACCESS_EXISTS) == PR_SUCCESS) {
               PR_Delete(headerFileName);
           }
           headerFile = PR_Open(headerFileName, PR_CREATE_FILE | PR_RDWR | PR_TRUNCATE, 00660);
           if (!headerFile) {
               PR_fprintf(PR_STDERR,
               "unable to open \"%s\" for writing (%ld, %ld).\n",
               headerFileName, PR_GetError(), PR_GetOSError());
               rv = SECFailure;
               goto cleanup;
           }
           cert = CERT_FindCertByNicknameOrEmailAddr(certHandle, nickNameStr);
           if (!cert) {
               PR_fprintf(PR_STDERR, "could not obtain certificate from file\n");
               rv = SECFailure;
               goto cleanup;
           }
           if (sigVerify) {
               hType = CERTVFY;
           }
           WriteToHeaderFile(cert->derCert.data, cert->derCert.len, hType, headerFile);
       cleanup:
           if (headerFile) {
               PR_Close(headerFile);
           }
           if (cert) {
               CERT_DestroyCertificate(cert);
           }
           return rv;
       }

      /*
        * Finds the public key from the certificate saved in the header file
        * and encrypts with it the contents of inFileName to encryptedFileName.
        */
       SECStatus FindKeyAndEncrypt(PK11SlotInfo *slot,
                                   secuPWData *pwdata,
                                   const char *headerFileName,
                                   const char *encryptedFileName,
                                   const char *inFileName)
       {
           SECStatus           rv;
           PRFileDesc          *headerFile      = NULL;
           PRFileDesc          *encFile         = NULL;
           PRFileDesc          *inFile          = NULL;
           CERTCertificate     *cert            = NULL;
           SECItem             data;
           unsigned char       ptext[MODBLOCKSIZE];
           unsigned char       encBuf[MODBLOCKSIZE];
           unsigned int        ptextLen;
           int                 index;
           unsigned int        nWritten;
           unsigned int        pad[1];
           SECItem             padItem;
           unsigned int        paddingLength    = 0;
           SECKEYPublicKey     *pubkey          = NULL;

          /* If the intermediate encrypted file already exists, delete it*/
           if (PR_Access(encryptedFileName, PR_ACCESS_EXISTS) == PR_SUCCESS) {
               PR_Delete(encryptedFileName);
           }

          /* Read certificate from header file */
           rv = ReadFromHeaderFile(headerFileName, CERTENC, &data, PR_TRUE);
           if (rv != SECSuccess) {
               PR_fprintf(PR_STDERR, "Could not read certificate from header file\n");
               goto cleanup;
           }
           /* Read in an ASCII cert and return a CERTCertificate */
           cert = CERT_DecodeCertFromPackage((char *)data.data, data.len);
           if (!cert) {
               PR_fprintf(PR_STDERR, "could not obtain certificate from file\n");
               rv = SECFailure;
               goto cleanup;
           }
           /* Extract the public key from certificate */
           pubkey = CERT_ExtractPublicKey(cert);
           if (!pubkey) {
               PR_fprintf(PR_STDERR, "could not get key from certificate\n");
               rv = SECFailure;
               goto cleanup;
           }

          /*  Open the encrypted file for writing */
           encFile = PR_Open(encryptedFileName,
                             PR_CREATE_FILE | PR_TRUNCATE | PR_RDWR, 00660);
           if (!encFile) {
               PR_fprintf(PR_STDERR,
                          "Unable to open \"%s\" for writing.\n",
                          encryptedFileName);
               rv = SECFailure;
               goto cleanup;
           }

          /*  Open the input file for reading */
           inFile = PR_Open(inFileName, PR_RDONLY, 0);
           if (!inFile) {
               PR_fprintf(PR_STDERR, "Unable to open \"%s\" for reading.\n",
                          inFileName);
               rv = SECFailure;
               goto cleanup;
           }

          /*  Open the header file to write padding */
           headerFile = PR_Open(headerFileName, PR_CREATE_FILE | PR_RDWR | PR_APPEND, 00660);
           if (!headerFile) {
               PR_fprintf(PR_STDERR, "Unable to open \"%s\" for writing.\n",
                          headerFileName);
               rv = SECFailure;
               goto cleanup;
           }
               
           /* Read input file  */
           while ((ptextLen = PR_Read(inFile, ptext, sizeof(ptext))) > 0) {
               if (ptextLen != MODBLOCKSIZE) {
                   paddingLength = MODBLOCKSIZE - ptextLen;
                   for ( index=0; index < paddingLength; index++) {
                       ptext[ptextLen+index] = (unsigned char)paddingLength;
                   }
                   ptextLen = MODBLOCKSIZE;
                }
                rv = PK11_PubEncryptRaw(pubkey, encBuf, ptext, ptextLen, NULL);
                nWritten = PR_Write(encFile, encBuf, ptextLen);
           }

          /* Write the padding to header file */
           pad[0] = paddingLength;
           padItem.type = siBuffer;
           padItem.data = (unsigned char *)pad;
           padItem.len  = sizeof(pad[0]);
           WriteToHeaderFile(padItem.data, padItem.len, PAD, headerFile);

      cleanup:
           if (headerFile) {
               PR_Close(headerFile);
           }
           if (encFile) {
               PR_Close(encFile);
           }
           if (inFile) {
               PR_Close(inFile);
           }
           if (pubkey) {
               SECKEY_DestroyPublicKey(pubkey);
           }
           if (cert) {
               CERT_DestroyCertificate(cert);
           }
           return rv;
       }

      /*
        * Finds the private key from db and signs the contents
        * of inFileName and writes to signatureFileName
        */
       SECStatus FindKeyAndSign(PK11SlotInfo *slot,
                                CERTCertDBHandle* certHandle,
                                secuPWData *pwdata,
                                const char *nickNameStr,
                                const char *headerFileName,
                                const char *inFileName)
       {
           SECStatus           rv;
           PRFileDesc          *headerFile      = NULL;
           PRFileDesc          *inFile          = NULL;
           CERTCertificate     *cert            = NULL;
           unsigned int        signatureLen     = 0;
           SECKEYPrivateKey    *privkey         = NULL;
           SECItem             sigItem;
           SECOidTag           hashOIDTag;
           
           /*  Open the header file to write padding */
           headerFile = PR_Open(headerFileName, PR_CREATE_FILE | PR_RDWR | PR_APPEND, 00660);
           if (!headerFile) {
               PR_fprintf(PR_STDERR, "Unable to open \"%s\" for writing.\n",
                          headerFileName);
               rv = SECFailure;
               goto cleanup;
           }

          /* Get the certificate by nick name  and write to header file */
           cert = CERT_FindCertByNicknameOrEmailAddr(certHandle, nickNameStr);
           if (!cert) {
               PR_fprintf(PR_STDERR, "could not obtain certificate by name - %s\n", nickNameStr);
               rv = SECFailure;
               goto cleanup;
           }
           WriteToHeaderFile(cert->derCert.data, cert->derCert.len, CERTVFY, headerFile);


           /* Find private key from certificate  */
           privkey = PK11_FindKeyByAnyCert(cert, NULL);
           if (privkey == NULL) {
               fprintf(stderr, "Couldn't find private key for cert\n");
               rv = SECFailure;
               goto cleanup;
           }
               
           /* Sign the contents of the input file */
           rv = SignData(inFileName, privkey, &sigItem);
           if (rv != SECSuccess) {
               PR_fprintf(PR_STDERR, "could not sign the contents from file - %s \n", inFileName);
               goto cleanup;
           }

          /* write signature to header file */
           WriteToHeaderFile(sigItem.data, sigItem.len, SIG, headerFile);

      cleanup:
           if (headerFile) {
               PR_Close(headerFile);
           }
           if (privkey) {
               SECKEY_DestroyPrivateKey(privkey);
           }
           if (cert) {
               CERT_DestroyCertificate(cert);
           }
           return rv;
       }

      /*
        * Finds the public key from certificate and verifies signature
        */
       SECStatus FindKeyAndVerify(PK11SlotInfo *slot,
                                CERTCertDBHandle* certHandle,
                                secuPWData *pwdata,
                                const char *headerFileName,
                                const char *inFileName)
       {
           SECStatus           rv               = SECFailure;
           PRFileDesc          *headerFile      = NULL;
           PRFileDesc          *inFile          = NULL;
           CERTCertificate     *cert            = NULL;
           SECKEYPublicKey     *pubkey          = NULL;
           SECItem             sigItem;
           SECItem             certData;
           

          /* Open the input file  */
           inFile = PR_Open(inFileName, PR_RDONLY, 0);
           if (!inFile) {
               PR_fprintf(PR_STDERR,
                          "Unable to open \"%s\" for reading.\n",
                          inFileName);
               rv = SECFailure;
               goto cleanup;
           }

          /* Open the header file to read the certificate and signature */
           headerFile = PR_Open(headerFileName, PR_RDONLY, 0);
           if (!headerFile) {
               PR_fprintf(PR_STDERR, "Unable to open \"%s\" for writing.\n",
                          headerFileName);
               rv = SECFailure;
               goto cleanup;
           }

          /* Read certificate from header file */
           rv = ReadFromHeaderFile(headerFileName, CERTVFY, &certData, PR_TRUE);
           if (rv != SECSuccess) {
               PR_fprintf(PR_STDERR, "Could not read certificate from header file\n");
               goto cleanup;
           }

          /* Read in an ASCII cert and return a CERTCertificate */
           cert = CERT_DecodeCertFromPackage((char *)certData.data, certData.len);
           if (!cert) {
               PR_fprintf(PR_STDERR, "could not obtain certificate from file\n");
               rv = SECFailure;
               goto cleanup;
           }

          /* Extract the public key from certificate */
           pubkey = CERT_ExtractPublicKey(cert);
           if (!pubkey) {
               PR_fprintf(PR_STDERR, "Could not get key from certificate\n");
               rv = SECFailure;
               goto cleanup;
           }

          /* Read signature from header file */
           rv = ReadFromHeaderFile(headerFileName, SIG, &sigItem, PR_TRUE);
           if (rv != SECSuccess) {
               PR_fprintf(PR_STDERR, "Could not read signature from header file\n");
               goto cleanup;
           }
               
           /* Verify with the public key */
           rv = VerifyData(inFileName, pubkey, &sigItem, pwdata);
           if (rv != SECSuccess) {
               PR_fprintf(PR_STDERR, "Couldn't verify the signature for file - %s\n", inFileName);
               goto cleanup;
           }

      cleanup:
           if (headerFile) {
               PR_Close(headerFile);
           }
           if (pubkey) {
               SECKEY_DestroyPublicKey(pubkey);
           }
           if (cert) {
               CERT_DestroyCertificate(cert);
           }
           return rv;
       }

      /*
        * Finds the private key corresponding to the certificate saved in the header file
        * and decrypts with it the contents of encryptedFileName to outFileName.
        */
       SECStatus FindKeyAndDecrypt(PK11SlotInfo *slot,
                                   secuPWData *pwdata,
                                   const char *headerFileName,
                                   const char *encryptedFileName,
                                   const char *outFileName)
       {
           SECStatus           rv;
           PRFileDesc          *encFile        = NULL;
           PRFileDesc          *outFile        = NULL;
           SECKEYPrivateKey    *pvtkey         = NULL;
           unsigned int        inFileLength    = 0;
           unsigned int        paddingLength   = 0;
           unsigned int        count           = 0;
           unsigned int        temp            = 0;
           unsigned char       ctext[MODBLOCKSIZE];
           unsigned char       decBuf[MODBLOCKSIZE];
           unsigned int        ctextLen;
           unsigned int        decBufLen;
           SECItem             padItem;
           SECItem             data;
           SECItem             signature;
           CERTCertificate     *cert            = NULL;

          /* Read certificate from header file */
           rv = ReadFromHeaderFile(headerFileName, CERTENC, &data, PR_TRUE);
           if (rv != SECSuccess) {
               PR_fprintf(PR_STDERR, "Could not read certificate from header file\n");
               goto cleanup;
           }

          /* Read padding from header file */
           rv = ReadFromHeaderFile(headerFileName, PAD, &padItem, PR_TRUE);
           if (rv != SECSuccess) {
               PR_fprintf(PR_STDERR,
                       "Could not retrieve PAD detail from header file\n");
               goto cleanup;
           }
           paddingLength = (unsigned int)padItem.data[0];
           inFileLength = FileSize(encryptedFileName);

          /* Read in an ASCII cert and return a CERTCertificate */
           cert = CERT_DecodeCertFromPackage((char *)data.data, data.len);
           if (!cert) {
               PR_fprintf(PR_STDERR, "could not obtain certificate from file\n");
               rv = SECFailure;
               goto cleanup;
           }

          /* Find private key from certificate  */
           pvtkey = PK11_FindKeyByAnyCert(cert, NULL);
           if (pvtkey == NULL) {
               fprintf(stderr, "Couldn't find private key for cert\n");
               rv = SECFailure;
               goto cleanup;
           }

          /* Open the out file to write */
           outFile = PR_Open(outFileName,
                             PR_CREATE_FILE | PR_TRUNCATE | PR_RDWR, 00660);
           if (!outFile) {
               PR_fprintf(PR_STDERR, "Unable to open \"%s\" for writing.\n",
                          outFileName);
               rv = SECFailure;
               goto cleanup;
           }
           /* Open the encrypted file for reading */
           encFile = PR_Open(encryptedFileName, PR_RDONLY, 0);
           if (!encFile) {
               PR_fprintf(PR_STDERR, "Unable to open \"%s\" for reading.\n",
                          encryptedFileName);
               rv = SECFailure;
               goto cleanup;
           }
           /* Read the encrypt file, decrypt and write to out file */
           while ((ctextLen = PR_Read(encFile, ctext, sizeof(ctext))) > 0) {
               count += ctextLen;
               rv = PK11_PubDecryptRaw(pvtkey, decBuf, &decBufLen, sizeof(decBuf), ctext, ctextLen);
               if (rv != SECSuccess) {
                   fprintf(stderr, "Couldn't decrypt\n");
                   goto cleanup;
               }
               if (decBufLen == 0) {
                   break;
               }
               if (count == inFileLength) {
                   decBufLen = decBufLen - paddingLength;
               }
               /* write the plain text to out file */
               temp = PR_Write(outFile, decBuf, decBufLen);
               if (temp != decBufLen) {
                   PR_fprintf(PR_STDERR, "write error\n");
                   rv = SECFailure;
                   break;
               }
            }
       cleanup:
           if (encFile) {
               PR_Close(encFile);
           }
           if (outFile) {
               PR_Close(outFile);
           }
           if (pvtkey) {
               SECKEY_DestroyPrivateKey(pvtkey);
           }
           if (cert) {
               CERT_DestroyCertificate(cert);
           }
           return rv;
       }

      /* Map option letter to command */
       static CommandType option2Command(char c)
       {
           switch (c) {
           case 'G': return GENERATE_CSR;
           case 'A': return ADD_CERT_TO_DB;
           case 'H': return SAVE_CERT_TO_HEADER;
           case 'E': return ENCRYPT;
           case 'D': return DECRYPT;
           case 'S': return SIGN;
           case 'V': return VERIFY;
           default:  return UNKNOWN;
           }
       }

      /*
        * This example illustrates basic encryption/decryption and MACing
        * Generates the RSA key pair as token object and outputs public key as cert request.
        * Reads cert request file and stores certificate in DB.
        * Input, store and trust CA certificate.
        * Write certificate to intermediate header file
        * Extract public key from certificate, encrypts the input file and write to external file.
        * Finds the matching private key, decrypts and write to external file
        *
        * How this sample is different from sample 5 ?
        *
        * 1. As in sample 5, output is a PKCS#10 CSR
        * 2. Input and store a cert in cert DB and also used to input, store and trust CA cert.
        * 3. Like sample 5, but puts cert in header
        * 4. Like sample 5, but finds key matching cert in header
       */
       int
       main(int argc, char **argv)
       {
           SECStatus           rv;
           PLOptState          *optstate;
           PLOptStatus         status;
           PRBool              initialized             = PR_FALSE;

          CommandType         cmd                     = UNKNOWN;
           const char          *dbdir                  = NULL;
           secuPWData          pwdata                  = { PW_NONE, 0 };

          char                *subjectStr             = NULL;
           CERTName            *subject                = 0;

          unsigned int        serialNumber            = 0;
           char                *serialNumberStr        = NULL;
           char                *trustStr               = NULL;
           CERTCertDBHandle    *certHandle;
           const char          *nickNameStr            = NULL;
           char                *issuerNameStr          = NULL;
           PRBool              selfsign                = PR_FALSE;
           PRBool              ascii                   = PR_FALSE;
           PRBool              sigVerify               = PR_FALSE;
           
           const char          *headerFileName         = NULL;
           const char          *encryptedFileName      = NULL;
           const char          *inFileName             = NULL;
           const char          *outFileName            = NULL;
           char                *certReqFileName        = NULL;
           char                *certFileName           = NULL;
           const char          *noiseFileName          = NULL;
           PK11SlotInfo        *slot                   = NULL;

          char * progName = strrchr(argv[0], '/');
           progName = progName ? progName + 1 : argv[0];

          /* Parse command line arguments */
           optstate = PL_CreateOptState(argc, argv, "GAHEDSVad:i:o:f:p:z:s:r:n:x:m:t:c:u:e:b:v:");
           while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
               switch (optstate->option) {
               case 'a':
                   ascii = PR_TRUE;
                   break;
               case 'G':   /* Generate a CSR */
               case 'A':   /* Add cert to database */
               case 'H':   /* Save cert to the header file */
               case 'E':   /* Encrypt with public key from cert in header file */
               case 'S':   /* Sign with private key */
               case 'D':   /* Decrypt with the matching private key */
               case 'V':   /* Verify with the matching public key */
                   cmd = option2Command(optstate->option);
                   break;
               case 'd':
                   dbdir = strdup(optstate->value);
                   break;
               case 'f':
                   pwdata.source = PW_FROMFILE;
                   pwdata.data = strdup(optstate->value);
                   break;
               case 'p':
                   pwdata.source = PW_PLAINTEXT;
                   pwdata.data = strdup(optstate->value);
                   break;
               case 'i':
                   inFileName = strdup(optstate->value);
                   break;
               case 'b':
                   headerFileName = strdup(optstate->value);
                   break;
               case 'e':
                   encryptedFileName = strdup(optstate->value);
                   break;
               case 'o':
                   outFileName = strdup(optstate->value);
                   break;
               case 'z':
                   noiseFileName = strdup(optstate->value);
                   break;
               case 's':
                   subjectStr  = strdup(optstate->value);
                   subject     = CERT_AsciiToName(subjectStr);
                   break;
               case 'r':
                   certReqFileName = strdup(optstate->value);
                   break;
               case 'c':
                   certFileName = strdup(optstate->value);
                   break;
               case 'u':
                   issuerNameStr = strdup(optstate->value);
                   break;
               case 'n':
                   nickNameStr = strdup(optstate->value);
                   break;
               case 'x':
                   selfsign = PR_TRUE;
                   break;
               case 'm':
                   serialNumberStr = strdup(optstate->value);
                   serialNumber    = atoi(serialNumberStr);
                   break;
               case 't':
                   trustStr = strdup(optstate->value);
                   break;
               case 'v':
                   sigVerify = PR_TRUE;
                   break;
               default:
                   Usage(progName);
                   break;
               }
           }
           PL_DestroyOptState(optstate);

          if (cmd == UNKNOWN || !dbdir)
               Usage(progName);

          /* Open DB for read/write and authenticate to it */
           PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
           initialized = PR_TRUE;
           rv = NSS_InitReadWrite(dbdir);
           if (rv != SECSuccess) {
               PR_fprintf(PR_STDERR, "NSS_InitReadWrite Failed\n");
               goto cleanup;
           }

          PK11_SetPasswordFunc(GetModulePassword);
           slot = PK11_GetInternalKeySlot();
           if (PK11_NeedLogin(slot)) {
               rv = PK11_Authenticate(slot, PR_TRUE, &pwdata);
               if (rv != SECSuccess) {
                   PR_fprintf(PR_STDERR, "Could not authenticate to token %s.\n",
                              PK11_GetTokenName(slot));
                   goto cleanup;
               }
           }

          switch (cmd) {
           case GENERATE_CSR:
               ValidateGenerateCSRCommand(progName, dbdir, subject, subjectStr,
                                          certReqFileName);
               /* Generate a CSR */
               rv = CreateCertRequest(slot, &pwdata, subject,
                                      certReqFileName, ascii);
               if (rv != SECSuccess) {
                   PR_fprintf(PR_STDERR, "Create Certificate Request: Failed\n");
                   goto cleanup;
               }
               break;
           case ADD_CERT_TO_DB:
               ValidateAddCertToDBCommand(progName, dbdir, nickNameStr, trustStr,
                                          certFileName, certReqFileName,
                                          issuerNameStr, serialNumberStr, selfsign);
               /* Add cert to database */
               rv = AddCertificateToDB(slot, &pwdata, certReqFileName, certFileName,
                                       issuerNameStr, certHandle, nickNameStr,
                                       trustStr, serialNumber, selfsign, ascii);
               if (rv != SECSuccess) {
                   PR_fprintf(PR_STDERR, "Add Certificate to DB: Failed\n");
                    goto cleanup;
               }
               break;
           case SAVE_CERT_TO_HEADER:
               ValidateSaveCertToHeaderCommand(progName, dbdir, nickNameStr, headerFileName);
               /* Save cert to the header file */
               rv = AddCertificateToHeader(slot, &pwdata, headerFileName, certHandle, nickNameStr, sigVerify);
               if (rv != SECSuccess) {
                   PR_fprintf(PR_STDERR, "Saving Certificate to header: Failed\n");
                   goto cleanup;
               }
               break;
           case ENCRYPT:
               ValidateEncryptCommand(progName, dbdir, nickNameStr, headerFileName, inFileName, encryptedFileName);
               /* Encrypt with public key from cert in header file */
               rv = FindKeyAndEncrypt(slot, &pwdata, headerFileName, encryptedFileName, inFileName);
               if (rv != SECSuccess) {
                   PR_fprintf(PR_STDERR, "Find public key and Encrypt : Failed\n");
                   goto cleanup;
               }
               break;
           case SIGN:
               ValidateSignCommand(progName, dbdir, nickNameStr, headerFileName, inFileName);
               /* Sign with private key */
               rv = FindKeyAndSign(slot, certHandle, &pwdata, nickNameStr, headerFileName, inFileName);
               if (rv != SECSuccess) {
                   PR_fprintf(PR_STDERR, "Find private key and sign : Failed\n");
                   goto cleanup;
               }
               break;
           case DECRYPT:
               ValidateDecryptCommand(progName, dbdir, headerFileName, encryptedFileName, outFileName);
               /* Decrypt with the matching private key */
               rv = FindKeyAndDecrypt(slot, &pwdata, headerFileName, encryptedFileName, outFileName);
               if (rv != SECSuccess) {
                   PR_fprintf(PR_STDERR, "Find private key and Decrypt : Failed\n");
               }
               break;
           case VERIFY:
               ValidateVerifyCommand(progName, dbdir, headerFileName, inFileName);
               /* Verify with the matching public key */
               rv = FindKeyAndVerify(slot, certHandle, &pwdata, headerFileName, inFileName);
               if (rv != SECSuccess) {
                   PR_fprintf(PR_STDERR, "Find public key and verify signature : Failed\n");
                   goto cleanup;
               }
           }
       cleanup:
           if (slot) {
               PK11_FreeSlot(slot);
           }
           if (initialized) {
               SECStatus rvShutdown = NSS_Shutdown();
               if (rvShutdown != SECSuccess) {
                   PR_fprintf(PR_STDERR, "Failed : NSS_Shutdown() - %s",
                              PORT_ErrorToString(rvShutdown));
                   rv = SECFailure;
               }
               PR_Cleanup();
           }
           return rv;
       }