| RSA BSAFE Cert-C |
Certificate Components for C |
| Crypto-C 6.2.1 Developer's Guide | ||
| Search |
/* $Id: demoutil.c,v 1.6 2004/03/02 05:18:37 gsingh Exp $ */ /* demoutil.c ** Copyright (c) 1999-2003, RSA Security Inc. ** ** This file is used to demonstrate how to interface to an RSA Security ** licensed development product. You have a royalty-free right to use, ** modify, reproduce and distribute this demonstration file (including ** any modified version), provided that you agree that RSA Security has ** no warranty, implied or otherwise, or liability for this demonstration ** file or any modified version. */ #include "demoutil.h" #ifdef _MSC_VER # pragma warning (disable: 171) /* invalid type conversion (often of very similar ptrs) */ #endif FILE *INPUT_FILE = (FILE *)0; char *INPUT_FILE_NAME = (char *)0; /* Specifies a file to place output, NULL for stdout. The user provides * this via the [-o filename] option, set by RSA_SetOptions. */ FILE *OUTPUT_FILE = (FILE *)0; char *OUTPUT_FILE_NAME = (char *)0; /* Specifies a file to place error messages, NULL for stderr. The user * provides this via the [-e filename] option, set by RSA_SetOptions. */ FILE *ERROR_FILE = (FILE *)0; char *ERROR_FILE_NAME = (char *)0; /* Specifies a file for the Cert-C status log provider to write output to. * The user sets this via the [-l logfile] option, set by RSA_SetOptions. * The default provider will use stderr if LOG_FILE_NAME is NULL. */ char *LOG_FILE_NAME = "rsacertc.log"; /* Specifies a file for the Cert-C status log provider to retrieve the format * control strings from. The user sets this via the [-s formatfile] option, * set by RSA_SetOptions. The default provider will look for "certc.msg" in * the current directory if FORMAT_STRINGS_FILE_NAME remains NULL. */ char *FORMAT_STRINGS_FILE_NAME = (char *)0; void RSA_PrintBuf (char *label, unsigned char *buf, unsigned int bufLen) { unsigned int i = 0, numBytes = 0; unsigned char line[17]; if (label != NULL) RSA_PrintMessage ("%s (%u bytes):\n", label, bufLen); for (i = 0; i < bufLen; i++) { /* remember the current character, if it's a printable ascii char */ if (isprint(buf[i])) line[i%16] = buf[i]; else line[i%16] = '.'; RSA_PrintMessage (" %02x", buf[i]); /* if we're at the end of a line */ if ((i & 15) == 15 || i == bufLen - 1) { line[i%16+1] = '\0'; /* lines don't always contain 16 bytes */ /* for the case where i == bufLen - 1, we must line up the beginning of * the ascii text correctly */ for (numBytes = i%16; numBytes < 15; numBytes++) RSA_PrintMessage (" "); RSA_PrintMessage (" [%s]\n", line); } } } /* end RSA_PrintBuf */ void RSA_PrintBufAsCArray (char *label, unsigned char *buffer, unsigned int bufferLen) { unsigned int count; RSA_PrintMessage ("unsigned char %s[%u] = {\n", label, bufferLen); for (count = 0 ; count < bufferLen; count++) { if ((count % 8) == 0) RSA_PrintMessage (" 0x%02X", buffer[count]); else RSA_PrintMessage (" 0x%02X", buffer[count]); if (count != (bufferLen - 1)) RSA_PrintMessage (","); if (((count % 8) == 7 ) || (count == (bufferLen - 1))) RSA_PrintMessage ("\n"); } RSA_PrintMessage ("};\n"); } /* end RSA_PrintBufAsCArray */ void RSA_PrintBitString (char *label, BIT_STRING bitString) { if (bitString.data == NULL) return; RSA_PrintMessage ("%s (%u bytes) ", label, bitString.len); RSA_PrintMessage ("Unused bits: %u\n", bitString.unusedBits); RSA_PrintBuf (NULL, bitString.data, bitString.len); } /* end PrintBitString */ int RSA_GetBitString (BIT_STRING *inputData, char *prompt) { int status = 0; ITEM bytes = {NULL_PTR, 0}; inputData->data = NULL_PTR; if (prompt != NULL) RSA_PrintMessage ("%s\n", prompt); status = RSA_GetItem (&bytes, "Enter hex-ascii bytes which make up the bit string"); if (status != 0) goto CLEANUP; inputData->data = bytes.data; inputData->len = bytes.len; for (;;) { status = RSA_GetInteger ((int *)&inputData->unusedBits, "Enter number of unused bits (0 - 7)"); if (status != 0) goto CLEANUP; if (inputData->unusedBits <= 7) break; RSA_PrintMessage ("Enter an integer between 0 and 7 inclusive.\n"); } CLEANUP: if (status != 0) RSA_PrintError ("RSA_GetBitString", status); if (status != 0) { T_free (bytes.data); inputData->data = NULL_PTR; inputData->len = 0; inputData->unusedBits = 0; } return status; } /* end RSA_GetBitString */ int RSA_GetItem (ITEM *inputData, char *prompt) { int status = 0, i = 0, commandIndex = 0; unsigned int value = 0; char c1, c2; char byteString[3]; /* used for call to strtoul below */ char command[RSA_DEMO_MAX_LINE_LEN]; int commandLen; for (;;) { inputData->data = NULL_PTR; status = RSA_GetCommand (command, sizeof (command), prompt); if (status != 0) break; commandLen = T_strlen (command); if (commandLen == 0) { status = RSA_DEMO_E_CANCEL; break; } /* number of bytes */ inputData->len = commandLen / 2 + commandLen % 2; inputData->data = T_malloc (inputData->len); if (inputData->data == NULL_PTR) { status = RSA_DEMO_E_ALLOC; break; } T_memset (inputData->data, 0, inputData->len); /* beginning with the least significant bit, fill in the input data to produce a binary in canonical order to match the given hex-ascii */ commandIndex = commandLen - 1; for (i = inputData->len - 1; i > -1 ; i--) { c1 = command[commandIndex--]; /* 0x00 - 0x0F, 'ones' place */ if (commandIndex < 0) c2 = '0'; else c2 = command[commandIndex--]; /* 'sixteenths' place */ if (!isxdigit (c1) || !isxdigit (c2)) { RSA_PrintMessage ("Invalid byte: %c%c, try again.\n", c2, c1); status = RSA_DEMO_E_BAD_COMMAND_FORMAT; break; } /* using the two left-most ascii characters, produce one byte value */ byteString[0] = c2, byteString[1] = c1, byteString[2] = '\0'; value = (unsigned int)(strtoul (byteString, NULL, 16)); /* make sure value only contains 1 byte */ if (value > 0xFF) { status = RSA_DEMO_E_INVALID_PARAMETER; break; } inputData->data[i] = (unsigned char)value; } if (status == 0) { RSA_PrintBuf ("Contents of byte array", inputData->data, inputData->len); break; } } if (status != 0) { T_free (inputData->data); inputData->data = NULL_PTR; inputData->len = 0; if (status != RSA_DEMO_E_CANCEL) RSA_PrintError ("RSA_GetItem", status); } return status; } /* end RSA_GetItem */ int RSA_GetInteger (int *response, char *prompt) { int status = 0; char command[RSA_DEMO_MAX_LINE_LEN]; for (;;) { status = RSA_GetCommand (command, sizeof (command), prompt); if (status != 0) break; if (T_strlen (command) == 0) { status = RSA_DEMO_E_CANCEL; *response = 0; break; } if (sscanf (command, "%i", response) > 0) break; RSA_PrintMessage ("Please enter an integer. Try again.\n"); } if (status != 0) RSA_PrintError ("RSA_GetInteger", status); return status; } /* end RSA_GetInteger */ int RSA_GetCommand (char *command, unsigned int maxCommandSize, char *prompt) { int status = 0; unsigned int i = 0, outputMaxLen = 0; unsigned char *output = NULL_PTR; /* In case RSA_SetOptions was not called... */ if (INPUT_FILE == NULL) INPUT_FILE = stdin; if (prompt != NULL) RSA_PrintMessage ("%s: ", prompt); /* Since fgets gets the newline and adds the null byte and we strip the * newline, use a temporary buffer so that we can say that RSA_GetCommand * gets at most maxCommandSize - 1 characters, instead of - 2, since that's * more consistent with other similar C functions. */ outputMaxLen = maxCommandSize + 1; output = T_malloc (outputMaxLen); if (output == NULL_PTR) { status = RSA_DEMO_E_ALLOC; goto CLEANUP; } /* Treat any line that begins with a # as a comment */ do { if (fgets ((char *)output, outputMaxLen, INPUT_FILE) == NULL) { status = RSA_DEMO_E_FILE_IO; goto CLEANUP; } } while (output[0] == '#'); /* Replace the line terminator with a '\0' */ for (i = 0; output[i] != '\0' && i < maxCommandSize; i++) if (output[i] == '\n' || output[i] == '\r' || i == maxCommandSize - 1) command[i] = '\0'; else command[i] = output[i]; /* If the input is read from a script or we are sending PrintMessage output * to an output file, echo the commands the user types in to the output. */ if ((INPUT_FILE_NAME != (char *)0) || (OUTPUT_FILE_NAME != (char *)0)) RSA_PrintMessage ("%s\n", command); CLEANUP: if (status != 0) RSA_PrintError ("RSA_GetCommand", status); T_free (output); return status; } /* end RSA_GetCommand */ int RSA_GetRequiredCommand (char *command, unsigned int maxCommandSize, char *prompt) { int status = 0, done = 0; do { status = RSA_GetCommand (command, maxCommandSize, prompt); if (status != 0) break; if (T_strlen (command) != 0) done = 1; } while (done == 0); if (status != 0) RSA_PrintError ("RSA_GetRequiredCommand", status); return status; } /* end RSA_GetRequiredCommand */ void RSA_PrintMessage (char *message, ...) { va_list argPtr; /* In case RSA_SetOptions was not called... */ if (OUTPUT_FILE == NULL) OUTPUT_FILE = stdout; va_start (argPtr, message); vfprintf (OUTPUT_FILE, message, argPtr); fflush (OUTPUT_FILE); /* Also print prompt to stdout if the OUTPUT_FILE is not stdout and we are * not getting input from a script. */ if (OUTPUT_FILE != stdout && INPUT_FILE == stdin) { vprintf (message, argPtr); fflush (stdout); } va_end (argPtr); } /* end RSA_PrintMessage */ static void PrintErrorInfo (int status) { switch (status) { case E_ATTRIBUTE_VALUE_LEN: /* 0x712 */ RSA_PrintMessage ("Length of given attribute value incorrect.\n"); break; case E_VERIFY_ASN_SIGNATURE: /* 0x725 */ case E_INVALID_SIGNATURE: /* 0x72e */ RSA_PrintMessage ("Signature does not verify.\n"); break; case E_LOG: /* 0x748 */ RSA_PrintMessage ("Log service provider error. Be sure that certc.msg,"); RSA_PrintMessage (" or the appropriate file,\nis available if "); RSA_PrintMessage ("necessary.\nIf your program uses RSA_SetOptions, be"); RSA_PrintMessage (" sure that the -s option has been\nspecified "); RSA_PrintMessage ("correctly.\n"); break; case RSA_DEMO_E_FILE_IO: RSA_PrintMessage ("File I/O error. Perhaps the file you are looking "); RSA_PrintMessage ("for does not exist, or\nyou have entered an "); RSA_PrintMessage ("invalid file name.\n"); break; } return; } /* end PrintErrorInfo */ void RSA_PrintError (char *task, int status) { /* In case RSA_SetOptions was not called... */ if (ERROR_FILE == NULL) ERROR_FILE = stderr; if (status == RSA_DEMO_E_CANCEL || status == RSA_DEMO_E_ACTION_PENDING) ; /* do nothing for non-fatal error codes */ else if (status == 0) { fprintf (ERROR_FILE, "%s\n", task); fflush (ERROR_FILE); if (INPUT_FILE == stdin && ERROR_FILE != stderr) { fprintf (stderr, "%s\n", task); fflush (stderr); } } else { fprintf (ERROR_FILE, "***ERROR 0x%04x: during %s\n", status, task); PrintErrorInfo (status); fflush (ERROR_FILE); if (INPUT_FILE == stdin && ERROR_FILE != stderr) { fprintf (stderr, "***ERROR 0x%04x: during %s\n", status, task); fflush (stderr); } } } /* end RSA_PrintError */ static int GetFileLength (char *filename, unsigned int *length) { int status = 0; FILE *file = (FILE *)0; if (T_strlen (filename) == 0) { status = RSA_DEMO_E_FILE_IO; goto EXIT_LABEL; } if ((file = fopen (filename, "rb")) == NULL) { status = RSA_DEMO_E_FILE_IO; file = (FILE *)0; RSA_PrintMessage ("Could not open %s.\n", filename); goto EXIT_LABEL; } if ((status = fseek (file, 0, SEEK_END)) != 0) goto EXIT_LABEL; *length = ftell (file); if (*length == -1) { status = RSA_DEMO_E_FILE_IO; goto EXIT_LABEL; } EXIT_LABEL: if (status != 0) *length = 0; if ((file != stdin) && (file != (FILE *)0)) fclose (file); return status; } /* end GetFileLength */ static int GetFileContents (char *filename, unsigned char *buffer, unsigned int *bytesRead, unsigned int bufferSize) { int status = 0; FILE *file = (FILE *)0; unsigned int minLen; if (T_strlen (filename) == 0) { status = RSA_DEMO_E_FILE_IO; goto EXIT_LABEL; } if (GetFileLength (filename, &minLen) != 0) { status = RSA_DEMO_E_FILE_IO; goto EXIT_LABEL; } if (minLen < bufferSize) { status = RSA_DEMO_E_BUFFER_TOO_SMALL; goto EXIT_LABEL; } if ((file = fopen (filename, "rb")) == NULL) { status = RSA_DEMO_E_FILE_IO; RSA_PrintMessage ("Could not open %s.\n", filename); goto EXIT_LABEL; } *bytesRead = fread (buffer, 1, bufferSize, file); EXIT_LABEL: if (status != 0) RSA_PrintError ("GetFileContents", status); if (file != (FILE *)0) fclose (file); return status; } /* end GetFileContents */ int RSA_GetFileToAllocBuffer (unsigned char **buffer, unsigned int *bufferLen, char *prompt) { int status = 0; char filenameBuf[RSA_DEMO_MAX_LINE_LEN]; char *filename = (char *)filenameBuf; unsigned int bytesRead; *buffer = NULL; if ((status = RSA_GetCommand (filenameBuf, sizeof (filenameBuf), prompt)) != 0) { RSA_PrintError ("Invalid file name", 0); goto EXIT_LABEL; } /* Strip leading whitespace from filename */ while (isspace (filename[0])) filename++; /* Cancel operation if user enters a blank */ if (T_strlen (filename) == 0) { status = RSA_DEMO_E_CANCEL; goto EXIT_LABEL; } if ((status = GetFileLength (filename, bufferLen)) != 0) goto EXIT_LABEL; if ((*buffer = T_malloc (*bufferLen)) == NULL) { status = RSA_DEMO_E_ALLOC; goto EXIT_LABEL; } if ((status = GetFileContents (filename, *buffer, &bytesRead, *bufferLen)) != 0) goto EXIT_LABEL; EXIT_LABEL: if (status != 0) { T_free (*buffer); *bufferLen = 0; *buffer = NULL; } return status; } /* end RSA_GetFileToAllocBuffer */ int RSA_WriteDataToFile (unsigned char *input, unsigned int inputLen, char *prompt) { int status = 0; char filenameBuf[RSA_DEMO_MAX_LINE_LEN]; char *filename = (char *)filenameBuf; if ((inputLen == 0) || (input == NULL)) goto EXIT_LABEL; if ((status = RSA_GetCommand (filenameBuf, sizeof (filenameBuf), prompt)) != 0) { status = RSA_DEMO_E_FILE_IO; goto EXIT_LABEL; } /* Strip leading whitespace from filename */ while (isspace (filename[0])) filename++; /* Cancel operation if user enters a blank */ if (T_strlen (filename) == 0) { status = RSA_DEMO_E_CANCEL; goto EXIT_LABEL; } status = RSA_WriteDataToNamedFile (input, inputLen, filename); EXIT_LABEL: if (status != 0) RSA_PrintError ("RSA_WriteDataToFile", status); return status; } /* end RSA_WriteDataToFile */ int RSA_WriteDataToNamedFile (unsigned char *input, unsigned int inputLen, char *filename) { int status = 0; FILE *file = (FILE *)0; if ((file = fopen (filename, "wb")) == NULL) { status = RSA_DEMO_E_FILE_IO; RSA_PrintMessage ("Could not open %s.\n", filename); goto EXIT_LABEL; } if (fwrite (input, 1, inputLen, file) < inputLen) { status = RSA_DEMO_E_FILE_IO; goto EXIT_LABEL; } EXIT_LABEL: if (status != 0) RSA_PrintError ("RSA_WriteDataToNamedFile", status); if (file != (FILE *)0) fclose (file); return status; } /* end RSA_WriteDataToNamedFile */ /* Prompts the user for a file name and obtains a handle to that file for * use with RSA_GetDataFromFile and RSA_AppendDataToFile. */ int RSA_OpenDataFilePrompt (FILE **fileHandle, int usage, char *prompt) { int status = 0; char filenameBuf[RSA_DEMO_MAX_LINE_LEN]; char *filename = (char *)filenameBuf; *fileHandle = NULL; status = RSA_GetCommand (filenameBuf, sizeof (filenameBuf), prompt); if (status != 0) { RSA_PrintError ("Invalid file name", 0); goto CLEANUP; } /* Strip leading whitespace from filename */ while (isspace (filename[0])) filename++; /* Cancel operation if user enters a blank */ if (T_strlen (filename) == 0) { status = RSA_DEMO_E_CANCEL; goto CLEANUP; } if (usage == RSA_DEMO_READ_BINARY) *fileHandle = fopen (filename, "rb"); else if (usage == RSA_DEMO_WRITE_BINARY) *fileHandle = fopen (filename, "wb"); if (*fileHandle == (FILE *)0) { status = RSA_DEMO_E_FILE_IO; goto CLEANUP; } CLEANUP: if (status != 0) { RSA_CloseDataFile (fileHandle); RSA_PrintError ("RSA_OpenDataFilePrompt", status); } return status; } /* end RSA_OpenDataFilePrompt */ void RSA_CloseDataFile (FILE **fileHandle) { if (fileHandle != NULL) { if (*fileHandle != (FILE *)0) { fclose (*fileHandle); *fileHandle = (FILE *)0; } } } /* end RSA_CloseDataFile */ int RSA_GetDataFromFile (FILE *inputFile, unsigned int bufferSize, unsigned char *buffer, unsigned int *bytesRead) { int status = 0; unsigned char dummy; *bytesRead = fread (buffer, 1, bufferSize, inputFile); /* When we read exactly bufferSize bytes, look ahead one character in case it happens to be the end of file (there were exactly bufferSize bytes left in the file). */ if (*bytesRead == bufferSize) fread (&dummy, 1, 1, inputFile); if (feof (inputFile)) { /* we are done reading the file */ status = 0; } else { /* more data remains to be read - roll back the lookahead character */ status = RSA_DEMO_E_MORE_DATA; fseek (inputFile, -1, SEEK_CUR); } return status; } /* end RSA_GetDataFromFile */ int RSA_AppendDataToFile (FILE *outputFile, unsigned char *buffer, unsigned int bufferLen) { int status = 0; if (fwrite (buffer, 1, bufferLen, outputFile) < bufferLen) status = RSA_DEMO_E_FILE_IO; return status; } /* end RSA_AppendDataToFile */ int RSA_SetOptions (FILE_LOG_PARAMS *logParams, int argc, char **argv) { unsigned int c, status = 0; /* initialize input, output and error file pointer */ INPUT_FILE = stdin; OUTPUT_FILE = stdout; ERROR_FILE = stderr; /* discard the name of the procedure being called */ --argc; ++argv; /* Process command-line arguments */ while (argc > 0) { /* all arguments must begin with a '-' */ if (argv[0][0] != '-') { status = RSA_DEMO_E_COMMAND_LINE_ARG; break; } /* get the first character following a '-' */ c = *++argv[0]; /* argv[0] is now a string without the '-' */ if (T_strlen(argv[0]) == 1) /* case where exactly one character follows a '-' */ switch (c) { case 'f': /* specify a file containing program inputs */ --argc; ++argv; if (argv[0] != NULL) { INPUT_FILE_NAME = argv[0]; INPUT_FILE = fopen (INPUT_FILE_NAME, "r"); if (INPUT_FILE == NULL) { RSA_PrintMessage ("Could not open %s.\n", INPUT_FILE_NAME); INPUT_FILE = stdin; INPUT_FILE_NAME = NULL; } } else { RSA_PrintError ("input file name needed: usage [-f inputfile]\n", 0); status = RSA_DEMO_E_COMMAND_LINE_ARG; break; } --argc; ++argv; break; case 'o': /* specify a file to place output text */ --argc; ++argv; OUTPUT_FILE_NAME = argv[0]; if ((ERROR_FILE_NAME == (char *)0) || (T_strcmp (OUTPUT_FILE_NAME, ERROR_FILE_NAME) != 0)) { OUTPUT_FILE = fopen (OUTPUT_FILE_NAME, "w"); if (OUTPUT_FILE == NULL) { RSA_PrintMessage ("Could not open %s.\n", OUTPUT_FILE_NAME); OUTPUT_FILE = stdout; OUTPUT_FILE_NAME = NULL; } } else OUTPUT_FILE = ERROR_FILE; --argc; ++argv; break; case 'e': /* specify a file to place error messages */ --argc; ++argv; ERROR_FILE_NAME = argv[0]; if ((OUTPUT_FILE_NAME == (char *)0) || (T_strcmp (OUTPUT_FILE_NAME, ERROR_FILE_NAME) != 0)) { ERROR_FILE = fopen (ERROR_FILE_NAME, "w"); if (ERROR_FILE == NULL) { RSA_PrintMessage ("Could not open %s.\n", ERROR_FILE_NAME); ERROR_FILE = stderr; ERROR_FILE_NAME = NULL; } } else ERROR_FILE = OUTPUT_FILE; --argc; ++argv; break; case 'l': /* specify a file to output log activity */ --argc; ++argv; LOG_FILE_NAME = argv[0]; --argc; ++argv; break; case 's': /* specify a file containing logging format strings */ --argc; ++argv; FORMAT_STRINGS_FILE_NAME = argv[0]; --argc; ++argv; break; default: status = RSA_DEMO_E_COMMAND_LINE_ARG; fprintf (stderr, "unrecognized option: %s\n", argv[0]); } else { status = RSA_DEMO_E_COMMAND_LINE_ARG; fprintf (stderr, "illegal option: %s\n", argv[0]); } /* If we get an apparently invalid argument */ if (status) { RSA_PrintError ("Usage: [-l logfile] [-s formatfile] [-o outputfile]\ [-e errorfile]\ \n [-l logfile] log activity in logfile, default is stderr\ \n [-s formatfile] file containing logging format strings\ \n [-o outputfile] send output to outputfile, default stdout\ \n [-e errorfile] send error output to errorfile, default stderr\ \n Options -l and -s are used to set up Cert-C file logging.", 0); return status; } } /* end of while loop for retrieving command-line args */ if ((INPUT_FILE_NAME != (char *)0) && (OUTPUT_FILE_NAME != (char *)0)) if (!T_strcmp (OUTPUT_FILE_NAME, INPUT_FILE_NAME)) { RSA_PrintError ("ERROR: output file name cannot match input file name", 0); return RSA_DEMO_E_COMMAND_LINE_ARG; } if ((INPUT_FILE_NAME != (char *)0) && (ERROR_FILE_NAME != (char *)0)) if (!T_strcmp (ERROR_FILE_NAME, INPUT_FILE_NAME)) { RSA_PrintError ("ERROR: error file name cannot match input file name", 0); return RSA_DEMO_E_COMMAND_LINE_ARG; } if ((INPUT_FILE == NULL) || (OUTPUT_FILE == NULL) || (ERROR_FILE == NULL)) return RSA_DEMO_E_FILE_IO; /* Attempt to initialize a status log provider if ctx is not NULL. If * initialization is unsuccessful, just continue. */ if (logParams != NULL) { logParams->logName = LOG_FILE_NAME; logParams->formatName = FORMAT_STRINGS_FILE_NAME; } return status; } /* end RSA_SetOptions */