RSA BSAFE Cert-C

Certificate Components for C

Crypto-C 6.2.1 Developer's Guide
Search

cmprev.c

Uses the CMP PKI service provider to send a certificate revocation message.

/* $Id: cmprev.c,v 1.4 2004/03/02 05:18:35 gsingh Exp $ */
/* cmprev.c
** Copyright (c) 2002-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.
**
** This program can be used to send a key update request to a CMP server.
** The key update request should be for a valid, non-revoked certificate.
** If the cert given for key update is not valid or revoked, the server
** should return an error.  This sample also contains an option to allow
** for key archival, provided that it is supported by the server.
**
** 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 "certc.h"
#include "rsacsp.h"
#include "imdb.h"
#include "cmp.h"
#include "pkixpath.h"
#include "filelog.h"
#include "demoutil.h"
#include "pkiutil.h"
#include "certutil.h"
#include "keyutil.h"
#include "nameutil.h"

/*  The number of service providers registered when the context is
 *  initialized.
 */
#define SP_COUNT 4

#define DEFAULT_CMP_URL "cmptcp://tr4.rsa.com:829"
#define CMP_PROVIDER_NAME "RSA CMP Provider"
#define EE_DB_NAME "Requestor's Database"
#define SENDER_DB_NAME "Sender's Cert Database"

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

  CERTC_CTX ctx = NULL;
  SERVICE_HANDLER spTable[SP_COUNT] = {
    {SPT_CRYPTO, "Default CSP", S_InitializeDefaultCSP},
    {SPT_DATABASE, EE_DB_NAME, S_InitializeMemoryDB},
    {SPT_DATABASE, SENDER_DB_NAME, S_InitializeMemoryDB},
    {SPT_CERT_PATH, "Cert Path Processing Provider", S_InitializePKIXPath}
  };
  
  POINTER spParams[SP_COUNT] = {0};

  SERVICE db = (SERVICE)NULL_PTR, senderDb = (SERVICE)NULL_PTR;

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

  PKI_CMP_SP_INIT_PARAMS cmpInitParams = {0};
  SERVICE_HANDLER cmpHandler = {
    SPT_PKI, CMP_PROVIDER_NAME, S_InitializeCMP
  };

  PKI_MSG_OBJ pkiMsgObj = (PKI_MSG_OBJ)NULL_PTR;

  PKI_PROTECT_INFO protectInfo = {0};
  CERT_PATH_CTX senderCertCtx = {0};
  LIST_OBJ trustedCerts = (LIST_OBJ)NULL_PTR;
  CERT_OBJ senderCert = (CERT_OBJ)NULL_PTR;
  CERT_FIELDS senderCertFields;
  B_KEY_OBJ senderPvtKey = (B_KEY_OBJ)NULL_PTR;
  
  PKI_SENDER_INFO senderInfo = {0};
  GENERAL_NAME senderGeneralName = {0};

  PKI_RECIPIENT_INFO recipientInfo = {0};
  GENERAL_NAME recipientGeneralName = {0};

  CERT_OBJ recipientCert = (CERT_OBJ)NULL_PTR;
  CERT_FIELDS recipientCertFields;
  ITEM recipientCertBer = {0};

  PKI_REVOKE_REQ_OBJ revReqObj = (PKI_REVOKE_REQ_OBJ)NULL_PTR;
  PKI_CERT_TEMPLATE_OBJ certTemplateObj = (PKI_CERT_TEMPLATE_OBJ)NULL_PTR;

  unsigned int reqIndex;

  PKI_MSG_OBJ pkiMsgRespObj = (PKI_MSG_OBJ)NULL_PTR;

  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 failure to register 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 ("CMP Cert Revocation Request Example\n");
  RSA_PrintMessage ("===================================\n");

  /* Step 1: Register CMP Provider */
  cmpInitParams.initChoice = PKI_CMP_INIT_METHOD_STRUCT;
  
  status = RSA_CreateTransportInfoFieldsPrompt
             (&cmpInitParams.method.initStruct.transport, DEFAULT_CMP_URL);
  if (status != 0)
    goto CLEANUP;

  status = RSA_CmpProfilePrompt (&cmpInitParams.method.initStruct.profile);
  if (status != 0)
    goto CLEANUP;

  status = C_RegisterService (ctx, &cmpHandler, (POINTER)&cmpInitParams,
                              SERVICE_ORDER_LAST);
  if (status != 0)
    goto CLEANUP;

  /* Step 2: Create PKI message object */
  status = C_CreatePKIMsgObject (ctx, &pkiMsgObj);
  if (status != 0)
    goto CLEANUP;

  status = C_SetPKIMsgType (pkiMsgObj, PKI_MSGTYPE_REVOKE_REQ);
  if (status != 0)
    goto CLEANUP;

  /* Set Message Protection:
   * This code could be modified to use an alternate protection type.
   * The protectInfo will be used when we call C_RequestPKIMsg.
   * The sender's CERT_PATH_CTX contains the cert to be updated, with the
   * existing private key, and here we set it to be explicitly trusted.
   * Since we are using a CERT_PATH_CTX, we need to register a provider
   * of type SPT_CERT_PATH with the current CERTC_CTX.  That was done
   * in this sample during the call to C_InitializeCertC.
   */
  status = C_BindService (ctx, SPT_DATABASE, SENDER_DB_NAME, &senderDb);
  if (status != 0)
    goto CLEANUP;

  RSA_PrintMessage ("Supply existing cert to revoke and corresponding ");
  RSA_PrintMessage ("private key.\n");
  RSA_PrintMessage ("Do not generate a new cert unless you are doing ");
  RSA_PrintMessage ("negative testing.\n");

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

  status = B_CreateKeyObject (&senderPvtKey);
  if (status != 0)
    goto CLEANUP;
  
  status = RSA_GetCertAndPvtKey (ctx, senderCert, senderPvtKey);
  if (status != 0)
    goto CLEANUP;

  status = C_CreateListObject (&trustedCerts);
  if (status != 0)
    goto CLEANUP;

  status = C_AddCertToList (trustedCerts, senderCert,
                            (unsigned int *)NULL_PTR);
  if (status != 0)
    goto CLEANUP;

  status = C_InsertCert (senderDb, senderCert);
  if (status != 0)
    goto CLEANUP;

  status = C_InsertPrivateKey (senderDb, senderCert, senderPvtKey);
  if (status != 0)
    goto CLEANUP;
  
  senderCertCtx.pathAlgorithm = PA_X509_V1;
  senderCertCtx.pathOptions = PF_IGNORE_REVOCATION;
  senderCertCtx.trustedCerts = trustedCerts;
  senderCertCtx.policies = ANY_POLICY;
  senderCertCtx.validationTime = PF_VALIDATION_TIME_NOW;
  senderCertCtx.database = senderDb;
  protectInfo.info.protectionCtx = &senderCertCtx;

  /* Because we have set PKI_MSG_PROTECTION_SIGN, note that we must add the
     CMP Signer's cert (CA cert) to the senderDb and a valid chain must exist
     from the CMP Signer's cert to a cert in the trustedCerts list. */
  status = C_SetPKIMsgProtectionType (pkiMsgObj, PKI_MSG_PROTECTION_SIGN);
  if (status != 0)
    goto CLEANUP;

  /* Set Sender:
   * If your server uses an alternate method of identifiying the requestor,
   * modify this code to popluate the PKI_SENDER_INFO with the appropriate
   * information.  Here we use the sender certificate (and matching private
   * key) that was just supplied above.
   */
  status = C_GetCertFields (senderCert, &senderCertFields);
  if (status != 0)
    goto CLEANUP;
  
  /* PKI_ENTITY_ISSUER_SERIAL is currently not supported by the CMP provider.
     as a workaround, use PKI_ENTITY_GENERALNAME_KEYID */
#if 0
  senderInfo.senderId.type = PKI_ENTITY_ISSUER_SERIAL;

  senderInfo.senderId.id.issuerSerialNumber.issuerName =
    senderCertFields.issuerName;
  senderInfo.senderId.id.issuerSerialNumber.serialNumber.data =
    senderCertFields.serialNumber.data;
  senderInfo.senderId.id.issuerSerialNumber.serialNumber.len =
    senderCertFields.serialNumber.len;
#else
  senderGeneralName.altNameType = CN_DIRECTORY_NAME;
  senderGeneralName.altName.directoryName = senderCertFields.subjectName;

  senderInfo.senderId.type = PKI_ENTITY_GENERALNAME_KEYID;
  senderInfo.senderId.id.generalNameKeyId.name = &senderGeneralName;
  senderInfo.senderId.id.generalNameKeyId.keyId.data = NULL_PTR;
  senderInfo.senderId.id.generalNameKeyId.keyId.len = 0;
#endif

  /* For simplicity, we set RSA with SHA1 as the signature algorithm.
     If desired, modify to use menuutil functions to prompt user. */
  senderInfo.digestAlgorithmId.algorithmId = DAI_SHA1;
  senderInfo.digestAlgorithmId.algorithmParam = NULL_PTR;
  senderInfo.signatureAlgorithmId.algorithmId = SA_RSA_ENCRYPTION;
  senderInfo.signatureAlgorithmId.algorithmParam = NULL_PTR;

  status = C_SetPKIMsgSender (pkiMsgObj, &senderInfo);
  if (status != 0)
    goto CLEANUP;

  /* Set the Recipient DN, identifying the CA.  If a cert is available,
   * extract the subject name from the CA cert.  Otherwise, prompt the user
   * to supply the DN in a name object.
   */
  RSA_PrintMessage ("Supply the CA certificate to identify the CA as the ");
  RSA_PrintMessage ("recipient.  This cert\nwill be used to envelope a ");
  RSA_PrintMessage ("message for the CA if you are using key archival\nand ");
  RSA_PrintMessage ("will be used to verify signed messages from the CA.\n");
  status = RSA_GetFileToAllocBuffer
             (&recipientCertBer.data, &recipientCertBer.len,
              "Enter name of file containing recipient cert");
  if (status != 0)
    goto CLEANUP;

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

  status = C_SetCertBER (recipientCert, recipientCertBer.data,
                         recipientCertBer.len);
  if (status != 0)
    goto CLEANUP;

  status = C_GetCertFields (recipientCert, &recipientCertFields);
  if (status != 0)
    goto CLEANUP;

  recipientGeneralName.altNameType = CN_DIRECTORY_NAME;
  recipientGeneralName.altName.directoryName = recipientCertFields.subjectName;

  status = C_InsertCert (senderDb, recipientCert);
  if (status != 0)
    goto CLEANUP;

  /* In addition, we'll just implicitly trust this cert */
  status = C_AddCertToList (trustedCerts, recipientCert,
                            (unsigned int *)NULL_PTR);
  if (status != 0)
    goto CLEANUP;

  recipientInfo.type = PKI_RECIPIENT_GENERALNAME_KEYID;
  recipientInfo.info.generalNameKeyId.name = &recipientGeneralName;

  status = C_SetPKIMsgRecipient (pkiMsgObj, &recipientInfo);
  if (status != 0)
    goto CLEANUP;

  /* Step 3: Create Revocation Request Object */
  status = C_CreatePKIRevokeReqObject (ctx, &revReqObj);
  if (status != 0)
    goto CLEANUP;

  /* In this example, we fill in the cert template with the information from
     the certificate to revoke.  Modify this code if the requirements of your
     server are different. */
  status = C_CreatePKICertTemplateObject (ctx, &certTemplateObj);
  if (status != 0)
    goto CLEANUP;

  status = C_GetPKICertTemplateFromCertObject (senderCert, certTemplateObj);
  if (status != 0)
    goto CLEANUP;

  status = C_SetPKIRevokeReqRevokeCert (revReqObj, certTemplateObj);
  if (status != 0)
    goto CLEANUP;

  /* Step 4: Add cert request to PKI message object */
  status = C_AddPKIMsg (pkiMsgObj, (POINTER)revReqObj, &reqIndex);
  if (status != 0)
    goto CLEANUP;

  /* Step 6: Send Request Message */
  status = C_CreatePKIMsgObject (ctx, &pkiMsgRespObj);
  if (status != 0)
    goto CLEANUP;

  status = C_BindService (ctx, SPT_DATABASE, EE_DB_NAME, &db);
  if (status != 0)
    goto CLEANUP;

  RSA_PrintMessage ("Sending Revocation Request...\n");
  status = C_RequestPKIMsg (ctx, CMP_PROVIDER_NAME, pkiMsgObj, &protectInfo,
                            db, pkiMsgRespObj);
  if (status != 0)
    goto CLEANUP;

  /* Step 7: Process Response Message */
  status = RSA_ProcessPkiMsgResp (ctx, pkiMsgRespObj, pkiMsgObj, RSA_DEMO_CMP,
                                  CMP_PROVIDER_NAME, &protectInfo, db);
  if (status != 0)
    goto CLEANUP;

CLEANUP:
  if (status != 0)
    RSA_PrintError ("cmprev.c", status);
  else
    RSA_PrintMessage ("Done!\n");

  RSA_DestroyTransportInfoFields (&cmpInitParams.method.initStruct.transport);

  B_DestroyKeyObject (&senderPvtKey);

  C_DestroyListObject (&trustedCerts);
  C_DestroyCertObject (&senderCert);
  C_DestroyPKICertTemplateObject (&certTemplateObj);
  C_DestroyPKIRevokeReqObject (&revReqObj);
  C_DestroyPKIMsgObject (&pkiMsgObj);
  C_DestroyPKIMsgObject (&pkiMsgRespObj);
  C_UnbindService (&senderDb);
  C_UnbindService (&db);
  C_FinalizeCertC (&ctx);

  return status;
}  /* end main */

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