Added support for MuscleCard applet. Thanks to Thomas Harning, David Corcoran of Identity Alliance
git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@2968 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
parent
e225efc982
commit
50490acca0
|
@ -20,7 +20,7 @@ libopensc_la_SOURCES = \
|
||||||
pkcs15-prkey.c pkcs15-pubkey.c pkcs15-sec.c \
|
pkcs15-prkey.c pkcs15-pubkey.c pkcs15-sec.c \
|
||||||
pkcs15-wrap.c pkcs15-algo.c pkcs15-cache.c pkcs15-syn.c \
|
pkcs15-wrap.c pkcs15-algo.c pkcs15-cache.c pkcs15-syn.c \
|
||||||
\
|
\
|
||||||
emv.c \
|
emv.c muscle.c muscle-filesystem.c \
|
||||||
\
|
\
|
||||||
ctbcs.c reader-ctapi.c reader-pcsc.c reader-openct.c \
|
ctbcs.c reader-ctapi.c reader-pcsc.c reader-openct.c \
|
||||||
\
|
\
|
||||||
|
@ -28,7 +28,7 @@ libopensc_la_SOURCES = \
|
||||||
card-cardos.c card-tcos.c card-emv.c card-default.c \
|
card-cardos.c card-tcos.c card-emv.c card-default.c \
|
||||||
card-mcrd.c card-starcos.c card-openpgp.c card-jcop.c \
|
card-mcrd.c card-starcos.c card-openpgp.c card-jcop.c \
|
||||||
card-oberthur.c card-belpic.c card-atrust-acos.c \
|
card-oberthur.c card-belpic.c card-atrust-acos.c \
|
||||||
card-incrypto34.c card-piv.c \
|
card-incrypto34.c card-piv.c card-muscle.c \
|
||||||
\
|
\
|
||||||
pkcs15-openpgp.c pkcs15-infocamere.c pkcs15-starcert.c \
|
pkcs15-openpgp.c pkcs15-infocamere.c pkcs15-starcert.c \
|
||||||
pkcs15-tcos.c pkcs15-esteid.c pkcs15-postecert.c pkcs15-gemsafe.c \
|
pkcs15-tcos.c pkcs15-esteid.c pkcs15-postecert.c pkcs15-gemsafe.c \
|
||||||
|
@ -41,7 +41,7 @@ include_HEADERS = \
|
||||||
cardctl.h asn1.h log.h ui.h \
|
cardctl.h asn1.h log.h ui.h \
|
||||||
errors.h types.h
|
errors.h types.h
|
||||||
|
|
||||||
noinst_HEADERS = cards.h ctbcs.h internal.h esteid.h
|
noinst_HEADERS = cards.h ctbcs.h internal.h esteid.h muscle.h muscle-filesystem.h
|
||||||
|
|
||||||
pkgconfigdir = $(libdir)/pkgconfig
|
pkgconfigdir = $(libdir)/pkgconfig
|
||||||
pkgconfig_DATA = libopensc.pc libpkcs15init.pc libscconf.pc
|
pkgconfig_DATA = libopensc.pc libpkcs15init.pc libscconf.pc
|
||||||
|
|
|
@ -28,6 +28,7 @@ OBJECTS = \
|
||||||
card-mcrd.obj card-starcos.obj card-openpgp.obj card-jcop.obj \
|
card-mcrd.obj card-starcos.obj card-openpgp.obj card-jcop.obj \
|
||||||
card-oberthur.obj card-belpic.obj card-atrust-acos.obj \
|
card-oberthur.obj card-belpic.obj card-atrust-acos.obj \
|
||||||
card-incrypto34.obj card-piv.obj\
|
card-incrypto34.obj card-piv.obj\
|
||||||
|
muscle.obj card-muscle.obj muscle-filesystem.obj \
|
||||||
\
|
\
|
||||||
pkcs15-openpgp.obj pkcs15-infocamere.obj pkcs15-starcert.obj \
|
pkcs15-openpgp.obj pkcs15-infocamere.obj pkcs15-starcert.obj \
|
||||||
pkcs15-tcos.obj pkcs15-esteid.obj pkcs15-postecert.obj \
|
pkcs15-tcos.obj pkcs15-esteid.obj pkcs15-postecert.obj \
|
||||||
|
|
|
@ -0,0 +1,772 @@
|
||||||
|
/*
|
||||||
|
* card-muscle.c: Support for MuscleCard Applet from musclecard.com
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006, Identity Alliance, Thomas Harning <support@identityalliance.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
#include "cardctl.h"
|
||||||
|
#include "muscle.h"
|
||||||
|
#include "muscle-filesystem.h"
|
||||||
|
#include <opensc/types.h>
|
||||||
|
#include <opensc.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* ATR Values pulled from the Muscle Card library's 'bundle' */
|
||||||
|
#if 0
|
||||||
|
/* UNUSED */
|
||||||
|
static struct sc_atr_table muscle_atrs[] = {
|
||||||
|
{ "3B:75:13:00:00:9C:02:02:01:02", NULL, "Muscle card", SC_CARD_TYPE_MUSCLE_GENERIC, 0, NULL },
|
||||||
|
{ "3B:65:00:00:9C:02:02:01:02", NULL, "Muscle card", SC_CARD_TYPE_MUSCLE_GENERIC, 0, NULL },
|
||||||
|
{ "3B:3B:94:00:90:65:AF:03:0D:01:74:83:0F:90:00", NULL, "Muscle card", SC_CARD_TYPE_MUSCLE_GENERIC, 0, NULL },
|
||||||
|
{ "3F:6D:00:00:80:31:80:65:B0:05:01:02:5E:83:00:90:00", NULL, "Muscle card", SC_CARD_TYPE_MUSCLE_GENERIC, 0, NULL },
|
||||||
|
{ NULL, NULL, NULL, 0, 0, NULL }
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static struct sc_card_operations muscle_ops;
|
||||||
|
static struct sc_card_driver muscle_drv = {
|
||||||
|
"Muscle Card Driver",
|
||||||
|
"muscle",
|
||||||
|
&muscle_ops,
|
||||||
|
NULL, 0, NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MUSCLE_DATA(card) ( (muscle_private_t*)card->drv_data )
|
||||||
|
#define MUSCLE_FS(card) ( ((muscle_private_t*)card->drv_data)->fs )
|
||||||
|
typedef struct muscle_private {
|
||||||
|
sc_security_env_t env;
|
||||||
|
unsigned short verifiedPins;
|
||||||
|
mscfs_t *fs;
|
||||||
|
int rsa_key_ref;
|
||||||
|
|
||||||
|
} muscle_private_t;
|
||||||
|
|
||||||
|
static int muscle_finish(sc_card_t *card)
|
||||||
|
{
|
||||||
|
muscle_private_t *priv = MUSCLE_DATA(card);
|
||||||
|
mscfs_free(priv->fs);
|
||||||
|
free(priv);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static u8 muscleAppletId[] = { 0xA0, 0x00,0x00,0x00, 0x01, 0x01 };
|
||||||
|
|
||||||
|
static int muscle_match_card(sc_card_t *card)
|
||||||
|
{
|
||||||
|
/* Use SELECT APPLET, since its a more deterministic way of detection */
|
||||||
|
return msc_select_applet(card, muscleAppletId, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Since Musclecard has a different ACL system then PKCS15
|
||||||
|
* objects need to have their READ/UPDATE/DELETE permissions mapped for files
|
||||||
|
* and directory ACLS need to be set
|
||||||
|
* For keys.. they have different ACLS, but are accessed in different locations, so it shouldn't be an issue here
|
||||||
|
*/
|
||||||
|
static unsigned short muscle_parse_singleAcl(const sc_acl_entry_t* acl)
|
||||||
|
{
|
||||||
|
unsigned short access = 0;
|
||||||
|
while(acl) {
|
||||||
|
int key = acl->key_ref;
|
||||||
|
int method = acl->method;
|
||||||
|
switch(method) {
|
||||||
|
case SC_AC_NEVER:
|
||||||
|
return 0xFFFF;
|
||||||
|
/* Ignore... other items overwrite these */
|
||||||
|
case SC_AC_NONE:
|
||||||
|
case SC_AC_UNKNOWN:
|
||||||
|
break;
|
||||||
|
case SC_AC_CHV:
|
||||||
|
access |= (1 << key); /* Assuming key 0 == SO */
|
||||||
|
break;
|
||||||
|
case SC_AC_AUT:
|
||||||
|
case SC_AC_TERM:
|
||||||
|
case SC_AC_PRO:
|
||||||
|
default:
|
||||||
|
/* Ignored */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
acl = acl->next;
|
||||||
|
}
|
||||||
|
return access;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void muscle_parse_acls(const sc_file_t* file, unsigned short* read, unsigned short* write, unsigned short* delete)
|
||||||
|
{
|
||||||
|
assert(read && write && delete);
|
||||||
|
*read = muscle_parse_singleAcl(sc_file_get_acl_entry(file, SC_AC_OP_READ));
|
||||||
|
*write = muscle_parse_singleAcl(sc_file_get_acl_entry(file, SC_AC_OP_UPDATE));
|
||||||
|
*delete = muscle_parse_singleAcl(sc_file_get_acl_entry(file, SC_AC_OP_DELETE));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int muscle_create_directory(sc_card_t *card, sc_file_t *file)
|
||||||
|
{
|
||||||
|
mscfs_t *fs = MUSCLE_FS(card);
|
||||||
|
u8 objectId[4];
|
||||||
|
unsigned id = file->id;
|
||||||
|
unsigned short read = 0, write = 0, delete = 0;
|
||||||
|
int objectSize;
|
||||||
|
int r;
|
||||||
|
if(id == 0) /* No null name files */
|
||||||
|
return SC_ERROR_INVALID_ARGUMENTS;
|
||||||
|
|
||||||
|
/* No nesting directories */
|
||||||
|
if(fs->currentPath[0] != 0x3F || fs->currentPath[1] != 0x00)
|
||||||
|
return SC_ERROR_NOT_SUPPORTED;
|
||||||
|
objectId[0] = ((id & 0xFF00) >> 8) & 0xFF;
|
||||||
|
objectId[1] = id & 0xFF;
|
||||||
|
objectId[2] = objectId[3] = 0;
|
||||||
|
|
||||||
|
objectSize = file->size;
|
||||||
|
|
||||||
|
muscle_parse_acls(file, &read, &write, &delete);
|
||||||
|
r = msc_create_object(card, *(int*)objectId, objectSize, read, write, delete);
|
||||||
|
mscfs_clear_cache(fs);
|
||||||
|
if(r >= 0) return 0;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int muscle_create_file(sc_card_t *card, sc_file_t *file)
|
||||||
|
{
|
||||||
|
mscfs_t *fs = MUSCLE_FS(card);
|
||||||
|
int objectSize = file->size;
|
||||||
|
unsigned short read = 0, write = 0, delete = 0;
|
||||||
|
unsigned int objectId;
|
||||||
|
int r;
|
||||||
|
if(file->type == SC_FILE_TYPE_DF)
|
||||||
|
return muscle_create_directory(card, file);
|
||||||
|
if(file->type != SC_FILE_TYPE_WORKING_EF)
|
||||||
|
return SC_ERROR_NOT_SUPPORTED;
|
||||||
|
if(file->id == 0) /* No null name files */
|
||||||
|
return SC_ERROR_INVALID_ARGUMENTS;
|
||||||
|
|
||||||
|
muscle_parse_acls(file, &read, &write, &delete);
|
||||||
|
|
||||||
|
mscfs_lookup_local(fs, file->id, (u8*)&objectId);
|
||||||
|
r = msc_create_object(card, objectId, objectSize, read, write, delete);
|
||||||
|
mscfs_clear_cache(fs);
|
||||||
|
if(r >= 0) return 0;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int muscle_read_binary(sc_card_t *card, unsigned int index, u8* buf, size_t count, unsigned long flags)
|
||||||
|
{
|
||||||
|
mscfs_t *fs = MUSCLE_FS(card);
|
||||||
|
int r;
|
||||||
|
u8 objectId[4];
|
||||||
|
mscfs_file_t *file;
|
||||||
|
|
||||||
|
r = mscfs_check_selection(fs, -1);
|
||||||
|
if(r < 0) SC_FUNC_RETURN(card->ctx, 0, r);
|
||||||
|
file = &fs->cache.array[fs->currentFileIndex];
|
||||||
|
memcpy(objectId, file->objectId, 4);
|
||||||
|
if(!file->ef) {
|
||||||
|
objectId[0] = objectId[2];
|
||||||
|
objectId[1] = objectId[3];
|
||||||
|
objectId[2] = objectId[3] = 0;
|
||||||
|
}
|
||||||
|
r = msc_read_object(card, *(int*)objectId, index, buf, count);
|
||||||
|
SC_FUNC_RETURN(card->ctx, 0, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int muscle_update_binary(sc_card_t *card, unsigned int index, const u8* buf, size_t count, unsigned long flags)
|
||||||
|
{
|
||||||
|
mscfs_t *fs = MUSCLE_FS(card);
|
||||||
|
int r;
|
||||||
|
mscfs_file_t *file;
|
||||||
|
u8 objectId[4];
|
||||||
|
|
||||||
|
r = mscfs_check_selection(fs, -1);
|
||||||
|
if(r < 0) SC_FUNC_RETURN(card->ctx, 0, r);
|
||||||
|
file = &fs->cache.array[fs->currentFileIndex];
|
||||||
|
|
||||||
|
memcpy(objectId, file->objectId, 4);
|
||||||
|
if(!file->ef) {
|
||||||
|
objectId[0] = objectId[2];
|
||||||
|
objectId[1] = objectId[3];
|
||||||
|
objectId[2] = objectId[3] = 0;
|
||||||
|
}
|
||||||
|
if(file->size < index + count) {
|
||||||
|
int newFileSize = index + count;
|
||||||
|
u8* buffer = malloc(newFileSize);
|
||||||
|
if(buffer == NULL) SC_FUNC_RETURN(card->ctx, 0, SC_ERROR_OUT_OF_MEMORY);
|
||||||
|
|
||||||
|
r = msc_read_object(card, *(int*)objectId, 0, buffer, file->size);
|
||||||
|
/* TODO: RETREIVE ACLS */
|
||||||
|
if(r < 0) goto update_bin_free_buffer;
|
||||||
|
r = msc_delete_object(card, *(int*)objectId, 0);
|
||||||
|
if(r < 0) goto update_bin_free_buffer;
|
||||||
|
r = msc_create_object(card, *(int*)objectId, newFileSize, 0,0,0);
|
||||||
|
if(r < 0) goto update_bin_free_buffer;
|
||||||
|
memcpy(buffer + index, buf, count);
|
||||||
|
r = msc_update_object(card, *(int*)objectId, 0, buffer, newFileSize);
|
||||||
|
if(r < 0) goto update_bin_free_buffer;
|
||||||
|
file->size = newFileSize;
|
||||||
|
update_bin_free_buffer:
|
||||||
|
free(buffer);
|
||||||
|
SC_FUNC_RETURN(card->ctx, 0, r);
|
||||||
|
} else {
|
||||||
|
r = msc_update_object(card, *(int*)objectId, index, buf, count);
|
||||||
|
}
|
||||||
|
//mscfs_clear_cache(fs);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int muscle_delete_mscfs_file(sc_card_t *card, mscfs_file_t *file_data)
|
||||||
|
{
|
||||||
|
mscfs_t *fs = MUSCLE_FS(card);
|
||||||
|
u8 *id = file_data->objectId;
|
||||||
|
int objectId = *(int*)id;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if(!file_data->ef) {
|
||||||
|
int x;
|
||||||
|
mscfs_file_t *childFile;
|
||||||
|
/* Delete children */
|
||||||
|
mscfs_check_cache(fs);
|
||||||
|
|
||||||
|
if (card->ctx->debug >= 2) {
|
||||||
|
sc_debug(card->ctx, "DELETING Children of: %02X%02X%02X%02X\n",
|
||||||
|
id[0],id[1],id[2],id[3]);
|
||||||
|
}
|
||||||
|
for(x = 0; x < fs->cache.size; x++) {
|
||||||
|
u8 *objectId;
|
||||||
|
childFile = &fs->cache.array[x];
|
||||||
|
objectId = childFile->objectId;
|
||||||
|
|
||||||
|
if(0 == memcmp(id + 2, objectId, 2)) {
|
||||||
|
if (card->ctx->debug >= 2) {
|
||||||
|
sc_debug(card->ctx, "DELETING: %02X%02X%02X%02X\n",
|
||||||
|
objectId[0],objectId[1],objectId[2],objectId[3]);
|
||||||
|
}
|
||||||
|
r = muscle_delete_mscfs_file(card, childFile);
|
||||||
|
if(r < 0) SC_FUNC_RETURN(card->ctx, 2,r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
objectId = objectId >> 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = msc_delete_object(card, objectId, 1);
|
||||||
|
/* Check if its the root... this file generally is virtual
|
||||||
|
* So don't return an error if it fails */
|
||||||
|
if((0 == memcmp(id, "\x3F\x00\x00\x00", 4))
|
||||||
|
|| (0 == memcmp(id, "\x3F\x00\x3F\x00", 4)))
|
||||||
|
return 0;
|
||||||
|
if(r < 0) SC_FUNC_RETURN(card->ctx, 2,r);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int muscle_delete_file(sc_card_t *card, const sc_path_t *path_in)
|
||||||
|
{
|
||||||
|
mscfs_t *fs = MUSCLE_FS(card);
|
||||||
|
mscfs_file_t *file_data = NULL;
|
||||||
|
int r = 0;
|
||||||
|
|
||||||
|
r = mscfs_loadFileInfo(fs, path_in->value, path_in->len, &file_data, NULL);
|
||||||
|
if(r < 0) SC_FUNC_RETURN(card->ctx, 2,r);
|
||||||
|
r = muscle_delete_mscfs_file(card, file_data);
|
||||||
|
mscfs_clear_cache(fs);
|
||||||
|
if(r < 0) SC_FUNC_RETURN(card->ctx, 2,r);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void muscle_load_single_acl(sc_file_t* file, int operation, unsigned short acl)
|
||||||
|
{
|
||||||
|
int key;
|
||||||
|
// Everybody by default....
|
||||||
|
sc_file_add_acl_entry(file, operation, SC_AC_NONE, 0);
|
||||||
|
if(acl == 0xFFFF) {
|
||||||
|
sc_file_add_acl_entry(file, operation, SC_AC_NEVER, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for(key = 0; key < 16; key++) {
|
||||||
|
if(acl >> key & 1) {
|
||||||
|
sc_file_add_acl_entry(file, operation, SC_AC_CHV, key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void muscle_load_file_acls(sc_file_t* file, mscfs_file_t *file_data)
|
||||||
|
{
|
||||||
|
muscle_load_single_acl(file, SC_AC_OP_READ, file_data->read);
|
||||||
|
muscle_load_single_acl(file, SC_AC_OP_WRITE, file_data->write);
|
||||||
|
muscle_load_single_acl(file, SC_AC_OP_UPDATE, file_data->write);
|
||||||
|
muscle_load_single_acl(file, SC_AC_OP_DELETE, file_data->delete);
|
||||||
|
}
|
||||||
|
static void muscle_load_dir_acls(sc_file_t* file, mscfs_file_t *file_data)
|
||||||
|
{
|
||||||
|
muscle_load_single_acl(file, SC_AC_OP_SELECT, 0);
|
||||||
|
muscle_load_single_acl(file, SC_AC_OP_LIST_FILES, 0);
|
||||||
|
muscle_load_single_acl(file, SC_AC_OP_LOCK, 0xFFFF);
|
||||||
|
muscle_load_single_acl(file, SC_AC_OP_DELETE, file_data->delete);
|
||||||
|
muscle_load_single_acl(file, SC_AC_OP_CREATE, file_data->write);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Required type = -1 for don't care, 1 for EF, 0 for DF */
|
||||||
|
static int select_item(sc_card_t *card, const sc_path_t *path_in, sc_file_t ** file_out, int requiredType)
|
||||||
|
{
|
||||||
|
mscfs_t *fs = MUSCLE_FS(card);
|
||||||
|
mscfs_file_t *file_data = NULL;
|
||||||
|
const u8 *path = path_in->value;
|
||||||
|
int pathlen = path_in->len;
|
||||||
|
int r = 0;
|
||||||
|
int objectIndex;
|
||||||
|
|
||||||
|
mscfs_check_cache(fs);
|
||||||
|
r = mscfs_loadFileInfo(fs, path_in->value, path_in->len, &file_data, &objectIndex);
|
||||||
|
if(r < 0) SC_FUNC_RETURN(card->ctx, 2,r);
|
||||||
|
|
||||||
|
/* Check if its the right type */
|
||||||
|
if(requiredType >= 0 && requiredType != file_data->ef) {
|
||||||
|
SC_FUNC_RETURN(card->ctx, 0, SC_ERROR_INVALID_ARGUMENTS);
|
||||||
|
}
|
||||||
|
/* Is it a file or directory */
|
||||||
|
if(file_data->ef) {
|
||||||
|
fs->currentPath[0] = file_data->objectId[0];
|
||||||
|
fs->currentPath[1] = file_data->objectId[1];
|
||||||
|
fs->currentFile[0] = file_data->objectId[2];
|
||||||
|
fs->currentFile[1] = file_data->objectId[3];
|
||||||
|
} else {
|
||||||
|
fs->currentPath[0] = file_data->objectId[pathlen - 2];
|
||||||
|
fs->currentPath[1] = file_data->objectId[pathlen - 1];
|
||||||
|
fs->currentFile[0] = 0;
|
||||||
|
fs->currentFile[1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs->currentFileIndex = objectIndex;
|
||||||
|
if(file_out) {
|
||||||
|
sc_file_t *file;
|
||||||
|
file = sc_file_new();
|
||||||
|
file->path = *path_in;
|
||||||
|
file->size = file_data->size;
|
||||||
|
file->id = (file_data->objectId[2] << 8) | file_data->objectId[3];
|
||||||
|
memcpy(file->name, path, pathlen);
|
||||||
|
file->namelen = pathlen;
|
||||||
|
if(!file_data->ef) {
|
||||||
|
file->type = SC_FILE_TYPE_DF;
|
||||||
|
} else {
|
||||||
|
file->type = SC_FILE_TYPE_WORKING_EF;
|
||||||
|
file->ef_structure = SC_FILE_EF_TRANSPARENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setup ACLS */
|
||||||
|
if(file_data->ef) {
|
||||||
|
muscle_load_file_acls(file, file_data);
|
||||||
|
} else {
|
||||||
|
muscle_load_dir_acls(file, file_data);
|
||||||
|
/* Setup directory acls... */
|
||||||
|
}
|
||||||
|
|
||||||
|
file->magic = SC_FILE_MAGIC;
|
||||||
|
*file_out = file;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int muscle_select_file(sc_card_t *card, const sc_path_t *path_in,
|
||||||
|
sc_file_t **file_out)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(card != NULL && path_in != NULL);
|
||||||
|
|
||||||
|
switch (path_in->type) {
|
||||||
|
case SC_PATH_TYPE_FILE_ID:
|
||||||
|
r = select_item(card, path_in, file_out, 1);
|
||||||
|
break;
|
||||||
|
case SC_PATH_TYPE_DF_NAME:
|
||||||
|
r = select_item(card, path_in, file_out, 0);
|
||||||
|
break;
|
||||||
|
case SC_PATH_TYPE_PATH:
|
||||||
|
r = select_item(card, path_in, file_out, -1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_INVALID_ARGUMENTS);
|
||||||
|
}
|
||||||
|
if(r > 0) r = 0;
|
||||||
|
SC_FUNC_RETURN(card->ctx, 2,r);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _listFile(mscfs_file_t *file, int reset, void *udata)
|
||||||
|
{
|
||||||
|
int next = reset ? 0x00 : 0x01;
|
||||||
|
return msc_list_objects( (sc_card_t*)udata, next, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int muscle_init(sc_card_t *card)
|
||||||
|
{
|
||||||
|
int r = 0;
|
||||||
|
muscle_private_t *priv;
|
||||||
|
|
||||||
|
card->name = "Muscle Card";
|
||||||
|
card->drv_data = malloc(sizeof(muscle_private_t));
|
||||||
|
if(!card->drv_data) {
|
||||||
|
SC_FUNC_RETURN(card->ctx, 0, SC_ERROR_OUT_OF_MEMORY);
|
||||||
|
}
|
||||||
|
memset(card->drv_data, 0, sizeof(muscle_private_t));
|
||||||
|
priv = MUSCLE_DATA(card);
|
||||||
|
priv->verifiedPins = 0;
|
||||||
|
priv->fs = mscfs_new();
|
||||||
|
if(!priv->fs) {
|
||||||
|
free(card->drv_data);
|
||||||
|
SC_FUNC_RETURN(card->ctx, 0, SC_ERROR_OUT_OF_MEMORY);
|
||||||
|
}
|
||||||
|
priv->fs->udata = card;
|
||||||
|
priv->fs->listFile = _listFile;
|
||||||
|
//r = autodetect_class(card);
|
||||||
|
card->cla = 0xB0;
|
||||||
|
if (r) {
|
||||||
|
sc_error(card->ctx, "unable to determine the right class byte\n");
|
||||||
|
return SC_ERROR_INVALID_CARD;
|
||||||
|
}
|
||||||
|
card->flags |= SC_CARD_FLAG_ONBOARD_KEY_GEN;
|
||||||
|
card->flags |= SC_CARD_FLAG_RNG;
|
||||||
|
card->caps |= SC_CARD_CAP_RNG;
|
||||||
|
/* FIXME: Card type detection */
|
||||||
|
if (1) {
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
flags = SC_ALGORITHM_RSA_RAW;
|
||||||
|
flags |= SC_ALGORITHM_RSA_HASH_NONE;
|
||||||
|
flags |= SC_ALGORITHM_ONBOARD_KEY_GEN;
|
||||||
|
|
||||||
|
_sc_card_add_rsa_alg(card, 512, flags, 0);
|
||||||
|
_sc_card_add_rsa_alg(card, 768, flags, 0);
|
||||||
|
_sc_card_add_rsa_alg(card, 1024, flags, 0);
|
||||||
|
_sc_card_add_rsa_alg(card, 2048, flags, 0);
|
||||||
|
}
|
||||||
|
card->max_recv_size = 1024 * 64;
|
||||||
|
card->max_send_size = 1024 * 64;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int muscle_list_files(sc_card_t *card, u8 *buf, size_t bufLen)
|
||||||
|
{
|
||||||
|
muscle_private_t* priv = MUSCLE_DATA(card);
|
||||||
|
mscfs_t *fs = priv->fs;
|
||||||
|
int x;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
mscfs_check_cache(priv->fs);
|
||||||
|
|
||||||
|
for(x = 0; x < fs->cache.size; x++) {
|
||||||
|
u8 *objectId;
|
||||||
|
objectId = fs->cache.array[x].objectId;
|
||||||
|
if (card->ctx->debug >= 2) {
|
||||||
|
sc_debug(card->ctx, "FILE: %02X%02X%02X%02X\n",
|
||||||
|
objectId[0],objectId[1],objectId[2],objectId[3]);
|
||||||
|
}
|
||||||
|
if(0 == memcmp(fs->currentPath, objectId, 2)) {
|
||||||
|
buf[0] = objectId[2];
|
||||||
|
buf[1] = objectId[3];
|
||||||
|
if(buf[0] == 0x00 && buf[1] == 0x00) continue; /* No directories/null names outside of root */
|
||||||
|
buf += 2;
|
||||||
|
count+=2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int (*iso_pin_cmd)(struct sc_card *, struct sc_pin_cmd_data *,
|
||||||
|
int *tries_left);
|
||||||
|
|
||||||
|
static int muscle_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *cmd,
|
||||||
|
int *tries_left)
|
||||||
|
{
|
||||||
|
muscle_private_t* priv = MUSCLE_DATA(card);
|
||||||
|
switch(cmd->cmd) {
|
||||||
|
case SC_PIN_CMD_VERIFY:
|
||||||
|
switch(cmd->pin_type) {
|
||||||
|
case SC_AC_CHV: {
|
||||||
|
sc_apdu_t apdu;
|
||||||
|
int r;
|
||||||
|
msc_verify_pin_apdu(card, &apdu, cmd->pin_reference, cmd->pin1.data, cmd->pin1.len);
|
||||||
|
cmd->apdu = &apdu;
|
||||||
|
cmd->pin1.offset = 5;
|
||||||
|
r = iso_pin_cmd(card, cmd, tries_left);
|
||||||
|
if(r >= 0)
|
||||||
|
priv->verifiedPins |= (1 << cmd->pin_reference);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
case SC_AC_TERM:
|
||||||
|
case SC_AC_PRO:
|
||||||
|
case SC_AC_AUT:
|
||||||
|
case SC_AC_NONE:
|
||||||
|
default:
|
||||||
|
sc_error(card->ctx, "Unsupported authentication method\n");
|
||||||
|
return SC_ERROR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
case SC_PIN_CMD_CHANGE:
|
||||||
|
switch(cmd->pin_type) {
|
||||||
|
case SC_AC_CHV: {
|
||||||
|
sc_apdu_t apdu;
|
||||||
|
msc_change_pin_apdu(card, &apdu, cmd->pin_reference, cmd->pin1.data, cmd->pin1.len, cmd->pin2.data, cmd->pin2.len);
|
||||||
|
cmd->apdu = &apdu;
|
||||||
|
return iso_pin_cmd(card, cmd, tries_left);
|
||||||
|
}
|
||||||
|
case SC_AC_TERM:
|
||||||
|
case SC_AC_PRO:
|
||||||
|
case SC_AC_AUT:
|
||||||
|
case SC_AC_NONE:
|
||||||
|
default:
|
||||||
|
sc_error(card->ctx, "Unsupported authentication method\n");
|
||||||
|
return SC_ERROR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
case SC_PIN_CMD_UNBLOCK:
|
||||||
|
switch(cmd->pin_type) {
|
||||||
|
case SC_AC_CHV: {
|
||||||
|
sc_apdu_t apdu;
|
||||||
|
msc_unblock_pin_apdu(card, &apdu, cmd->pin_reference, cmd->pin1.data, cmd->pin1.len);
|
||||||
|
cmd->apdu = &apdu;
|
||||||
|
return iso_pin_cmd(card, cmd, tries_left);
|
||||||
|
}
|
||||||
|
case SC_AC_TERM:
|
||||||
|
case SC_AC_PRO:
|
||||||
|
case SC_AC_AUT:
|
||||||
|
case SC_AC_NONE:
|
||||||
|
default:
|
||||||
|
sc_error(card->ctx, "Unsupported authentication method\n");
|
||||||
|
return SC_ERROR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
sc_error(card->ctx, "Unsupported command\n");
|
||||||
|
return SC_ERROR_NOT_SUPPORTED;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int muscle_card_extract_key(sc_card_t *card, sc_cardctl_muscle_key_info_t *info)
|
||||||
|
{
|
||||||
|
/* CURRENTLY DONT SUPPOT EXTRACTING PRIVATE KEYS... */
|
||||||
|
switch(info->keyType) {
|
||||||
|
case 1: // RSA
|
||||||
|
return msc_extract_rsa_public_key(card,
|
||||||
|
info->keyLocation,
|
||||||
|
&info->modLength,
|
||||||
|
&info->modValue,
|
||||||
|
&info->expLength,
|
||||||
|
&info->expValue);
|
||||||
|
default:
|
||||||
|
return SC_ERROR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int muscle_card_import_key(sc_card_t *card, sc_cardctl_muscle_key_info_t *info)
|
||||||
|
{
|
||||||
|
/* CURRENTLY DONT SUPPOT EXTRACTING PRIVATE KEYS... */
|
||||||
|
switch(info->keyType) {
|
||||||
|
case 0x02: // RSA_PRIVATE
|
||||||
|
case 0x03: // RSA_PRIVATE_CRT
|
||||||
|
return msc_import_key(card,
|
||||||
|
info->keyLocation,
|
||||||
|
info);
|
||||||
|
default:
|
||||||
|
return SC_ERROR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int muscle_card_generate_key(sc_card_t *card, sc_cardctl_muscle_gen_key_info_t *info)
|
||||||
|
{
|
||||||
|
return msc_generate_keypair(card,
|
||||||
|
info->privateKeyLocation,
|
||||||
|
info->publicKeyLocation,
|
||||||
|
info->keyType,
|
||||||
|
info->keySize,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int muscle_card_verified_pins(sc_card_t *card, sc_cardctl_muscle_verified_pins_info_t *info)
|
||||||
|
{
|
||||||
|
muscle_private_t* priv = MUSCLE_DATA(card);
|
||||||
|
info->verifiedPins = priv->verifiedPins;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static int muscle_card_ctl(sc_card_t *card, unsigned long request, void *data)
|
||||||
|
{
|
||||||
|
switch(request) {
|
||||||
|
case SC_CARDCTL_MUSCLE_GENERATE_KEY:
|
||||||
|
return muscle_card_generate_key(card, (sc_cardctl_muscle_gen_key_info_t*) data);
|
||||||
|
case SC_CARDCTL_MUSCLE_EXTRACT_KEY:
|
||||||
|
return muscle_card_extract_key(card, (sc_cardctl_muscle_key_info_t*) data);
|
||||||
|
case SC_CARDCTL_MUSCLE_IMPORT_KEY:
|
||||||
|
return muscle_card_import_key(card, (sc_cardctl_muscle_key_info_t*) data);
|
||||||
|
case SC_CARDCTL_MUSCLE_VERIFIED_PINS:
|
||||||
|
return muscle_card_verified_pins(card, (sc_cardctl_muscle_verified_pins_info_t*) data);
|
||||||
|
default:
|
||||||
|
return SC_ERROR_NOT_SUPPORTED; /* Unsupported.. whatever it is */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int muscle_set_security_env(sc_card_t *card,
|
||||||
|
const sc_security_env_t *env,
|
||||||
|
int se_num)
|
||||||
|
{
|
||||||
|
muscle_private_t* priv = MUSCLE_DATA(card);
|
||||||
|
|
||||||
|
if (env->operation != SC_SEC_OPERATION_SIGN &&
|
||||||
|
env->operation != SC_SEC_OPERATION_DECIPHER) {
|
||||||
|
sc_error(card->ctx, "Invalid crypto operation supplied.\n");
|
||||||
|
return SC_ERROR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
if (env->algorithm != SC_ALGORITHM_RSA) {
|
||||||
|
sc_error(card->ctx, "Invalid crypto algorithm supplied.\n");
|
||||||
|
return SC_ERROR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
/* ADJUST FOR PKCS1 padding support for decryption only */
|
||||||
|
if ((env->algorithm_flags & SC_ALGORITHM_RSA_PADS) ||
|
||||||
|
(env->algorithm_flags & SC_ALGORITHM_RSA_HASHES)) {
|
||||||
|
sc_error(card->ctx, "Card supports only raw RSA.\n");
|
||||||
|
return SC_ERROR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT) {
|
||||||
|
if (env->key_ref_len != 1 ||
|
||||||
|
(env->key_ref[0] > 0x0F)) {
|
||||||
|
sc_error(card->ctx, "Invalid key reference supplied.\n");
|
||||||
|
return SC_ERROR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
priv->rsa_key_ref = env->key_ref[0];
|
||||||
|
}
|
||||||
|
if (env->flags & SC_SEC_ENV_ALG_REF_PRESENT) {
|
||||||
|
sc_error(card->ctx, "Algorithm reference not supported.\n");
|
||||||
|
return SC_ERROR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
//if (env->flags & SC_SEC_ENV_FILE_REF_PRESENT)
|
||||||
|
// if (memcmp(env->file_ref.value, "\x00\x12", 2) != 0) {
|
||||||
|
// sc_error(card->ctx, "File reference is not 0012.\n");
|
||||||
|
// return SC_ERROR_NOT_SUPPORTED;
|
||||||
|
// }
|
||||||
|
priv->env = *env;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int muscle_restore_security_env(sc_card_t *card, int se_num)
|
||||||
|
{
|
||||||
|
muscle_private_t* priv = MUSCLE_DATA(card);
|
||||||
|
memset(&priv->env, 0, sizeof(priv->env));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int muscle_decipher(sc_card_t * card,
|
||||||
|
const u8 * crgram, size_t crgram_len, u8 * out,
|
||||||
|
size_t out_len)
|
||||||
|
{
|
||||||
|
muscle_private_t* priv = MUSCLE_DATA(card);
|
||||||
|
|
||||||
|
u8 key_id;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
/* saniti check */
|
||||||
|
if (priv->env.operation != SC_SEC_OPERATION_DECIPHER)
|
||||||
|
return SC_ERROR_INVALID_ARGUMENTS;
|
||||||
|
|
||||||
|
key_id = priv->rsa_key_ref * 2; /* Private key */
|
||||||
|
|
||||||
|
if (out_len < crgram_len) {
|
||||||
|
sc_error(card->ctx, "Output buffer too small");
|
||||||
|
return SC_ERROR_BUFFER_TOO_SMALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = msc_compute_crypt(card,
|
||||||
|
key_id,
|
||||||
|
0x00, /* RSA NO PADDING */
|
||||||
|
0x04, /* decrypt */
|
||||||
|
crgram,
|
||||||
|
out,
|
||||||
|
crgram_len,
|
||||||
|
out_len);
|
||||||
|
SC_TEST_RET(card->ctx, r, "Card signature failed");
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int muscle_compute_signature(sc_card_t *card, const u8 *data,
|
||||||
|
size_t data_len, u8 * out, size_t outlen)
|
||||||
|
{
|
||||||
|
muscle_private_t* priv = MUSCLE_DATA(card);
|
||||||
|
u8 key_id;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
key_id = priv->rsa_key_ref * 2; /* Private key */
|
||||||
|
|
||||||
|
if (outlen < data_len) {
|
||||||
|
sc_error(card->ctx, "Output buffer too small");
|
||||||
|
return SC_ERROR_BUFFER_TOO_SMALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = msc_compute_crypt(card,
|
||||||
|
key_id,
|
||||||
|
0x00, /* RSA NO PADDING */
|
||||||
|
0x04, /* -- decrypt raw... will do what we need since signing isn't yet supported */
|
||||||
|
data,
|
||||||
|
out,
|
||||||
|
data_len,
|
||||||
|
outlen);
|
||||||
|
SC_TEST_RET(card->ctx, r, "Card signature failed");
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int muscle_get_challenge(sc_card_t *card, u8 *rnd, size_t len)
|
||||||
|
{
|
||||||
|
return msc_get_challenge(card, len, 0, NULL, rnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int muscle_logout(sc_card_t *card)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct sc_card_driver * sc_get_driver(void)
|
||||||
|
{
|
||||||
|
struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
|
||||||
|
|
||||||
|
muscle_ops = *iso_drv->ops;
|
||||||
|
iso_pin_cmd = iso_drv->ops->pin_cmd;
|
||||||
|
muscle_ops.check_sw = iso_drv->ops->check_sw;
|
||||||
|
muscle_ops.pin_cmd = muscle_pin_cmd;
|
||||||
|
muscle_ops.get_response = iso_drv->ops->get_response;
|
||||||
|
muscle_ops.match_card = muscle_match_card;
|
||||||
|
muscle_ops.init = muscle_init;
|
||||||
|
muscle_ops.finish = muscle_finish;
|
||||||
|
muscle_ops.logout = muscle_logout;
|
||||||
|
|
||||||
|
muscle_ops.get_challenge = muscle_get_challenge;
|
||||||
|
|
||||||
|
muscle_ops.set_security_env = muscle_set_security_env;
|
||||||
|
muscle_ops.restore_security_env = muscle_restore_security_env;
|
||||||
|
muscle_ops.compute_signature = muscle_compute_signature;
|
||||||
|
muscle_ops.decipher = muscle_decipher;
|
||||||
|
muscle_ops.card_ctl = muscle_card_ctl;
|
||||||
|
muscle_ops.read_binary = muscle_read_binary;
|
||||||
|
muscle_ops.update_binary = muscle_update_binary;
|
||||||
|
muscle_ops.create_file = muscle_create_file;
|
||||||
|
muscle_ops.select_file = muscle_select_file;
|
||||||
|
muscle_ops.delete_file = muscle_delete_file;
|
||||||
|
muscle_ops.list_files = muscle_list_files;
|
||||||
|
|
||||||
|
return &muscle_drv;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
struct sc_card_driver * sc_get_muscle_driver(void)
|
||||||
|
{
|
||||||
|
return sc_get_driver();
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -188,6 +188,8 @@ int sc_connect_card(sc_reader_t *reader, int slot_id, sc_card_t **card_out)
|
||||||
sc_debug(ctx, "trying driver: %s\n", drv->short_name);
|
sc_debug(ctx, "trying driver: %s\n", drv->short_name);
|
||||||
if (ops == NULL || ops->match_card == NULL)
|
if (ops == NULL || ops->match_card == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
/* Needed if match_card() needs to talk with the card (e.g. card-muscle) */
|
||||||
|
*card->ops = *ops;
|
||||||
if (ops->match_card(card) != 1)
|
if (ops->match_card(card) != 1)
|
||||||
continue;
|
continue;
|
||||||
if (ctx->debug >= 3)
|
if (ctx->debug >= 3)
|
||||||
|
|
|
@ -121,7 +121,16 @@ enum {
|
||||||
SC_CARDCTL_INCRYPTO34_PUT_DATA_SECI,
|
SC_CARDCTL_INCRYPTO34_PUT_DATA_SECI,
|
||||||
SC_CARDCTL_INCRYPTO34_GENERATE_KEY,
|
SC_CARDCTL_INCRYPTO34_GENERATE_KEY,
|
||||||
SC_CARDCTL_INCRYPTO34_CHANGE_KEY_DATA,
|
SC_CARDCTL_INCRYPTO34_CHANGE_KEY_DATA,
|
||||||
SC_CARDCTL_INCRYPTO34_ERASE_FILES
|
SC_CARDCTL_INCRYPTO34_ERASE_FILES,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Muscle specific calls
|
||||||
|
*/
|
||||||
|
SC_CARDCTL_MUSCLE_BASE = _CTL_PREFIX('M','S','C'),
|
||||||
|
SC_CARDCTL_MUSCLE_GENERATE_KEY,
|
||||||
|
SC_CARDCTL_MUSCLE_EXTRACT_KEY,
|
||||||
|
SC_CARDCTL_MUSCLE_IMPORT_KEY,
|
||||||
|
SC_CARDCTL_MUSCLE_VERIFIED_PINS
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -347,6 +356,44 @@ struct sc_cardctl_setcos_gen_store_key_info {
|
||||||
unsigned char *primeq;
|
unsigned char *primeq;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Muscle stuff
|
||||||
|
*/
|
||||||
|
typedef struct sc_cardctl_muscle_gen_key_info {
|
||||||
|
int keyType;
|
||||||
|
int keySize;
|
||||||
|
int privateKeyLocation;
|
||||||
|
int publicKeyLocation;
|
||||||
|
} sc_cardctl_muscle_gen_key_info_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct sc_cardctl_muscle_key_info {
|
||||||
|
int keyType;
|
||||||
|
int keyLocation;
|
||||||
|
int keySize;
|
||||||
|
int modLength;
|
||||||
|
u8* modValue;
|
||||||
|
int expLength;
|
||||||
|
u8* expValue;
|
||||||
|
int pLength;
|
||||||
|
u8* pValue;
|
||||||
|
int qLength;
|
||||||
|
u8* qValue;
|
||||||
|
int pqLength;
|
||||||
|
u8* pqValue;
|
||||||
|
int dp1Length;
|
||||||
|
u8* dp1Value;
|
||||||
|
int dq1Length;
|
||||||
|
u8* dq1Value;
|
||||||
|
int gLength;
|
||||||
|
u8* gValue;
|
||||||
|
int yLength;
|
||||||
|
u8* yValue;
|
||||||
|
} sc_cardctl_muscle_key_info_t;
|
||||||
|
|
||||||
|
typedef struct sc_cardctl_muscle_verified_pins_info {
|
||||||
|
unsigned verifiedPins;
|
||||||
|
} sc_cardctl_muscle_verified_pins_info_t;
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -114,7 +114,11 @@ enum {
|
||||||
|
|
||||||
/* PIV-II type cards */
|
/* PIV-II type cards */
|
||||||
SC_CARD_TYPE_PIV_II_BASE = 14000,
|
SC_CARD_TYPE_PIV_II_BASE = 14000,
|
||||||
SC_CARD_TYPE_PIV_II_GENERIC
|
SC_CARD_TYPE_PIV_II_GENERIC,
|
||||||
|
|
||||||
|
/* Muscle cards */
|
||||||
|
SC_CARD_TYPE_MUSCLE_BASE = 15000,
|
||||||
|
SC_CARD_TYPE_MUSCLE_GENERIC
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -70,6 +70,7 @@ static const struct _sc_driver_entry internal_card_drivers[] = {
|
||||||
#endif
|
#endif
|
||||||
{ "belpic", (void *(*)(void)) sc_get_belpic_driver },
|
{ "belpic", (void *(*)(void)) sc_get_belpic_driver },
|
||||||
{ "atrust-acos",(void *(*)(void))sc_get_atrust_acos_driver },
|
{ "atrust-acos",(void *(*)(void))sc_get_atrust_acos_driver },
|
||||||
|
{ "muscle", (void *(*)(void)) sc_get_muscle_driver }, // Above EMV because the detection gets caught there first
|
||||||
{ "emv", (void *(*)(void)) sc_get_emv_driver },
|
{ "emv", (void *(*)(void)) sc_get_emv_driver },
|
||||||
{ "incrypto34", (void *(*)(void)) sc_get_incrypto34_driver },
|
{ "incrypto34", (void *(*)(void)) sc_get_incrypto34_driver },
|
||||||
#ifdef HAVE_OPENSSL
|
#ifdef HAVE_OPENSSL
|
||||||
|
|
|
@ -0,0 +1,237 @@
|
||||||
|
/*
|
||||||
|
* muscle-filesystem.c: Support for MuscleCard Applet from musclecard.com
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006, Identity Alliance, Thomas Harning <support@identityalliance.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "muscle-filesystem.h"
|
||||||
|
#include <opensc/errors.h>
|
||||||
|
#include <memory.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#define MSCFS_NO_MEMORY SC_ERROR_OUT_OF_MEMORY
|
||||||
|
#define MSCFS_INVALID_ARGS SC_ERROR_INVALID_ARGUMENTS
|
||||||
|
#define MSCFS_FILE_NOT_FOUND SC_ERROR_FILE_NOT_FOUND
|
||||||
|
#define MSCFS_CACHE_INCREMENT 128
|
||||||
|
|
||||||
|
|
||||||
|
static u8* ignoredFiles[] = {
|
||||||
|
"l0\0\0",
|
||||||
|
"L0\0\0",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
mscfs_t *mscfs_new() {
|
||||||
|
mscfs_t *fs = (mscfs_t*)malloc(sizeof(mscfs_t));
|
||||||
|
memset(fs, 0, sizeof(mscfs_t));
|
||||||
|
memcpy(fs->currentPath, "\x3F\x00", 2);
|
||||||
|
return fs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mscfs_free(mscfs_t *fs) {
|
||||||
|
mscfs_clear_cache(fs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mscfs_clear_cache(mscfs_t* fs) {
|
||||||
|
if(!fs->cache.array) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
free(fs->cache.array);
|
||||||
|
fs->cache.array = NULL;
|
||||||
|
fs->cache.totalSize = 0;
|
||||||
|
fs->cache.size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mscfs_is_ignored(mscfs_t* fs, u8* objectId)
|
||||||
|
{
|
||||||
|
int ignored = 0;
|
||||||
|
u8** ptr = ignoredFiles;
|
||||||
|
while(ptr && *ptr && !ignored) {
|
||||||
|
if(0 == memcmp(objectId, *ptr, 4))
|
||||||
|
ignored = 1;
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
return ignored;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mscfs_push_file(mscfs_t* fs, mscfs_file_t *file)
|
||||||
|
{
|
||||||
|
mscfs_cache_t *cache = &fs->cache;
|
||||||
|
if(!cache->array || cache->size == cache->totalSize) {
|
||||||
|
int length = cache->totalSize + MSCFS_CACHE_INCREMENT;
|
||||||
|
mscfs_file_t *oldArray;
|
||||||
|
cache->totalSize = length;
|
||||||
|
oldArray = cache->array;
|
||||||
|
cache->array = malloc(sizeof(mscfs_file_t) * length);
|
||||||
|
if(!cache->array)
|
||||||
|
return MSCFS_NO_MEMORY;
|
||||||
|
if(oldArray) {
|
||||||
|
memcpy(cache->array, oldArray, sizeof(mscfs_file_t) * cache->size);
|
||||||
|
free(oldArray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cache->array[cache->size] = *file;
|
||||||
|
cache->size++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mscfs_update_cache(mscfs_t* fs) {
|
||||||
|
mscfs_file_t file;
|
||||||
|
int r;
|
||||||
|
mscfs_clear_cache(fs);
|
||||||
|
r = fs->listFile(&file, 1, fs->udata);
|
||||||
|
if(r == 0)
|
||||||
|
return 0;
|
||||||
|
else if(r < 0)
|
||||||
|
return r;
|
||||||
|
while(1) {
|
||||||
|
if(!mscfs_is_ignored(fs, file.objectId)) {
|
||||||
|
/* Check if its a directory in the root */
|
||||||
|
if(file.objectId[2] == 0 && file.objectId[3] == 0) {
|
||||||
|
file.objectId[2] = file.objectId[0];
|
||||||
|
file.objectId[3] = file.objectId[1];
|
||||||
|
file.objectId[0] = 0x3F;
|
||||||
|
file.objectId[1] = 0x00;
|
||||||
|
file.ef = 0;
|
||||||
|
} else {
|
||||||
|
file.ef = 1; /* File is a working elementary file */
|
||||||
|
}
|
||||||
|
|
||||||
|
mscfs_push_file(fs, &file);
|
||||||
|
}
|
||||||
|
r = fs->listFile(&file, 0, fs->udata);
|
||||||
|
if(r == 0)
|
||||||
|
break;
|
||||||
|
else if(r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
return fs->cache.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mscfs_check_cache(mscfs_t* fs)
|
||||||
|
{
|
||||||
|
if(!fs->cache.array) {
|
||||||
|
mscfs_update_cache(fs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int mscfs_lookup_path(mscfs_t* fs, const u8 *path, int pathlen, u8 objectId[4], int isDirectory)
|
||||||
|
{
|
||||||
|
if ((pathlen & 1) != 0) /* not divisble by 2 */
|
||||||
|
return MSCFS_INVALID_ARGS;
|
||||||
|
if(isDirectory) {
|
||||||
|
/* Directory must be right next to root */
|
||||||
|
if((0 == memcmp(path, "\x3F\x00", 2) && pathlen == 4)
|
||||||
|
|| (0 == memcmp(fs->currentPath, "\x3F\x00", 2) && pathlen == 2)) {
|
||||||
|
objectId[0] = path[pathlen - 2];
|
||||||
|
objectId[1] = path[pathlen - 1];
|
||||||
|
objectId[2] = objectId[3] = 0;
|
||||||
|
} else {
|
||||||
|
return MSCFS_INVALID_ARGS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
objectId[0] = fs->currentPath[0];
|
||||||
|
objectId[1] = fs->currentPath[1];
|
||||||
|
/* Chop off the root in the path */
|
||||||
|
if(pathlen > 2 && memcmp(path, "\x3F\x00", 2) == 0) {
|
||||||
|
path += 2;
|
||||||
|
pathlen -= 2;
|
||||||
|
objectId[0] = 0x3F;
|
||||||
|
objectId[1] = 0x00;
|
||||||
|
}
|
||||||
|
/* Limit to a single directory */
|
||||||
|
if(pathlen > 4)
|
||||||
|
return MSCFS_INVALID_ARGS;
|
||||||
|
/* Reset to root */
|
||||||
|
if(0 == memcmp(path, "\x3F\x00", 2) && pathlen == 2) {
|
||||||
|
objectId[0] = objectId[2] = path[0];
|
||||||
|
objectId[1] = objectId[3] = path[1];
|
||||||
|
} else if(pathlen == 2) { /* Path preserved for current-path */
|
||||||
|
objectId[2] = path[0];
|
||||||
|
objectId[3] = path[1];
|
||||||
|
} else if(pathlen == 4) {
|
||||||
|
objectId[0] = path[0];
|
||||||
|
objectId[1] = path[1];
|
||||||
|
objectId[2] = path[2];
|
||||||
|
objectId[3] = path[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mscfs_lookup_local(mscfs_t* fs, const int id, u8 objectId[4])
|
||||||
|
{
|
||||||
|
objectId[0] = fs->currentPath[0];
|
||||||
|
objectId[1] = fs->currentPath[1];
|
||||||
|
objectId[2] = (id >> 8) & 0xFF;
|
||||||
|
objectId[3] = id & 0xFF;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -1 any, 0 DF, 1 EF */
|
||||||
|
int mscfs_check_selection(mscfs_t *fs, int requiredItem)
|
||||||
|
{
|
||||||
|
if(fs->currentPath[0] == 0 && fs->currentPath[1] == 0)
|
||||||
|
return MSCFS_INVALID_ARGS;
|
||||||
|
if(requiredItem == 1 && fs->currentFile[0] == 0 && fs->currentFile[1] == 0)
|
||||||
|
return MSCFS_INVALID_ARGS;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mscfs_loadFileInfo(mscfs_t* fs, const u8 *path, int pathlen, mscfs_file_t **file_data, int* index)
|
||||||
|
{
|
||||||
|
u8 fullPath[4];
|
||||||
|
int x;
|
||||||
|
assert(fs != NULL && path != NULL && file_data != NULL);
|
||||||
|
mscfs_lookup_path(fs, path, pathlen, fullPath, 0);
|
||||||
|
|
||||||
|
/* Obtain file information while checking if it exists */
|
||||||
|
mscfs_check_cache(fs);
|
||||||
|
if(index) *index = -1;
|
||||||
|
for(x = 0; x < fs->cache.size; x++) {
|
||||||
|
u8 *objectId;
|
||||||
|
*file_data = &fs->cache.array[x];
|
||||||
|
objectId = (*file_data)->objectId;
|
||||||
|
if(0 == memcmp(objectId, fullPath, 4)) {
|
||||||
|
if(index) *index = x;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*file_data = NULL;
|
||||||
|
}
|
||||||
|
if(*file_data == NULL && (0 == memcmp("\x3F\x00\x00\x00", fullPath, 4) || 0 == memcmp("\x3F\x00\x3F\x00", fullPath, 4 ))) {
|
||||||
|
static mscfs_file_t ROOT_FILE;
|
||||||
|
ROOT_FILE.ef = 0;
|
||||||
|
ROOT_FILE.size = 0;
|
||||||
|
/* Faked Root ID */
|
||||||
|
ROOT_FILE.objectId[0] = 0x3F;
|
||||||
|
ROOT_FILE.objectId[1] = 0x00;
|
||||||
|
ROOT_FILE.objectId[2] = 0x3F;
|
||||||
|
ROOT_FILE.objectId[3] = 0x00;
|
||||||
|
|
||||||
|
ROOT_FILE.read = 0;
|
||||||
|
ROOT_FILE.write = 0x02; /* User Pin access */
|
||||||
|
ROOT_FILE.delete = 0x02;
|
||||||
|
|
||||||
|
*file_data = &ROOT_FILE;
|
||||||
|
if(index) *index = -2;
|
||||||
|
} else if(*file_data == NULL) {
|
||||||
|
return MSCFS_FILE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* muscle-filesystem.h: Support for MuscleCard Applet from musclecard.com
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006, Identity Alliance, Thomas Harning <support@identityalliance.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MUSCLE_FILESYSTEM_H
|
||||||
|
#define MUSCLE_FILESYSTEM_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <opensc/types.h>
|
||||||
|
|
||||||
|
typedef struct mscfs_file {
|
||||||
|
u8 objectId[4];
|
||||||
|
size_t size;
|
||||||
|
unsigned short read, write, delete;
|
||||||
|
int ef;
|
||||||
|
} mscfs_file_t;
|
||||||
|
|
||||||
|
typedef struct mscfs_cache {
|
||||||
|
int size;
|
||||||
|
int totalSize;
|
||||||
|
mscfs_file_t *array;
|
||||||
|
} mscfs_cache_t;
|
||||||
|
|
||||||
|
typedef struct mscsfs {
|
||||||
|
u8 currentFile[2];
|
||||||
|
u8 currentPath[2];
|
||||||
|
int currentFileIndex;
|
||||||
|
mscfs_cache_t cache;
|
||||||
|
void* udata;
|
||||||
|
int (*listFile)(mscfs_file_t *fileOut, int reset, void* udata);
|
||||||
|
} mscfs_t;
|
||||||
|
|
||||||
|
mscfs_t *mscfs_new();
|
||||||
|
void mscfs_free(mscfs_t *fs);
|
||||||
|
void mscfs_clear_cache(mscfs_t* fs);
|
||||||
|
int mscfs_push_file(mscfs_t* fs, mscfs_file_t *file);
|
||||||
|
int mscfs_update_cache(mscfs_t* fs);
|
||||||
|
|
||||||
|
void mscfs_check_cache(mscfs_t* fs);
|
||||||
|
|
||||||
|
int mscfs_lookup_path(mscfs_t* fs, const u8 *path, int pathlen, u8 objectId[4], int
|
||||||
|
isDirectory);
|
||||||
|
|
||||||
|
int mscfs_lookup_local(mscfs_t* fs, const int id, u8 objectId[4]);
|
||||||
|
/* -1 any, 0 DF, 1 EF */
|
||||||
|
int mscfs_check_selection(mscfs_t *fs, int requiredItem);
|
||||||
|
int mscfs_loadFileInfo(mscfs_t* fs, const u8 *path, int pathlen, mscfs_file_t **file_data, int* index);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
* muscle.h: Support for MuscleCard Applet from musclecard.com
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006, Identity Alliance, Thomas Harning <support@identityalliance.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
#ifndef MUSCLE_H_
|
||||||
|
#define MUSCLE_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include <opensc/types.h>
|
||||||
|
#include <opensc.h>
|
||||||
|
#include <opensc/cardctl.h>
|
||||||
|
|
||||||
|
#include "muscle-filesystem.h"
|
||||||
|
|
||||||
|
int msc_list_objects(sc_card_t* card, u8 next, mscfs_file_t* file);
|
||||||
|
int msc_partial_read_object(sc_card_t *card, unsigned int le_objectId, int offset, u8 *data, size_t dataLength);
|
||||||
|
int msc_read_object(sc_card_t *card, unsigned int objectId, int offset, u8 *data, size_t dataLength);
|
||||||
|
int msc_create_object(sc_card_t *card, unsigned int objectId, size_t objectSize, unsigned short read, unsigned short write, unsigned short deletion);
|
||||||
|
int msc_partial_update_object(sc_card_t *card, unsigned int le_objectId, int offset, const u8 *data, size_t dataLength);
|
||||||
|
int msc_update_object(sc_card_t *card, unsigned int objectId, int offset, const u8 *data, size_t dataLength);
|
||||||
|
int msc_zero_object(sc_card_t *card, unsigned int objectId, size_t dataLength);
|
||||||
|
|
||||||
|
int msc_delete_object(sc_card_t *card, unsigned int objectId, int zero);
|
||||||
|
int msc_select_applet(sc_card_t *card, u8 *appletId, size_t appletIdLength);
|
||||||
|
|
||||||
|
int msc_verify_pin(sc_card_t *card, int pinNumber, const u8 *pinValue, int pinLength, int *tries);
|
||||||
|
void msc_verify_pin_apdu(sc_card_t *card, sc_apdu_t *apdu, int pinNumber, const u8 *pinValue, int pinLength);
|
||||||
|
int msc_unblock_pin(sc_card_t *card, int pinNumber, const u8 *pukValue, int pukLength, int *tries);
|
||||||
|
void msc_unblock_pin_apdu(sc_card_t *card, sc_apdu_t *apdu, int pinNumber, const u8 *pukValue, int pukLength);
|
||||||
|
int msc_change_pin(sc_card_t *card, int pinNumber, const u8 *pinValue, int pinLength, const u8 *newPin, int newPinLength, int *tries);
|
||||||
|
void msc_change_pin_apdu(sc_card_t *card, sc_apdu_t *apdu, int pinNumber, const u8 *pinValue, int pinLength, const u8 *newPin, int newPinLength);
|
||||||
|
|
||||||
|
int msc_get_challenge(sc_card_t *card, short dataLength, short seedLength, u8 *seedData, u8* outputData);
|
||||||
|
|
||||||
|
int msc_generate_keypair(sc_card_t *card, int privateKey, int publicKey, int algorithm, int keySize, int options);
|
||||||
|
int msc_extract_rsa_public_key(sc_card_t *card,
|
||||||
|
int keyLocation,
|
||||||
|
int* modLength,
|
||||||
|
u8** modulus,
|
||||||
|
int* expLength,
|
||||||
|
u8** exponent);
|
||||||
|
int msc_extract_key(sc_card_t *card,
|
||||||
|
int keyLocation);
|
||||||
|
int msc_compute_crypt_init(sc_card_t *card,
|
||||||
|
int keyLocation,
|
||||||
|
int cipherMode,
|
||||||
|
int cipherDirection,
|
||||||
|
const u8* initData,
|
||||||
|
u8* outputData,
|
||||||
|
size_t dataLength,
|
||||||
|
size_t* outputDataLength);
|
||||||
|
int msc_compute_crypt_process(
|
||||||
|
sc_card_t *card,
|
||||||
|
int keyLocation,
|
||||||
|
const u8* inputData,
|
||||||
|
u8* outputData,
|
||||||
|
size_t dataLength,
|
||||||
|
size_t* outputDataLength);
|
||||||
|
int msc_compute_crypt_final(
|
||||||
|
sc_card_t *card,
|
||||||
|
int keyLocation,
|
||||||
|
const u8* inputData,
|
||||||
|
u8* outputData,
|
||||||
|
size_t dataLength,
|
||||||
|
size_t* outputDataLength);
|
||||||
|
int msc_compute_crypt(sc_card_t *card,
|
||||||
|
int keyLocation,
|
||||||
|
int cipherMode,
|
||||||
|
int cipherDirection,
|
||||||
|
const u8* data,
|
||||||
|
u8* outputData,
|
||||||
|
size_t dataLength,
|
||||||
|
size_t outputDataLength);
|
||||||
|
int msc_import_key(sc_card_t *card,
|
||||||
|
int keyLocation,
|
||||||
|
sc_cardctl_muscle_key_info_t *data);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /*MUSCLE_H_*/
|
|
@ -1154,6 +1154,7 @@ extern sc_card_driver_t *sc_get_belpic_driver(void);
|
||||||
extern sc_card_driver_t *sc_get_atrust_acos_driver(void);
|
extern sc_card_driver_t *sc_get_atrust_acos_driver(void);
|
||||||
extern sc_card_driver_t *sc_get_incrypto34_driver(void);
|
extern sc_card_driver_t *sc_get_incrypto34_driver(void);
|
||||||
extern sc_card_driver_t *sc_get_piv_driver(void);
|
extern sc_card_driver_t *sc_get_piv_driver(void);
|
||||||
|
extern sc_card_driver_t *sc_get_muscle_driver(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,8 @@ HEADERSDIR = $(TOPDIR)\src\include\opensc
|
||||||
OBJECTS = profile.obj pkcs15-lib.obj keycache.obj \
|
OBJECTS = profile.obj pkcs15-lib.obj keycache.obj \
|
||||||
pkcs15-miocos.obj pkcs15-gpk.obj pkcs15-cflex.obj \
|
pkcs15-miocos.obj pkcs15-gpk.obj pkcs15-cflex.obj \
|
||||||
pkcs15-cardos.obj pkcs15-jcop.obj pkcs15-starcos.obj \
|
pkcs15-cardos.obj pkcs15-jcop.obj pkcs15-starcos.obj \
|
||||||
pkcs15-oberthur.obj pkcs15-setcos.obj pkcs15-incrypto34.obj
|
pkcs15-oberthur.obj pkcs15-setcos.obj pkcs15-incrypto34.obj \
|
||||||
|
pkcs15-muscle.obj
|
||||||
|
|
||||||
all: install-headers $(TARGET)
|
all: install-headers $(TARGET)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,170 @@
|
||||||
|
#
|
||||||
|
# PKCS15 r/w profile for MuscleCards
|
||||||
|
#
|
||||||
|
|
||||||
|
cardinfo {
|
||||||
|
label = "MUSCLE";
|
||||||
|
manufacturer = "Identity Alliance";
|
||||||
|
|
||||||
|
max-pin-length = 8;
|
||||||
|
min-pin-length = 4;
|
||||||
|
pin-encoding = ascii-numeric;
|
||||||
|
|
||||||
|
}
|
||||||
|
option default {
|
||||||
|
macros {
|
||||||
|
protected = *=$PIN, READ=NONE;
|
||||||
|
unprotected = *=NONE;
|
||||||
|
so-pin-flags = local, initialized; #, soPin;
|
||||||
|
so-min-pin-length = 4;
|
||||||
|
so-pin-attempts = 2;
|
||||||
|
so-auth-id = 1;
|
||||||
|
so-puk-attempts = 4;
|
||||||
|
so-min-puk-length = 4;
|
||||||
|
unusedspace-size = 128;
|
||||||
|
odf-size = 256;
|
||||||
|
aodf-size = 256;
|
||||||
|
cdf-size = 512;
|
||||||
|
prkdf-size = 256;
|
||||||
|
pukdf-size = 256;
|
||||||
|
dodf-size = 256;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PIN so-pin {
|
||||||
|
reference = 0;
|
||||||
|
flags = local, initialized;
|
||||||
|
}
|
||||||
|
PIN so-puk {
|
||||||
|
reference = 0;
|
||||||
|
}
|
||||||
|
PIN user-pin {
|
||||||
|
reference = 1;
|
||||||
|
attempts = 3;
|
||||||
|
flags = local, initialized;
|
||||||
|
}
|
||||||
|
PIN user-puk {
|
||||||
|
reference = 1;
|
||||||
|
attempts = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
filesystem {
|
||||||
|
DF MF {
|
||||||
|
path = 3F00;
|
||||||
|
type = DF;
|
||||||
|
acl = *=NONE, ERASE=$PIN;
|
||||||
|
# This is the DIR file
|
||||||
|
EF DIR {
|
||||||
|
type = EF;
|
||||||
|
file-id = 2F00;
|
||||||
|
size = 128;
|
||||||
|
acl = *=$PIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Here comes the application DF
|
||||||
|
DF PKCS15-AppDF {
|
||||||
|
type = DF;
|
||||||
|
file-id = 5015;
|
||||||
|
aid = A0:00:00:00:63:50:4B:43:53:2D:31:35;
|
||||||
|
acl = *=$PIN;
|
||||||
|
size = 1; # NO DATA SHOULD BE STORED DIRECTLY HERE!
|
||||||
|
|
||||||
|
EF PKCS15-ODF {
|
||||||
|
file-id = 5031;
|
||||||
|
size = $odf-size;
|
||||||
|
ACL = $unprotected;
|
||||||
|
}
|
||||||
|
|
||||||
|
EF PKCS15-TokenInfo {
|
||||||
|
file-id = 5032;
|
||||||
|
ACL = $unprotected;
|
||||||
|
size = 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
EF PKCS15-UnusedSpace {
|
||||||
|
file-id = 5033;
|
||||||
|
size = $unusedspace-size;
|
||||||
|
ACL = $unprotected;
|
||||||
|
}
|
||||||
|
|
||||||
|
EF PKCS15-AODF {
|
||||||
|
file-id = 4401;
|
||||||
|
size = $aodf-size;
|
||||||
|
ACL = $protected;
|
||||||
|
}
|
||||||
|
|
||||||
|
EF PKCS15-PrKDF {
|
||||||
|
file-id = 4402;
|
||||||
|
size = $prkdf-size;
|
||||||
|
acl = $protected;
|
||||||
|
}
|
||||||
|
|
||||||
|
EF PKCS15-PuKDF {
|
||||||
|
file-id = 4403;
|
||||||
|
size = $pukdf-size;
|
||||||
|
acl = $protected;
|
||||||
|
}
|
||||||
|
|
||||||
|
EF PKCS15-CDF {
|
||||||
|
file-id = 4404;
|
||||||
|
size = $cdf-size;
|
||||||
|
acl = $protected;
|
||||||
|
}
|
||||||
|
|
||||||
|
EF PKCS15-DODF {
|
||||||
|
file-id = 4405;
|
||||||
|
size = $dodf-size;
|
||||||
|
ACL = $protected;
|
||||||
|
}
|
||||||
|
template key-domain {
|
||||||
|
# This is a dummy entry - pkcs15-init insists that
|
||||||
|
# this is present
|
||||||
|
EF private-key {
|
||||||
|
file-id = FFFF;
|
||||||
|
ACL = *=$PIN, READ=NEVER;
|
||||||
|
}
|
||||||
|
EF public-key {
|
||||||
|
file-id = 3000;
|
||||||
|
structure = transparent;
|
||||||
|
ACL = *=NEVER,
|
||||||
|
READ=NONE,
|
||||||
|
UPDATE=$PIN,
|
||||||
|
ERASE=$PIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Certificate template
|
||||||
|
EF certificate {
|
||||||
|
file-id = 3100;
|
||||||
|
structure = transparent;
|
||||||
|
ACL = *=NEVER,
|
||||||
|
READ=NONE,
|
||||||
|
UPDATE=$PIN,
|
||||||
|
ERASE=$PIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Extractable private keys are stored in transparent EFs.
|
||||||
|
# Encryption of the content is performed by libopensc.
|
||||||
|
EF extractable-key {
|
||||||
|
file-id = 3200;
|
||||||
|
structure = transparent;
|
||||||
|
ACL = *=NEVER,
|
||||||
|
READ=$PIN,
|
||||||
|
UPDATE=$PIN,
|
||||||
|
ERASE=$PIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
# data objects are stored in transparent EFs.
|
||||||
|
EF data {
|
||||||
|
file-id = 3300;
|
||||||
|
structure = transparent;
|
||||||
|
ACL = *=NEVER,
|
||||||
|
READ=NONE,
|
||||||
|
UPDATE=$PIN,
|
||||||
|
ERASE=$PIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -399,6 +399,7 @@ extern struct sc_pkcs15init_operations *sc_pkcs15init_get_starcos_ops(void);
|
||||||
extern struct sc_pkcs15init_operations *sc_pkcs15init_get_oberthur_ops(void);
|
extern struct sc_pkcs15init_operations *sc_pkcs15init_get_oberthur_ops(void);
|
||||||
extern struct sc_pkcs15init_operations *sc_pkcs15init_get_setcos_ops(void);
|
extern struct sc_pkcs15init_operations *sc_pkcs15init_get_setcos_ops(void);
|
||||||
extern struct sc_pkcs15init_operations *sc_pkcs15init_get_incrypto34_ops(void);
|
extern struct sc_pkcs15init_operations *sc_pkcs15init_get_incrypto34_ops(void);
|
||||||
|
extern struct sc_pkcs15init_operations *sc_pkcs15init_get_muscle_ops(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -155,6 +155,7 @@ static struct profile_operations {
|
||||||
{ "oberthur", (void *) sc_pkcs15init_get_oberthur_ops },
|
{ "oberthur", (void *) sc_pkcs15init_get_oberthur_ops },
|
||||||
{ "setcos", (void *) sc_pkcs15init_get_setcos_ops },
|
{ "setcos", (void *) sc_pkcs15init_get_setcos_ops },
|
||||||
{ "incrypto34", (void *) sc_pkcs15init_get_incrypto34_ops },
|
{ "incrypto34", (void *) sc_pkcs15init_get_incrypto34_ops },
|
||||||
|
{ "muscle", (void*) sc_pkcs15init_get_muscle_ops },
|
||||||
{ NULL, NULL },
|
{ NULL, NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,328 @@
|
||||||
|
/*
|
||||||
|
* pkcs15-muscle.c: Support for MuscleCard Applet from musclecard.com
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006, Identity Alliance, Thomas Harning <support@identityalliance.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
#include <opensc/pkcs15.h>
|
||||||
|
#include <opensc/opensc.h>
|
||||||
|
#include <opensc/cardctl.h>
|
||||||
|
#include <opensc/cards.h>
|
||||||
|
#include <opensc/log.h>
|
||||||
|
#include "pkcs15-init.h"
|
||||||
|
#include "profile.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define MUSCLE_KEY_ID_MIN 0x00
|
||||||
|
#define MUSCLE_KEY_ID_MAX 0x0F
|
||||||
|
|
||||||
|
static int muscle_erase_card(sc_profile_t *profile, sc_card_t *card)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
struct sc_file *file;
|
||||||
|
struct sc_path path;
|
||||||
|
memset(&file, 0, sizeof(file));
|
||||||
|
sc_format_path("3F00", &path);
|
||||||
|
if ((r = sc_select_file(card, &path, &file)) < 0)
|
||||||
|
return r;
|
||||||
|
if ((r = sc_pkcs15init_authenticate(profile, card, file, SC_AC_OP_ERASE)) < 0)
|
||||||
|
return r;
|
||||||
|
if ((r = sc_delete_file(card, &path)) < 0)
|
||||||
|
return r;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int muscle_init_card(sc_profile_t *profile, sc_card_t *card)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
muscle_create_dir(sc_profile_t *profile, sc_card_t *card, sc_file_t *df)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
struct sc_file *file;
|
||||||
|
struct sc_path path;
|
||||||
|
memset(&file, 0, sizeof(file));
|
||||||
|
sc_format_path("3F00", &path);
|
||||||
|
if ((r = sc_select_file(card, &path, &file)) < 0)
|
||||||
|
return r;
|
||||||
|
if ((r = sc_pkcs15init_authenticate(profile, card, file, SC_AC_OP_CREATE)) < 0)
|
||||||
|
return r;
|
||||||
|
/* Create the application DF */
|
||||||
|
if ((r = sc_pkcs15init_create_file(profile, card, df)) < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if ((r = sc_select_file(card, &df->path, NULL)) < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
muscle_create_pin(sc_profile_t *profile, sc_card_t *card,
|
||||||
|
sc_file_t *df, sc_pkcs15_object_t *pin_obj,
|
||||||
|
const unsigned char *pin, size_t pin_len,
|
||||||
|
const unsigned char *puk, size_t puk_len)
|
||||||
|
{
|
||||||
|
sc_file_t *file;
|
||||||
|
sc_pkcs15_pin_info_t *pin_info = (sc_pkcs15_pin_info_t *) pin_obj->data;
|
||||||
|
int r;
|
||||||
|
int type;
|
||||||
|
if (pin_info->flags & SC_PKCS15_PIN_FLAG_SO_PIN) {
|
||||||
|
type = SC_PKCS15INIT_SO_PIN;
|
||||||
|
} else {
|
||||||
|
type = SC_PKCS15INIT_USER_PIN;
|
||||||
|
}
|
||||||
|
if ((r = sc_select_file(card, &df->path, &file)) < 0)
|
||||||
|
return r;
|
||||||
|
if ((r = sc_pkcs15init_authenticate(profile, card, file, SC_AC_OP_WRITE)) < 0)
|
||||||
|
return r;
|
||||||
|
sc_keycache_set_pin_name(&df->path,
|
||||||
|
pin_info->reference,
|
||||||
|
type);
|
||||||
|
pin_info->flags &= ~SC_PKCS15_PIN_FLAG_LOCAL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
muscle_select_pin_reference(sc_profile_t *profike, sc_card_t *card,
|
||||||
|
sc_pkcs15_pin_info_t *pin_info)
|
||||||
|
{
|
||||||
|
int preferred;
|
||||||
|
|
||||||
|
if (pin_info->flags & SC_PKCS15_PIN_FLAG_SO_PIN) {
|
||||||
|
preferred = 0;
|
||||||
|
} else {
|
||||||
|
preferred = 1;
|
||||||
|
}
|
||||||
|
if (pin_info->reference <= preferred) {
|
||||||
|
pin_info->reference = preferred;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pin_info->reference > 2)
|
||||||
|
return SC_ERROR_INVALID_ARGUMENTS;
|
||||||
|
|
||||||
|
/* Caller, please select a different PIN reference */
|
||||||
|
return SC_ERROR_INVALID_PIN_REFERENCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Select a key reference
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
muscle_select_key_reference(sc_profile_t *profile, sc_card_t *card,
|
||||||
|
sc_pkcs15_prkey_info_t *key_info)
|
||||||
|
{
|
||||||
|
struct sc_file *df = profile->df_info->file;
|
||||||
|
|
||||||
|
if (key_info->key_reference < MUSCLE_KEY_ID_MIN)
|
||||||
|
key_info->key_reference = MUSCLE_KEY_ID_MIN;
|
||||||
|
if (key_info->key_reference > MUSCLE_KEY_ID_MAX)
|
||||||
|
return SC_ERROR_TOO_MANY_OBJECTS;
|
||||||
|
|
||||||
|
key_info->path = df->path;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a private key object.
|
||||||
|
* This is a no-op.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
muscle_create_key(sc_profile_t *profile, sc_card_t *card,
|
||||||
|
sc_pkcs15_object_t *obj)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Store a private key object.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
muscle_store_key(sc_profile_t *profile, sc_card_t *card,
|
||||||
|
sc_pkcs15_object_t *obj,
|
||||||
|
sc_pkcs15_prkey_t *key)
|
||||||
|
{
|
||||||
|
sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data;
|
||||||
|
sc_file_t* prkf;
|
||||||
|
struct sc_pkcs15_prkey_rsa *rsa;
|
||||||
|
sc_cardctl_muscle_key_info_t info;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) {
|
||||||
|
sc_error(card->ctx, "Muscle supports RSA keys only.");
|
||||||
|
return SC_ERROR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
/* Verification stuff */
|
||||||
|
/* Used for verification AND for obtaining private key acls */
|
||||||
|
r = sc_profile_get_file_by_path(profile, &key_info->path, &prkf);
|
||||||
|
if(!prkf) SC_FUNC_RETURN(card->ctx, 2,SC_ERROR_NOT_SUPPORTED);
|
||||||
|
r = sc_pkcs15init_authenticate(profile, card, prkf, SC_AC_OP_CRYPTO);
|
||||||
|
if (r < 0) {
|
||||||
|
sc_file_free(prkf);
|
||||||
|
SC_FUNC_RETURN(card->ctx, 2,SC_ERROR_NOT_SUPPORTED);
|
||||||
|
}
|
||||||
|
sc_file_free(prkf);
|
||||||
|
r = muscle_select_key_reference(profile, card, key_info);
|
||||||
|
if (r < 0) {
|
||||||
|
SC_FUNC_RETURN(card->ctx, 2,r);
|
||||||
|
}
|
||||||
|
rsa = &key->u.rsa;
|
||||||
|
|
||||||
|
info.keySize = rsa->modulus.len << 3;
|
||||||
|
info.keyType = 0x03; /* CRT type */
|
||||||
|
info.keyLocation = key_info->key_reference * 2; /* Mult by 2 to preserve even/odd keynumber structure */
|
||||||
|
|
||||||
|
info.pLength = rsa->p.len;
|
||||||
|
info.pValue = rsa->p.data;
|
||||||
|
info.qLength = rsa->q.len;
|
||||||
|
info.qValue = rsa->q.data;
|
||||||
|
|
||||||
|
info.pqLength = rsa->iqmp.len;
|
||||||
|
info.pqValue = rsa->iqmp.data;
|
||||||
|
|
||||||
|
info.dp1Length = rsa->dmp1.len;
|
||||||
|
info.dp1Value = rsa->dmp1.data;
|
||||||
|
info.dq1Length = rsa->dmq1.len;
|
||||||
|
info.dq1Value = rsa->dmq1.data;
|
||||||
|
|
||||||
|
r = sc_card_ctl(card, SC_CARDCTL_MUSCLE_IMPORT_KEY, &info);
|
||||||
|
if (r < 0) {
|
||||||
|
sc_error(card->ctx, "Unable to import key");
|
||||||
|
SC_FUNC_RETURN(card->ctx, 2,r);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
muscle_generate_key(sc_profile_t *profile, sc_card_t *card,
|
||||||
|
sc_pkcs15_object_t *obj,
|
||||||
|
sc_pkcs15_pubkey_t *pubkey)
|
||||||
|
{
|
||||||
|
sc_cardctl_muscle_gen_key_info_t args;
|
||||||
|
sc_cardctl_muscle_key_info_t extArgs;
|
||||||
|
sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data;
|
||||||
|
sc_file_t* prkf;
|
||||||
|
unsigned int keybits;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) {
|
||||||
|
sc_error(card->ctx, "Muscle supports only RSA keys (for now).");
|
||||||
|
SC_FUNC_RETURN(card->ctx, 2,SC_ERROR_NOT_SUPPORTED);
|
||||||
|
}
|
||||||
|
keybits = key_info->modulus_length & ~7UL;
|
||||||
|
if (keybits > 2048) {
|
||||||
|
sc_error(card->ctx, "Unable to generate key, max size is %d",
|
||||||
|
2048);
|
||||||
|
SC_FUNC_RETURN(card->ctx, 2,SC_ERROR_INVALID_ARGUMENTS);
|
||||||
|
}
|
||||||
|
/* Verification stuff */
|
||||||
|
/* Used for verification AND for obtaining private key acls */
|
||||||
|
r = sc_profile_get_file_by_path(profile, &key_info->path, &prkf);
|
||||||
|
if(!prkf) SC_FUNC_RETURN(card->ctx, 2,SC_ERROR_NOT_SUPPORTED);
|
||||||
|
r = sc_pkcs15init_authenticate(profile, card, prkf, SC_AC_OP_CRYPTO);
|
||||||
|
if (r < 0) {
|
||||||
|
sc_file_free(prkf);
|
||||||
|
SC_FUNC_RETURN(card->ctx, 2,SC_ERROR_NOT_SUPPORTED);
|
||||||
|
}
|
||||||
|
sc_file_free(prkf);
|
||||||
|
|
||||||
|
/* END VERIFICATION STUFF */
|
||||||
|
|
||||||
|
/* Public key acls... get_file_by_path as well? */
|
||||||
|
|
||||||
|
memset(&args, 0, sizeof(args));
|
||||||
|
args.keyType = 0x01; // RSA forced
|
||||||
|
args.privateKeyLocation = key_info->key_reference * 2;
|
||||||
|
args.publicKeyLocation = key_info->key_reference * 2 + 1;
|
||||||
|
|
||||||
|
args.keySize = keybits;
|
||||||
|
|
||||||
|
r = sc_card_ctl(card, SC_CARDCTL_MUSCLE_GENERATE_KEY, &args);
|
||||||
|
if (r < 0) {
|
||||||
|
sc_error(card->ctx, "Unable to generate key");
|
||||||
|
SC_FUNC_RETURN(card->ctx, 2,r);
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&extArgs, 0, sizeof(extArgs));
|
||||||
|
memset(pubkey, 0, sizeof(*pubkey));
|
||||||
|
|
||||||
|
extArgs.keyType = 0x01;
|
||||||
|
extArgs.keyLocation = args.publicKeyLocation;
|
||||||
|
r = sc_card_ctl(card, SC_CARDCTL_MUSCLE_EXTRACT_KEY, &extArgs);
|
||||||
|
if (r < 0) {
|
||||||
|
sc_error(card->ctx, "Unable to extract the public key");
|
||||||
|
SC_FUNC_RETURN(card->ctx, 2,r);
|
||||||
|
}
|
||||||
|
|
||||||
|
pubkey->algorithm = SC_ALGORITHM_RSA;
|
||||||
|
pubkey->u.rsa.modulus.len = extArgs.modLength;
|
||||||
|
pubkey->u.rsa.modulus.data = extArgs.modValue;
|
||||||
|
pubkey->u.rsa.exponent.len = extArgs.expLength;
|
||||||
|
pubkey->u.rsa.exponent.data = extArgs.expValue;
|
||||||
|
|
||||||
|
if (r < 0) {
|
||||||
|
if (pubkey->u.rsa.modulus.data)
|
||||||
|
free (pubkey->u.rsa.modulus.data);
|
||||||
|
if (pubkey->u.rsa.exponent.data)
|
||||||
|
free (pubkey->u.rsa.exponent.data);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct sc_pkcs15init_operations sc_pkcs15init_muscle_operations = {
|
||||||
|
muscle_erase_card, /* erase card */
|
||||||
|
muscle_init_card, /* init_card */
|
||||||
|
muscle_create_dir, /* create_dir */
|
||||||
|
NULL, /* create_domain */
|
||||||
|
muscle_select_pin_reference, /* select pin reference */
|
||||||
|
muscle_create_pin, /* Create PIN */
|
||||||
|
muscle_select_key_reference, /* select_key_reference */
|
||||||
|
muscle_create_key, /* create_key */
|
||||||
|
muscle_store_key, /* store_key */
|
||||||
|
muscle_generate_key, /* generate_key */
|
||||||
|
NULL, NULL, /* encode private/public key */
|
||||||
|
NULL, /* finalize_card */
|
||||||
|
NULL, /* old - initapp*/
|
||||||
|
NULL, /* new_pin */
|
||||||
|
NULL, /* new key */
|
||||||
|
NULL, /* new file */
|
||||||
|
NULL, /* generate key */
|
||||||
|
NULL /* delete_object */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sc_pkcs15init_operations *
|
||||||
|
sc_pkcs15init_get_muscle_ops(void)
|
||||||
|
{
|
||||||
|
return &sc_pkcs15init_muscle_operations;
|
||||||
|
}
|
Loading…
Reference in New Issue