RSA BSAFE Cert-C

Certificate Components for C

Crypto-C 6.2.1 Developer's Guide
Search

cert.c

Displays a certificate object from a file. Extracts objects from a certificate. Generates a certificate object. Verifies certificate signature.

/* $Id: cert.c,v 1.5 2004/03/02 05:18:35 gsingh Exp $ */
/* cert.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.
**
** Demonstrate how to parse certificates or generate certificates.
**
** When compiling, define the macro RSA_REQUIRE_FILE_LOG (-D compile
** option, or equivelent) to force the program to return an error code
** if file logging cannot be initialized.  For example, if the file
** containing the log message format strings cannot be located (certc.msg
** or equivalent).
*/

#include "demoutil.h"
#include "certutil.h"
#include "filelog.h"
#include "rsacsp.h"

/*  The number of service providers used in this example.  Here, we must
 *  register a crypto service provider.
 */
#define SP_COUNT 1

/*  DisplayCertObj reads in the BER encoding of a certificate from a file
 *  and then prints out the information in this certificate.  A properly
 *  initialized CERTC_CTX must be passed in.
 */
static int DisplayCertObj (CERTC_CTX ctx);

/*  GenerateCertObj obtains information from the user and creates a 
 *  certificate object.  It then stores the BER encoding of the 
 *  certificate in a file specified by the user.  A properly initialized
 *  CERTC_CTX must be passed in.
 */
static int GenerateCertObj (CERTC_CTX ctx);

/*  VerifyCertSignature reads in the BER encoding of a certificate 
 *  from a file and verifies that certificate's signature, given a public key.
 *  It then prints out a message stating whether or not the certificate was
 *  verified.  A properly initialized CERTC_CTX must be passed in.  To do path
 *  validation for certificate validity checking, see the
 *  samples/validate/chain.c or samples/validate/validate.c sample for the use
 *  of C_BuildCertPath.
 */
static int VerifyCertSignature (CERTC_CTX ctx);

/*  ExtractObjsFromCert reads in the BER encoding of a certificate
 *  from a file.  It then extracts the fields in the cert, prints
 *  them out, and optionally saves them to a file.  A properly 
 *  initialized CERTC_CTX must be passed in.
 */
static int ExtractObjsFromCert (CERTC_CTX ctx);

int main (int argc, char *argv[])
{
  int status = 0;
  char command[RSA_DEMO_MAX_LINE_LEN];

  CERTC_CTX ctx = NULL;
  SERVICE_HANDLER spTable[SP_COUNT];
  POINTER spParams[SP_COUNT];

  FILE_LOG_PARAMS logParams = {NULL, NULL};
  SERVICE_HANDLER logHandler = {
    SPT_LOG, "Default File Log", S_InitializeFileLog
  };

  /* Since we are going to be performing operations using Crypto-C, we need
     to register an instance of the crypto provider. */
  spTable[0].type = SPT_CRYPTO;
  spTable[0].name = "BSAFE Crypto-C";
  spTable[0].Initialize = S_InitializeDefaultCSP;

  spParams[0] = NULL;

  status = RSA_SetOptions (&logParams, argc, argv);
  if (status != 0)
    goto CLEANUP;

  status = C_InitializeCertC (spTable, spParams, SP_COUNT, &ctx);
  if (status != 0)
    goto CLEANUP;

  /* Attempt to initialize file logging, but unless RSA_REQUIRE_FILE_LOG is
   * defined, treat it as a non-fatal condition.
   */
  status = C_RegisterService (ctx, &logHandler, (POINTER)&logParams,
                              SERVICE_ORDER_FIRST);
#ifdef RSA_REQUIRE_FILE_LOG
  if (status != 0)
    goto CLEANUP;
#endif
  
  RSA_PrintMessage ("Cert Object Demonstration\n");
  RSA_PrintMessage ("=========================\n");

  for (;;) {
    RSA_PrintMessage ("\nCert Object Operations\n");
    RSA_PrintMessage ("  A - Display certificate object from a file\n");
    RSA_PrintMessage ("  B - Generate certificate object\n");
    RSA_PrintMessage ("  C - Verify certificate signature\n");    
    RSA_PrintMessage ("  D - Extract objects from certificate\n");
    status = RSA_GetCommand (command, sizeof (command),
                             "Enter choice (blank to quit)");
    if (status != 0)
      goto CLEANUP;

    switch (command[0]) {
      case 'a':
      case 'A':
        status = DisplayCertObj (ctx);
        break;
      case 'b':
      case 'B':
        status = GenerateCertObj (ctx);
        break;
      case 'c':
      case 'C':
        status = VerifyCertSignature (ctx);
        break;
      case 'd':
      case 'D':
        status = ExtractObjsFromCert (ctx);
        break;
      case '\0':
      case 'q':
      case 'Q':
        goto CLEANUP;
      default:
        RSA_PrintMessage ("Unrecognized Option: %c\n", command[0]);
        status = RSA_DEMO_E_INVALID_PARAMETER;
    }

    if (status != 0)
      RSA_PrintMessage ("Operation not completed.\n");
    else
      RSA_PrintMessage ("Operation successful!\n");
  }
    
CLEANUP:
  if (status != 0)
    RSA_PrintError ("cert.c", status);

  C_FinalizeCertC (&ctx);

  return status;
}  /* end main */

/* See function declaration at the top for a description */
static int DisplayCertObj (CERTC_CTX ctx)
{
  int status = 0;
  
  unsigned char *certBer = NULL;
  unsigned int certBerLen = 0;
  
  CERT_OBJ certObj = NULL;
  ITEM output;

  status = RSA_GetFileToAllocBuffer (&certBer, &certBerLen,
                                     "Enter name of cert object binary");
  if (status != 0)
    goto CLEANUP;

  status = C_CreateCertObject (&certObj, ctx);
  if (status != 0)
    goto CLEANUP;

  status = C_SetCertBER (certObj, certBer, certBerLen);
  if (status != 0)
    goto CLEANUP;

  RSA_PrintMessage ("\nCert Object Contents\n");

  /* RSA_PrintCertObject is described in samples/common/include/certutil.h */
  status = RSA_PrintCertObject (certObj);
  if (status != 0)
    goto CLEANUP;

  /* Check the cert for any inconsistencies.  Cert-C is lenient in allowing
     certs with abnormalities to be imported using C_SetCertBER, but will not
     allow the export of certs with incorrect encodings to be exported using
     C_GetCertDER. */
  status = C_GetCertDER (certObj, &output.data, &output.len);
  if (status != 0) {
    RSA_PrintMessage ("Please examine the certificate binary ");
    RSA_PrintMessage ("for problems with the encoding.\n");
    RSA_PrintMessage ("C_SetCertBER passed but C_GetCertDER fails.\n");
    goto CLEANUP;
  }

CLEANUP:
  if (status != 0)
    RSA_PrintError ("DisplayCertObj", status);

  C_DestroyCertObject (&certObj);
  T_free (certBer);

  return status;
}  /* end DisplayCertObj */

/* See function declaration at the top for a description */
static int GenerateCertObj (CERTC_CTX ctx)
{
  int status = 0;

  CERT_OBJ certObj = (CERT_OBJ)NULL_PTR;

  unsigned char *certBer = NULL_PTR;
  unsigned int certBerLen = 0;

  status = C_CreateCertObject (&certObj, ctx);
  if (status != 0)
    goto CLEANUP;

  /* RSA_GetInputToCertObject is described in
     samples/common/include/certutil.h. */
  status = RSA_GetInputToCertObject (ctx, certObj, NULL);
  if (status != 0)
    goto CLEANUP;

  status = C_GetCertDER (certObj, &certBer, &certBerLen);
  if (status != 0)
    goto CLEANUP;

  status = RSA_WriteDataToFile
           (certBer, certBerLen,
            "Enter file name to store cert object binary");
  if (status != 0)
    goto CLEANUP;
  
CLEANUP:
  if (status != 0)
    RSA_PrintError ("GenerateCertObj", status);

  C_DestroyCertObject (&certObj);
  
  return status;
}  /* end GenerateCertObj */

/* See function declaration at the top for a description */
static int VerifyCertSignature (CERTC_CTX ctx)
{
  int status = 0;
  
  unsigned char *certBer = NULL_PTR;
  unsigned int certBerLen = 0;

  B_KEY_OBJ publicKey = (B_KEY_OBJ)NULL_PTR;
  CERT_OBJ certObj = (CERT_OBJ)NULL_PTR;

  status = RSA_GetFileToAllocBuffer (&certBer, &certBerLen,
                                     "Enter name of cert object binary");
  if (status != 0)
    goto CLEANUP;

  status = C_CreateCertObject (&certObj, ctx);
  if (status != 0)
    goto CLEANUP;

  status = C_SetCertBER (certObj, certBer, certBerLen);
  if (status != 0)
    goto CLEANUP;
  
  RSA_PrintMessage ("Supply public key to verify signature, or enter blank\n");
  RSA_PrintMessage ("to use the key contained in the cert.\n");

  /* RSA_GetKeyObjFromFile and RSA_GetPubKeyFromCert are described
     in samples/common/include/keyutil.h */
  status = RSA_GetKeyObjFromFile (RSA_DEMO_PUBLIC_KEY, &publicKey);
  if (status == RSA_DEMO_E_CANCEL) {
    status = RSA_GetPubKeyFromCert (certObj, &publicKey);
  }

  if (status != 0)
    goto CLEANUP;

  /* Note that this procedure only verifies the certificate signature given
   * the appropriate public key.  Should more sophisticated checking be
   * required (for example, verifying a chain of certs or checking the validity
   * period), see the APIs for Certification Path Processing 
   * (namely C_BuildCertPath).
   */
  status = C_VerifyCertSignature (certObj, publicKey);
  if (status != 0)
    goto CLEANUP;

  RSA_PrintMessage ("Signature verified!\n");
  
CLEANUP:
  if (status != 0)
    RSA_PrintError ("VerifyCertSignature", status);

  B_DestroyKeyObject (&publicKey);
  C_DestroyCertObject (&certObj);
  T_free (certBer);

  return status;
}  /* end VerifyCertSignature */

/* See function declaration at the top for a description */
static int ExtractObjsFromCert (CERTC_CTX ctx)
{
  int status = 0;
  
  unsigned char *certBer = NULL, *ber = NULL;
  unsigned int certBerLen, berLen = 0;

  B_KEY_OBJ publicKey = (B_KEY_OBJ)NULL_PTR;
  CERT_OBJ certObj = (CERT_OBJ)NULL_PTR;
  CERT_FIELDS certFields;

  char *nameStr = NULL;

  status = RSA_GetFileToAllocBuffer (&certBer, &certBerLen,
                                     "Enter name of cert object binary");
  if (status != 0)
    goto CLEANUP;

  status = C_CreateCertObject (&certObj, ctx);
  if (status != 0)
    goto CLEANUP;

  status = C_SetCertBER (certObj, certBer, certBerLen);
  if (status != 0)
    goto CLEANUP;

  status = C_GetCertFields (certObj, &certFields);
  if (status != 0)
    goto CLEANUP;

  status = C_GetNameStringReverse (certFields.issuerName, &nameStr);
  if (status != 0)
    goto CLEANUP;

  RSA_PrintMessage ("\nIssuer Name:  %s\n", nameStr);

  status = C_GetNameDER (certFields.issuerName, &ber, &berLen);
  if (status != 0)
    goto CLEANUP;

  status = RSA_WriteDataToFile
           (ber, berLen, "Enter name of file to store issuer name binary");
  if (status == RSA_DEMO_E_CANCEL)
    status = 0; /* you don't have to save if you don't want to */
  else if (status != 0)
    goto CLEANUP;

  status = C_GetNameStringReverse (certFields.subjectName, &nameStr);
  if (status != 0)
    goto CLEANUP;

  RSA_PrintMessage ("\nSubject Name:  %s\n", nameStr);

  status = C_GetNameDER (certFields.subjectName, &ber, &berLen);
  if (status != 0)
    goto CLEANUP;

  status = RSA_WriteDataToFile
           (ber, berLen, "Enter name of file to store subject name binary");
  if (status == RSA_DEMO_E_CANCEL)
    status = 0; /* you don't have to save if you don't want to */
  else if (status != 0)
    goto CLEANUP;

  status = RSA_WriteDataToFile
           (certFields.publicKey.data, certFields.publicKey.len,
            "Enter name of file to store public key BER");
  if (status == RSA_DEMO_E_CANCEL)
    status = 0; /* you don't have to save if you don't want to */
  else if (status != 0)
    goto CLEANUP;

  if (certFields.version == CERT_VERSION_3) {
    status = C_GetExtensionsObjectDER (certFields.certExtensions, &ber,
                                       &berLen);
    if (status != 0)
      goto CLEANUP;

    status = RSA_WriteDataToFile
             (ber, berLen,
              "Enter name of file to store cert extensions binary");
    if (status == RSA_DEMO_E_CANCEL)
      status = 0; /* you don't have to save if you don't want to */
    else if (status != 0)
      goto CLEANUP;
  }

CLEANUP:
  if (status != 0)
    RSA_PrintError ("ExtractObjsFromCert", status);

  B_DestroyKeyObject (&publicKey);
  C_DestroyCertObject (&certObj);
  T_free (certBer);

  return status;
}  /* end ExtractObjsFromCert */

Copyright (c) 1999-2005 RSA Security Inc. All rights reserved. 067-001001-2720-001-000 - 2.7.2