RSA BSAFE Cert-C

Certificate Components for C

Crypto-C 6.2.1 Developer's Guide
Search

certutil.c

Prints information contained in a Cert object. Gathers user input to place into a Cert object.

/* $Id: certutil.c,v 1.3 2004/03/02 05:18:37 gsingh Exp $ */
/* certutil.c
** Copyright (c) 1999-2002, 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.
**
** This file contains routines that are used to print the information
** contained in a cert object in a readable manner, as well as routines used
** to gather user input to place into a cert object.
*/

#include "certutil.h"

int RSA_SaveCertObjToFile (CERT_OBJ certObj)
{
  int status = 0;
  ITEM certBer = {NULL, 0};

  status = C_GetCertDER (certObj, &certBer.data, &certBer.len);
  if (status != 0)
    goto CLEANUP;

  status = RSA_WriteDataToFile (certBer.data, certBer.len,
                                "Enter name of file to store cert binary");

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

  return status;
}  /* end RSA_SaveCertObjToFile */

int RSA_SaveCertListToFiles (LIST_OBJ certList)
{
  int status = 0;
  unsigned int count, i;
  POINTER entry = NULL;

  status = C_GetListObjectCount (certList, &count);
  if (status != 0)
    goto CLEANUP;

  for (i = 0; i < count; i++) {
    status = C_GetListObjectEntry (certList, i, (POINTER *)&entry);
    if (status != 0)
      goto CLEANUP;

    status = RSA_PrintCertInfo ((CERT_OBJ)entry);
    if (status != 0)
      goto CLEANUP;

    status = RSA_SaveCertObjToFile ((CERT_OBJ)entry);
    if (status == RSA_DEMO_E_CANCEL)
      status = 0;  /* saving to file is optional */
    else if (status != 0)
      goto CLEANUP;
  }

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

  return status;
}

int RSA_PrintCertObject (CERT_OBJ certObj)
{
  int status = 0;
  
  CERT_FIELDS certFields;
  B_KEY_OBJ publicKey = NULL;

  A_RSA_KEY *rsaPublicInfo = NULL;
  A_DSA_PUBLIC_KEY *dsaPublicInfo = NULL;

  ITEM keyData = {0};
  unsigned int keyBits = 0;

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

  switch (certFields.version) {
    case CERT_VERSION_1:
      RSA_PrintMessage ("Version 1 certificate\n");
      break;
    case CERT_VERSION_2:
      RSA_PrintMessage ("Version 2 certificate\n");
      break;
    case CERT_VERSION_3:
      RSA_PrintMessage ("Version 3 certificate\n");
      break;
    default:
      RSA_PrintMessage ("Unknown version: %u\n", certFields.version);
  }

  RSA_PrintBuf ("Serial Number", certFields.serialNumber.data,
                certFields.serialNumber.len);

  RSA_PrintSignatureAlgorithm (certFields.signatureAlgorithm);
  RSA_PrintNameObject ("Issuer Name", certFields.issuerName);
  RSA_PrintUint4Time ("Validity Start", certFields.validity.start);
  RSA_PrintUint4Time ("Validity End", certFields.validity.end);
  RSA_PrintNameObject ("Subject Name", certFields.subjectName);

  RSA_PrintMessage ("********************\n");

  /* Print out the key size in bits */
  status = B_CreateKeyObject (&publicKey);
  if (status != 0)
    goto CLEANUP;

  status = RSA_SetKeyBer (RSA_DEMO_PUBLIC_KEY, publicKey,
                          certFields.publicKey);
  if (status != 0)
    goto CLEANUP;

  /* check if it's an RSA public key */
  status = B_GetKeyInfo ((POINTER *)&rsaPublicInfo, publicKey, KI_RSAPublic);
  if (status == 0) {
    RSA_PrintMessage ("RSA");
    keyData.data = rsaPublicInfo->modulus.data;
    keyData.len = rsaPublicInfo->modulus.len;
  } else {
    /* check if it's a DSA public key */
    status = B_GetKeyInfo ((POINTER *)&dsaPublicInfo, publicKey,
                           KI_DSAPublic);
    if (status == 0) {
      RSA_PrintMessage ("DSA");
      keyData.data = dsaPublicInfo->params.prime.data;
      keyData.len = dsaPublicInfo->params.prime.len;
    } else {
      /* unrecognized key */
      RSA_PrintMessage ("Unrecognized Key Data!\n");
      status = RSA_DEMO_E_NOT_IMPLEMENTED;
      goto CLEANUP;
    }
  }

  keyBits = B_IntegerBits (keyData.data, keyData.len);

  RSA_PrintMessage (" Public Key - %u bits\n", keyBits);

  RSA_PrintBuf ("Public Key BER", certFields.publicKey.data,
                certFields.publicKey.len);

  if (certFields.version != CERT_VERSION_1) {
    RSA_PrintBitString ("Issuer Unique ID", certFields.issuerUniqueID);
    RSA_PrintBitString ("Subject Unique ID", certFields.subjectUniqueID);
  }

  RSA_PrintExtensionsObject (certFields.certExtensions);

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

  B_DestroyKeyObject (&publicKey);

  return status;
}  /* end RSA_PrintCertObject */

int RSA_PrintCertInfo (CERT_OBJ certObj)
{
  int status = 0;
  CERT_FIELDS certFields;
  char *nameString = NULL;

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

  status = C_GetNameString (certFields.subjectName, &nameString);
  if (status != 0)
    goto CLEANUP;

  RSA_PrintMessage ("Subject: %s\n", nameString);

  status = C_GetNameString (certFields.issuerName, &nameString);
  if (status != 0)
    goto CLEANUP;

  RSA_PrintMessage ("Issuer: %s\n", nameString);

  RSA_PrintBuf ("Serial Number", certFields.serialNumber.data,
                certFields.serialNumber.len);

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

  return status;
}  /* end RSA_PrintCertInfo */

int RSA_AddCertsToDbPrompt (CERTC_CTX ctx, SERVICE database)
{
  int status = 0;
  ITEM certBer = {NULL, 0};
  CERT_OBJ certObj = NULL;

  for (;;) {
    status = RSA_GetFileToAllocBuffer
             (&certBer.data, &certBer.len,
              "Enter name of cert binary file (blank when finished)");
    if (status == RSA_DEMO_E_CANCEL) {
      status = 0;
      break;
    }
    else if (status != 0)
      goto CLEANUP;

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

    status = C_SetCertBER (certObj, certBer.data, certBer.len);
    if (status != 0)
      goto CLEANUP;

    /* Note that another option is to use C_InsertCertList, perhaps in
     * conjunction with RSA_AddCertsToListPrompt.
     */
    status = C_InsertCert (database, certObj);
    if (status != 0)
      goto CLEANUP;

    T_free (certBer.data);
    certBer.data = NULL;
    C_DestroyCertObject (&certObj);
  }
  
CLEANUP:
  if (status != 0)
    RSA_PrintError ("RSA_AddCertsToDbPrompt", status);
  
  C_DestroyCertObject (&certObj);

  return status;
}  /* end RSA_AddCertsToDbPrompt */

int RSA_AddCertsToListPrompt (CERTC_CTX ctx, LIST_OBJ certList)
{
  int status = 0;
  ITEM certBer = {NULL, 0};
  CERT_OBJ certObj = NULL;

  for (;;) {
    status = RSA_GetFileToAllocBuffer
             (&certBer.data, &certBer.len,
              "Enter name of cert binary file (blank when finished)");
    if (status == RSA_DEMO_E_CANCEL) {
      status = 0;
      break;
    }
    else if (status != 0)
      goto CLEANUP;

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

    status = C_SetCertBER (certObj, certBer.data, certBer.len);
    if (status != 0)
      goto CLEANUP;

    /*  C_AddUniqueCertToList is another option...  */
    status = C_AddCertToList (certList, certObj, NULL);
    if (status != 0)
      goto CLEANUP;

    T_free (certBer.data);
    certBer.data = NULL;
    C_DestroyCertObject (&certObj);
  }

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

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

int RSA_PrintCertList (LIST_OBJ certs)
{
  int status = 0;
  unsigned int numEntries = 0, i = 0;
  POINTER entry = NULL;

  status = C_GetListObjectCount (certs, &numEntries);
  if (status != 0)
    goto CLEANUP;

  if (numEntries == 0)
    RSA_PrintMessage ("No entries.\n");
  
  for (i = 0; i < numEntries; i++) {
    status = C_GetListObjectEntry (certs, i, &entry);
    if (status != 0)
      goto CLEANUP;

    RSA_PrintMessage ("***Cert #%d:\n", i+1);
    status = RSA_PrintCertInfo ((CERT_OBJ)entry);
    if (status != 0)
      goto CLEANUP;
  }

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

  return status;
}  /* end RSA_PrintCertList */

int RSA_GetInputToCertObject (CERTC_CTX ctx, CERT_OBJ certObj,
                              B_KEY_OBJ savedPrivate)
{
  int status = 0;
  CERT_FIELDS certFields;
  ALGORITHM_IDENTIFIER signatureAlg;
  B_KEY_OBJ publicKey = NULL, privateKey = NULL;
  ITEM privateKeyBer = {NULL, 0};

  T_memset ((POINTER)&certFields, 0, sizeof (certFields));

  status = RSA_ChooseCertVersionPrompt (&certFields.version);
  if (status != 0)
    goto CLEANUP;

  status = RSA_GetItem (&certFields.serialNumber,
                        "Enter hex-ascii serial number (blank to quit)");
  if (status != 0)
    goto CLEANUP;

  status = RSA_ChooseSignatureAlgorithmPrompt (&signatureAlg);
  if (status != 0)
    goto CLEANUP;

  certFields.signatureAlgorithm = signatureAlg.algorithmId;

  status = C_CreateNameObject (&certFields.issuerName);
  if (status != 0)
    goto CLEANUP;

  status = RSA_GetNameObject (certFields.issuerName, "issuer");
  if (status != 0)
    goto CLEANUP;

  status = RSA_GetInputToUint4Time (&certFields.validity.start,
                                    "Enter validity start");
  if (status != 0)
    goto CLEANUP;

  status = RSA_GetInputToUint4Time (&certFields.validity.end,
                                    "Enter validity end");
  if (status != 0)
    goto CLEANUP;

  status = C_CreateNameObject (&certFields.subjectName);
  if (status != 0)
    goto CLEANUP;
  
  status = RSA_GetNameObject (certFields.subjectName, "subject");
  if (status != 0)
    goto CLEANUP;

  /* This code makes the assumption that if you generate a keypair, you will
   * want to sign the certificate with the private key you just generated.
   * If desired, this code can be modified to always ask for the signing key.
   * To do that, just use another B_KEY_OBJ and put the RSA_GetKeyObjFromFile
   * with RSA_DEMO_PRIVATE_KEY and the new key object outside the "else".
   */
  status = RSA_GetFileToAllocBuffer
           (&certFields.publicKey.data, &certFields.publicKey.len,
            "Enter name of file containing public key BER (blank to create)");
  if (status == RSA_DEMO_E_CANCEL) {
    status = RSA_GenerateKeypair (ctx, &publicKey, &privateKey);
    if (status != 0)
      goto CLEANUP;

    status = RSA_GetKeyBer (RSA_DEMO_PUBLIC_KEY, publicKey,
                            &certFields.publicKey);
    if (status != 0)
      goto CLEANUP;
  }
  else if (status != 0)
    goto CLEANUP;
  else {
    RSA_PrintMessage ("We need a private key to sign the certificate.\n");
    status = RSA_GetKeyObjFromFile (RSA_DEMO_PRIVATE_KEY, &privateKey);
    if (status != 0)
      goto CLEANUP;
  }

  if (certFields.version == CERT_VERSION_1) {
    certFields.issuerUniqueID.data = NULL_PTR;
    certFields.issuerUniqueID.len = 0;
    certFields.issuerUniqueID.unusedBits = 0;
    certFields.subjectUniqueID.data = NULL_PTR;
    certFields.subjectUniqueID.len = 0;
    certFields.subjectUniqueID.unusedBits = 0;
  }
  else {
    status = RSA_GetBitString
             (&certFields.issuerUniqueID,
              "Enter optional unique ID of cert issuer (blank to omit)");
    if (status != 0 && status != RSA_DEMO_E_CANCEL)
      goto CLEANUP;

    status = RSA_GetBitString
             (&certFields.subjectUniqueID,
              "Enter optional unique ID of cert subject (blank to omit)");
    if (status != 0 && status != RSA_DEMO_E_CANCEL)
      goto CLEANUP;
  }

  status = C_CreateExtensionsObject (&certFields.certExtensions,
                                     CERT_EXTENSIONS_OBJ, ctx);
  if (status != 0)
    goto CLEANUP;

  if (certFields.version == CERT_VERSION_3) {
    status = RSA_GetExtensionsObject (certFields.certExtensions,
                                      CERT_EXTENSIONS_OBJ);
    if (status != 0)
      goto CLEANUP;
  }

  certFields.reserved = NULL_PTR;

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

  status = C_SignCert (certObj, privateKey);
  if (status != 0)
    goto CLEANUP;

  /* check if the caller wants the private key */
  if (savedPrivate != NULL) {
    status = RSA_GetKeyBer (RSA_DEMO_PRIVATE_KEY, privateKey,
                            &privateKeyBer);
    if (status != 0)
      goto CLEANUP;

    status = RSA_SetKeyBer (RSA_DEMO_PRIVATE_KEY, savedPrivate,
                            privateKeyBer);
  }
  
CLEANUP:
  if (status != 0)
    RSA_PrintError ("RSA_GetInputToCertObject", status);

  C_DestroyNameObject (&certFields.issuerName);
  C_DestroyNameObject (&certFields.subjectName);
  B_DestroyKeyObject (&publicKey);
  B_DestroyKeyObject (&privateKey);
  C_DestroyExtensionsObject (&certFields.certExtensions);
  T_free (certFields.serialNumber.data);
  T_free (certFields.publicKey.data);
  T_free (certFields.issuerUniqueID.data);
  T_free (certFields.subjectUniqueID.data);
  
  return status;
}  /* end RSA_GetInputToCertObject */

int RSA_GetCertObject (CERTC_CTX ctx, CERT_OBJ certObj,
                       B_KEY_OBJ savedPrivate)
{
  int status = 0;
  unsigned char *certBer = NULL_PTR;
  unsigned int certBerLen = 0;

  RSA_PrintMessage ("Enter name of file containing cert object binary\n");
  
  status = RSA_GetFileToAllocBuffer (&certBer, &certBerLen,
                                     "(blank to create a new one)");
  if (status == RSA_DEMO_E_CANCEL) {
    status = RSA_GetInputToCertObject (ctx, certObj, savedPrivate);
    /* whatever happens, we're done here */
    goto CLEANUP;
  }
  if (status != 0)
    goto CLEANUP;

  status = C_SetCertBER (certObj, certBer, certBerLen);
  if (status != 0)
    goto CLEANUP;
  
CLEANUP:
  if (status != 0)
    RSA_PrintError ("RSA_GetCertObject", status);

  T_free (certBer);
  
  return status;
}  /* end RSA_GetCertObject */

int RSA_GetCertAndPvtKey (CERTC_CTX ctx, CERT_OBJ certObj, B_KEY_OBJ pvtKey)
{
  int status = 0;
  ITEM certBer = {NULL, 0}, pvtKeyBer = {NULL, 0};

  /*  If the user gives a cert, the user must also give the private key.
   *  Otherwise generate a cert and get the private key that was used to
   *  generate the cert.  We could be making a bad assumption here, that
   *  the private key that signed the cert is the one to be associated with
   *  the cert -- for example, chaining? -- this can be modified to ignore
   *  the signing key and always ask the user for a private key.
   */
  RSA_PrintMessage ("Enter name of file containing cert object binary\n");
  status = RSA_GetFileToAllocBuffer (&certBer.data, &certBer.len,
                                     "(blank to generate a new one)");
  if (status == RSA_DEMO_E_CANCEL)  /* if user enters a blank */
    status = RSA_GetInputToCertObject (ctx, certObj, pvtKey);
  else if (status == 0) {
    RSA_PrintMessage ("Enter name of file containing corresponding private");
    status = RSA_GetFileToAllocBuffer (&pvtKeyBer.data, &pvtKeyBer.len,
                                       " key\n(blank to cancel)");
  }
  if (status != 0)
    goto CLEANUP;

  if (certBer.len > 0) {
    status = C_SetCertBER (certObj, certBer.data, certBer.len);
    if (status != 0)
      goto CLEANUP;
  }

  if (pvtKeyBer.len > 0) {
    status = RSA_SetKeyBer (RSA_DEMO_PRIVATE_KEY, pvtKey, pvtKeyBer);
    if (status != 0)
      goto CLEANUP;
  }
  
CLEANUP:
  if (status != 0)
    RSA_PrintError ("RSA_GetCertAndPvtKey", status);

  T_free (certBer.data);
  T_free (pvtKeyBer.data);
  
  return status;
}  /* end RSA_GetCertAndPvtKey */

int RSA_PrintCertId (CERT_IDENTIFIER certId)
{
  int status = 0;
  char *nameString = NULL;

  switch (certId.type) {
    case ISSUER_SERIAL:
      status = C_GetNameStringReverse (certId.id.issuerSerialNumber.issuerName,
                                       &nameString);
      if (status != 0)
        goto CLEANUP;

      RSA_PrintMessage ("Issuer = %s\n", nameString);
      RSA_PrintBuf ("Serial Number",
                    certId.id.issuerSerialNumber.serialNumber.data,
                    certId.id.issuerSerialNumber.serialNumber.len);
      break;
    default:
      status = RSA_DEMO_E_INVALID_PARAMETER;
  }
  
CLEANUP:
  if (status != 0)
    RSA_PrintError ("RSA_PrintCertId", status);
  
  return status;
}  /* end PrintCertId */

int RSA_ChooseCertVersionPrompt (UINT2 *version)
{
  int status = 0;

  RSA_DEMO_TABLE_ENTRY verTable[3];
  RSA_DEMO_TABLE_ENTRY *choice = (RSA_DEMO_TABLE_ENTRY *)NULL_PTR;

  verTable[0].description = "Version 1";
  verTable[0].val.value = CERT_VERSION_1;
  verTable[1].description = "Version 2";
  verTable[1].val.value = CERT_VERSION_2;
  verTable[2].description = "Version 3";
  verTable[2].val.value = CERT_VERSION_3;

  status = ChooseTableEntryPrompt
           (verTable, sizeof (verTable) / sizeof (RSA_DEMO_TABLE_ENTRY),
            &choice);
  if (status != 0)
    goto CLEANUP;

  *version = (UINT2)choice->val.value;

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

  return status;
}  /* end RSA_ChooseCertVersionPrompt */


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