| RSA BSAFE Crypto-C |
Cryptographic Components for C |
| Search |
/* $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 */