RSA BSAFE Cert-C

Certificate Components for C

Crypto-C 6.2.1 Developer's Guide
Search

mscapicert.c

Prints out the certificates contained in "MY" CryptoAPI database provider certificate store..

/* $Id: mscapicert.c,v 1.7 2004/03/02 05:18:39 gsingh Exp $ */
/* mscapicert.c
** Copyright (c) 2000-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.
**
** Print out the certificates contained in "MY" CAPI cert store.
**
** 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).
**
** Because CAPI is only supported on the Windows platform, this sample
** will only compile and run there.
**
*/

#include "certc.h"
#include "filelog.h"
#include "demoutil.h"
#include "dbutil.h"
#include "certutil.h"
#include "capiprov.h"
#include "rsacsp.h"

/*  The number of service providers used in this example.
 */
#define SP_COUNT 2

#ifdef WIN32  /* Do CryptoAPI stuff only on a Win32 machine */
/*  Use certificates with corresponding private keys in the given database
 *  to create a PKCS #7 SignedData messages.
 */
static int SignDataWithDbKeys (CERTC_CTX ctx, char *dbName);

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

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

  MS_CAPI_DB_PARAMS capiDbParams;
  FILE_LOG_PARAMS logParams = {NULL, NULL};

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

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

  spTable[0].type = SPT_DATABASE;                   /* Service Provider Type */
  spTable[0].name = "CAPI Database";        /* unique null-terminated string */
  spTable[0].Initialize = S_InitializeCryptoAPIDB;         /* see capiprov.h */

  /* We need to register a Crypto provider in order to do crypto operations,
   * in this case signing data, using the B_KEY_OBJ that we retrieved from
   * the CAPI store.
   */
  spTable[1].type = SPT_CRYPTO;
  spTable[1].name = "Crypto Provider";
  spTable[1].Initialize = S_InitializeDefaultCSP;

  /*  If we have LIST_OBJs already containing certs, CRLs, or other info, we
   *  can provide a MEMORY_DB_PARAMS structure filled with LIST_OBJs.  However,
   *  since that is not the case here, we pass in a NULL to let the Cert-C
   *  library handle the management of the list objects.
   */
  spParams[0] = (POINTER)&capiDbParams;  
  spParams[1] = NULL;

  capiDbParams.pCryptoProviderName =
    "Microsoft Enhanced Cryptographic Provider v1.0";
  capiDbParams.pKeyContainerName = "";
  capiDbParams.pCertSystemStoreName = "MY";
  capiDbParams.dwProviderType = 1;
  capiDbParams.dwKeySpec = 0;

  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

  status = SignDataWithDbKeys (ctx, spTable[0].name);

CLEANUP:
  if (status != 0)
    RSA_PrintError ("mscapicert.c", status);
  
  /*  Unregister all currently registered providers, free allocated memory,
   *  and set ctx to NULL_PTR.
   */
  C_FinalizeCertC (&ctx);

  return (status);
}  /* end main */

static int SignDataWithDbKeys (CERTC_CTX ctx, char *dbName)
{
  int status = 0;

  SERVICE db = (SERVICE)NULL_PTR;
  LIST_OBJ certList = (LIST_OBJ)NULL_PTR;
  DB_ITERATOR iterator = (DB_ITERATOR)NULL_PTR;
  CERT_OBJ certObj = (CERT_OBJ)NULL_PTR;
  B_KEY_OBJ privateKey = (B_KEY_OBJ)NULL_PTR;

  unsigned int certCount = 0, i = 0;

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

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

  RSA_PrintMessage ("Retrieving first cert...\n");
  /*  To walk through the certs in the database, we need to initialize an
   *  iterator by first calling C_SelectFirstCert().  Subsequent calls can
   *  then be made to C_SelectNextCert().  When the iterator is NULL_PTR, we
   *  know that any memory associated with it has been freed and no certs
   *  remain in the database.  Should you need to dispose of the iterator
   *  before all certs have been retrieved, you may call C_FreeIterator().
   */
  status = C_SelectFirstCert (db, &iterator, certList);
  if (iterator == NULL) {
    RSA_PrintMessage ("Database empty.\n");
    status = 0;
  }
  else if (status != 0)
    goto CLEANUP;
  else
    /*  Retrieve all of the remaining certificates.  When there are no more
     *  certificates, the iterator will be set to NULL.
     */
    for (;;) {
      RSA_PrintMessage ("Retrieving another cert from database...\n");
      status = C_SelectNextCert (&iterator, certList);
      if (iterator == NULL) {
        status = 0;
        break;
      }
      else if (status != 0)
        goto CLEANUP;
    }

  /*  Now that we have a list object filled with certificates, print out some
   *  information about each certificate.
   */
  status = C_GetListObjectCount (certList, &certCount);
  if (status != 0)
    goto CLEANUP;

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

    RSA_PrintMessage ("\n***Certificate #%u:\n", i + 1);
    status = RSA_PrintCertInfo (certObj);
    if (status != 0)
      goto CLEANUP;

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

    status = C_SelectPrivateKeyByCert (db, certObj, privateKey);
    if (status == E_NOT_FOUND) {
      RSA_PrintMessage ("No private key.\n");
      break;
    }
    else if (status != 0)
      goto CLEANUP;

    RSA_PrintMessage ("Found corresponding private key.\n");

    /* Sign some data using the key and cert we just got */
    {
      ITEM dataToSign = {NULL, 0}, p7Data = {NULL, 0};
      ITEM p7SignedData = {NULL, 0};

      SIGNER_INFO signer;
      LIST_OBJ signerList = NULL;

      CERT_FIELDS certFields;

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

      status = RSA_GetFileToAllocBuffer (&dataToSign.data, &dataToSign.len,
                                         "Enter name of file to sign");
      if (status != 0)
        goto CLEANUP;

      status = C_WriteDataMsg (ctx, &dataToSign, &p7Data);
      if (status != 0)
        goto CLEANUP;

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

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

      signer.signerCertId.type = ISSUER_SERIAL;
      signer.signerCertId.id.issuerSerialNumber.issuerName =
        certFields.issuerName;
      signer.signerCertId.id.issuerSerialNumber.serialNumber.data =
        certFields.serialNumber.data;
      signer.signerCertId.id.issuerSerialNumber.serialNumber.len =
        certFields.serialNumber.len;
      signer.digestAlgorithmId.algorithmId = DAI_SHA1;
      signer.signatureAlgorithmId.algorithmId = SA_RSA_ENCRYPTION;

      status = C_AddSignerToList (signerList, &signer, NULL);
      if (status != 0)
        goto CLEANUP;

      status = C_WriteSignedDataMsg (ctx, NULL, db, &p7Data, 0, NULL, NULL,
                                     signerList, &p7SignedData);
      if (status != 0)
        goto CLEANUP;

      status = RSA_WriteDataToFile (p7SignedData.data, p7SignedData.len,
                                    "Enter name of file to store signed data");
      if (status != 0 && status != RSA_DEMO_E_CANCEL)
        goto CLEANUP;

      C_DestroyListObject (&signerList);
      T_free (dataToSign.data);
      T_free (p7Data.data);
      T_free (p7SignedData.data);
    }
  }

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

  B_DestroyKeyObject (&privateKey);
  C_DestroyListObject (&certList);
  C_FreeIterator (&iterator);
  C_UnbindService (&db);
  
  return (status);
}  /* end SignDataWithDbKeys */

#else /* ! WIN32 */

int main (int argc, char *argv[])
{
  return 0;
}

#endif /* ! WIN32 */


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