RSA BSAFE Crypto-C

Cryptographic Components for C

Search

p11rsakeygen.c

/* $Id: p11rsakeygen.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 RSA keypair, using the specified hardware
 *  In this case the keypair generated can then be used for signing
 *  and verifying.
 */

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

#define RSA_MODULUS_BITS 2048
#define BLOCK_SIZE ((RSA_MODULUS_BITS + 7) / 8)


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

int MAIN(int argc, char *argv[])
{
  B_ALGORITHM_OBJ rsaGen = (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 */
  B_KEYPAIR_GEN_PARAMS keypairGenParams;
  A_RSA_KEY_GEN_PARAMS keyGenParams;

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

  static unsigned char f4data[] = {0x01, 0x00, 0x01};

  /*  Stores the information needed in order to access the
   *  hardware installed
  */
  B_PKCS11_SESSION p11Session;
  ITEM passphrase = {NULL, 0};
  unsigned char *tokenLabel = NULL;
  unsigned int libraryNameLen = 0;

  /*  The current chooser which holds the hardware AMs
   *  that are to be used
   */
  B_ALGORITHM_METHOD *RSA_GEN_HW_CHOOSER[] = {
    (B_ALGORITHM_METHOD *)&AM_PKCS11_RSA_KEY_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

  };

  /*  The backup chooser which holds the software AMs that should
   *  be used if the hardware AMs are not available
   */
  B_ALGORITHM_METHOD *RSA_GEN_SW_CHOOSER[] = {
    &AM_SHA,
    &AM_SHA_RANDOM,
    &AM_RSA_KEY_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;

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

  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;

  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 ("RSA 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;

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

    /*  Allocating memory for the keys and algorithm object  */
    if ((status = B_CreateKeyObject (&publicKey)) != 0)
      break;

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

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

    /*  The information needed to generate the keys  */
    keyGenParams.modulusBits = 1024;
    keyGenParams.publicExponent.data = f4data;
    keyGenParams.publicExponent.len = sizeof (f4data);

    keypairGenParams.privateKeyAttributes.keyUsage =
      CF_DIGITAL_SIGNATURE | CF_KEY_ENCIPHERMENT | CF_DATA_ENCIPHERMENT;
    keypairGenParams.privateKeyAttributes.tokenFlag =
      TF_RESIDE_ON_TOKEN | TF_PRIVATE;
    keypairGenParams.privateKeyAttributes.start = 0;
    keypairGenParams.privateKeyAttributes.end = 0;
    keypairGenParams.publicKeyAttributes.keyUsage =
      CF_DIGITAL_SIGNATURE | CF_KEY_ENCIPHERMENT | CF_DATA_ENCIPHERMENT;
    keypairGenParams.publicKeyAttributes.tokenFlag = TF_RESIDE_ON_TOKEN;
    keypairGenParams.publicKeyAttributes.start = 0;
    keypairGenParams.publicKeyAttributes.end = 0;
    keypairGenParams.keypairGenInfoType = AI_RSAKeyGen;
    keypairGenParams.keypairGenInfo = (POINTER)&keyGenParams;

    /*  Setting the algorithm with the key information */
    if ((status = B_SetAlgorithmInfo (rsaGen, AI_KeypairGen,
                                      (POINTER)&keypairGenParams)) != 0)
      break;

    /*  Generate a random object for creating the keys */
    if ((status = RSA_CreateRandomAlgorithmObject (&random)) != 0)
      break;

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

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

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

    /*  Generate the keypair */
    if ((status = B_GenerateKeypair (rsaGen, 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_RSAPublicBER)) != 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_PKCS_RSAPrivateBER);
    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 (&rsaGen);
  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