RSA BSAFE Cert-C

Certificate Components for C

Crypto-C 6.2.1 Developer's Guide
Search

dbutil.c

Routines useful in interfacing with database providers.

/* $Id: dbutil.c,v 1.8 2004/03/02 05:18:37 gsingh Exp $ */
/* dbutil.c
** Copyright (c) 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 useful in interfacing with database
** providers.
*/

#include "certc.h"
#include "bsafe.h"
#include "demoutil.h"
#include "certutil.h"
#include "crlutil.h"
#include "keyutil.h"
#include "dbutil.h"

static int RSA_RsaPrivateToPublic (B_KEY_OBJ privateKey, B_KEY_OBJ *publicKey)
{
  int status;
  
  A_PKCS_RSA_PRIVATE_KEY *privateKeyInfo;
  A_RSA_KEY publicKeyInfo;

  status = B_CreateKeyObject (publicKey);
  if (status != 0)
    goto CLEANUP;  
  
  status = B_GetKeyInfo ((POINTER *)&privateKeyInfo, privateKey,
                         KI_PKCS_RSAPrivate);
  if (status != 0)
    goto CLEANUP;

  publicKeyInfo.modulus.data = privateKeyInfo->modulus.data;
  publicKeyInfo.modulus.len = privateKeyInfo->modulus.len;
  publicKeyInfo.exponent.data = privateKeyInfo->publicExponent.data;
  publicKeyInfo.exponent.len = privateKeyInfo->publicExponent.len;

  status = B_SetKeyInfo (*publicKey, KI_RSAPublic, (POINTER)&publicKeyInfo);
  
CLEANUP:
  if (status != 0)
    B_DestroyKeyObject (publicKey);

  return status;
}  /* end RSA_RsaPrivateToPublic */

static int TestDsaKeypair (CERTC_CTX ctx, B_KEY_OBJ privateKey,
                           B_KEY_OBJ publicKey)
{
  int status;

  B_ALGORITHM_OBJ signObj = (B_ALGORITHM_OBJ)NULL_PTR;
  B_ALGORITHM_OBJ verifyObj = (B_ALGORITHM_OBJ)NULL_PTR;
  B_ALGORITHM_OBJ randomObj;
  B_ALGORITHM_CHOOSER chooser;

  unsigned char dataToSign[] = {
    0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88
  };
  
  unsigned int dataToSignLen = sizeof (dataToSign);

#define MAX_DSA_SIG_LEN 48

  unsigned char signature[MAX_DSA_SIG_LEN];
  unsigned int signatureLen;

  /* sign arbitrary data */
  status = B_CreateAlgorithmObject (&signObj);
  if (status != 0)
    goto CLEANUP;

  status = B_SetAlgorithmInfo (signObj, AI_DSAWithSHA1, NULL_PTR);
  if (status != 0)
    goto CLEANUP;

  status = C_GetChooser (ctx, &chooser);
  if (status != 0)
    goto CLEANUP;

  status = B_SignInit (signObj, privateKey, chooser, NULL);
  if (status != 0)
    goto CLEANUP;

  status = B_SignUpdate (signObj, dataToSign, dataToSignLen, NULL);
  if (status != 0)
    goto CLEANUP;

  status = C_GetRandomObject (ctx, &randomObj);
  if (status != 0)
    goto CLEANUP;

  status = B_SignFinal (signObj, signature, &signatureLen, sizeof (signature),
                        randomObj, NULL);
  if (status != 0)
    goto CLEANUP;

  /* verify signature to check keypair match */
  status = B_CreateAlgorithmObject (&verifyObj);
  if (status != 0)
    goto CLEANUP;

  status = B_SetAlgorithmInfo (verifyObj, AI_DSAWithSHA1, NULL_PTR);
  if (status != 0)
    goto CLEANUP;

  status = B_VerifyInit (verifyObj, publicKey, chooser, NULL);
  if (status != 0)
    goto CLEANUP;

  status = B_VerifyUpdate (verifyObj, dataToSign, dataToSignLen, NULL);
  if (status != 0)
    goto CLEANUP;

  status = B_VerifyFinal (verifyObj, signature, signatureLen, NULL, NULL);

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

  B_DestroyAlgorithmObject (&signObj);
  B_DestroyAlgorithmObject (&verifyObj);

  return status;
}  /* end TestDsaKeypair */

static int RSA_DsaPrivateToPublic (CERTC_CTX ctx, B_KEY_OBJ privateKey,
                                   B_KEY_OBJ *publicKey)
{
  int status;

  A_DSA_PUBLIC_KEY dsaPublicKeyInfo = {{0}};
  A_DSA_PRIVATE_KEY *dsaPrivateInfo;

  B_KEY_OBJ tmpRsaPublic = (B_KEY_OBJ)NULL_PTR;
  A_RSA_KEY rsaPublicInfo;

  B_ALGORITHM_OBJ encryptObj = (B_ALGORITHM_OBJ)NULL_PTR;
  B_ALGORITHM_CHOOSER chooser;
  ITEM plaintext, ciphertext = {0};
  unsigned int ciphertextMaxLen, outputLenUpdate, outputLenFinal;

  /* initialize our output argument first */
  status = B_CreateKeyObject (publicKey);
  if (status != 0)
    goto CLEANUP;

  status = B_GetKeyInfo ((POINTER *)&dsaPrivateInfo, privateKey,
                         KI_DSAPrivate);
  if (status != 0)
    goto CLEANUP;

  /* The DSA public value is y = g^x mod p, where g is the base, x is the
     private value, and p is the prime.  Given g, x, and p, we can use an
     RSA encryption operation to derive y.  Use g as the plaintext, x as
     the public exponent, and p as the modulus. */
  status = B_CreateKeyObject (&tmpRsaPublic);
  if (status != 0)
    goto CLEANUP;

  rsaPublicInfo.modulus.data = dsaPrivateInfo->params.prime.data;
  rsaPublicInfo.modulus.len = dsaPrivateInfo->params.prime.len;
  rsaPublicInfo.exponent.data = dsaPrivateInfo->x.data;
  rsaPublicInfo.exponent.len = dsaPrivateInfo->x.len;

  status = B_SetKeyInfo (tmpRsaPublic, KI_RSAPublic, (POINTER)&rsaPublicInfo);
  if (status != 0)
    goto CLEANUP;

  status = B_CreateAlgorithmObject (&encryptObj);
  if (status != 0)
    goto CLEANUP;

  status = B_SetAlgorithmInfo (encryptObj, AI_RSAPublic, NULL_PTR);
  if (status != 0)
    goto CLEANUP;

  status = C_GetChooser (ctx, &chooser);
  if (status != 0)
    goto CLEANUP;

  status = B_EncryptInit (encryptObj, tmpRsaPublic, chooser, NULL);
  if (status != 0)
    goto CLEANUP;

  plaintext.data = dsaPrivateInfo->params.base.data;
  plaintext.len = dsaPrivateInfo->params.base.len;

  ciphertextMaxLen = plaintext.len;
  ciphertext.data = T_malloc (ciphertextMaxLen);
  if (ciphertext.data == NULL_PTR) {
    status = RSA_DEMO_E_ALLOC;
    goto CLEANUP;
  }

  status = B_EncryptUpdate (encryptObj, ciphertext.data, &outputLenUpdate,
                            ciphertextMaxLen, plaintext.data, plaintext.len,
                            NULL, NULL);
  if (status != 0)
    goto CLEANUP;

  status = B_EncryptFinal (encryptObj, ciphertext.data + outputLenUpdate,
                           &outputLenFinal, ciphertextMaxLen - outputLenUpdate,
                           NULL, NULL);
  if (status != 0)
    goto CLEANUP;

  ciphertext.len = outputLenUpdate + outputLenFinal;

  /* Now that we have derived the DSA public value, construct the public key */
  dsaPublicKeyInfo.y.data = ciphertext.data;
  dsaPublicKeyInfo.y.len = ciphertext.len;
  dsaPublicKeyInfo.params.prime.data = dsaPrivateInfo->params.prime.data;
  dsaPublicKeyInfo.params.prime.len = dsaPrivateInfo->params.prime.len;
  dsaPublicKeyInfo.params.subPrime.data = dsaPrivateInfo->params.subPrime.data;
  dsaPublicKeyInfo.params.subPrime.len = dsaPrivateInfo->params.subPrime.len;
  dsaPublicKeyInfo.params.base.data = dsaPrivateInfo->params.base.data;
  dsaPublicKeyInfo.params.base.len = dsaPrivateInfo->params.base.len;

  status = B_SetKeyInfo (*publicKey, KI_DSAPublic, (POINTER)&dsaPublicKeyInfo);
  if (status != 0)
    goto CLEANUP;

  status = TestDsaKeypair (ctx, privateKey, *publicKey);
  
CLEANUP:
  if (status != 0)
    B_DestroyKeyObject (publicKey);

  T_free (ciphertext.data);
  B_DestroyKeyObject (&tmpRsaPublic);
  B_DestroyAlgorithmObject (&encryptObj);
  
  return status;
}  /* end RSA_DsaPrivateToPublic */

int RSAUTIL_InsertPrivateKey (CERTC_CTX ctx, SERVICE db, B_KEY_OBJ privateKey)
{
  int status;

  B_KEY_OBJ publicKey = (B_KEY_OBJ)NULL_PTR;
  ITEM publicKeyBer = {0};

  /* First, check if it's an RSA private key */
  status = RSA_RsaPrivateToPublic (privateKey, &publicKey);
  if (status != 0)
    /* if not, maybe it's a DSA private key */
    status = RSA_DsaPrivateToPublic (ctx, privateKey, &publicKey);

  if (status != 0) {
    /* some problem with derivation of public key info */
    status = RSA_DEMO_E_NOT_IMPLEMENTED;
    goto CLEANUP;
  }

  status = RSA_GetKeyBer (RSA_DEMO_PUBLIC_KEY, publicKey, &publicKeyBer);
  if (status != 0)
    goto CLEANUP;

  status = C_InsertPrivateKeyBySPKI (db, &publicKeyBer, privateKey);

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

  T_free (publicKeyBer.data);
  B_DestroyKeyObject (&publicKey);

  return status;
}  /* end RSA_InsertPrivateKey */

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

  SERVICE db = (SERVICE)NULL_PTR;

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

  status = RSA_DumpDatabaseServiceContents (db);

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

  C_UnbindService (&db);
  
  return (status);
}  /* end RSA_DumpDatabaseContents */

static int DumpDatabaseCerts (SERVICE db)
{
  int status = 0;

  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_CreateListObject (&certList);
  if (status != 0)
    goto CLEANUP;

  /*  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 {
    RSA_PrintMessage ("Retrieving first cert...\n");
    
    /*  Retrieve all of the remaining certificates.  When there are no more
     *  certificates, the iterator will be set to NULL.
     */
    for (;;) {
      status = C_SelectNextCert (&iterator, certList);
      if (iterator == NULL) {
        status = 0;
        break;
      }
      else if (status != 0)
        goto CLEANUP;

      RSA_PrintMessage ("Retrieving another cert from database...\n");      
    }
  }

  /*  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 corresponding private key.\n");
      status = 0;
    }
    else if (status != 0)
      goto CLEANUP;
    else {
      RSA_PrintMessage ("Private key corresponding to certificate #%u:\n",
                        i + 1);
      RSA_PrintPrivateKeyInfo (privateKey);
      RSA_PrintMessage ("***\n");
    }

    B_DestroyKeyObject (&privateKey);
  }

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

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

static int DumpDatabaseCrls (SERVICE db)
{
  int status = 0;

  LIST_OBJ crlList = (LIST_OBJ)NULL_PTR;
  DB_ITERATOR iterator = (DB_ITERATOR)NULL_PTR;

  RSA_PrintMessage ("\nChecking for CRLs...\n");

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

  /*  To walk through the certs in the database, we need to initialize an
   *  iterator by first calling C_SelectFirstCRL().  Subsequent calls can
   *  then be made to C_SelectNextCRL().  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_SelectFirstCRL (db, &iterator, crlList);
  if (iterator == NULL) {
    RSA_PrintMessage ("Database empty.\n");
    status = 0;
  }
  else if (status != 0)
    goto CLEANUP;
  else
    /*  Retrieve all of the remaining CRLs.  When there are no more
     *  CRLs, the iterator will be set to NULL.
     */
    for (;;) {
      RSA_PrintMessage ("Retrieving CRL...\n");
      status = C_SelectNextCRL (&iterator, crlList);
      if (iterator == NULL) {
        status = 0;
        break;
      }
      else if (status != 0)
        goto CLEANUP;
    }

  /*  Now that we have a list object filled with CRLs, print out some
   *  information about each CRL.
   */
  status = RSA_PrintCrlList (crlList);

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

  C_DestroyListObject (&crlList);
  C_FreeIterator (&iterator);

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


static int DumpDatabasePrivateKeys (SERVICE db)
{
  int status = 0;
  unsigned int i;

  DB_ITERATOR iterator = (DB_ITERATOR)NULL_PTR;
  B_KEY_OBJ privateKey = (B_KEY_OBJ)NULL_PTR;

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

  status = C_SelectFirstPrivateKey (db, &iterator, privateKey);
  if (iterator == NULL) {
    RSA_PrintMessage ("No private keys in database.\n");
    status = 0;
  }
  else if (status == 0)
  {
    RSA_PrintMessage ("\n***Private Key #%u:\n", 1);
    RSA_PrintPrivateKeyInfo (privateKey);

    /*  Retrieve all of the remaining private keys.  When there are no more
     *  certificates, the iterator will be set to NULL.
     */
    for (i = 2;; i++) {
          B_DestroyKeyObject (&privateKey);
          status = B_CreateKeyObject (&privateKey);
      if (status != 0)
        goto CLEANUP;

      status = C_SelectNextPrivateKey (&iterator, privateKey);
      if (iterator == NULL) {
        status = 0;
        break;
      }
      else if (status != 0)
        goto CLEANUP;

      RSA_PrintMessage ("\n***Private Key #%u:\n", i);
      RSA_PrintPrivateKeyInfo (privateKey);
    }
  }

CLEANUP:
  if ( privateKey != (B_KEY_OBJ)NULL_PTR)
  {
      B_DestroyKeyObject (&privateKey);
  }
  if (status != 0)
    RSA_PrintError ("DumpDatabasePrivateKeys", status);

  C_FreeIterator (&iterator);
  
  return status;
}  /* end DumpDatabasePrivateKeys */

int RSA_DumpDatabaseServiceContents (SERVICE db)
{
  int status = 0;

  status = DumpDatabaseCerts (db);
  if (status != 0)
    goto CLEANUP;

  status = DumpDatabaseCrls (db);
  if (status != 0)
    goto CLEANUP;

  status = DumpDatabasePrivateKeys (db);

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

  return status;
}  /* end RSA_DumpDatabaseServiceContents */

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