G'day,

[resent, test program now attached]

Following on from my problem with viewing multiple data objects, I wrote a test program (attached) that performs the following:

  o  Confirm that no data objects exist on the card
  o  Create a data object
  o  Delete the created data object
  o  Confirm that no data objects exist on the card

On a card with no data objects on it (as confirmed by muscleTool), this is what I get:

$ ./p11-delete-data-object-test --module /usr/local/lib/libmusclepkcs11.so --slot 1 --pin 00000000
## Loading module: /usr/local/lib/libmusclepkcs11.so ...ok
## Opening session for slot = 01 ... ok
## Performing login with PIN '00000000' .... ok
## Searching for data object ... ok (no objects found)
## Creating data object ... ok (handle = 0x804D508)
## Deleting object 0x804D508 ... ok
## Searching for data object ... ok (object=0x804D508)
Error: data object was not deleted

Using muscleTool shows the following objects:


muscle [MuscleCard Applet] > list
           Object ID  Object Size     READ   WRITE   DELETE
   -----------------  -----------    ------  ------  ------
                  o0          512    ALWAYS  PIN #1  PIN #1
                  O0            4    PIN #1  PIN #1  PIN #1


Which seems to indicate that the C_DestroyObject implementation does not work, at least for data objects (unless I'm doing something wrong).

-- Geoff
/*
 * Program to add, delete, and view a data object via PKCS#11
 */
#include <stdio.h>
#include <assert.h>
#include <dlfcn.h>
#include <string.h>
#include <stdlib.h>

/* unix defns for pkcs11.h */
#define CK_PTR *

#define CK_DEFINE_FUNCTION(returnType, name) \
   returnType name

#define CK_DECLARE_FUNCTION(returnType, name) \
   returnType name

#define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
   returnType (* name)

#define CK_CALLBACK_FUNCTION(returnType, name) \
   returnType (* name)

#ifndef NULL_PTR
#define NULL_PTR 0
#endif

#include <pkcs11.h>

typedef struct Session {
  CK_FUNCTION_LIST_PTR functions;
  CK_SESSION_HANDLE handle;
} Session;

static Session *open_session (const char *module, int slot, char *pin);
static void close_session (const Session *session);
static CK_OBJECT_HANDLE get_data_object (const Session *session);
static CK_OBJECT_HANDLE create_data_object (const Session *session);
static void delete_data_object (const Session *session, 
                                CK_OBJECT_HANDLE hObject);
static const char *get_rv_string(const CK_RV rv);

static void printUsage (const char *progname) {
  printf ("Usage: %s {option}\n", progname);
  printf ("Options:\n");
  printf ("  --module <path>       Path to PKCS#11 module\n");
  printf ("  --slot <num>          Slot number to use [DEFAULT=0]\n");
  printf ("  --pin <pin>           PIN for user login\n");
  printf ("  --help                Show this help\n");
}

int main (int argc, char **argv) {
  const char *module = NULL;
  int slot = 0;
  char *pin = NULL;
  int i;
  Session *session;
  CK_OBJECT_HANDLE hObject;

  /* Process args. */
  for (i = 1; i < argc; i++) {
    const char *arg = argv[i];
    if (strcmp (arg, "--module") == 0) {
      module = argv[++i];
    }
    else if (strcmp (arg, "--slot") == 0) {
      slot = atoi (argv[++i]);
    }
    else if (strcmp (arg, "--pin") == 0) {
      pin = argv[++i];
    }
    else if (strcmp (arg, "--help") == 0) {
      printUsage (argv[0]);
      exit (0);
    }
    else {
      printf ("*** Unknown option: '%s' ***\n", arg);
      printUsage (argv[0]);
      exit (-1);
    }
  }

  /* Make sure a module was specified. */
  if (module == NULL) {
    printf ("*** Must specify a module ***\n");
    printUsage (argv[0]);
    exit (-1);
  }

  /* Open a session */
  session = open_session (module, slot, pin);
  if (session == NULL) {
    exit (-1);
  }

  /* Make sure no data objects already exist */
  hObject = get_data_object (session);
  if (hObject != CK_INVALID_HANDLE) {
    printf ("Error: data object already exists. "
            "Please delete all data objects\n");
    return -1;
  }

  /* Create a data object */
  hObject = create_data_object (session);
  assert (hObject != CK_INVALID_HANDLE);

  /* Delete the data object */
  delete_data_object (session, hObject);

  /* Perform lookup to see if data object still exists */
  hObject = get_data_object (session);
  if (hObject != CK_INVALID_HANDLE) {
    printf ("Error: data object was not deleted\n");
    return -1;
  }
  
  printf ("Test successful\n");

  /* Close the session */
  close_session (session);

  return 0;
}

/**
 * Create data object 
 */
static CK_OBJECT_HANDLE create_data_object (const Session *session)
{
  CK_OBJECT_HANDLE hObject;
  CK_RV rv;
  CK_BBOOL true = TRUE;
  CK_BBOOL false = FALSE;
  CK_OBJECT_CLASS objectClass = CKO_DATA;
  CK_ATTRIBUTE template[] = {
    { CKA_CLASS, &objectClass, sizeof (CK_OBJECT_CLASS) },
    { CKA_TOKEN, &true, sizeof (CK_BBOOL) },
    { CKA_PRIVATE, &false, sizeof (CK_BBOOL) },
    { CKA_MODIFIABLE, &true, sizeof (CK_BBOOL) },
    { CKA_APPLICATION, "test", 4 },
    { CKA_LABEL, "test", 4 },
    { CKA_VALUE, "test", 4 }
  };
  CK_ULONG ulTemplateSize = sizeof (template) / sizeof (template[0]);
  
  /* Pre-condition checks */
  assert (session != NULL);

  printf ("## Creating data object ... ");
  rv = (*session->functions->C_CreateObject) (session->handle, 
                                              template,
                                              ulTemplateSize,
                                              &hObject); 
  if (rv != CKR_OK) {
    printf ("failed: %s\n", get_rv_string (rv));
    return CK_INVALID_HANDLE;
  }
  printf ("ok (handle = 0x%04X)\n", hObject);
  
  return hObject;
}
/**
 * Get handle of a data object.
 */
static CK_OBJECT_HANDLE get_data_object (const Session *session)
{
  CK_RV rv;
  CK_OBJECT_HANDLE hObject = CK_INVALID_HANDLE;
  CK_OBJECT_CLASS objClass = CKO_DATA;
  CK_ULONG ulCount;

  /* Template matches all objects with CKA_CLASS == CKO_DATA */
  CK_ATTRIBUTE template[] = {
    { CKA_CLASS, &objClass, sizeof (objClass) },
  };
  CK_ULONG ulTemplateCount = sizeof (template) / sizeof (template[0]);
  
  /* Pre-condition checks. */
  assert (session != NULL);

  /* Initiate the object search */
  printf ("## Searching for data object ... ");
  rv = (*session->functions->C_FindObjectsInit)(session->handle, template, 
                                                ulTemplateCount);
  if (rv != CKR_OK && rv != CKR_ATTRIBUTE_TYPE_INVALID) {
    printf ("failed: %s\n", get_rv_string (rv));
    return CK_INVALID_HANDLE;
  }
  
  /* Perform the search */
  rv = (*session->functions->C_FindObjects) (session->handle, 
                                             &hObject, 1, &ulCount);
  if (rv != CKR_OK) {
    printf ("failed: %s\n", get_rv_string (rv));
    return CK_INVALID_HANDLE;
  }

  /* Remember to call C_FindObjectsFinal to terminate the search */
  (*session->functions->C_FindObjectsFinal)(session->handle);

  printf ("ok");
  if (ulCount == 0) {
    printf (" (no objects found)\n");
  }
  else {
    printf (" (object=0x%04X)\n", hObject);
  }

  return hObject;
}

/**
 * Delete all data objects
 */
static void delete_data_object (const Session *session, 
                                CK_OBJECT_HANDLE hObject)
{
  CK_RV rv;

  /* Pre-condition checks. */
  assert (session != NULL);
  assert (hObject != CK_INVALID_HANDLE);

  printf ("## Deleting object 0x%04X ... ", hObject);
  rv = (*session->functions->C_DestroyObject) (session->handle, hObject);
  if (rv != CKR_OK) {
    printf ("failed: %s\n", get_rv_string (rv));
  }
  else {
    printf ("ok\n");
  }  
}

/**
 * Open a new session.
 */
static Session *open_session (const char *module, int slot, char *pin) {
  Session *session;
  void *hModule;
  CK_C_GetFunctionList pC_GetFunctionList;
  CK_RV rv;
  
  /* Pre-condition checks */
  assert (module != NULL);
  
  session = (Session *) calloc (1, sizeof (Session));
  assert (session != NULL); 

  /* Load the PKCS #11 module. */
  printf ("## Loading module: %s ...", module);
  fflush (stdout);
  hModule = dlopen (module, RTLD_LAZY);
  printf ((hModule == NULL) ? "failed\n" : "ok\n");
  assert (hModule!=NULL);

  /* Get function pointer to C_GetFunctionList. */
  pC_GetFunctionList = 
    (CK_C_GetFunctionList) dlsym (hModule, "C_GetFunctionList");
  assert (pC_GetFunctionList!=NULL);

  /* Get function pointers to all PKCS #11 functions. */
  rv = (*pC_GetFunctionList) (&session->functions);
  assert (rv == CKR_OK);

  /* Initalize Cryptoki. */
  rv = (*session->functions->C_Initialize) (NULL);
  assert (rv==CKR_OK);
  
  /* Open a read/write session on the given slot */
  printf ("## Opening session for slot = %02d ... ", slot);
  rv = (*session->functions->C_OpenSession)(slot, 
                                            CKF_SERIAL_SESSION|CKF_RW_SESSION,
                                            0, 0, &session->handle);
  if (rv != CKR_OK) {
    printf ("failed: %s\n", get_rv_string (rv));
    return NULL;
  }
  printf ("ok\n");  

  if (pin != NULL) {
    printf ("## Performing login with PIN '%s' .... ", pin);
    rv = (*session->functions->C_Login)(session->handle, CKU_USER, 
                                        pin, strlen(pin));
    if (rv != CKR_OK) {
      printf ("failed: %s\n", get_rv_string (rv));
      return NULL;
    }
    printf ("ok\n");  
  }

  return session;
} 

/**
 * Close the session.
 */
static void close_session (const Session *session) {
  CK_RV rv;

  /* Pre-condition checks */
  assert (session != NULL); 
    
  printf ("## Finalizing ... ");
  rv = (*session->functions->C_Finalize)(0);
  if (rv != CKR_OK) {
    printf ("failed: %s\n", get_rv_string (rv));
  }
  else {
    printf ("ok\n");
  }
}   

static const char *get_rv_string(const CK_RV rv) {
  static char buf[128];

  switch (rv) {
  case CKR_ARGUMENTS_BAD: return "bad arguments";
  case CKR_CANCEL: return "cancel";
  case CKR_CRYPTOKI_NOT_INITIALIZED: return "cryptoki not initialized";
  case CKR_DATA_LEN_RANGE: return "data len range";
  case CKR_DATA_INVALID: return "data invalid";
  case CKR_DEVICE_ERROR: return "device error";
  case CKR_DEVICE_MEMORY: return "device memory";
  case CKR_DEVICE_REMOVED: return "device removed";
  case CKR_FUNCTION_CANCELED: return "function canceled";
  case CKR_FUNCTION_FAILED: return "function failed";
  case CKR_FUNCTION_NOT_SUPPORTED: return "function not supported";
  case CKR_GENERAL_ERROR: return "general error";
  case CKR_HOST_MEMORY: return "host memory";
  case CKR_OK: return "ok";
  case CKR_OPERATION_ACTIVE: return "operation active";
  case CKR_OPERATION_NOT_INITIALIZED: return "operation not initialized";
  case CKR_PIN_INCORRECT: return "pin incorrect";
  case CKR_PIN_LOCKED: return "pin locked";
  case CKR_RANDOM_SEED_NOT_SUPPORTED: return "random seed not supported";
  case CKR_RANDOM_NO_RNG: return "no rng";
  case CKR_SESSION_CLOSED: return "session closed";
  case CKR_SESSION_COUNT: return "session count";
  case CKR_SESSION_HANDLE_INVALID: return "session handle invalid";
  case CKR_SESSION_PARALLEL_NOT_SUPPORTED: return "session parallel not supported";
  case CKR_SESSION_READ_ONLY: return "session read only";
  case CKR_SESSION_EXISTS: return "session exists";
  case CKR_SESSION_READ_ONLY_EXISTS: return "session read-only exists";
  case CKR_SESSION_READ_WRITE_SO_EXISTS: return "session read write SO exists";
  case CKR_SIGNATURE_INVALID: return "signature invalid";
  case CKR_SIGNATURE_LEN_RANGE: return "signature len range";
  case CKR_SLOT_ID_INVALID: return "slot id invalid";
  case CKR_TEMPLATE_INCOMPLETE: return "template incomplete";
  case CKR_TEMPLATE_INCONSISTENT: return "template inconsistent";
  case CKR_TOKEN_NOT_PRESENT: return "token not present";
  case CKR_TOKEN_NOT_RECOGNIZED: return "token not recognized";
  case CKR_USER_ALREADY_LOGGED_IN: return "user already logged in";
  case CKR_USER_NOT_LOGGED_IN: return "user not logged in";
  case CKR_USER_PIN_NOT_INITIALIZED: return "user pin not initialized";
  case CKR_USER_TOO_MANY_TYPES: return "user too many types";
  case CKR_USER_TYPE_INVALID: return "user type invalid";
  }

  sprintf (buf, "Unknown error: %lu", rv);
  return strdup (buf);
}
_______________________________________________
Muscle mailing list
[email protected]
http://lists.drizzle.com/mailman/listinfo/muscle

Reply via email to