RSA BSAFE Crypto-C

Cryptographic Components for C

Search

p11dsasign.c

/* $Id: p11dsasign.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 either generate a DSA keypair, or use an already
 *  generated DSA keypair.  This keypair will be used, (with the given
 *  hardware) to sign and verify some given data.
*/

#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 MAX_BLOCK_SIZE 256


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

int MAIN(int argc, char *argv[])
{
  B_ALGORITHM_OBJ randomAlgorithm = (B_ALGORITHM_OBJ)NULL_PTR;
  B_ALGORITHM_OBJ digitalSigner = (B_ALGORITHM_OBJ)NULL_PTR;
  B_ALGORITHM_OBJ digitalVerifier = (B_ALGORITHM_OBJ)NULL_PTR;
  B_KEY_OBJ publicKey = (B_KEY_OBJ)NULL_PTR;
  B_KEY_OBJ privateKey = (B_KEY_OBJ)NULL_PTR;

  /*  The data to be signed */
  unsigned char *inputData = (unsigned char *)"Sign this sentence.";
  unsigned int inputDataLen;

  /*  The signature block that is created */
  unsigned char signature[MAX_BLOCK_SIZE];
  unsigned int signatureLen;

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

  char userInput[RSA_DEMO_MAX_LINE_LEN];

  /*  Stores the device (hardware or software) that is
   *  being used */
  ITEM deviceName = {NULL, 0};

  /*  Contains the information needed to connect to the hardware */
  B_PKCS11_SESSION p11Session;
  ITEM passphrase = {NULL, 0};
  unsigned char *tokenLabel = NULL;
  unsigned int libraryNameLen = 0;

  /*  Indicates if the keys are to be generated in software or not */
  unsigned int usetoken = 0;

  /*  Used to hold the key information */
  ITEM publicBER = {NULL, 0};
  ITEM privateBER = {NULL, 0};
  KI_TOKEN_INFO privateToken = {NULL, 0, NULL, 0};
  KI_TOKEN_INFO *tokenInfo = NULL;

  /*  The objects needed if a keypair needs to be generated */
  B_ALGORITHM_OBJ dsaParamGen = (B_ALGORITHM_OBJ)NULL_PTR;
  B_ALGORITHM_OBJ dsaKeyGenObj = (B_ALGORITHM_OBJ)NULL_PTR;
  B_DSA_PARAM_GEN_PARAMS dsaParamGenParams;


  /*  This chooser contains the AMs used with hardware.  Since some platforms
   *  do not support public key operations, (and it is usually faster to
   *  implement these operations in software)  the software AMs are included
   *  for the public key operations
   */
  B_ALGORITHM_METHOD *DSA_GEN_HW_CHOOSER[] = {
    (B_ALGORITHM_METHOD *)&AM_PKCS11_DSA_SIGN,
    (B_ALGORITHM_METHOD *)&AM_PKCS11_DSA_VERIFY,
    (B_ALGORITHM_METHOD *)&AM_PKCS11_DSA_KEY_GEN,
    (B_ALGORITHM_METHOD *)&AM_SHA,
    (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 chooser contains the software AMs that are to be used if the
   *  hardware AMs are not available
   */
  B_ALGORITHM_METHOD *DSA_GEN_SW_CHOOSER[] = {
    &AM_SHA,
    &AM_SHA_RANDOM,
    &AM_DSA_KEY_GEN,
    &AM_DSA_PARAM_GEN,
    &AM_DSA_SIGN,
    &AM_DSA_VERIFY,
    (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 new chooser that is generated, which contains the hardware AMs
   *  and, if needed, the software AMs
   */
  B_ALGORITHM_CHOOSER hwChooserGen = (B_ALGORITHM_CHOOSER)NULL_PTR;

  A_SURRENDER_CTX generalSurrenderContext;
  int generalFlag;

  /* 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. */
    p11Session.libraryName = NULL;
    p11Session.tokenLabel.data = NULL;
    p11Session.passPhrase.data = NULL;

    /* 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 ("Digital Signature\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') {
        usetoken = 1;
        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;

      }
      /*  Create a random Object to use to generate the keypair */
      if ((status = RSA_CreateRandomAlgorithmObject (&randomAlgorithm)) != 0)
        break;

      /*  Generate the Chooser to be used */
      if ((status = B_CreateHardwareChooser (DSA_GEN_HW_CHOOSER,
                                            &hwChooserGen,
                                            DSA_GEN_SW_CHOOSER,
                                            HI_PKCS11Session,
                                            (POINTER)&p11Session)) != 0)
        break;


      /* We can either use the PKCS #11 device as one for hardware key storage
         or a crypto accelerator.  If it's a key storage device, prompt the user
         for the files containing the token information.  We make the assumption
         that the device will not be performing any public key operations; the
         user must supply the public key BER that corresponds to the private key
         token information.  If it's strictly an accelerator, we give the option
         to generate a software keypair and then feed it to the encrypt
         routines. */
      if (usetoken == 1) {
        RSA_PrintMessage ("To use a key token, supply the file containing the");
        status = RSA_GetFileToAllocBuffer
                 (&privateToken.manufacturerId.data,
                  &privateToken.manufacturerId.len,
                  " manufacturer ID\n(blank otherwise)");

        if (status != RSA_DEMO_E_CANCEL) {
          /* We want to use a token and have the manufacturer's ID */
          status = RSA_GetFileToAllocBuffer
                      (&privateToken.internalKey.data,
                       &privateToken.internalKey.len,
                       "Enter private key Token (blank to cancel)");

          if (status != RSA_DEMO_E_CANCEL) {
            RSA_PrintMessage ("Enter corresponding public key BER");
            status = RSA_GetFileToAllocBuffer
                       (&publicBER.data, &publicBER.len,
                        " (blank to cancel)");

            if ( status != RSA_DEMO_E_CANCEL) {

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

              if ((status = B_SetKeyInfo (publicKey, KI_DSAPublicBER,
                                  (POINTER)&publicBER)) != 0)
                break;

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

              if ((status = B_SetKeyInfo (privateKey, KI_Token,
                                  (POINTER)&privateToken)) != 0)
                break;
            }
          }
        }
      }
      if ((status == RSA_DEMO_E_CANCEL) || (usetoken != 1)) {
        /*  Generate a software keypair. */
        /*  First the parameters must be generated */
        dsaParamGenParams.primeBits = DSA_PRIME_BITS;

        RSA_PrintMessage("Generating Parameters and Keys in Software ");

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

        if ((status = B_SetAlgorithmInfo ( dsaParamGen, AI_DSAParamGen,
                                  (POINTER)&dsaParamGenParams )) != 0)
          break;

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

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

        /*  These parameters are set into the key gen algorithm object
         *  so they can be used to generate the keys
        */
        if ((status = B_GenerateParameters (dsaParamGen, dsaKeyGenObj,
                      randomAlgorithm, &generalSurrenderContext)) !=0)
          break;

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

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

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

        if ((status = B_GenerateKeypair ( dsaKeyGenObj, publicKey,
                                privateKey, randomAlgorithm,
                                (A_SURRENDER_CTX *)NULL_PTR)) != 0)
          break;
      }

      if (status != 0)
        break;

      RSA_PrintMessage ("\nComputing a Digital Signature\n");
      RSA_PrintMessage ("=============================\n");

      inputDataLen = T_strlen ((char *)inputData);
      RSA_PrintBuf ("Data to Sign", inputData, inputDataLen);

      /*  Create an algorithm object */
      if ((status = B_CreateAlgorithmObject (&digitalSigner)) != 0)
        break;

      /*  Set the algorithm object to AI_SHA1WithRSAEncryption */
      if ((status = B_SetAlgorithmInfo (digitalSigner, AI_DSAWithSHA1,
                                      NULL_PTR)) != 0)
        break;

      /*  Init */
      if ((status = B_SignInit (digitalSigner, privateKey,
                              hwChooserGen,
                              (A_SURRENDER_CTX *)NULL_PTR)) != 0)
        break;

      /*  Find out which device is doing the signing  */
      if ((status = B_GetDevice (&deviceName, digitalSigner)) != 0)
        break;

      RSA_PrintBuf ("Device Used for Signing", deviceName.data, deviceName.len);

      /*  Update  -- digest the data to sign */
      RSA_PrintMessage ("Digesting the input data...\n");
      if ((status = B_SignUpdate (digitalSigner, inputData, inputDataLen,
                                (A_SURRENDER_CTX *)NULL_PTR)) != 0)
        break;

      /*  Final --  Encrypt the digest and output the result to a
                    signature buffer */
      RSA_PrintMessage ("Encrypting the digest...\n\n");
      if ((status = B_SignFinal (digitalSigner, signature, &signatureLen,
                               sizeof (signature), randomAlgorithm,
                               (A_SURRENDER_CTX *)NULL_PTR)) != 0)
        break;

      RSA_PrintBuf ("Digital Signature", signature, signatureLen);

      RSA_PrintMessage ("\nVerifying the Digital Signature\n");
      RSA_PrintMessage ("===============================\n");

      /*  Create an algorithm object */
      if ((status = B_CreateAlgorithmObject (&digitalVerifier)) != 0)
        break;

      /*  Set the algorithm object to the same AI */
      if ((status = B_SetAlgorithmInfo (digitalVerifier,
                                        AI_DSAWithSHA1,
                                        NULL_PTR)) != 0)
        break;

      /*  Init */
      if ((status = B_VerifyInit (digitalVerifier, publicKey,
                                  hwChooserGen,
                                  (A_SURRENDER_CTX *)NULL_PTR)) != 0)
        break;

      /*  Find out which device is doing the signing  */
      if ((status = B_GetDevice (&deviceName, digitalVerifier)) != 0)
        break;

      RSA_PrintBuf ("Device Used for Verification",
                    deviceName.data, deviceName.len);

      /*  Update */
      if ((status = B_VerifyUpdate (digitalVerifier, inputData, inputDataLen,
                                    (A_SURRENDER_CTX *)NULL_PTR)) != 0)
        break;

      /*  Final */
      if ((status = B_VerifyFinal (digitalVerifier, signature, signatureLen,
                                   (B_ALGORITHM_OBJ)NULL_PTR,
                                   (A_SURRENDER_CTX *)NULL_PTR)) != 0)
        break;
    } while (0);

    if (status != 0) {
      RSA_PrintError ("pkcs11dsasign", status);
      printf("status is %d\n", status);
      if (status == BE_KEY_INFO || status == BE_WRONG_KEY_INFO) {
        RSA_PrintMessage("This could be due to an error when entering \n");
        RSA_PrintMessage("the token information or the dll library \n");
      }
    }
    else {
      RSA_PrintMessage ("\nDigital Signature verified!\n");
    }

  /*  Destroy all objects and free memory */
  B_DestroyAlgorithmObject (&randomAlgorithm);
  B_DestroyAlgorithmObject (&digitalSigner);
  B_DestroyAlgorithmObject (&digitalVerifier);
  B_DestroyHardwareChooser (&hwChooserGen);
  B_DestroyKeyObject (&privateKey);
  B_DestroyKeyObject (&publicKey);

  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);

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

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