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