RSA BSAFE Crypto-C

Cryptographic Components for C

Search

p11dsakeygen.c

/* $Id: p11dsakeygen.c,v 1.7 2004/12/03 02:08:39 sparki Exp $ */
/*
 * Copyright (C) 1998-2004 RSA Security Inc.
 *
 * This file shall only be used to demonstrate how to interface to an
 * RSA Security Inc. licensed development product.
 *
 * You have a royalty-free right to use, reproduce and distribute this
 * demonstration file, provided that you agree that RSA Security Inc.
 * has no warranty, implied or otherwise, or liability for this
 * demonstration file (including any modified version).  This software
 * is provided "as is" without warranties or representations of any
 * kind. RSA Security disclaims all conditions and warranties, statutory
 * and otherwise, both express and implied, with respect to the software,
 * its quality and performance, including but not limited to, all
 * implied warranties of merchantability, fitness for a particular
 * purpose, title and noninfringement of third party rights. Without
 * limiting the foregoing, RSA Security does not warrant that the
 * software is error-free or that errors in the product will be
 * corrected. You agree that RSA Security shall not be liable for any
 * direct, indirect, incidental, special, consequential, punitive or
 * other damages whatsoever resulting from your use of this software
 * or any modified version.
 *
 *
 */

/*  This program will generate a DSA keypair, using the specified hardware.
 *  If parameters that are used to generate the keypair have already been
 *  created then the user will have the option to use those otherwise
 *  new parameters will be created.
 */

#include "bsafe.h"
#include "demoutil.h"  /* in samples/common/include */
#include "bsfutil.h"   /* in samples/common/include */
#include "surrctx.h"   /* in samples/common/include */

#define DSA_PRIME_BITS 512
#define BLOCK_SIZE 256


#ifdef CRYPTOC_APP
#define MAIN p11dsakeygenMain
#else
#define MAIN main
#endif

int MAIN(int argc, char *argv[])
{
  B_ALGORITHM_OBJ dsaGen = (B_ALGORITHM_OBJ)NULL_PTR;
  B_ALGORITHM_OBJ random = (B_ALGORITHM_OBJ)NULL_PTR;
  B_KEY_OBJ publicKey = (B_KEY_OBJ)NULL_PTR;
  B_KEY_OBJ privateKey = (B_KEY_OBJ)NULL_PTR;

  A_SURRENDER_CTX generalSurrenderContext;
  int generalFlag;

  /*  Used to hold the public key information */
  ITEM *cryptocPublicKeyBER;
  ITEM myPublicKeyBER = {NULL, 0};

  /*  Used to hold the private key information */
  ITEM *getPrivateKey;
  ITEM privateKeyBER = {NULL, 0};

  KI_TOKEN_INFO *tokenInfo = NULL;

  /*  Holds the parameters needed to generate the keys */
  A_DSA_PUBLIC_KEY *pubKeyData;
  A_DSA_PARAMS DSAParams;

  /*  Stores the device (hardware or software) that is
   *  being used */
  ITEM deviceName;

  /*  Stores the information needed in order to access the
   *  hardware installed
  */
  B_PKCS11_SESSION p11Session;

  unsigned char *tokenLabel = NULL;
  unsigned int libraryNameLen = 0;

  /*  The current chooser which holds the hardware AMs
   *  that are to be used
   */
  B_ALGORITHM_METHOD *DSA_GEN_HW_CHOOSER[] = {
    (B_ALGORITHM_METHOD *)&AM_DSA_PARAM_GEN,
    (B_ALGORITHM_METHOD *)&AM_PKCS11_DSA_KEY_GEN,
    (B_ALGORITHM_METHOD *)&AM_SHA_RANDOM,
    (B_ALGORITHM_METHOD *)NULL_PTR
    /* This will fix a problem that the IA64 compiler finds when *
                 * seeing a short chooser list */
                #ifdef IA64_FORCE_LARGE
                                IA64_FORCE_LARGE
                #endif

  };


  /*  The backup chooser which holds the software AMs that should
   *  be used if the hardware AMs are not available
   */
  B_ALGORITHM_METHOD *DSA_GEN_SW_CHOOSER[] = {
    &AM_SHA_RANDOM,
    &AM_SHA,
    &AM_DSA_KEY_GEN,
    &AM_DSA_PARAM_GEN,
    (B_ALGORITHM_METHOD *)NULL_PTR
    /* This will fix a problem that the IA64 compiler finds when *
                 * seeing a short chooser list */
                #ifdef IA64_FORCE_LARGE
                                IA64_FORCE_LARGE
                #endif

  };

  /*  This will hold the new chooser created */
  B_ALGORITHM_CHOOSER hwChooserGen = (B_ALGORITHM_CHOOSER)NULL_PTR;

  /*  This is used to hold the already generated parameters */
  B_KEYPAIR_GEN_PARAMS p11KeyGenParams;
  B_DSA_PARAM_GEN_PARAMS dsaParamGenParams;

  /*  This generates and holds parameters if they have not been generated */
  B_ALGORITHM_OBJ dsaParamGen = (B_ALGORITHM_OBJ)NULL_PTR;
  B_ALGORITHM_OBJ dsaParamStore = (B_ALGORITHM_OBJ)NULL_PTR;
  B_KEY_OBJ publicTemp = (B_KEY_OBJ)NULL_PTR;
  B_KEY_OBJ privateTemp = (B_KEY_OBJ)NULL_PTR;

  /*  Used to check for errors */
  int status;

  int usetoken = 0;

  char userInput[RSA_DEMO_MAX_LINE_LEN];

  /* see samples/common/source/surrctx.c for RSA_GeneralSurrenderFunction */
  generalSurrenderContext.Surrender = RSA_GeneralSurrenderFunction;
  generalSurrenderContext.handle = (POINTER)&generalFlag;
  generalSurrenderContext.reserved = NULL_PTR;

  T_memset ((POINTER)&DSAParams, 0, sizeof (DSAParams));

  do {
    /* Initialize these fields to facilitate graceful cleanup on
       error conditions. */
    T_memset ((POINTER)&p11Session, 0, sizeof (p11Session));

    /* The RSA_* demo code utilities are described in
       common/include/demoutil.h.  This procedure simply checks the
       command-line arguments for input or output options. */
    if ((status = RSA_SetOptions (argc, argv)) != 0)
      break;

    RSA_PrintMessage ("DSA PKCS #11 Key Generation\n");
    RSA_PrintMessage ("===========================\n");

    /*  The information needed in order to access the hardware platform */
    p11Session.sessionHandle = 0;

    /* We could supply a CK_FUNCTION_LIST for the device we want this
       B_PKCS11_SESSION information to identify.  However, we specify
       NULL here to indicate that Crypto-C should obtain the CK_FUNCTION_LIST
       using the libraryName and tokenLabel to identify the device for this
       session. */
    p11Session.cryptokiFunctions = NULL_PTR;

    /* This name will be the one that Crypto-C tries to load with, for
       example, LoadLibrary.  */
    RSA_PrintMessage ("Enter name of PKCS #11 shared library");
    if ((status = RSA_GetCommand (userInput, sizeof (userInput),
                                  " (blank to omit)")) != 0)
      break;

    /* p11Session.libraryName should be a NUL-terminated string */
    libraryNameLen = T_strlen (userInput) + 1;
    p11Session.libraryName = (char *)T_malloc (libraryNameLen);
    if (p11Session.libraryName == NULL) {
      status = RSA_DEMO_E_ALLOC;
      break;
    }

    T_memcpy ((unsigned char *)p11Session.libraryName, (unsigned char *)userInput,
              libraryNameLen);

    RSA_PrintMessage ("Enter token name");
    if ((status = RSA_GetCommand (userInput, sizeof (userInput),
                                  " (blank to omit)")) != 0)
      break;

    if (userInput[0] != '\0') {
      p11Session.tokenLabel.len = T_strlen (userInput);
      tokenLabel = T_malloc (p11Session.tokenLabel.len);

      /* we don't want to free p11Session.tokenLabel ourselves, since
         in the case where no token name is supplied, Crypto-C places
         its own buffer in p11Session.tokenLabel.data */
      p11Session.tokenLabel.data = tokenLabel;
      if (p11Session.tokenLabel.data == NULL) {
        status = RSA_DEMO_E_ALLOC;
        break;
      }

      T_memcpy (p11Session.tokenLabel.data, (unsigned char *)userInput,
                p11Session.tokenLabel.len);
    }

    RSA_PrintMessage ("Enter passphrase or PIN to access PKCS #11 device");
    if ((status = RSA_GetCommand (userInput, sizeof (userInput),
                                  " (blank to omit)")) != 0)
      break;

    if (userInput[0] != '\0') {
      p11Session.passPhrase.len = T_strlen (userInput);
      p11Session.passPhrase.data = T_malloc (p11Session.passPhrase.len);
      if (p11Session.passPhrase.data == NULL) {
        status = RSA_DEMO_E_ALLOC;
        break;
      }

      T_memcpy (p11Session.passPhrase.data, (unsigned char *)userInput,
                p11Session.passPhrase.len);
      T_memset ((unsigned char *)userInput, 0, sizeof (userInput));
    }

    p11Session.surrenderContext = (A_SURRENDER_CTX *)NULL_PTR;

    /*  Generate a random object that will be used to create the keys */
    if ((status = RSA_CreateRandomAlgorithmObject (&random)) != 0)
      break;

    /*  Use the two defined choosers to create a new chooser */
    if ((status = B_CreateHardwareChooser
                    (DSA_GEN_HW_CHOOSER, &hwChooserGen, DSA_GEN_SW_CHOOSER,
                     HI_PKCS11Session, (POINTER)&p11Session)) != 0)
      break;

    /*  Create the objects that will be used to generate the key pair */
    if ((status = B_CreateKeyObject (&publicKey)) != 0)
      break;

    if ((status = B_CreateKeyObject (&privateKey)) != 0)
      break;

    if ((status = B_CreateAlgorithmObject(&dsaGen)) !=0)
        break;

    do{

      /*  Obtain the pre-generated Parameter data if it exists*/
      RSA_PrintMessage("To use already generated parameters, ");
      RSA_PrintMessage ("please supply the following files \n");
      status = RSA_GetFileToAllocBuffer
               (&DSAParams.prime.data,
                &DSAParams.prime.len,
                "Enter the file with the prime information: \n(blank otherwise)");

      if ( status == RSA_DEMO_E_CANCEL ) {
        break;
      }
      else {
        RSA_PrintBuf("prime", DSAParams.prime.data, DSAParams.prime.len);
      }

      status = RSA_GetFileToAllocBuffer
               (&DSAParams.subPrime.data,
                &DSAParams.subPrime.len,
                "Enter the file with the subprime information: \n(blank otherwise)");

      if ( status == RSA_DEMO_E_CANCEL )
      {
        break;
      }
      else {
        RSA_PrintBuf("subprime", DSAParams.subPrime.data, DSAParams.subPrime.len);
      }

      status = RSA_GetFileToAllocBuffer
               (&DSAParams.base.data,
                &DSAParams.base.len,
                "Enter the file with the base information: \n(blank otherwise)");

      if ( status == RSA_DEMO_E_CANCEL ) {
        break;
      }
      else {
        RSA_PrintBuf("base", DSAParams.base.data, DSAParams.base.len);
      }


    }while(0);

    /*  If the parameters were not preGenerated then generate them */
    if (status == RSA_DEMO_E_CANCEL)
    {
            /*  The parameters need to be generated */
      dsaParamGenParams.primeBits = DSA_PRIME_BITS;

      /*  The algorithm object used to generate the parameters */
      if ((status = B_CreateAlgorithmObject (&dsaParamGen)) != 0)
          break;

      /*  In Crypto-C the only way to obtain these parameters is to
       *  generate a keypair and then extract the parameters from the
       *  keys generated.  This will hopefully change in future version.
       *  These next objects are used to create the key pair
      */
      if ((status = B_CreateAlgorithmObject (&dsaParamStore)) !=0)
        break;

      if ((status = B_CreateKeyObject(&publicTemp)) !=0)
        break;

      if ((status = B_CreateKeyObject(&privateTemp)) !=0)
        break;

      /*  The parameters must be generated in software */
      if ((status = B_SetAlgorithmInfo ( dsaParamGen, AI_DSAParamGen,
          (POINTER)&dsaParamGenParams)) != 0)
        break;

      if ((status = B_GenerateInit
         (dsaParamGen, hwChooserGen, (A_SURRENDER_CTX *)NULL_PTR)) != 0)
        break;

      /*  Generate the Parameters and store them in dsaGen so they can
       *  be used to generate keys
      */
      if ((status = B_GenerateParameters(dsaParamGen, dsaParamStore, random,
                      &generalSurrenderContext)) !=0)
        break;


    /*  Obtain the device used to generate the keys */
    if ((status = B_GetDevice (&deviceName, dsaParamGen)) != 0)
      break;

    RSA_PrintBuf ("\nDevice Name for Generating Parameters", deviceName.data, deviceName.len);

      if ((status = B_GenerateInit
         (dsaParamStore, hwChooserGen, (A_SURRENDER_CTX *)NULL_PTR)) != 0)
        break;

      /*  The Parameter algorithm object is no longer needed */
      B_DestroyAlgorithmObject(&dsaParamGen);

      /*  Generate the Key Pair */
      if ((status = B_GenerateKeypair
        (dsaParamStore, publicTemp, privateTemp, random, (A_SURRENDER_CTX *)NULL_PTR)) != 0)
        break;

    /*  Obtain the device used to generate the keys */
    if ((status = B_GetDevice (&deviceName, dsaGen)) != 0)
      break;

    /*  Retrieve the parameters so they can be stored for later use */
      if ((status = B_GetKeyInfo
          ((POINTER *)&pubKeyData, publicTemp, KI_DSAPublic)) != 0)
        break;

      /*  This Algorithm Object is no longer needed */
      B_DestroyAlgorithmObject(&dsaParamStore);

      /*  Store the Prime parameter */
      DSAParams.prime.len = pubKeyData->params.prime.len;
      DSAParams.prime.data = T_malloc(DSAParams.prime.len);
      T_memcpy(DSAParams.prime.data, pubKeyData->params.prime.data, DSAParams.prime.len);

      RSA_PrintMessage ("\nThe DSA Parameters:\n");
      RSA_PrintBuf ("Prime", DSAParams.prime.data,
                    DSAParams.prime.len);

      status = RSA_WriteDataToFile
                 (DSAParams.prime.data, DSAParams.prime.len,
                  "Optionally enter name of file for the DSA prime");
      if ((status != 0) && (status != RSA_DEMO_E_CANCEL))
        break;

      /*  Store the subPrime parameter */
      DSAParams.subPrime.len = pubKeyData->params.subPrime.len;
      DSAParams.subPrime.data = T_malloc(DSAParams.subPrime.len);
      T_memcpy(DSAParams.subPrime.data, pubKeyData->params.subPrime.data, DSAParams.subPrime.len);

      RSA_PrintBuf ("Subprime", DSAParams.subPrime.data,
                    DSAParams.subPrime.len);

      status = RSA_WriteDataToFile
                 (DSAParams.subPrime.data, DSAParams.subPrime.len,
                  "Optionally enter name of file for the DSA subprime");
      if ((status != 0) && (status != RSA_DEMO_E_CANCEL))
        break;

      /*  Store the Base parameter */
      DSAParams.base.len = pubKeyData->params.base.len;
      DSAParams.base.data = T_malloc(DSAParams.base.len);
      T_memcpy(DSAParams.base.data, pubKeyData->params.base.data, DSAParams.base.len);

      RSA_PrintBuf ("Base", DSAParams.base.data,
                    DSAParams.base.len);

      status = RSA_WriteDataToFile
                 (DSAParams.base.data, DSAParams.base.len,
                  "Optionally enter name of file for the DSA base");
      if ((status != 0) && (status != RSA_DEMO_E_CANCEL))
        break;

    }

    /*  Generate the key pair from the previosly generated parameters */
    /*  The information needed to generate the keys  */
    p11KeyGenParams.privateKeyAttributes.keyUsage = CF_DIGITAL_SIGNATURE;
    p11KeyGenParams.privateKeyAttributes.tokenFlag = TF_PRIVATE;
    p11KeyGenParams.privateKeyAttributes.start = 0;
    p11KeyGenParams.privateKeyAttributes.end = 0;
    p11KeyGenParams.publicKeyAttributes.keyUsage = CF_DIGITAL_SIGNATURE;
    p11KeyGenParams.publicKeyAttributes.tokenFlag = TF_RESIDE_ON_TOKEN;
    p11KeyGenParams.publicKeyAttributes.start = 0;
    p11KeyGenParams.publicKeyAttributes.end = 0;
    p11KeyGenParams.keypairGenInfoType = AI_DSAKeyGen;
    p11KeyGenParams.keypairGenInfo = (POINTER)&DSAParams;

    /*  Set the algorithm with the key information */
    if ((status = B_SetAlgorithmInfo (dsaGen, AI_KeypairGen,
                                      (POINTER)&p11KeyGenParams)) != 0)
       break;

    /*  Initialize the algorithm object with the correct chooser */
    if ((status = B_GenerateInit (dsaGen, hwChooserGen,
                                (A_SURRENDER_CTX *)NULL_PTR)) != 0)
       break;

    if ((status = B_GetDevice (&deviceName, dsaGen)) != 0)
       break;

    RSA_PrintBuf ("Device Name for Key Generation", deviceName.data, deviceName.len);

    /*  Generate the keypair */
    if ((status = B_GenerateKeypair (dsaGen, publicKey, privateKey, random,
                                     (A_SURRENDER_CTX *)NULL_PTR)) != 0)
       break;

    RSA_PrintMessage ("\n   Distributing Your Public Key\n");
    RSA_PrintMessage ("   ============================\n");

    /*  Obtain the public key information and print it out */
    if ((status = B_GetKeyInfo ((POINTER *)&cryptocPublicKeyBER, publicKey,
                                KI_DSAPublicBER)) != 0)
      break;

    myPublicKeyBER.len = cryptocPublicKeyBER->len;
    myPublicKeyBER.data = T_malloc (myPublicKeyBER.len);
    if (myPublicKeyBER.data == NULL_PTR) {
      status = RSA_DEMO_E_ALLOC;
      break;
    }

    T_memcpy (myPublicKeyBER.data, cryptocPublicKeyBER->data,
              myPublicKeyBER.len);

    RSA_PrintMessage ("The DER-encoded X.509 SubjectPublicKeyInfo\n");
    RSA_PrintBuf ("SubjectPublicKeyInfo", myPublicKeyBER.data,
                  myPublicKeyBER.len);

    status = RSA_WriteDataToFile
               (myPublicKeyBER.data, myPublicKeyBER.len,
                "Optionally enter name of file for public key BER");
    if ((status != 0) && (status != RSA_DEMO_E_CANCEL))
      break;

    status = B_GetKeyInfo ((POINTER *)&tokenInfo, publicKey, KI_Token);

    if (status == 0) {
      /* we have a public key in hardware */
      RSA_PrintMessage ("\nPublic key token information\n");
      RSA_PrintBuf ("KI_TOKEN_INFO.manufacturerId",
                    tokenInfo->manufacturerId.data,
                    tokenInfo->manufacturerId.len);
      RSA_PrintBuf ("KI_TOKEN_INFO.internalKey", tokenInfo->internalKey.data,
                    tokenInfo->internalKey.len);
    } else
      status = 0; /* not a fatal error */

    /*  Obtain the private key information and print it out */
    status = B_GetKeyInfo ((POINTER *)&getPrivateKey, privateKey,
                           KI_DSAPrivateBER);
    if (status == 0) {
      /* we have a KI_PKCS_RSAPrivateBER */
      privateKeyBER.len = getPrivateKey->len;
      privateKeyBER.data = T_malloc (privateKeyBER.len);
      if (privateKeyBER.data == NULL_PTR) {
        status = RSA_DEMO_E_ALLOC;
        break;
      }

      T_memcpy (privateKeyBER.data, getPrivateKey->data,
                privateKeyBER.len);

      RSA_PrintMessage ("\nThe DER-encoded PKCS #8 PrivateKeyInfo\n");
      RSA_PrintBuf ("PrivateKeyInfo", privateKeyBER.data,
                    privateKeyBER.len);

      status = RSA_WriteDataToFile
                 (privateKeyBER.data, privateKeyBER.len,
                  "Optionally enter name of file for private key BER");
      if ((status != 0) && (status != RSA_DEMO_E_CANCEL))
        break;
    } else
      status = 0; /* not a fatal error */

    status = B_GetKeyInfo ((POINTER *)&tokenInfo, privateKey, KI_Token);
    if (status == 0) {
      /* we have a private key in hardware */
      RSA_PrintMessage ("\nPrivate key token information\n");
      RSA_PrintBuf ("KI_TOKEN_INFO.manufacturerId",
                    tokenInfo->manufacturerId.data,
                    tokenInfo->manufacturerId.len);
      RSA_PrintBuf ("KI_TOKEN_INFO.internalKey", tokenInfo->internalKey.data,
                    tokenInfo->internalKey.len);

      status = RSA_WriteDataToFile
                 (tokenInfo->manufacturerId.data,
                  tokenInfo->manufacturerId.len,
                  "Optionally enter name of file for token manufacturer ID");
      if ((status != 0) && (status != RSA_DEMO_E_CANCEL))
        break;

      status = RSA_WriteDataToFile
                 (tokenInfo->internalKey.data, tokenInfo->internalKey.len,
                  "Optionally enter name of file for private key token info");
      if ((status != 0) && (status != RSA_DEMO_E_CANCEL))
        break;
    } else
      status = 0; /* not a fatal error */

    RSA_PrintMessage ("Finished!\n");
  } while (0);

  if (status != 0)
    RSA_PrintError ("p11keygen", status);

  /*  Destroy all objects  */
  B_DestroyAlgorithmObject (&random);
  B_DestroyAlgorithmObject (&dsaGen);
  B_DestroyHardwareChooser (&hwChooserGen);
  B_DestroyKeyObject (&privateKey);
  B_DestroyKeyObject (&publicKey);

  /*  Free up any memory allocated  */
  if (p11Session.libraryName != NULL)
    T_free ((unsigned char *)p11Session.libraryName);

  if (tokenLabel != NULL)
    T_free (tokenLabel);

  if (p11Session.passPhrase.data != NULL)
    T_free (p11Session.passPhrase.data);

  if (myPublicKeyBER.data != NULL_PTR)
    T_free (myPublicKeyBER.data);

  if (privateKeyBER.data != NULL_PTR)
    T_free (privateKeyBER.data);

  return (status);
} /*  end main  */

Copyright (c) 1999-2005 RSA Security Inc. All rights reserved. 068-001001-6210-001-000 - 6.2.1