RSA BSAFE Cert-C

Certificate Components for C

Crypto-C 6.2.1 Developer's Guide
Search

pkiutil.c

Procedures used by the PKI Transaction Service samples. Examples include examining transmission statuses, processing message responses, obtaining encoded certificates IDs, etc.

/* $Id: pkiutil.c,v 1.6 2004/03/02 05:18:38 gsingh Exp $ */
/* pkiutil.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.
**
** These procedures are used by the PKI Transaction Service samples.
*/

#include "certc.h"
#include "cmp.h"
#include "scep.h"
#include "scepdb.h"
#include "pkiutil.h"
#include "menuutil.h"
#include "nameutil.h"
#include "keyutil.h"
#include "certutil.h"
#include "crlutil.h"

#ifdef _MSC_VER
# pragma warning (disable: 171) /* invalid type conversion (often of very similar ptrs) */
# pragma warning (disable: 981) /* operands are evaluated in unspecified order */
#endif

static int ProcessCertRespMsg (CERTC_CTX ctx, PKI_MSG_OBJ pkiMsgRespObj,
                               PKI_MSG_OBJ pkiMsgReqObj,
                               unsigned int msgCount, int protocolFlag,
                               char *pkiProviderName, 
                               PKI_PROTECT_INFO *protectInfo, SERVICE db)
{
  int status = 0;
  char userInput[RSA_DEMO_MAX_LINE_LEN];
  unsigned int i, certReqStatus;

  PKI_CERT_RESP_OBJ certRespObj;
  PKI_STATUS_INFO_OBJ certRespStatusObj;
  
  PKI_MSG_OBJ pkiMsgConfReqObj = (PKI_MSG_OBJ)NULL_PTR;
  PKI_CERT_CONF_REQ_OBJ certConfReqObj = (PKI_CERT_CONF_REQ_OBJ)NULL_PTR;

  PKI_MSG_OBJ pkiMsgConfRespObj = (PKI_MSG_OBJ)NULL_PTR;

  LIST_OBJ caCerts;
  CERT_OBJ newCert;
  ITEM certDer, transId, nonce;

  PKI_SENDER_INFO reqSender;
  PKI_RECIPIENT_INFO reqRecipient;

  unsigned int protectionType;

  int confStatus;

  /* In the case of CMP, a confirmation response message is sent after
     examining the incoming request.  Set up the PKI_MSG_OBJ container
     for the confirmation response and add a PKI_CERT_CONF_REQ_OBJ to
     the PKI_MSG_OBJ for each message in the response. */
  if (protocolFlag == RSA_DEMO_CMP) {
    status = C_CreatePKIMsgObject (ctx, &pkiMsgConfReqObj);
    if (status != 0)
      goto CLEANUP;

    status = C_SetPKIMsgType (pkiMsgConfReqObj, PKI_MSGTYPE_CERT_CONF_REQ);
    if (status != 0)
      goto CLEANUP;

    /* Use the same protection type as the original request */
    status = C_GetPKIMsgProtectionType (pkiMsgReqObj, &protectionType);
    if (status != 0 && status != E_VALUE_NOT_SET)
      goto CLEANUP;

    if (status != E_VALUE_NOT_SET) {
      status = C_SetPKIMsgProtectionType (pkiMsgConfReqObj,
                                          protectionType);
      if (status != 0)
        goto CLEANUP;
    }

    /* The sender of the confirmation is the same as the sender of the
       original request. */
    status = C_GetPKIMsgSender (pkiMsgReqObj, &reqSender);
    if (status != 0 && status != E_VALUE_NOT_SET)
      goto CLEANUP;

    if (status != E_VALUE_NOT_SET) {
      status = C_SetPKIMsgSender (pkiMsgConfReqObj, &reqSender);
      if (status != 0)
        goto CLEANUP;
    }

    /* The recipient of the confirmation is the same as the recipient of
       the original request. */
    status = C_GetPKIMsgRecipient (pkiMsgReqObj, &reqRecipient);
    if (status != 0 && status != E_VALUE_NOT_SET)
      goto CLEANUP;

    if (status != E_VALUE_NOT_SET) {
      status = C_SetPKIMsgRecipient (pkiMsgConfReqObj, &reqRecipient);
      if (status != 0)
        goto CLEANUP;
    }

    /* The transaction ID of the confirmation must match that of the
       original request/response. (rfc2510bis-05, section 3.1.1) */
    status = C_GetPKIMsgTransID (pkiMsgRespObj, &transId);
    if (status != 0)
      goto CLEANUP;

    status = C_SetPKIMsgTransID (pkiMsgConfReqObj, &transId);
    if (status != 0)
      goto CLEANUP;

    /* Set the recipientNonce of the confirmation request with the
       senderNonce, set by the CA, of the related certificate response
       message. */
    status = C_GetPKIMsgSenderNonce (pkiMsgRespObj, &nonce);
    if (status != 0)
      goto CLEANUP;

    status = C_SetPKIMsgRecipientNonce (pkiMsgConfReqObj, &nonce);
    if (status != 0)
      goto CLEANUP;
  }  /* done setting up container for CMP confirmation message */

  for (i = 0; i < msgCount; i++) {
    RSA_PrintMessage ("Reading response #%u...\n", i+1);

    status = C_GetPKIMsg (pkiMsgRespObj, (POINTER *)&certRespObj, i);
    if (status != 0)
      goto CLEANUP;

    status = C_GetPKICertRespStatus (certRespObj, &certRespStatusObj);
    if (status != 0)
      goto CLEANUP;

    status = RSA_PrintPkiStatusInfoObj (certRespStatusObj);
    if (status != 0)
      goto CLEANUP;

    status = C_GetPKIStatus ((POINTER)certRespStatusObj, &certReqStatus);
    if (status != 0)
      goto CLEANUP;

    if (certReqStatus == PKI_STATUS_GRANTED ||
        certReqStatus == PKI_STATUS_GRANTED_MODS) {
      status = C_GetPKICertRespRequestedCert (certRespObj, &newCert);
      if (status != 0)
        goto CLEANUP;

      RSA_PrintMessage ("Examine the issued certificate:\n");
      status = RSA_PrintCertObject (newCert);
      if (status != 0)
        goto CLEANUP;

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

      status = RSA_WriteDataToFile (certDer.data, certDer.len,
                                    "Enter name of file to store cert binary");
      if (status == RSA_DEMO_E_CANCEL)
        status = 0;  /* saving the cert is optional */
      else if (status != 0)
        goto CLEANUP;

      /* Get trusted CA certs from the response */
      status = C_GetPKICertRespCACerts (certRespObj, &caCerts);
      if (status != 0 && status != E_VALUE_NOT_SET)
        goto CLEANUP;

      if (status == 0) {
        RSA_PrintMessage ("\nThese are the trusted certs returned in the ");
        RSA_PrintMessage ("response.\n");
        status = RSA_SaveCertListToFiles (caCerts);
        if (status != 0)
          goto CLEANUP;
      } else if (status == E_VALUE_NOT_SET)
        status = 0; /* not a fatal error */

      /* CMP requires user confirmation of issued cert */
      if (protocolFlag == RSA_DEMO_CMP) {
        /* Create the actual confirmation message to add to the PKI message */
        status = C_CreatePKICertConfReqObject (ctx, &certConfReqObj);
        if (status != 0)
          goto CLEANUP;

        status = RSA_GetCommand
                   (userInput, sizeof (userInput),
                    "\nIs the issued certificate acceptable (y/n)");
        if (status != 0)
          goto CLEANUP;

        if (userInput[0] == 'y' || userInput[0] == 'Y')
          confStatus = PKI_CERT_CONF_ACCEPT;
        else
          confStatus = PKI_CERT_CONF_REJECT;

        status = C_SetPKICertConfReqConfirmStatus (certConfReqObj, confStatus);
        if (status != 0)
          goto CLEANUP;

        status = C_SetPKICertConfReqCert (certConfReqObj, newCert);
        if (status != 0)
          goto CLEANUP;

        status = C_AddPKIMsg (pkiMsgConfReqObj, (POINTER)certConfReqObj,
                              (unsigned int *)NULL_PTR);
        if (status != 0)
          goto CLEANUP;
      }
    } else if (certReqStatus == PKI_STATUS_WAITING) {
      RSA_PrintMessage ("The request has not yet been processed by the CA.\n");

      /* maybe a real application would do something more graceful... */
      status = RSA_DEMO_E_ACTION_PENDING;
      goto CLEANUP;
    } else
      RSA_PrintMessage ("Certificate not returned.\n");

    C_DestroyPKICertConfReqObject (&certConfReqObj);
  }

  /* We have finished processing the response messages.  For CMP, that means
     that we have populated the pkiMsgConfReqObj with the necessary
     confirmation messages.  Now we send our PKI message. */
  if (protocolFlag == RSA_DEMO_CMP) {
    /* Send confirmation message and obtain response */
    status = C_CreatePKIMsgObject (ctx, &pkiMsgConfRespObj);
    if (status != 0)
      goto CLEANUP;

    status = C_RequestPKIMsg (ctx, pkiProviderName, pkiMsgConfReqObj,
                              protectInfo, db, pkiMsgConfRespObj);
    if (status != 0)
      goto CLEANUP;

    /* Process the confirmation response */
    status = RSA_ProcessPkiMsgResp (ctx, pkiMsgConfRespObj,
                                    pkiMsgConfReqObj, protocolFlag,
                                    pkiProviderName, protectInfo, db);
    if (status != 0)
      goto CLEANUP;
  }

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

  C_DestroyPKICertConfReqObject (&certConfReqObj);
  C_DestroyPKIMsgObject (&pkiMsgConfRespObj);
  C_DestroyPKIMsgObject (&pkiMsgConfReqObj);

  return status;
}  /* end ProcessCertRespMsg */

static int ProcessRevRespMsg (PKI_MSG_OBJ pkiMsgRespObj,
                              unsigned int msgCount)
{
  int status = 0;
  unsigned int i, revReqStatus;

  PKI_REVOKE_RESP_OBJ revRespObj;
  PKI_STATUS_INFO_OBJ revRespStatusObj;

  LIST_OBJ crlList;
  PKI_CERT_IDENTIFIER certId;

  for (i = 0; i < msgCount; i++) {
    RSA_PrintMessage ("Reading response #%u...\n", i+1);

    status = C_GetPKIMsg (pkiMsgRespObj, (POINTER *)&revRespObj, i);
    if (status != 0)
      goto CLEANUP;

    status = C_GetPKIRevokeRespStatus (revRespObj, &revRespStatusObj);
    if (status != 0)
      goto CLEANUP;

    status = RSA_PrintPkiStatusInfoObj (revRespStatusObj);
    if (status != 0)
      goto CLEANUP;

    status = C_GetPKIStatus ((POINTER)revRespStatusObj, &revReqStatus);
    if (status != 0)
      goto CLEANUP;

    if (revReqStatus == PKI_STATUS_GRANTED ||
        revReqStatus == PKI_STATUS_GRANTED_MODS) {
      RSA_PrintMessage ("Revocation Request Successful!\n");

      status = C_GetPKIRevokeRespCRLs (revRespObj, &crlList);
      if (status != 0 && status != E_VALUE_NOT_SET)
        goto CLEANUP;

      if (status == 0) {
        RSA_PrintMessage ("CRLs returned in revocation response:\n");
        status = RSA_PrintCrlList (crlList);
        if (status != 0)
          goto CLEANUP;
      } else
        status = 0;  /* E_VALUE_NOT_SET is not a fatal error */

      status = C_GetPKIRevokeRespCertID (revRespObj, &certId);
      if (status != 0 && status != E_VALUE_NOT_SET)
        goto CLEANUP;

      if (status == 0) {
        /* Print out the certId info */
      } else
        status = 0;  /* E_VALUE_NOT_SET is not a fatal error */
    }
  }

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

  return status; 
}  /* end ProcessRevRespMsg */

static int ProcessErrorMsg (PKI_MSG_OBJ pkiMsgRespObj, unsigned int msgCount)
{
  int status = 0;
  unsigned int i;

  PKI_ERROR_MSG_OBJ errorMsgObj;

  for (i = 0; i < msgCount; i++) {
    RSA_PrintMessage ("Reading error message #%u...\n", i+1);

    status = C_GetPKIMsg (pkiMsgRespObj, (POINTER *)&errorMsgObj, i);
    if (status != 0)
      goto CLEANUP;

    status = RSA_PrintPkiErrorMsgObj (errorMsgObj);
    if (status != 0)
      goto CLEANUP;
  }

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

  return status;
}  /* end ProcessErrorMsg */

int RSA_ProcessPkiMsgResp (CERTC_CTX ctx, PKI_MSG_OBJ pkiMsgRespObj,
                           PKI_MSG_OBJ pkiMsgReqObj,
                           int protocolFlag, char *pkiProviderName,
                           PKI_PROTECT_INFO *protectInfo, SERVICE db)
{
  int status;
  
  unsigned int msgType, msgCount;

  status = C_GetPKIMsgType (pkiMsgRespObj, &msgType);
  if (status != 0)
    goto CLEANUP;

  status = C_GetPKIMsgCount (pkiMsgRespObj, &msgCount);
  if (status != 0)
    goto CLEANUP;

  switch (msgType) {
    case PKI_MSGTYPE_CERT_RESP:
      RSA_PrintMessage ("\nProcessing Certificate Response Message...\n");
      status = ProcessCertRespMsg (ctx, pkiMsgRespObj, pkiMsgReqObj, msgCount,
                                   protocolFlag, pkiProviderName, protectInfo,
                                   db);
      break;
    case PKI_MSGTYPE_KEY_UPDATE_RESP:
      RSA_PrintMessage ("\nProcessing Key Update Response Message...\n");
      /* note that a PKI_KEY_UPDATE_RESP_OBJ is really just a
         PKI_CERT_RESP_OBJ */
      status = ProcessCertRespMsg (ctx, pkiMsgRespObj, pkiMsgReqObj, msgCount,
                                   protocolFlag, pkiProviderName, protectInfo,
                                   db);
      break;
    case PKI_MSGTYPE_CERT_CONF_RESP:
      RSA_PrintMessage ("\nSuccessful confirmation!\n");
      /* no additional processing necessary */
      break;
    case PKI_MSGTYPE_REVOKE_RESP:
      RSA_PrintMessage ("\nProcessing Revocation Response Message...\n");
      status = ProcessRevRespMsg (pkiMsgRespObj, msgCount);
      break;
    case PKI_MSGTYPE_ERROR_MSG:
      RSA_PrintMessage ("\nProcessing Error Message...\n");
      status = ProcessErrorMsg (pkiMsgRespObj, msgCount);
      break;
    default:
      RSA_PrintMessage ("\nUnrecognized Response Message Type (%u)...\n",
                        msgType);
  }

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

  return status;
}  /* end RSA_ProcessPkiMsgResp */

int RSA_CreateTransportInfoFieldsPrompt (TRANSPORT_INFO *transportInfo,
                                         char *defaultDestUrl)
{
  int status;
  char userInput[RSA_DEMO_MAX_LINE_LEN];

  ITEM destUrl = {0};

  T_memset ((POINTER)transportInfo, 0, sizeof (*transportInfo));

  status = C_CreateListObject (&transportInfo->destList);
  if (status != 0)
    goto CLEANUP;

  RSA_PrintMessage ("Enter server URL (default %s)\n", defaultDestUrl);
  status = RSA_GetCommand (userInput, sizeof (userInput), NULL);
  if (status != 0)
    goto CLEANUP;

  if (T_strlen (userInput) == 0) {
    RSA_PrintMessage ("Using default URL...\n");
    destUrl.data = (POINTER)defaultDestUrl;
    destUrl.len = T_strlen (defaultDestUrl);
  } else {
    destUrl.data = (POINTER)userInput;
    destUrl.len = T_strlen (userInput);
  }

  status = C_AddItemToList (transportInfo->destList, &destUrl, NULL);
  if (status != 0)
    goto CLEANUP;

CLEANUP:
  if (status != 0) {
    RSA_DestroyTransportInfoFields (transportInfo);
    RSA_PrintError ("RSA_CreateTransportInfoFieldsPrompt", status);
  }

  return status;
}  /* end RSA_CreateTransportInfoFieldsPrompt */

void RSA_DestroyTransportInfoFields (TRANSPORT_INFO *transportInfo)
{
  C_DestroyListObject (&transportInfo->destList);
  C_DestroyListObject (&transportInfo->proxyList);

  return;
}  /* end RSA_DestroyTransportInfoFields */

int RSA_ScepDbProfilePrompt (unsigned int *scepDbProfile)
{
  int status;

  RSA_DEMO_TABLE_ENTRY scepDbProfileTable[5] = {{0}};
  RSA_DEMO_TABLE_ENTRY *result = NULL;

  *scepDbProfile = 0;

  scepDbProfileTable[0].description = "DB_SCEP_PROFILE_GENERIC";
  scepDbProfileTable[0].val.value = DB_SCEP_PROFILE_GENERIC;
  scepDbProfileTable[1].description = "DB_SCEP_PROFILE_KEON";
  scepDbProfileTable[1].val.value = DB_SCEP_PROFILE_KEON;
  scepDbProfileTable[2].description = "DB_SCEP_PROFILE_VERISIGN";
  scepDbProfileTable[2].val.value = DB_SCEP_PROFILE_VERISIGN;
  scepDbProfileTable[3].description = "DB_SCEP_PROFILE_KCA6";
  scepDbProfileTable[3].val.value = DB_SCEP_PROFILE_KCA6;
  scepDbProfileTable[4].description = "DB_SCEP_PROFILE_MSCA";
  scepDbProfileTable[4].val.value = DB_SCEP_PROFILE_MSCA;

  RSA_PrintMessage ("SCEP DB Profiles\n");
  status = ChooseTableEntryPrompt
             (scepDbProfileTable,
              sizeof (scepDbProfileTable) / sizeof (scepDbProfileTable[0]),
              &result);
  if (status != 0)
    goto CLEANUP;

  *scepDbProfile = result->val.value;

CLEANUP:
  return status;
}  /* end RSA_ScepDbProfilePrompt */

int RSA_ScepProfilePrompt (unsigned int *scepProfile)
{
  int status;

  RSA_DEMO_TABLE_ENTRY scepProfileTable[5] = {{0}};
  RSA_DEMO_TABLE_ENTRY *result = NULL;

  *scepProfile = 0;

  scepProfileTable[0].description = "PKI_SCEP_PROFILE_GENERIC";
  scepProfileTable[0].val.value = PKI_SCEP_PROFILE_GENERIC;
  scepProfileTable[1].description = "PKI_SCEP_PROFILE_KEON";
  scepProfileTable[1].val.value = PKI_SCEP_PROFILE_KEON;
  scepProfileTable[2].description = "PKI_SCEP_PROFILE_VERISIGN";
  scepProfileTable[2].val.value = PKI_SCEP_PROFILE_VERISIGN;
  scepProfileTable[3].description = "PKI_SCEP_PROFILE_KCA6";
  scepProfileTable[3].val.value = PKI_SCEP_PROFILE_KCA6;
  scepProfileTable[4].description = "PKI_SCEP_PROFILE_MSCA";
  scepProfileTable[4].val.value = PKI_SCEP_PROFILE_MSCA;

  RSA_PrintMessage ("SCEP Profiles\n");
  status = ChooseTableEntryPrompt
             (scepProfileTable,
              sizeof (scepProfileTable) / sizeof (scepProfileTable[0]),
              &result);
  if (status != 0)
    goto CLEANUP;

  *scepProfile = result->val.value;

CLEANUP:
  return status;
}  /* end RSA_ScepProfilePrompt */

int RSA_CmpProfilePrompt (unsigned int *cmpProfile)
{
  int status;

  RSA_DEMO_TABLE_ENTRY cmpProfileTable[6] = {{0}};
  RSA_DEMO_TABLE_ENTRY *result = NULL;

  *cmpProfile = 0;

  cmpProfileTable[0].description = "PKI_CMP_PROFILE_CERTICOM";
  cmpProfileTable[0].val.value = PKI_CMP_PROFILE_CERTICOM;
  cmpProfileTable[1].description = "PKI_CMP_PROFILE_SSH";
  cmpProfileTable[1].val.value = PKI_CMP_PROFILE_SSH;
  cmpProfileTable[2].description = "PKI_CMP_PROFILE_KCA6";
  cmpProfileTable[2].val.value = PKI_CMP_PROFILE_KCA6;
  cmpProfileTable[3].description = "PKI_CMP_PROFILE_CERTICOM_V1";
  cmpProfileTable[3].val.value = PKI_CMP_PROFILE_CERTICOM_V1;
  cmpProfileTable[4].description = "PKI_CMP_PROFILE_SSH_V1";
  cmpProfileTable[4].val.value = PKI_CMP_PROFILE_SSH_V1;
  cmpProfileTable[5].description = "PKI_CMP_PROFILE_ENTRUST_V1";
  cmpProfileTable[5].val.value = PKI_CMP_PROFILE_ENTRUST_V1;

  RSA_PrintMessage ("CMP Profiles\n");
  status = ChooseTableEntryPrompt
             (cmpProfileTable,
              sizeof (cmpProfileTable) / sizeof (cmpProfileTable[0]),
              &result);
  if (status != 0)
    goto CLEANUP;

  *cmpProfile = result->val.value;

CLEANUP:
  return status;
}  /* end RSA_CmpProfilePrompt */

int RSA_SetOldCertIdControl (CERTC_CTX ctx, CERT_OBJ certObj,
                             ATTRIBUTES_OBJ controls)
{
  int status;

  CERT_FIELDS certFields;
  GENERAL_NAME issuer = {0};
  LIST_OBJ certIdList = (LIST_OBJ)NULL_PTR;
  ITEM issuerDer = {0}, serialNumberDer = {0}, certIdDer = {0};

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

  /* used to hold elements of the certId SEQUENCE */
  status = C_CreateListObject (&certIdList);
  if (status != 0)
    goto CLEANUP;

  issuer.altNameType = CN_DIRECTORY_NAME;
  issuer.altName.directoryName = certFields.issuerName;

  status = C_DEREncodeGeneralName (ctx, &issuer, &issuerDer.data,
                                   &issuerDer.len);
  if (status != 0)
    goto CLEANUP;

  /* first element of certId is the issuer GeneralName */
  status = C_AddItemToList (certIdList, &issuerDer, (unsigned int *)NULL_PTR);
  if (status != 0)
    goto CLEANUP;

  status = C_DEREncodeString (ctx, VT_INTEGER, VTC_UNIVERSAL,
                              certFields.serialNumber.data,
                              certFields.serialNumber.len,
                              &serialNumberDer.data, &serialNumberDer.len);
  if (status != 0)
    goto CLEANUP;

  /* second element of certId is the serialNumber INTEGER */
  status = C_AddItemToList (certIdList, &serialNumberDer,
                            (unsigned int *)NULL_PTR);
  if (status != 0)
    goto CLEANUP;

  /* obtain DER-encoded certId */
  status = C_DEREncodeList (ctx, VT_SEQUENCE, VTC_UNIVERSAL, certIdList,
                            &certIdDer.data, &certIdDer.len);
  if (status != 0)
    goto CLEANUP;

  status = C_AddAttributeValueBER (controls, ID_REGCTRL_OLDCERTID,
                                   ID_REGCTRL_OLDCERTID_LEN, certIdDer.data,
                                   certIdDer.len);

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

  T_free (serialNumberDer.data);
  T_free (issuerDer.data);
  T_free (certIdDer.data);

  C_DestroyListObject (&certIdList);

  return status;
}  /* end RSA_SetOldCertIdControl */

int RSA_RegInfoPrompt (ATTRIBUTES_OBJ regInfo,
                       RSA_DEMO_REG_INFO_ENTRY *regInfoEntries,
                       unsigned int numEntries)
{
  int status = 0;
  unsigned int i = 0;
  char userInput[RSA_DEMO_MAX_LINE_LEN];
  ITEM attribBer = {NULL, 0}, newAttribBer = {NULL, 0};

  RSA_PrintMessage ("Enter name of file containing attributes object ");
  status = RSA_GetFileToAllocBuffer (&attribBer.data, &attribBer.len,
                                     "BER binary\n(blank to create)");
  if (status == RSA_DEMO_E_CANCEL)
    status = 0;  /* continue on and populate a new object */
  else if (status != 0)
    goto CLEANUP;
  else { /* we have data from a file */
    status = C_SetAttributesBER (regInfo, attribBer.data, attribBer.len);
    goto CLEANUP;  /* either way, we're done */
  }

  RSA_PrintMessage ("Supply name-value pairs for regInfo.\n");
  for (i = 0; i < numEntries; i++) {
    if (regInfoEntries[i].valueString != NULL) { /* a value is already given */
      status = C_AddStringAttribute
               (regInfo, (POINTER)regInfoEntries[i].nameString,
                T_strlen (regInfoEntries[i].nameString),
                regInfoEntries[i].valueTag,
                (POINTER)regInfoEntries[i].valueString,
                T_strlen (regInfoEntries[i].valueString));
      if (status != 0)
        goto CLEANUP;
    }
    else {  /* prompt the user for the value */
      RSA_PrintMessage ("Enter value for %s\n", regInfoEntries[i].nameString);
      status = RSA_GetCommand (userInput, sizeof (userInput),
                               "Value (blank to omit)");
      if (userInput[0] == '\0')
        continue;
      else if (status != 0)
        goto CLEANUP;

      status = C_AddStringAttribute(regInfo,
                                    (POINTER)regInfoEntries[i].nameString,
                                    T_strlen (regInfoEntries[i].nameString),
                                    regInfoEntries[i].valueTag,
                                    (POINTER)userInput, T_strlen (userInput));
      if (status != 0)
        goto CLEANUP;
    }
  }

  /* optionally save attributes object to speed things up in the future... */
  status = C_GetAttributesDER (regInfo, &newAttribBer.data, &newAttribBer.len);
  if (status != 0)
    goto CLEANUP;

  RSA_PrintMessage ("Enter name of file to store attributes object - perhaps");
  RSA_PrintMessage (" for future use\n");
  status = RSA_WriteDataToFile (newAttribBer.data, newAttribBer.len,
                                "(blank not to save)");
  if (status == RSA_DEMO_E_CANCEL)
    status = 0;

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

  return status;
}  /* end RSA_RegInfoPrompt */

int RSA_PrintPkiStatusInfo (PKI_STATUS_INFO *statusInfo)
{
  int status = 0;

  RSA_PrintMessage ("Warning: this function has been deprecated!\n");
  RSA_PrintMessage ("Status:\n");
  switch (statusInfo->status) {
    case PKI_STATUS_GRANTED:
      RSA_PrintMessage ("  PKI_STATUS_GRANTED\n");
      break;
    case PKI_STATUS_GRANTED_MODS:
      RSA_PrintMessage ("  PKI_STATUS_GRANTED_MODS\n");
      break;
    case PKI_STATUS_REJECTED:
      RSA_PrintMessage ("  PKI_STATUS_REJECTED\n");
      break;
    case PKI_STATUS_WAITING:
      RSA_PrintMessage ("  PKI_STATUS_WAITING\n");
      break;
    case PKI_STATUS_WARNING_REVOCATION:
      RSA_PrintMessage ("  PKI_STATUS_WARNING_REVOCATION\n");
      break;
    case PKI_STATUS_REVOCATION:
      RSA_PrintMessage ("  PKI_STATUS_REVOCATION\n");
      break;
    case PKI_STATUS_WARNING_KEY_UPDATE:
      RSA_PrintMessage ("  PKI_STATUS_WARNING_KEY_UPDATE\n");
      break;
    default:
      RSA_PrintMessage ("  status = 0x%04x:\n", statusInfo->status);
  }

  RSA_PrintMessage ("Fail info:\n");
  switch (statusInfo->failInfo) {
    case PKI_FAIL_BAD_ALG:
      RSA_PrintMessage ("  PKI_FAIL_BAD_ALG\n");
      break;
    case PKI_FAIL_BAD_MESSAGE_CHECK:
      RSA_PrintMessage ("  PKI_FAIL_BAD_MESSAGE_CHECK\n");
      break;
    case PKI_FAIL_BAD_REQUEST:
      RSA_PrintMessage ("  PKI_FAIL_BAD_REQUEST\n");
      break;
    case PKI_FAIL_BAD_TIME:
      RSA_PrintMessage ("  PKI_FAIL_BAD_TIME\n");
      break;
    case PKI_FAIL_BAD_CERT_ID:
      RSA_PrintMessage ("  PKI_FAIL_BAD_CERT_ID\n");
      break;
    case PKI_FAIL_BAD_DATA_FORMAT:
      RSA_PrintMessage ("  PKI_FAIL_BAD_DATA_FORMAT\n");
      break;
    case PKI_FAIL_WRONG_AUTHORITY:
      RSA_PrintMessage ("  PKI_FAIL_WRONG_AUTHORITY\n");
      break;
    case PKI_FAIL_INCORRECT_DATA:
      RSA_PrintMessage ("  PKI_FAIL_INCORRECT_DATA\n");
      break;
    case PKI_FAIL_MISSING_TIMESTAMP:
      RSA_PrintMessage ("  PKI_FAIL_MISSING_TIMESTAMP\n");
      break;
    case PKI_FAIL_BAD_POP:
      RSA_PrintMessage ("  PKI_FAIL_BAD_POP\n");
      break;
    case PKI_FAIL_SERVER_ERROR:
      RSA_PrintMessage ("  PKI_FAIL_SERVER_ERROR\n");
      break;
    case PKI_FAIL_REMOTE_SERVER_ERROR:
      RSA_PrintMessage ("  PKI_FAIL_REMOTE_SERVER_ERROR\n");
      break;
    default:
      RSA_PrintMessage ("  status = 0x%04x\n", statusInfo->failInfo);
  }

  RSA_PrintMessage ("Status response code = %d\n",
                    statusInfo->failInfoAux);

  status = RSA_PrintStringList (statusInfo->statusString);

  return status;
}  /* end RSA_PrintPkiStatusInfo */

int RSA_PrintPkiStatusInfoObj (PKI_STATUS_INFO_OBJ statusInfoObj)
{
  int status = 0;

  unsigned int msgStatus, failInfo, failInfoAux;
  LIST_OBJ statusStringList;

  RSA_PrintMessage ("\nStatus Info Object Contents\n");

  status = C_GetPKIStatus ((POINTER)statusInfoObj, &msgStatus);
  if (status != 0 && status != E_VALUE_NOT_SET)
    goto CLEANUP;

  if (status == E_VALUE_NOT_SET)
    RSA_PrintMessage ("Message status not set.\n");
  else {
    RSA_PrintMessage ("Status:\n");
    switch (msgStatus) {
      case PKI_STATUS_GRANTED:
        RSA_PrintMessage ("  PKI_STATUS_GRANTED\n");
        break;
      case PKI_STATUS_GRANTED_MODS:
        RSA_PrintMessage ("  PKI_STATUS_GRANTED_MODS\n");
        break;
      case PKI_STATUS_REJECTED:
        RSA_PrintMessage ("  PKI_STATUS_REJECTED\n");
        break;
      case PKI_STATUS_WAITING:
        RSA_PrintMessage ("  PKI_STATUS_WAITING\n");
        break;
      case PKI_STATUS_WARNING_REVOCATION:
        RSA_PrintMessage ("  PKI_STATUS_WARNING_REVOCATION\n");
        break;
      case PKI_STATUS_REVOCATION:
        RSA_PrintMessage ("  PKI_STATUS_REVOCATION\n");
        break;
      case PKI_STATUS_WARNING_KEY_UPDATE:
        RSA_PrintMessage ("  PKI_STATUS_WARNING_KEY_UPDATE\n");
        break;
      default:
        RSA_PrintMessage ("  status = 0x%04x:\n", msgStatus);
    }
  }

  status = C_GetPKIStatusString ((POINTER)statusInfoObj, &statusStringList);
  if (status != 0 && status != E_VALUE_NOT_SET)
    goto CLEANUP;

  if (status == E_VALUE_NOT_SET)
    RSA_PrintMessage ("Status string value not set.\n");
  else {
    RSA_PrintMessage ("Status Strings:\n");
    status = RSA_PrintStringList (statusStringList);
    if (status != 0)
      goto CLEANUP;
  }
  
  status = C_GetPKIFailInfo ((POINTER)statusInfoObj, &failInfo);
  if (status != 0 && status != E_VALUE_NOT_SET)
    goto CLEANUP;

  if (status == E_VALUE_NOT_SET)
    RSA_PrintMessage ("Fail info value not set.\n");
  else {
    RSA_PrintMessage ("Fail info:\n");
    if (failInfo & PKI_FAIL_BAD_ALG)
      RSA_PrintMessage ("  PKI_FAIL_BAD_ALG\n");
    if (failInfo & PKI_FAIL_BAD_MESSAGE_CHECK)
      RSA_PrintMessage ("  PKI_FAIL_BAD_MESSAGE_CHECK\n");
    if (failInfo & PKI_FAIL_BAD_REQUEST)
      RSA_PrintMessage ("  PKI_FAIL_BAD_REQUEST\n");
    if (failInfo & PKI_FAIL_BAD_TIME)
      RSA_PrintMessage ("  PKI_FAIL_BAD_TIME\n");
    if (failInfo & PKI_FAIL_BAD_CERT_ID)
      RSA_PrintMessage ("  PKI_FAIL_BAD_CERT_ID\n");
    if (failInfo & PKI_FAIL_BAD_DATA_FORMAT)
      RSA_PrintMessage ("  PKI_FAIL_BAD_DATA_FORMAT\n");
    if (failInfo & PKI_FAIL_WRONG_AUTHORITY)
      RSA_PrintMessage ("  PKI_FAIL_WRONG_AUTHORITY\n");
    if (failInfo & PKI_FAIL_INCORRECT_DATA)
      RSA_PrintMessage ("  PKI_FAIL_INCORRECT_DATA\n");
    if (failInfo & PKI_FAIL_MISSING_TIMESTAMP)
      RSA_PrintMessage ("  PKI_FAIL_MISSING_TIMESTAMP\n");
    if (failInfo & PKI_FAIL_BAD_POP)
      RSA_PrintMessage ("  PKI_FAIL_BAD_POP\n");
    if (failInfo & PKI_FAIL_CERT_REVOKED)
      RSA_PrintMessage ("  PKI_FAIL_CERT_REVOKED\n");
    if (failInfo & PKI_FAIL_CERT_CONFIRMED)
      RSA_PrintMessage ("  PKI_FAIL_CERT_CONFIRMED\n");
    if (failInfo & PKI_FAIL_WRONG_INTEGRITY)
      RSA_PrintMessage ("  PKI_FAIL_WRONG_INTEGRITY\n");
    if (failInfo & PKI_FAIL_BAD_RECIPIENT_NONCE)
      RSA_PrintMessage ("  PKI_FAIL_BAD_RECIPIENT_NONCE\n");
    if (failInfo & PKI_FAIL_TIME_NOT_AVALIABLE)
      RSA_PrintMessage ("  PKI_FAIL_TIME_NOT_AVALIABLE\n");
    if (failInfo & PKI_FAIL_UNACCEPTED_POLICY)
      RSA_PrintMessage ("  PKI_FAIL_UNACCEPTED_POLICY\n");
    if (failInfo & PKI_FAIL_UNACCEPTED_EXTENSION)
      RSA_PrintMessage ("  PKI_FAIL_UNACCEPTED_EXTENSION\n");
    if (failInfo & PKI_FAIL_ADD_INFO_NOT_AVAILABLE)
      RSA_PrintMessage ("  PKI_FAIL_ADD_INFO_NOT_AVAILABLE\n");
    if (failInfo & PKI_FAIL_BAD_SENDER_NONCE)
      RSA_PrintMessage ("  PKI_FAIL_BAD_SENDER_NONCE\n");
    if (failInfo & PKI_FAIL_BAD_CERT_TEMPLATE)
      RSA_PrintMessage ("  PKI_FAIL_BAD_CERT_TEMPLATE\n");
    if (failInfo & PKI_FAIL_SIGNER_NOT_TRUSTED)
      RSA_PrintMessage ("  PKI_FAIL_SIGNER_NOT_TRUSTED\n");
    if (failInfo & PKI_FAIL_TRANSACTION_ID_IN_USE)
      RSA_PrintMessage ("  PKI_FAIL_TRANSACTION_ID_IN_USE\n");
    if (failInfo & PKI_FAIL_UNSUPPORTED_VERSION)
      RSA_PrintMessage ("  PKI_FAIL_UNSUPPORTED_VERSION\n");
    if (failInfo & PKI_FAIL_NOT_AUTHORIZED)
      RSA_PrintMessage ("  PKI_FAIL_NOT_AUTHORIZED\n");
    if (failInfo & PKI_FAIL_SYSTEM_UNAVAIL)
      RSA_PrintMessage ("  PKI_FAIL_SYSTEM_UNAVAIL\n");
    if (failInfo & PKI_FAIL_SYSTEM_FAILURE)
      RSA_PrintMessage ("  PKI_FAIL_SYSTEM_FAILURE\n");
    if (failInfo & PKI_FAIL_DUPLICATE_CERTREQ)
      RSA_PrintMessage ("  PKI_FAIL_DUPLICATE_CERTREQ\n");
    if (failInfo & PKI_FAIL_SERVER_ERROR)
      RSA_PrintMessage ("  PKI_FAIL_SERVER_ERROR\n");
    if (failInfo & PKI_FAIL_REMOTE_SERVER_ERROR)
      RSA_PrintMessage ("  PKI_FAIL_REMOTE_SERVER_ERROR\n");
  }
  
  status = C_GetPKIFailInfoAux ((POINTER)statusInfoObj, &failInfoAux);
  if (status != 0 && status != E_VALUE_NOT_SET)
    goto CLEANUP;

  if (status == E_VALUE_NOT_SET) {
    status = 0;  /* not a fatal error */
    RSA_PrintMessage ("Auxiliary failInfo not set.\n");
  } else {
    RSA_PrintMessage ("The following is a provider-specific failure code.\n");
    RSA_PrintMessage ("Auxiliary failInfo status = 0x%04x\n", failInfoAux);
  }
  
CLEANUP:
  if (status != 0)
    RSA_PrintError ("RSA_PrintPkiStatusInfoObj", status);

  return status;
}  /* end RSA_PrintPkiStatusInfoObj */

int RSA_PrintPkiErrorMsgObj (PKI_ERROR_MSG_OBJ errorMsgObj)
{
  int status;
  LIST_OBJ failInfoAuxStringList;

  /* Error message objects contain the same fields as a status info */
  status = RSA_PrintPkiStatusInfoObj ((POINTER)errorMsgObj);
  if (status != 0)
    goto CLEANUP;

  status = C_GetPKIFailInfoAuxString (errorMsgObj, &failInfoAuxStringList);
  if (status != 0 && status != E_VALUE_NOT_SET)
    goto CLEANUP;

  if (status == E_VALUE_NOT_SET) {
    status = 0;  /* not a fatal error */
    RSA_PrintMessage ("Auxiliary failInfo string value not set.\n");
  } else {
    RSA_PrintMessage ("Auxiliary failInfo Strings:\n");
    status = RSA_PrintStringList (failInfoAuxStringList);
    if (status != 0)
      goto CLEANUP;
  }  

CLEANUP:
  if (status != 0)
    RSA_PrintError ("RSA_PrintPkiErrorMsgObj", status);
  
  return status;
}  /* end RSA_PrintPkiErrorMsgObj */

int RSA_PrintStringList (LIST_OBJ stringList)
{
  int status = 0;
  unsigned int entryCount = 0, i = 0;
  ITEM *entry = NULL;

  if (stringList == NULL)
    goto CLEANUP;

  status = C_GetListObjectCount (stringList, &entryCount);
  if (status != 0)
    goto CLEANUP;

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

    RSA_PrintMessage ("String #%u\n", i+1);
    RSA_PrintBuf (NULL, entry->data, entry->len);
  }

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

  return status;
}  /* end RSA_PrintStringList */

int RSA_GetRequestorInfo (CERTC_CTX ctx, NAME_OBJ *requestor,
                          B_KEY_OBJ *publicKey, B_KEY_OBJ *privateKey)
{
  int status = 0;
  ITEM publicBer = {NULL, 0}, privateBer = {NULL, 0};

  *publicKey = NULL;
  *privateKey = NULL;

  status = C_CreateNameObject (requestor);
  if (status != 0)
    goto CLEANUP;

  status = RSA_GetNameObject (*requestor, "requestor subject");
  if (status != 0)
    goto CLEANUP;

  RSA_PrintMessage ("Supply the requestor's keypair\n");

  /* Prompt the user for the BER-encoded public key.  If the user enters a
   * blank, a new keypair will be generated on the fly and publicBer will be
   * {NULL, 0}.  Otherwise, if the user supplies a public key, a private key
   * must also be supplied.
   */
  status = RSA_GetFileToAllocBuffer
           (&publicBer.data, &publicBer.len,
            "Enter name of file containing public key BER (blank to create)");
  if (status == RSA_DEMO_E_CANCEL)
    status = RSA_GenerateKeypair (ctx, publicKey, privateKey);
  else if (status == 0) 
    /* user supplied public key, must supply private key also */
    status = RSA_GetFileToAllocBuffer
             (&privateBer.data, &privateBer.len,
            "Enter name of file containing private key BER (blank to cancel)");
  if (status != 0) /* if one of the previous calls failed */
    goto CLEANUP;

  if (publicBer.data != NULL) {
    /* RSA_GenerateKeypair was not called in this case */
    status = B_CreateKeyObject (publicKey);
    if (status != 0)
      goto CLEANUP;

    status = B_CreateKeyObject (privateKey);
    if (status != 0)
      goto CLEANUP;

    status = RSA_SetKeyBer (RSA_DEMO_PUBLIC_KEY, *publicKey, publicBer);
    if (status != 0)
      goto CLEANUP;

    status = RSA_SetKeyBer (RSA_DEMO_PRIVATE_KEY, *privateKey, privateBer);
    if (status != 0)
      goto CLEANUP;
  }

CLEANUP:
  if (status != 0) {
    C_DestroyNameObject (requestor);
    B_DestroyKeyObject (publicKey);
    B_DestroyKeyObject (privateKey);
    RSA_PrintError ("RSA_GetRequestorInfo", status);
  }

  if (privateBer.data != NULL) {
    T_memset (privateBer.data, 0, privateBer.len);
    T_free (privateBer.data);
  }

  T_free (publicBer.data);

  return status;
} /* end RSA_GetRequestorInfo */

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