Alessandro Premoli:

add support for reading, writing and deleting private (require cache_pins) and
public data objects in PKCS11. updated the pkcs11-tool and fixed a few
bugs in the code. Tested on an aladdin etoken.


git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@3176 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
aj 2007-06-21 09:37:18 +00:00
parent a4cd33e77f
commit 4cc1a50a49
5 changed files with 308 additions and 33 deletions

View File

@ -1286,6 +1286,88 @@ static CK_RV pkcs15_create_certificate(struct sc_pkcs11_card *p11card,
out: return rv;
}
static CK_RV pkcs15_create_data(struct sc_pkcs11_card *p11card,
struct sc_pkcs11_slot *slot,
struct sc_profile *profile,
CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
CK_OBJECT_HANDLE_PTR phObject)
{
struct pkcs15_fw_data *fw_data = (struct pkcs15_fw_data *) p11card->fw_data;
struct sc_pkcs15init_dataargs args;
struct pkcs15_any_object *data_any_obj;
struct sc_pkcs15_object *data_obj;
struct sc_pkcs15_pin_info *pin;
CK_BBOOL bValue;
int rc, rv;
memset(&args, 0, sizeof(args));
args.app_oid.value[0] = -1;
rv = CKR_OK;
while (ulCount--) {
CK_ATTRIBUTE_PTR attr = pTemplate++;
switch (attr->type) {
/* Skip attrs we already know or don't care for */
case CKA_CLASS:
break;
case CKA_PRIVATE:
rv = attr_extract(attr, &bValue, NULL);
if (bValue) {
pin = slot_data_pin_info(slot->fw_data);
if (pin == NULL) {
rv = CKR_TEMPLATE_INCOMPLETE;
goto out;
}
args.auth_id = pin->auth_id;
}
break;
case CKA_LABEL:
args.label = (char *) attr->pValue;
break;
case CKA_ID:
args.id.len = sizeof(args.id.value);
rv = attr_extract(attr, args.id.value, &args.id.len);
if (rv != CKR_OK)
goto out;
break;
case CKA_APPLICATION:
args.app_label = (char *) attr->pValue;
break;
case CKA_OBJECT_ID:
rv = attr_extract(attr, args.app_oid.value, NULL);
if (rv != CKR_OK)
goto out;
break;
case CKA_VALUE:
args.der_encoded.len = attr->ulValueLen;
args.der_encoded.value = (u8 *) attr->pValue;
break;
default:
/* ignore unknown attrs, or flag error? */
continue;
}
}
if (args.der_encoded.len == 0) {
rv = CKR_TEMPLATE_INCOMPLETE;
goto out;
}
rc = sc_pkcs15init_store_data_object(fw_data->p15_card, profile, &args, &data_obj);
if (rc < 0) {
rv = sc_to_cryptoki_error(rc, p11card->reader);
goto out;
}
/* Create a new pkcs11 object for it */
__pkcs15_create_data_object(fw_data, data_obj, &data_any_obj);
pkcs15_add_object(slot, data_any_obj, phObject);
rv = CKR_OK;
out: return rv;
}
static CK_RV pkcs15_create_object(struct sc_pkcs11_card *p11card,
struct sc_pkcs11_slot *slot,
CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
@ -1326,6 +1408,10 @@ static CK_RV pkcs15_create_object(struct sc_pkcs11_card *p11card,
rv = pkcs15_create_certificate(p11card, slot, profile,
pTemplate, ulCount, phObject);
break;
case CKO_DATA:
rv = pkcs15_create_data(p11card, slot, profile,
pTemplate, ulCount, phObject);
break;
default:
rv = CKR_FUNCTION_NOT_SUPPORTED;
}
@ -2338,15 +2424,14 @@ static int pkcs15_dobj_get_value(struct sc_pkcs11_session *session,
if (rv < 0)
return sc_to_cryptoki_error(rv, reader);
if (slot_data_pin_info(data)) {
rv = revalidate_pin(data, session);
if (rv < 0)
goto done;
}
if ((rv = sc_pkcs15_read_data_object(fw_data->p15_card, dobj->info, out_data)) < 0)
goto done;
rv = sc_pkcs15_read_data_object(fw_data->p15_card, dobj->info, out_data);
/* Do we have to try a re-login and then try to sign again? */
if (rv == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED) {
rv = revalidate_pin(data, session);
if (rv == 0)
rv = sc_pkcs15_read_data_object(fw_data->p15_card, dobj->info, out_data);
}
done:
sc_unlock(card);
if (rv < 0)
@ -2432,12 +2517,55 @@ static CK_RV pkcs15_dobj_get_attribute(struct sc_pkcs11_session *session,
return CKR_OK;
}
static CK_RV pkcs15_dobj_destroy(struct sc_pkcs11_session *session, void *object)
{
struct pkcs15_data_object *obj = (struct pkcs15_data_object*) object;
struct sc_pkcs11_card *card = session->slot->card;
struct pkcs15_fw_data *fw_data = (struct pkcs15_fw_data *) card->fw_data;
struct pkcs15_slot_data *data = slot_data(session->slot->fw_data);
struct sc_profile *profile = NULL;
int reader = session->slot->card->reader;
int rv;
rv = sc_lock(card->card);
if (rv < 0)
return sc_to_cryptoki_error(rv, card->reader);
/* Bind the profile */
rv = sc_pkcs15init_bind(card->card, "pkcs15", NULL, &profile);
if (rv < 0) {
sc_unlock(card->card);
return sc_to_cryptoki_error(rv, card->reader);
}
/* Add the PINs the user presented so far to the keycache */
add_pins_to_keycache(card, session->slot);
/* Delete object in smartcard */
rv = sc_pkcs15init_delete_object(fw_data->p15_card, profile, obj->base.p15_object);
/* Do we have to try a re-login and then try to delete again? */
if (rv == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED) {
rv = revalidate_pin(data, session);
if (rv == 0)
rv = sc_pkcs15init_delete_object(fw_data->p15_card, profile, obj->base.p15_object);
}
sc_pkcs15init_unbind(profile);
sc_unlock(card->card);
if (rv < 0)
return sc_to_cryptoki_error(rv, reader);
return CKR_OK;
}
struct sc_pkcs11_object_ops pkcs15_dobj_ops = {
pkcs15_dobj_release,
pkcs15_dobj_set_attribute,
pkcs15_dobj_get_attribute,
sc_pkcs11_any_cmp_attribute,
NULL,
pkcs15_dobj_destroy,
NULL,
NULL,
NULL,

View File

@ -236,6 +236,8 @@ CK_RV attr_extract(CK_ATTRIBUTE_PTR pAttr, void *ptr, size_t *sizep)
size = sizeof(CKA_CERTIFICATE_TYPE); break;
case CKA_MODULUS_BITS:
size = sizeof(CK_ULONG); break;
case CKA_OBJECT_ID:
size = sizeof(struct sc_object_id); break;
default:
return CKR_FUNCTION_FAILED;
}

View File

@ -69,7 +69,34 @@ CK_RV C_CopyObject(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_RV C_DestroyObject(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_OBJECT_HANDLE hObject) /* the object's handle */
{
return CKR_FUNCTION_NOT_SUPPORTED;
struct sc_pkcs11_session *session;
struct sc_pkcs11_object *object;
char object_name[64];
int rv;
rv = sc_pkcs11_lock();
if (rv != CKR_OK)
return rv;
snprintf(object_name, sizeof(object_name), "C_DestroyObject : Object %lu",
(unsigned long) hObject);
sc_debug( context, object_name );
rv = pool_find(&session_pool, hSession, (void**) &session);
if (rv != CKR_OK)
goto out;
rv = pool_find_and_delete(&session->slot->object_pool, hObject, (void**) &object);
if (rv != CKR_OK)
goto out;
if (object->ops->destroy_object == NULL)
rv = CKR_FUNCTION_NOT_SUPPORTED;
else
rv = object->ops->destroy_object(session, object);
out: sc_pkcs11_unlock();
return rv;
}
CK_RV C_GetObjectSize(CK_SESSION_HANDLE hSession, /* the session's handle */

View File

@ -1789,8 +1789,7 @@ sc_pkcs15init_store_data_object(struct sc_pkcs15_card *p15card,
int r, i;
unsigned int tid = 0x01;
if ((label = args->label) == NULL)
label = "Data Object";
label = args->label;
if (!args->id.len) {
/* Select an ID if the user didn't specify one, otherwise
@ -1831,7 +1830,10 @@ sc_pkcs15init_store_data_object(struct sc_pkcs15_card *p15card,
if (object == NULL)
return SC_ERROR_OUT_OF_MEMORY;
data_object_info = (sc_pkcs15_data_info_t *) object->data;
if (label != NULL) {
if (args->app_label != NULL) {
strlcpy(data_object_info->app_label, args->app_label,
sizeof(data_object_info->app_label));
} else if (label != NULL) {
strlcpy(data_object_info->app_label, label,
sizeof(data_object_info->app_label));
}
@ -2715,6 +2717,8 @@ sc_pkcs15init_new_object(int type, const char *label, sc_pkcs15_id_t *auth_id, v
break;
case SC_PKCS15_TYPE_DATA_OBJECT:
object->flags = DEFAULT_DATA_FLAGS;
if (auth_id->len != 0)
object->flags |= SC_PKCS15_CO_FLAG_PRIVATE;
data_size = sizeof(sc_pkcs15_data_info_t);
break;
}
@ -2803,21 +2807,25 @@ int sc_pkcs15init_delete_object(sc_pkcs15_card_t *p15card,
{
sc_path_t path;
struct sc_pkcs15_df *df;
int r;
int r, stored_in_ef = 0;
switch(obj->type & SC_PKCS15_TYPE_CLASS_MASK)
{
case SC_PKCS15_TYPE_PUBKEY:
path = ((sc_pkcs15_pubkey_info_t *)obj->data)->path;
stored_in_ef = 1;
break;
case SC_PKCS15_TYPE_PRKEY:
path = ((sc_pkcs15_prkey_info_t *)obj->data)->path;
stored_in_ef = 1;
break;
case SC_PKCS15_TYPE_CERT:
path = ((sc_pkcs15_cert_info_t *)obj->data)->path;
stored_in_ef = 1;
break;
case SC_PKCS15_TYPE_DATA_OBJECT:
path = ((sc_pkcs15_data_info_t *)obj->data)->path;
stored_in_ef = 1;
break;
default:
return SC_ERROR_NOT_SUPPORTED;
@ -2827,13 +2835,26 @@ int sc_pkcs15init_delete_object(sc_pkcs15_card_t *p15card,
if ((r = set_so_pin_from_card(p15card, profile)) < 0)
return r;
/* If there's a card-specific way to delete objects, use it.
* Otherwise, just set its label to "deleted" to indicate
* that we can re-used it when we have to make a next
* object in the future. */
if (profile->ops->delete_object != NULL) {
r = profile->ops->delete_object(profile, p15card->card,
obj->type, obj->data, &path);
/* if the object is stored in a normal EF try to
* delete the EF */
if (stored_in_ef != 0) {
r = sc_pkcs15init_delete_by_path(profile, p15card->card, &path);
if (r != SC_SUCCESS) {
sc_error(p15card->card->ctx, "sc_pkcs15init_delete_by_path failed: %d", r);
return r;
}
/* Get the DF we're part of. If there's no DF, fine, we haven't
* been added yet. */
if ((df = obj->df) != NULL) {
/* Unlink the object and update the DF */
sc_pkcs15_remove_object(p15card, obj);
}
} else if (profile->ops->delete_object != NULL) {
/* If there's a card-specific way to delete objects, use it.
* Otherwise, just set its label to "deleted" to indicate
* that we can re-used it when we have to make a next
* object in the future. */
r = profile->ops->delete_object(profile, p15card->card, obj->type, obj->data, &path);
if (r < 0) {
sc_error(p15card->card->ctx, "ops->delete_object() failed: %d", r);
return r;
@ -2844,18 +2865,16 @@ int sc_pkcs15init_delete_object(sc_pkcs15_card_t *p15card,
if ((df = obj->df) != NULL) {
/* Unlink the object and update the DF */
sc_pkcs15_remove_object(p15card, obj);
r = sc_pkcs15init_update_any_df(p15card, profile, df, 0);
}
}
else {
} else {
/* Get the DF we're part of. If there's no DF, fine, we haven't
* been added yet. */
if ((df = obj->df) != NULL) {
/*Change the label into "deleted" and update the DF */
strcpy(obj->label, "deleted");
r = sc_pkcs15init_update_any_df(p15card, profile, df, 0);
}
}
r = sc_pkcs15init_update_any_df(p15card, profile, df, 0);
/* mark card as dirty */
profile->dirty = 1;

View File

@ -46,6 +46,7 @@ enum {
OPT_MODULE = 0x100,
OPT_SLOT,
OPT_SLOT_LABEL,
OPT_APPLICATION_LABEL,
OPT_APPLICATION_ID,
OPT_SO_PIN,
OPT_INIT_TOKEN,
@ -75,6 +76,8 @@ const struct option options[] = {
{ "key-type", 1, 0, OPT_KEY_TYPE },
{ "write-object", 1, 0, 'w' },
{ "read-object", 0, 0, 'r' },
{ "delete-object", 0, 0, 'b' },
{ "application-label", 1, 0, OPT_APPLICATION_LABEL },
{ "application-id", 1, 0, OPT_APPLICATION_ID },
{ "type", 1, 0, 'y' },
{ "id", 1, 0, 'd' },
@ -112,8 +115,9 @@ const char *option_help[] = {
"Change your User PIN",
"Key pair generation",
"Specify the type and length of the key to create, for example rsa:1024",
"Write an object (key, cert) to the card",
"Write an object (key, cert, data) to the card",
"Get object's CKA_VALUE attribute (use with --type)",
"Specify the application label of the data object (use with --type data)",
"Specify the application id of the data object (use with --type data)",
"Specify the type of object (e.g. cert, privkey, pubkey, data)",
"Specify the id of the object",
@ -150,6 +154,7 @@ static size_t opt_object_id_len = 0, new_object_id_len = 0;
static char * opt_object_label = NULL;
static char * opt_pin = NULL;
static char * opt_so_pin = NULL;
static char * opt_application_label = NULL;
static char * opt_application_id = NULL;
static char * opt_key_type = NULL;
static int opt_is_private = 0;
@ -215,6 +220,7 @@ static int gen_keypair(CK_SLOT_ID, CK_SESSION_HANDLE,
CK_OBJECT_HANDLE *, CK_OBJECT_HANDLE *, const char *);
static int write_object(CK_SLOT_ID slot, CK_SESSION_HANDLE session);
static int read_object(CK_SLOT_ID slot, CK_SESSION_HANDLE session);
static int delete_object(CK_SLOT_ID slot, CK_SESSION_HANDLE session);
static void set_id_attr(CK_SLOT_ID slot, CK_SESSION_HANDLE session);
static int find_object(CK_SESSION_HANDLE, CK_OBJECT_CLASS,
CK_OBJECT_HANDLE_PTR,
@ -264,6 +270,7 @@ main(int argc, char * argv[])
int do_gen_keypair = 0;
int do_write_object = 0;
int do_read_object = 0;
int do_delete_object = 0;
int do_set_id = 0;
int do_test = 0;
int do_test_kpgen_certwrite = 0;
@ -277,7 +284,7 @@ main(int argc, char * argv[])
CK_RV rv;
while (1) {
c = getopt_long(argc, argv, "ILMOa:d:e:hi:klm:o:p:scvty:w:z:r",
c = getopt_long(argc, argv, "ILMOa:bd:e:hi:klm:o:p:scvty:w:z:r",
options, &long_optind);
if (c == -1)
break;
@ -320,6 +327,11 @@ main(int argc, char * argv[])
do_read_object = 1;
action_count++;
break;
case 'b':
need_session |= NEED_SESSION_RW;
do_delete_object = 1;
action_count++;
break;
case 'e':
need_session |= NEED_SESSION_RW;
do_set_id = 1;
@ -407,6 +419,9 @@ main(int argc, char * argv[])
case OPT_MODULE:
opt_module = optarg;
break;
case OPT_APPLICATION_LABEL:
opt_application_label = optarg;
break;
case OPT_APPLICATION_ID:
opt_application_id = optarg;
break;
@ -572,11 +587,22 @@ main(int argc, char * argv[])
if (opt_object_class_str == NULL)
fatal("You should specify type of the object to read");
if (opt_object_id_len == 0 && opt_object_label == NULL &&
opt_application_id == NULL)
opt_application_label == NULL && opt_application_id == NULL)
fatal("You should specify at least one of the "
"object ID, object label or application ID\n");
"object ID, object label, application label or application ID\n");
read_object(opt_slot, session);
}
if (do_delete_object) {
if (opt_object_class_str == NULL)
fatal("You should specify type of the object to delete");
if (opt_object_id_len == 0 && opt_object_label == NULL &&
opt_application_label == NULL && opt_application_id == NULL)
fatal("You should specify at least one of the "
"object ID, object label, application label or application ID\n");
delete_object(opt_slot, session);
}
if (do_set_id) {
if (opt_object_class_str == NULL)
fatal("You should specify the object type with the -y option\n");
@ -1162,8 +1188,9 @@ static void parse_rsa_private_key(struct rsakey_info *rsa,
#define MAX_OBJECT_SIZE 5000
/* Currently only for certificates (-type cert) and private keys
(-type privkey). Note: only RSA private keys are supported. */
/* Currently only for certificates (-type cert),
private keys (-type privkey) and data objetcs (-type data).
Note: only RSA private keys are supported. */
int
write_object(CK_SLOT_ID slot, CK_SESSION_HANDLE session)
{
@ -1176,6 +1203,7 @@ write_object(CK_SLOT_ID slot, CK_SESSION_HANDLE session)
CK_OBJECT_HANDLE cert_obj, privkey_obj, data_obj;
CK_ATTRIBUTE cert_templ[20], privkey_templ[20], data_templ[20];
int n_cert_attr = 0, n_privkey_attr = 0, n_data_attr = 0;
struct sc_object_id oid;
#if 0
CK_ATTRIBUTE pubkey_templ[20];
CK_OBJECT_HANDLE pubkey_obj;
@ -1328,13 +1356,22 @@ write_object(CK_SLOT_ID slot, CK_SESSION_HANDLE session)
if (opt_is_private != 0) {
FILL_ATTR(data_templ[n_data_attr], CKA_PRIVATE,
&_true, sizeof(_true));
n_data_attr++;
}
if (opt_application_label != NULL) {
FILL_ATTR(data_templ[n_data_attr], CKA_APPLICATION,
opt_application_label, strlen(opt_application_label));
n_data_attr++;
}
if (opt_application_id != NULL) {
FILL_ATTR(data_templ[n_data_attr], CKA_APPLICATION,
opt_application_id, strlen(opt_application_id));
sc_format_oid(&oid, opt_application_id);
FILL_ATTR(data_templ[n_data_attr], CKA_OBJECT_ID,
(unsigned char *)oid.value, sizeof(oid.value));
n_data_attr++;
}
if (opt_object_label != NULL) {
FILL_ATTR(data_templ[n_data_attr], CKA_LABEL,
opt_object_label, strlen(opt_object_label));
@ -1868,6 +1905,12 @@ read_object(CK_SLOT_ID slot, CK_SESSION_HANDLE session)
nn_attrs++;
}
if (opt_application_label != NULL) {
FILL_ATTR(attrs[nn_attrs], CKA_APPLICATION,
opt_application_label, strlen(opt_application_label));
nn_attrs++;
}
if (opt_application_id != NULL) {
sc_format_oid(&oid, opt_application_id);
FILL_ATTR(attrs[nn_attrs], CKA_OBJECT_ID,
@ -1900,6 +1943,62 @@ read_object(CK_SLOT_ID slot, CK_SESSION_HANDLE session)
return 1;
}
/*
* Delete object.
*/
int
delete_object(CK_SLOT_ID slot, CK_SESSION_HANDLE session)
{
CK_RV rv;
CK_ATTRIBUTE attrs[20];
CK_OBJECT_CLASS clazz = opt_object_class;
CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE;
int nn_attrs = 0;
struct sc_object_id oid;
if (opt_object_class_str != NULL) {
FILL_ATTR(attrs[nn_attrs], CKA_CLASS,
&clazz, sizeof(clazz));
nn_attrs++;
}
if (opt_object_id_len != 0) {
FILL_ATTR(attrs[nn_attrs], CKA_ID,
opt_object_id, opt_object_id_len);
nn_attrs++;
}
if (opt_object_label != NULL) {
FILL_ATTR(attrs[nn_attrs], CKA_LABEL,
opt_object_label, strlen(opt_object_label));
nn_attrs++;
}
if (opt_application_label != NULL) {
FILL_ATTR(attrs[nn_attrs], CKA_APPLICATION,
opt_application_label, strlen(opt_application_label));
nn_attrs++;
}
if (opt_application_id != NULL) {
sc_format_oid(&oid, opt_application_id);
FILL_ATTR(attrs[nn_attrs], CKA_OBJECT_ID,
(unsigned char *)oid.value, sizeof(oid.value));
nn_attrs++;
}
rv = find_object_with_attributes(session, &obj, attrs, nn_attrs, 0);
if (rv != CKR_OK)
p11_fatal("find_object_with_attributes()", rv);
else if (obj==CK_INVALID_HANDLE)
fatal("object not found\n");
rv = p11->C_DestroyObject(session, obj);
if (rv != CKR_OK)
p11_fatal("C_DestroyObject()", rv);
return 1;
}
static CK_ULONG get_private_key_length(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE prkey)
{
unsigned char *id;