add initial support of Gemsafe applet V1 cards
Thanks to David Mattes for the patch http://www.opensc-project.org/pipermail/opensc-devel/2007-November/010558.html git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@3296 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
parent
1eb6fba882
commit
07e6b23a26
@ -279,7 +279,7 @@ app default {
|
||||
# Default: yes
|
||||
# enable_builtin_emulation = yes;
|
||||
# list of the builtin pkcs15 emulators to test
|
||||
builtin_emulators = esteid, openpgp, tcos, starcert, infocamere, postecert, actalis, atrust-acos, gemsafeGPK, tccardos, PIV-II;
|
||||
builtin_emulators = esteid, openpgp, tcos, starcert, infocamere, postecert, actalis, atrust-acos, gemsafeGPK, gemsafeV1, tccardos, PIV-II;
|
||||
|
||||
# additional settings per driver
|
||||
#
|
||||
|
@ -20,6 +20,7 @@ libopensc_la_SOURCES = \
|
||||
pkcs15.c pkcs15-cert.c pkcs15-data.c pkcs15-pin.c \
|
||||
pkcs15-prkey.c pkcs15-pubkey.c pkcs15-sec.c \
|
||||
pkcs15-wrap.c pkcs15-algo.c pkcs15-cache.c pkcs15-syn.c \
|
||||
pkcs15-gemsafeV1.c \
|
||||
\
|
||||
emv.c muscle.c muscle-filesystem.c \
|
||||
\
|
||||
@ -30,7 +31,7 @@ libopensc_la_SOURCES = \
|
||||
card-mcrd.c card-starcos.c card-openpgp.c card-jcop.c \
|
||||
card-oberthur.c card-belpic.c card-atrust-acos.c \
|
||||
card-incrypto34.c card-piv.c card-muscle.c card-acos5.c \
|
||||
card-asepcos.c card-akis.c\
|
||||
card-asepcos.c card-akis.c card-gemsafeV1.c \
|
||||
\
|
||||
pkcs15-openpgp.c pkcs15-infocamere.c pkcs15-starcert.c \
|
||||
pkcs15-tcos.c pkcs15-esteid.c pkcs15-postecert.c pkcs15-gemsafeGPK.c \
|
||||
|
681
src/libopensc/card-gemsafeV1.c
Normal file
681
src/libopensc/card-gemsafeV1.c
Normal file
@ -0,0 +1,681 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* Initially written by David Mattes (david.mattes@boeing.com) */
|
||||
|
||||
#include "internal.h"
|
||||
#include "cardctl.h"
|
||||
#include "asn1.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static struct sc_card_operations gemsafe_ops;
|
||||
static struct sc_card_operations *iso_ops = NULL;
|
||||
|
||||
static struct sc_card_driver gemsafe_drv = {
|
||||
"driver for the Gemplus GemSAFE V1 applet",
|
||||
"gemsafeV1",
|
||||
&gemsafe_ops,
|
||||
NULL, 0, NULL
|
||||
};
|
||||
|
||||
static const char *gemexpresso_atrs[] = {
|
||||
/* standard version */
|
||||
"3B:7B:94:00:00:80:65:B0:83:01:01:74:83:00:90:00",
|
||||
"3B:6B:00:00:80:65:B0:83:01:01:74:83:00:90:00",
|
||||
/* fips 140 version */
|
||||
"3B:6B:00:00:80:65:B0:83:01:03:74:83:00:90:00",
|
||||
/* TODO: add more ATRs */
|
||||
"3B:7A:94:00:00:80:65:A2:01:01:01:3D:72:D6:43",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const u8 gemsafe_def_aid[] = {0xA0, 0x00, 0x00, 0x00, 0x18, 0x0A,
|
||||
0x00, 0x00, 0x01, 0x63, 0x42, 0x00};
|
||||
/*
|
||||
static const u8 gemsafe_def_aid[] = {0xA0, 0x00, 0x00, 0x00, 0x63, 0x50,
|
||||
0x4B, 0x43, 0x53, 0x2D, 0x31, 0x35};
|
||||
*/
|
||||
|
||||
typedef struct gemsafe_exdata_st {
|
||||
u8 aid[16];
|
||||
size_t aid_len;
|
||||
} gemsafe_exdata;
|
||||
|
||||
static int get_conf_aid(sc_card_t *card, u8 *aid, size_t *len)
|
||||
{
|
||||
sc_context_t *ctx = card->ctx;
|
||||
scconf_block *conf_block, **blocks;
|
||||
int i;
|
||||
const char *str_aid;
|
||||
|
||||
SC_FUNC_CALLED(ctx, 1);
|
||||
|
||||
conf_block = NULL;
|
||||
for (i = 0; ctx->conf_blocks[i] != NULL; i++) {
|
||||
blocks = scconf_find_blocks(ctx->conf, ctx->conf_blocks[i],
|
||||
"card", "gemsafeV1");
|
||||
if (blocks[0] != NULL)
|
||||
conf_block = blocks[0];
|
||||
free(blocks);
|
||||
}
|
||||
|
||||
if (!conf_block) {
|
||||
sc_debug(ctx, "no card specific options configured, trying default AID\n");
|
||||
return SC_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
str_aid = scconf_get_str(conf_block, "aid", NULL);
|
||||
if (!str_aid) {
|
||||
sc_debug(ctx, "no aid configured, trying default AID\n");
|
||||
return SC_ERROR_INTERNAL;
|
||||
}
|
||||
return sc_hex_to_bin(str_aid, aid, len);
|
||||
}
|
||||
|
||||
static int gp_select_applet(sc_card_t *card, const u8 *aid, size_t aid_len)
|
||||
{
|
||||
int r;
|
||||
u8 buf[SC_MAX_APDU_BUFFER_SIZE];
|
||||
struct sc_context *ctx = card->ctx;
|
||||
struct sc_apdu apdu;
|
||||
|
||||
SC_FUNC_CALLED(ctx, 1);
|
||||
|
||||
sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xa4, 0x04, 0x00);
|
||||
apdu.lc = aid_len;
|
||||
apdu.data = aid;
|
||||
apdu.datalen = aid_len;
|
||||
apdu.resp = buf;
|
||||
apdu.le = 256;
|
||||
apdu.resplen = sizeof(buf);
|
||||
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
SC_TEST_RET(ctx, r, "APDU transmit failed");
|
||||
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
||||
if (r)
|
||||
SC_FUNC_RETURN(ctx, 2, r);
|
||||
|
||||
return SC_SUCCESS;
|
||||
}
|
||||
|
||||
static int gemsafe_match_card(struct sc_card *card)
|
||||
{
|
||||
int i, match = -1;
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
|
||||
for (i = 0; gemexpresso_atrs[i] != NULL; i++) {
|
||||
u8 defatr[SC_MAX_ATR_SIZE];
|
||||
size_t len = sizeof(defatr);
|
||||
const char *atrp = gemexpresso_atrs[i];
|
||||
|
||||
if (sc_hex_to_bin(atrp, defatr, &len))
|
||||
continue;
|
||||
if (len != card->atr_len)
|
||||
continue;
|
||||
if (memcmp(card->atr, defatr, len) != 0)
|
||||
continue;
|
||||
match = i + 1;
|
||||
break;
|
||||
}
|
||||
if (match == -1)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int gemsafe_init(struct sc_card *card)
|
||||
{
|
||||
int r;
|
||||
gemsafe_exdata *exdata = NULL;
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
|
||||
card->name = "GemSAFE V1";
|
||||
card->cla = 0x00;
|
||||
|
||||
exdata = (gemsafe_exdata *)calloc(1, sizeof(gemsafe_exdata));
|
||||
if (!exdata)
|
||||
return SC_ERROR_OUT_OF_MEMORY;
|
||||
exdata->aid_len = sizeof(exdata->aid);
|
||||
/* try to get a AID from the config file */
|
||||
r = get_conf_aid(card, exdata->aid, &exdata->aid_len);
|
||||
if (r < 0) {
|
||||
/* failed, use default value */
|
||||
memcpy(exdata->aid, gemsafe_def_aid, sizeof(gemsafe_def_aid));
|
||||
exdata->aid_len = sizeof(gemsafe_def_aid);
|
||||
}
|
||||
|
||||
/* increase lock_count here to prevent sc_unlock to select
|
||||
* applet twice in gp_select_applet */
|
||||
card->lock_count++;
|
||||
/* SELECT applet */
|
||||
r = gp_select_applet(card, exdata->aid, exdata->aid_len);
|
||||
if (r < 0) {
|
||||
free(exdata);
|
||||
sc_debug(card->ctx, "applet selection failed\n");
|
||||
return SC_ERROR_INTERNAL;
|
||||
}
|
||||
card->lock_count--;
|
||||
|
||||
/* set the supported algorithm */
|
||||
r = gemsafe_match_card(card);
|
||||
if (r > 0) {
|
||||
unsigned long flags;
|
||||
|
||||
flags = SC_ALGORITHM_RSA_PAD_PKCS1;
|
||||
flags |= SC_ALGORITHM_RSA_PAD_ISO9796;
|
||||
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->drv_data = exdata;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gemsafe_finish(sc_card_t *card)
|
||||
{
|
||||
gemsafe_exdata *exdata = (gemsafe_exdata *)card->drv_data;
|
||||
|
||||
if (exdata)
|
||||
free(exdata);
|
||||
return SC_SUCCESS;
|
||||
}
|
||||
|
||||
static int gemsafe_select_file(struct sc_card *card, const struct sc_path *path,
|
||||
struct sc_file **file_out)
|
||||
{
|
||||
/* so far just call the iso select file (but this will change) */
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
|
||||
return iso_ops->select_file(card, path, file_out);
|
||||
}
|
||||
|
||||
static int gemsafe_sc2acl(sc_file_t *file, unsigned ops, u8 sc_byte)
|
||||
{
|
||||
int r;
|
||||
unsigned int meth = 0;
|
||||
|
||||
if (sc_byte == 0xff) {
|
||||
r = sc_file_add_acl_entry(file, ops, SC_AC_NEVER, 0);
|
||||
return r;
|
||||
}
|
||||
if (sc_byte == 0x00) {
|
||||
r = sc_file_add_acl_entry(file, ops, SC_AC_NONE, 0);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* XXX: OR combination of access rights are currently not supported
|
||||
* hence ignored */
|
||||
if (sc_byte & 0x40)
|
||||
meth |= SC_AC_PRO;
|
||||
if (sc_byte & 0x20)
|
||||
meth |= SC_AC_AUT | SC_AC_TERM;
|
||||
if (sc_byte & 0x10)
|
||||
meth |= SC_AC_CHV;
|
||||
|
||||
return sc_file_add_acl_entry(file, ops, meth, sc_byte & 0x0f);
|
||||
}
|
||||
|
||||
static int gemsafe_setacl(sc_card_t *card, sc_file_t *file, const u8 *data,
|
||||
int is_df)
|
||||
{
|
||||
int r;
|
||||
u8 cond;
|
||||
const u8 *p = data + 1;
|
||||
struct sc_context *ctx = card->ctx;
|
||||
|
||||
if (is_df) {
|
||||
if (*data & 0x04) /* CREATE DF */
|
||||
cond = *p++;
|
||||
else
|
||||
cond = 0xff;
|
||||
if(ctx->debug >= 3)
|
||||
sc_debug(ctx, "DF security byte CREATE DF: %02x\n", cond);
|
||||
r = gemsafe_sc2acl(file, SC_AC_OP_CREATE, cond);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (*data & 0x02) /* CREATE EF */
|
||||
cond = *p;
|
||||
else
|
||||
cond = 0xff;
|
||||
if(ctx->debug >= 3)
|
||||
sc_debug(ctx, "DF security byte CREATE EF: %02x\n", cond);
|
||||
/* XXX: opensc doesn't currently separate access conditions for
|
||||
* CREATE EF and CREATE DF, this should be changed */
|
||||
r = gemsafe_sc2acl(file, SC_AC_OP_CREATE, cond);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else {
|
||||
/* XXX: ACTIVATE FILE and DEACTIVATE FILE ac are currently not
|
||||
* supported => ignore them */
|
||||
if (*data & 0x02) /* UPDATE BINARY, ERASE BINARY */
|
||||
cond = *p++;
|
||||
else
|
||||
cond = 0xff;
|
||||
if(ctx->debug >= 3)
|
||||
sc_debug(ctx, "EF security byte UPDATE/ERASE BINARY: %02x\n", cond);
|
||||
r = gemsafe_sc2acl(file, SC_AC_OP_UPDATE, cond);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = gemsafe_sc2acl(file, SC_AC_OP_WRITE, cond);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = gemsafe_sc2acl(file, SC_AC_OP_ERASE, cond);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (*data & 0x01) /* READ BINARY */
|
||||
cond = *p;
|
||||
else
|
||||
cond = 0xff;
|
||||
if(ctx->debug >= 3)
|
||||
sc_debug(ctx, "EF security byte READ BINARY: %02x\n", cond);
|
||||
r = gemsafe_sc2acl(file, SC_AC_OP_READ, cond);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return SC_SUCCESS;
|
||||
}
|
||||
|
||||
static int gemsafe_process_fci(struct sc_card *card, struct sc_file *file,
|
||||
const u8 *buf, size_t len)
|
||||
{
|
||||
int r;
|
||||
size_t tlen;
|
||||
const u8 *tag = NULL, *p = buf;
|
||||
const char *type;
|
||||
struct sc_context *ctx = card->ctx;
|
||||
|
||||
SC_FUNC_CALLED(ctx, 1);
|
||||
|
||||
r = iso_ops->process_fci(card, file, buf, len);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (ctx->debug >= 3)
|
||||
sc_debug(ctx, "processing GemSAFE V1 specific FCI information\n");
|
||||
|
||||
|
||||
tag = sc_asn1_find_tag(ctx, p, len, 0x82, &tlen);
|
||||
if (!tag) {
|
||||
/* no FDB => we have a DF */
|
||||
type = "DF";
|
||||
file->type = SC_FILE_TYPE_DF;
|
||||
} else {
|
||||
type = "EF";
|
||||
file->type = SC_FILE_TYPE_WORKING_EF;
|
||||
}
|
||||
|
||||
if (ctx->debug >= 3)
|
||||
sc_debug(ctx, "file type: %s\n", type);
|
||||
|
||||
tag = sc_asn1_find_tag(ctx, p, len, 0x8C, &tlen);
|
||||
if (tag) {
|
||||
r = gemsafe_setacl(card, file, tag, type == "DF" ? 1 : 0);
|
||||
if (r < 0) {
|
||||
sc_debug(ctx, "unable to set ACL\n");
|
||||
return SC_ERROR_INTERNAL;
|
||||
}
|
||||
} else
|
||||
sc_debug(ctx, "error: AM and SC bytes missing\n");
|
||||
|
||||
return SC_SUCCESS;
|
||||
}
|
||||
|
||||
static u8 gemsafe_flags2algref(const struct sc_security_env *env)
|
||||
{
|
||||
u8 ret = 0;
|
||||
|
||||
if (env->operation == SC_SEC_OPERATION_SIGN) {
|
||||
if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1)
|
||||
ret = 0x12;
|
||||
else if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_ISO9796)
|
||||
ret = 0x11;
|
||||
} else if (env->operation == SC_SEC_OPERATION_DECIPHER) {
|
||||
if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1)
|
||||
ret = 0x13;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gemsafe_restore_security_env(struct sc_card *card, int se_num)
|
||||
{
|
||||
int r;
|
||||
struct sc_apdu apdu;
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
|
||||
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x22, 0x73, (u8) se_num);
|
||||
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
|
||||
|
||||
return sc_check_sw(card, apdu.sw1, apdu.sw2);
|
||||
}
|
||||
|
||||
|
||||
static int gemsafe_set_security_env(struct sc_card *card,
|
||||
const struct sc_security_env *env,
|
||||
int se_num)
|
||||
{
|
||||
int r;
|
||||
struct sc_apdu apdu;
|
||||
u8 sbuf[SC_MAX_APDU_BUFFER_SIZE], *p = sbuf;
|
||||
u8 alg_ref = 0;
|
||||
struct sc_context *ctx = card->ctx;
|
||||
|
||||
SC_FUNC_CALLED(ctx, 1);
|
||||
|
||||
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0);
|
||||
switch (env->operation) {
|
||||
case SC_SEC_OPERATION_DECIPHER:
|
||||
apdu.p2 = 0xB8;
|
||||
break;
|
||||
case SC_SEC_OPERATION_SIGN:
|
||||
apdu.p2 = 0xB6;
|
||||
break;
|
||||
default:
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
apdu.le = 0;
|
||||
|
||||
/* first step: set the algorithm reference */
|
||||
if (env->flags & SC_SEC_ENV_ALG_REF_PRESENT)
|
||||
alg_ref = env->algorithm_ref & 0xFF;
|
||||
else
|
||||
alg_ref = gemsafe_flags2algref(env);
|
||||
if (alg_ref) {
|
||||
/* set the algorithm reference */
|
||||
*p++ = 0x80;
|
||||
*p++ = 0x01;
|
||||
*p++ = alg_ref;
|
||||
} else
|
||||
sc_debug(ctx, "unknown algorithm flags '%x'\n", env->algorithm_flags);
|
||||
/* second step: set the key reference */
|
||||
if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT) {
|
||||
/* set the key reference */
|
||||
if (env->flags & SC_SEC_ENV_KEY_REF_ASYMMETRIC)
|
||||
*p++ = 0x83;
|
||||
else
|
||||
*p++ = 0x84;
|
||||
*p++ = env->key_ref_len;
|
||||
memcpy(p, env->key_ref, env->key_ref_len);
|
||||
p += env->key_ref_len;
|
||||
}
|
||||
|
||||
|
||||
r = p - sbuf;
|
||||
apdu.lc = r;
|
||||
apdu.datalen = r;
|
||||
apdu.data = sbuf;
|
||||
apdu.resplen = 0;
|
||||
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
|
||||
return sc_check_sw(card, apdu.sw1, apdu.sw2);
|
||||
}
|
||||
|
||||
static int gemsafe_compute_signature(struct sc_card *card, const u8 * data,
|
||||
size_t data_len, u8 * out, size_t outlen)
|
||||
{
|
||||
int r;
|
||||
struct sc_apdu apdu;
|
||||
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
|
||||
u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
|
||||
sc_context_t *ctx = card->ctx;
|
||||
|
||||
SC_FUNC_CALLED(ctx, 1);
|
||||
|
||||
if (data_len > 36) {
|
||||
sc_debug(ctx, "error: input data too long: %lu bytes\n", data_len);
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
|
||||
sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x9E, 0xAC);
|
||||
apdu.cla |= 0x80;
|
||||
apdu.resp = rbuf;
|
||||
apdu.resplen = sizeof(rbuf);
|
||||
apdu.le = 256;
|
||||
/* we sign a digestInfo object => tag 0x90 */
|
||||
sbuf[0] = 0x90;
|
||||
sbuf[1] = (u8)data_len;
|
||||
memcpy(sbuf + 2, data, data_len);
|
||||
apdu.data = sbuf;
|
||||
apdu.lc = data_len + 2;
|
||||
apdu.datalen = data_len + 2;
|
||||
apdu.sensitive = 1;
|
||||
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
|
||||
if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
|
||||
int len = apdu.resplen > outlen ? outlen : apdu.resplen;
|
||||
|
||||
memcpy(out, apdu.resp, len);
|
||||
SC_FUNC_RETURN(card->ctx, 4, len);
|
||||
}
|
||||
SC_FUNC_RETURN(card->ctx, 2, sc_check_sw(card, apdu.sw1, apdu.sw2));
|
||||
}
|
||||
|
||||
static int gemsafe_decipher(struct sc_card *card, const u8 * crgram,
|
||||
size_t crgram_len, u8 *out, size_t outlen)
|
||||
{
|
||||
int r;
|
||||
struct sc_apdu apdu;
|
||||
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
|
||||
sc_context_t *ctx = card->ctx;
|
||||
|
||||
SC_FUNC_CALLED(ctx, 1);
|
||||
if (crgram_len > 255)
|
||||
SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_INVALID_ARGUMENTS);
|
||||
|
||||
sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x80, 0x84);
|
||||
apdu.cla |= 0x80;
|
||||
apdu.resp = rbuf;
|
||||
apdu.resplen = sizeof(rbuf);
|
||||
apdu.le = crgram_len;
|
||||
apdu.sensitive = 1;
|
||||
|
||||
apdu.data = crgram;
|
||||
apdu.lc = crgram_len;
|
||||
apdu.datalen = crgram_len;
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
|
||||
if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
|
||||
int len = apdu.resplen > outlen ? outlen : apdu.resplen;
|
||||
|
||||
memcpy(out, apdu.resp, len);
|
||||
SC_FUNC_RETURN(card->ctx, 2, len);
|
||||
}
|
||||
SC_FUNC_RETURN(card->ctx, 2, sc_check_sw(card, apdu.sw1, apdu.sw2));
|
||||
}
|
||||
|
||||
static int gemsafe_build_pin_apdu(struct sc_card *card,
|
||||
struct sc_apdu *apdu,
|
||||
struct sc_pin_cmd_data *data)
|
||||
{
|
||||
static u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
|
||||
int r, len = 0, pad = 0, use_pin_pad = 0, ins, p1 = 0;
|
||||
|
||||
switch (data->pin_type) {
|
||||
case SC_AC_CHV:
|
||||
break;
|
||||
default:
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
|
||||
if (data->flags & SC_PIN_CMD_NEED_PADDING)
|
||||
pad = 1;
|
||||
if (data->flags & SC_PIN_CMD_USE_PINPAD)
|
||||
use_pin_pad = 1;
|
||||
|
||||
data->pin1.offset = 5;
|
||||
|
||||
switch (data->cmd) {
|
||||
case SC_PIN_CMD_VERIFY:
|
||||
ins = 0x20;
|
||||
if ((r = sc_build_pin(sbuf, sizeof(sbuf), &data->pin1, pad)) < 0)
|
||||
return r;
|
||||
len = r;
|
||||
break;
|
||||
case SC_PIN_CMD_CHANGE:
|
||||
ins = 0x24;
|
||||
if (data->pin1.len != 0 || use_pin_pad) {
|
||||
if ((r = sc_build_pin(sbuf, sizeof(sbuf), &data->pin1, pad)) < 0)
|
||||
return r;
|
||||
len += r;
|
||||
} else {
|
||||
/* implicit test */
|
||||
p1 = 1;
|
||||
}
|
||||
|
||||
data->pin2.offset = data->pin1.offset + len;
|
||||
if ((r = sc_build_pin(sbuf+len, sizeof(sbuf)-len, &data->pin2, pad)) < 0)
|
||||
return r;
|
||||
len += r;
|
||||
break;
|
||||
case SC_PIN_CMD_UNBLOCK:
|
||||
ins = 0x2C;
|
||||
if (data->pin1.len != 0 || use_pin_pad) {
|
||||
if ((r = sc_build_pin(sbuf, sizeof(sbuf), &data->pin1, pad)) < 0)
|
||||
return r;
|
||||
len += r;
|
||||
} else {
|
||||
p1 |= 0x02;
|
||||
}
|
||||
|
||||
if (data->pin2.len != 0 || use_pin_pad) {
|
||||
data->pin2.offset = data->pin1.offset + len;
|
||||
if ((r = sc_build_pin(sbuf+len, sizeof(sbuf)-len, &data->pin2, pad)) < 0)
|
||||
return r;
|
||||
len += r;
|
||||
} else {
|
||||
p1 |= 0x01;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
sc_format_apdu(card, apdu, SC_APDU_CASE_3_SHORT,
|
||||
ins, p1, data->pin_reference);
|
||||
|
||||
apdu->lc = len;
|
||||
apdu->datalen = len;
|
||||
apdu->data = sbuf;
|
||||
apdu->resplen = 0;
|
||||
apdu->sensitive = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gemsafe_pin_cmd(struct sc_card *card, struct sc_pin_cmd_data *data,
|
||||
int *tries_left)
|
||||
{
|
||||
struct sc_apdu local_apdu, *apdu;
|
||||
int r;
|
||||
|
||||
if (tries_left)
|
||||
*tries_left = -1;
|
||||
|
||||
/* See if we've been called from another card driver, which is
|
||||
* passing an APDU to us (this allows to write card drivers
|
||||
* whose PIN functions behave "mostly like ISO" except in some
|
||||
* special circumstances.
|
||||
*/
|
||||
if (data->apdu == NULL) {
|
||||
r = gemsafe_build_pin_apdu(card, &local_apdu, data);
|
||||
if (r < 0)
|
||||
return r;
|
||||
data->apdu = &local_apdu;
|
||||
}
|
||||
apdu = data->apdu;
|
||||
|
||||
if (!(data->flags & SC_PIN_CMD_USE_PINPAD)) {
|
||||
/* Transmit the APDU to the card */
|
||||
r = sc_transmit_apdu(card, apdu);
|
||||
|
||||
/* Clear the buffer - it may contain pins */
|
||||
memset((void *) apdu->data, 0, apdu->datalen);
|
||||
} else {
|
||||
/* Call the reader driver to collect
|
||||
* the PIN and pass on the APDU to the card */
|
||||
if (data->pin1.offset == 0) {
|
||||
sc_error(card->ctx,
|
||||
"Card driver didn't set PIN offset");
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
if (card->reader
|
||||
&& card->reader->ops
|
||||
&& card->reader->ops->perform_verify) {
|
||||
r = card->reader->ops->perform_verify(card->reader,
|
||||
card->slot,
|
||||
data);
|
||||
/* sw1/sw2 filled in by reader driver */
|
||||
} else {
|
||||
sc_error(card->ctx,
|
||||
"Card reader driver does not support "
|
||||
"PIN entry through reader key pad");
|
||||
r = SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't pass references to local variables up to the caller. */
|
||||
if (data->apdu == &local_apdu)
|
||||
data->apdu = NULL;
|
||||
|
||||
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
|
||||
if (apdu->sw1 == 0x63) {
|
||||
if ((apdu->sw2 & 0xF0) == 0xC0 && tries_left != NULL)
|
||||
*tries_left = apdu->sw2 & 0x0F;
|
||||
return SC_ERROR_PIN_CODE_INCORRECT;
|
||||
}
|
||||
return sc_check_sw(card, apdu->sw1, apdu->sw2);
|
||||
}
|
||||
|
||||
static struct sc_card_driver *sc_get_driver(void)
|
||||
{
|
||||
struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
|
||||
if (!iso_ops)
|
||||
iso_ops = iso_drv->ops;
|
||||
/* use the standard iso operations as default */
|
||||
gemsafe_ops = *iso_drv->ops;
|
||||
/* gemsafe specfic functions */
|
||||
gemsafe_ops.match_card = gemsafe_match_card;
|
||||
gemsafe_ops.init = gemsafe_init;
|
||||
gemsafe_ops.finish = gemsafe_finish;
|
||||
gemsafe_ops.select_file = gemsafe_select_file;
|
||||
gemsafe_ops.restore_security_env = gemsafe_restore_security_env;
|
||||
gemsafe_ops.set_security_env = gemsafe_set_security_env;
|
||||
gemsafe_ops.decipher = gemsafe_decipher;
|
||||
gemsafe_ops.compute_signature = gemsafe_compute_signature;
|
||||
gemsafe_ops.process_fci = gemsafe_process_fci;
|
||||
gemsafe_ops.pin_cmd = gemsafe_pin_cmd;
|
||||
|
||||
return &gemsafe_drv;
|
||||
}
|
||||
|
||||
struct sc_card_driver *sc_get_gemsafeV1_driver(void)
|
||||
{
|
||||
return sc_get_driver();
|
||||
}
|
||||
|
@ -58,6 +58,7 @@ static const struct _sc_driver_entry internal_card_drivers[] = {
|
||||
#ifdef HAVE_OPENSSL
|
||||
{ "gpk", (void *(*)(void)) sc_get_gpk_driver },
|
||||
#endif
|
||||
{ "gemsafeV1", (void *(*)(void)) sc_get_gemsafeV1_driver },
|
||||
{ "miocos", (void *(*)(void)) sc_get_miocos_driver },
|
||||
{ "mcrd", (void *(*)(void)) sc_get_mcrd_driver },
|
||||
{ "asepcos", (void *(*)(void)) sc_get_asepcos_driver },
|
||||
|
@ -1160,6 +1160,7 @@ extern sc_card_driver_t *sc_get_cardos_driver(void);
|
||||
extern sc_card_driver_t *sc_get_cryptoflex_driver(void);
|
||||
extern sc_card_driver_t *sc_get_cyberflex_driver(void);
|
||||
extern sc_card_driver_t *sc_get_gpk_driver(void);
|
||||
extern sc_card_driver_t *sc_get_gemsafeV1_driver(void);
|
||||
extern sc_card_driver_t *sc_get_iso7816_driver(void);
|
||||
extern sc_card_driver_t *sc_get_miocos_driver(void);
|
||||
extern sc_card_driver_t *sc_get_mcrd_driver(void);
|
||||
|
500
src/libopensc/pkcs15-gemsafeV1.c
Normal file
500
src/libopensc/pkcs15-gemsafeV1.c
Normal file
@ -0,0 +1,500 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* Initially written by David Mattes (david.mattes@boeing.com) */
|
||||
|
||||
#include "internal.h"
|
||||
#include "pkcs15.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define MANU_ID "Gemplus"
|
||||
#define APPLET_NAME "GemSAFE V1"
|
||||
#define DRIVER_SERIAL_NUMBER "v0.9"
|
||||
|
||||
int sc_pkcs15emu_gemsafeV1_init_ex(sc_pkcs15_card_t *, sc_pkcs15emu_opt_t *);
|
||||
|
||||
static int
|
||||
sc_pkcs15emu_add_cert(sc_pkcs15_card_t *p15card,
|
||||
int type, int authority,
|
||||
const sc_path_t *path,
|
||||
const sc_pkcs15_id_t *id,
|
||||
const char *label, int obj_flags);
|
||||
|
||||
static int
|
||||
sc_pkcs15emu_add_pin(sc_pkcs15_card_t *p15card,
|
||||
const sc_pkcs15_id_t *id, const char *label,
|
||||
const sc_path_t *path, int ref, int type,
|
||||
unsigned int min_length,
|
||||
unsigned int max_length,
|
||||
int flags, int tries_left, const char pad_char, int obj_flags);
|
||||
|
||||
static int
|
||||
sc_pkcs15emu_add_prkey(sc_pkcs15_card_t *p15card,
|
||||
const sc_pkcs15_id_t *id,
|
||||
const char *label,
|
||||
int type, unsigned int modulus_length, int usage,
|
||||
const sc_path_t *path, int ref,
|
||||
const sc_pkcs15_id_t *auth_id, int obj_flags);
|
||||
|
||||
typedef struct cdata_st {
|
||||
const char *label;
|
||||
int authority;
|
||||
const char *path;
|
||||
const char *id;
|
||||
int obj_flags;
|
||||
} cdata;
|
||||
|
||||
const cdata gemsafe_cert[] = {
|
||||
{"DS certificate", 0, "3F0016000004","45", SC_PKCS15_CO_FLAG_MODIFIABLE},
|
||||
{NULL, 0, NULL, 0, 0}
|
||||
};
|
||||
|
||||
typedef struct pdata_st {
|
||||
const char *id;
|
||||
const char *label;
|
||||
const char *path;
|
||||
int ref;
|
||||
int type;
|
||||
unsigned int maxlen;
|
||||
unsigned int minlen;
|
||||
int flags;
|
||||
int tries_left;
|
||||
const char pad_char;
|
||||
int obj_flags;
|
||||
} pindata;
|
||||
|
||||
const pindata gemsafe_pin[] = {
|
||||
{ "01", "DS pin", NULL, 0x01, SC_PKCS15_PIN_TYPE_BCD,
|
||||
16, 6, SC_PKCS15_PIN_FLAG_NEEDS_PADDING | SC_PKCS15_PIN_FLAG_LOCAL,
|
||||
3, 0xFF,
|
||||
SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE },
|
||||
{ NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
typedef struct prdata_st {
|
||||
const char *id;
|
||||
const char *label;
|
||||
unsigned int modulus_len;
|
||||
int usage;
|
||||
const char *path;
|
||||
int ref;
|
||||
const char *auth_id;
|
||||
int obj_flags;
|
||||
} prdata;
|
||||
|
||||
#define USAGE_NONREP SC_PKCS15_PRKEY_USAGE_NONREPUDIATION
|
||||
#define USAGE_KE SC_PKCS15_PRKEY_USAGE_ENCRYPT | \
|
||||
SC_PKCS15_PRKEY_USAGE_DECRYPT | \
|
||||
SC_PKCS15_PRKEY_USAGE_WRAP | \
|
||||
SC_PKCS15_PRKEY_USAGE_UNWRAP
|
||||
#define USAGE_AUT SC_PKCS15_PRKEY_USAGE_ENCRYPT | \
|
||||
SC_PKCS15_PRKEY_USAGE_DECRYPT | \
|
||||
SC_PKCS15_PRKEY_USAGE_WRAP | \
|
||||
SC_PKCS15_PRKEY_USAGE_UNWRAP | \
|
||||
SC_PKCS15_PRKEY_USAGE_SIGN
|
||||
|
||||
const prdata gemsafe_prkeys[] = {
|
||||
{ "45", "DS key", 1024, USAGE_AUT, NULL,
|
||||
0x03, "01", SC_PKCS15_CO_FLAG_PRIVATE},
|
||||
{ NULL, NULL, 0, 0, NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
static int gemsafe_get_cert_len(sc_card_t *card, sc_path_t *path)
|
||||
{
|
||||
const char *fn_name = "gemsafe_get_cert_len";
|
||||
int r;
|
||||
u8 ibuf[248];
|
||||
struct sc_file *file;
|
||||
size_t objlen, certlen;
|
||||
int block=0;
|
||||
int found = 0;
|
||||
unsigned int offset=0, index, i=0;
|
||||
|
||||
r = sc_select_file(card, path, &file);
|
||||
if (r < 0)
|
||||
return 0;
|
||||
|
||||
/* Apparently, the Applet max read "quanta" is 248 bytes */
|
||||
/* Initial read */
|
||||
r = sc_read_binary(card, offset, ibuf, 248, 0);
|
||||
if (r < 0)
|
||||
return 0;
|
||||
|
||||
/* Actual stored object size is encoded in first 2 bytes
|
||||
* (allocated EF space is much greater!)
|
||||
*/
|
||||
objlen = (((size_t) ibuf[0]) << 8) | ibuf[1];
|
||||
//fprintf(stderr, "%s: Certificate object is of size: %d\n", fn_name, objlen);
|
||||
|
||||
if (objlen < 1 || objlen > 10240) {
|
||||
fprintf(stderr, "%s: Invalid object size: %d\n", fn_name, objlen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Using (block+1) in while loop avoids using final cert object data block */
|
||||
while (!found && ( (block+1) * 248 < objlen) ) {
|
||||
/* Check current buffer */
|
||||
for (i = 0; i < 248; i++) {
|
||||
if (ibuf[i] == 0x30 && ibuf[i+1] == 0x82) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Grab another buffer */
|
||||
if (!found) {
|
||||
block++;
|
||||
offset = block*248;
|
||||
r = sc_read_binary(card, offset, ibuf, 248, 0);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "%s: Could not read cert object\n", fn_name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
index = block*248 + i;
|
||||
|
||||
/* DER Cert len is encoded this way */
|
||||
certlen = ((((size_t) ibuf[i+2]) << 8) | ibuf[i+3]) + 4;
|
||||
//fprintf(stderr, "%s: certlen: %04X\n", fn_name, certlen);
|
||||
|
||||
path->index = index;
|
||||
path->count = certlen;
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
static int gemsafe_detect_card( sc_pkcs15_card_t *p15card)
|
||||
{
|
||||
fprintf(stderr, "In gemsafe_detect_card\n");
|
||||
return SC_SUCCESS;
|
||||
}
|
||||
|
||||
static int sc_pkcs15emu_gemsafeV1_init( sc_pkcs15_card_t *p15card)
|
||||
{
|
||||
const char *fn_name = "sc_pkcs15emu_gemsafe_init";
|
||||
|
||||
int r, i;
|
||||
struct sc_path path;
|
||||
struct sc_file *file = NULL;
|
||||
struct sc_card *card = p15card->card;
|
||||
struct sc_apdu apdu;
|
||||
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
|
||||
char * endptr;
|
||||
float version=0.0;
|
||||
|
||||
fprintf(stderr, "%s: Setting pkcs15 parameters\n", fn_name);
|
||||
|
||||
if (p15card->label)
|
||||
free(p15card->label);
|
||||
p15card->label = malloc(strlen(APPLET_NAME) + 1);
|
||||
if (!p15card->label)
|
||||
return SC_ERROR_INTERNAL;
|
||||
strcpy(p15card->label, APPLET_NAME);
|
||||
|
||||
if (p15card->serial_number)
|
||||
free(p15card->serial_number);
|
||||
p15card->serial_number = malloc(strlen(DRIVER_SERIAL_NUMBER) + 1);
|
||||
if (!p15card->serial_number)
|
||||
return SC_ERROR_INTERNAL;
|
||||
strcpy(p15card->serial_number, DRIVER_SERIAL_NUMBER);
|
||||
|
||||
/* the GemSAFE applet version number */
|
||||
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xca, 0xdf, 0x03);
|
||||
apdu.cla = 0x80;
|
||||
apdu.resp = rbuf;
|
||||
apdu.resplen = sizeof(rbuf);
|
||||
/* Manual says Le=0x05, but should be 0x08 to return full version numer */
|
||||
apdu.le = 0x08;
|
||||
apdu.lc = 0;
|
||||
apdu.datalen = 0;
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
|
||||
if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
|
||||
return SC_ERROR_INTERNAL;
|
||||
if (r != SC_SUCCESS)
|
||||
return SC_ERROR_INTERNAL;
|
||||
endptr = (char *)(apdu.resp + apdu.resplen);
|
||||
version = strtod( (const char *)(apdu.resp + 4), &endptr);
|
||||
fprintf(stderr, "%s: version (float): %f, version (int): %d\n",
|
||||
fn_name, version, (int)version);
|
||||
p15card->version = (int)version;
|
||||
|
||||
/* the manufacturer ID, in this case GemPlus */
|
||||
if (p15card->manufacturer_id)
|
||||
free(p15card->manufacturer_id);
|
||||
p15card->manufacturer_id = malloc(strlen(MANU_ID) + 1);
|
||||
if (!p15card->manufacturer_id)
|
||||
return SC_ERROR_INTERNAL;
|
||||
strcpy(p15card->manufacturer_id, MANU_ID);
|
||||
|
||||
/* Add RSA algorithm */
|
||||
card->algorithm_count = 0;
|
||||
_sc_card_add_rsa_alg( card, 1024, SC_ALGORITHM_RSA_PAD_PKCS1, 0);
|
||||
|
||||
/* set certs */
|
||||
fprintf(stderr, "%s: Setting certificate\n", fn_name);
|
||||
for (i = 0; gemsafe_cert[i].label; i++) {
|
||||
struct sc_pkcs15_id p15Id;
|
||||
|
||||
sc_format_path(gemsafe_cert[i].path, &path);
|
||||
if (!gemsafe_get_cert_len(card, &path))
|
||||
/* skip errors */
|
||||
continue;
|
||||
sc_pkcs15_format_id(gemsafe_cert[i].id, &p15Id);
|
||||
sc_pkcs15emu_add_cert(p15card, SC_PKCS15_TYPE_CERT_X509,
|
||||
gemsafe_cert[i].authority, &path, &p15Id,
|
||||
gemsafe_cert[i].label, gemsafe_cert[i].obj_flags);
|
||||
}
|
||||
/* set gemsafe_pin */
|
||||
fprintf(stderr, "%s: Setting PIN\n", fn_name);
|
||||
for (i = 0; gemsafe_pin[i].label; i++) {
|
||||
struct sc_pkcs15_id p15Id;
|
||||
|
||||
sc_pkcs15_format_id(gemsafe_pin[i].id, &p15Id);
|
||||
sc_pkcs15emu_add_pin(p15card, &p15Id, gemsafe_pin[i].label,
|
||||
&path, gemsafe_pin[i].ref, gemsafe_pin[i].type,
|
||||
gemsafe_pin[i].minlen, gemsafe_pin[i].maxlen,
|
||||
gemsafe_pin[i].flags,
|
||||
gemsafe_pin[i].tries_left, gemsafe_pin[i].pad_char,
|
||||
gemsafe_pin[i].obj_flags);
|
||||
}
|
||||
/* set private keys */
|
||||
fprintf(stderr, "%s: Setting private key\n", fn_name);
|
||||
for (i = 0; gemsafe_prkeys[i].label; i++) {
|
||||
struct sc_pkcs15_id p15Id,
|
||||
authId, *pauthId;
|
||||
sc_pkcs15_format_id(gemsafe_prkeys[i].id, &p15Id);
|
||||
if (gemsafe_prkeys[i].auth_id) {
|
||||
sc_pkcs15_format_id(gemsafe_prkeys[i].auth_id, &authId);
|
||||
pauthId = &authId;
|
||||
} else
|
||||
pauthId = NULL;
|
||||
sc_pkcs15emu_add_prkey(p15card, &p15Id, gemsafe_prkeys[i].label,
|
||||
SC_PKCS15_TYPE_PRKEY_RSA,
|
||||
gemsafe_prkeys[i].modulus_len, gemsafe_prkeys[i].usage,
|
||||
&path, gemsafe_prkeys[i].ref, pauthId,
|
||||
gemsafe_prkeys[i].obj_flags);
|
||||
}
|
||||
|
||||
/* select the application DF */
|
||||
fprintf(stderr,"%s: Selecting application DF\n", fn_name);
|
||||
sc_format_path("3F001600", &path);
|
||||
r = sc_select_file(card, &path, &file);
|
||||
if (r != SC_SUCCESS || !file)
|
||||
return SC_ERROR_INTERNAL;
|
||||
/* set the application DF */
|
||||
if (p15card->file_app)
|
||||
free(p15card->file_app);
|
||||
p15card->file_app = file;
|
||||
|
||||
return SC_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
int sc_pkcs15emu_gemsafeV1_init_ex( sc_pkcs15_card_t *p15card,
|
||||
sc_pkcs15emu_opt_t *opts)
|
||||
{
|
||||
if (opts && opts->flags & SC_PKCS15EMU_FLAGS_NO_CHECK)
|
||||
return sc_pkcs15emu_gemsafeV1_init(p15card);
|
||||
else {
|
||||
int r = gemsafe_detect_card(p15card);
|
||||
if (r)
|
||||
return SC_ERROR_WRONG_CARD;
|
||||
return sc_pkcs15emu_gemsafeV1_init(p15card);
|
||||
}
|
||||
}
|
||||
|
||||
static sc_pkcs15_df_t *
|
||||
sc_pkcs15emu_get_df(sc_pkcs15_card_t *p15card, int type)
|
||||
{
|
||||
sc_pkcs15_df_t *df;
|
||||
sc_file_t *file;
|
||||
int created = 0;
|
||||
|
||||
while (1) {
|
||||
for (df = p15card->df_list; df; df = df->next) {
|
||||
if (df->type == type) {
|
||||
if (created)
|
||||
df->enumerated = 1;
|
||||
return df;
|
||||
}
|
||||
}
|
||||
|
||||
assert(created == 0);
|
||||
|
||||
file = sc_file_new();
|
||||
if (!file)
|
||||
return NULL;
|
||||
sc_format_path("11001101", &file->path);
|
||||
sc_pkcs15_add_df(p15card, type, &file->path, file);
|
||||
sc_file_free(file);
|
||||
created++;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
sc_pkcs15emu_add_object(sc_pkcs15_card_t *p15card, int type,
|
||||
const char *label, void *data,
|
||||
const sc_pkcs15_id_t *auth_id, int obj_flags)
|
||||
{
|
||||
sc_pkcs15_object_t *obj;
|
||||
int df_type;
|
||||
|
||||
obj = (sc_pkcs15_object_t *) calloc(1, sizeof(*obj));
|
||||
|
||||
obj->type = type;
|
||||
obj->data = data;
|
||||
|
||||
if (label)
|
||||
strncpy(obj->label, label, sizeof(obj->label)-1);
|
||||
|
||||
obj->flags = obj_flags;
|
||||
if (auth_id)
|
||||
obj->auth_id = *auth_id;
|
||||
|
||||
switch (type & SC_PKCS15_TYPE_CLASS_MASK) {
|
||||
case SC_PKCS15_TYPE_AUTH:
|
||||
df_type = SC_PKCS15_AODF;
|
||||
break;
|
||||
case SC_PKCS15_TYPE_PRKEY:
|
||||
df_type = SC_PKCS15_PRKDF;
|
||||
break;
|
||||
case SC_PKCS15_TYPE_PUBKEY:
|
||||
df_type = SC_PKCS15_PUKDF;
|
||||
break;
|
||||
case SC_PKCS15_TYPE_CERT:
|
||||
df_type = SC_PKCS15_CDF;
|
||||
break;
|
||||
default:
|
||||
sc_error(p15card->card->ctx,
|
||||
"Unknown PKCS15 object type %d\n", type);
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
|
||||
obj->df = sc_pkcs15emu_get_df(p15card, df_type);
|
||||
sc_pkcs15_add_object(p15card, obj);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sc_pkcs15emu_add_pin(sc_pkcs15_card_t *p15card,
|
||||
const sc_pkcs15_id_t *id, const char *label,
|
||||
const sc_path_t *path, int ref, int type,
|
||||
unsigned int min_length,
|
||||
unsigned int max_length,
|
||||
int flags, int tries_left, const char pad_char, int obj_flags)
|
||||
{
|
||||
sc_pkcs15_pin_info_t *info;
|
||||
|
||||
info = (sc_pkcs15_pin_info_t *) calloc(1, sizeof(*info));
|
||||
info->auth_id = *id;
|
||||
info->min_length = min_length;
|
||||
info->max_length = max_length;
|
||||
info->stored_length = max_length;
|
||||
info->type = type;
|
||||
info->reference = ref;
|
||||
info->flags = flags;
|
||||
info->tries_left = tries_left;
|
||||
info->magic = SC_PKCS15_PIN_MAGIC;
|
||||
info->pad_char = pad_char;
|
||||
|
||||
if (path)
|
||||
info->path = *path;
|
||||
if (type == SC_PKCS15_PIN_TYPE_BCD)
|
||||
info->stored_length /= 2;
|
||||
|
||||
return sc_pkcs15emu_add_object(p15card,
|
||||
SC_PKCS15_TYPE_AUTH_PIN,
|
||||
label, info, NULL, obj_flags);
|
||||
}
|
||||
|
||||
static int
|
||||
sc_pkcs15emu_add_cert(sc_pkcs15_card_t *p15card,
|
||||
int type, int authority,
|
||||
const sc_path_t *path,
|
||||
const sc_pkcs15_id_t *id,
|
||||
const char *label, int obj_flags)
|
||||
{
|
||||
/* const char *label = "Certificate"; */
|
||||
sc_pkcs15_cert_info_t *info;
|
||||
info = (sc_pkcs15_cert_info_t *) calloc(1, sizeof(*info));
|
||||
info->id = *id;
|
||||
info->authority = authority;
|
||||
if (path)
|
||||
info->path = *path;
|
||||
|
||||
return sc_pkcs15emu_add_object(p15card, type, label, info, NULL, obj_flags);
|
||||
}
|
||||
|
||||
static int
|
||||
sc_pkcs15emu_add_prkey(sc_pkcs15_card_t *p15card,
|
||||
const sc_pkcs15_id_t *id,
|
||||
const char *label,
|
||||
int type, unsigned int modulus_length, int usage,
|
||||
const sc_path_t *path, int ref,
|
||||
const sc_pkcs15_id_t *auth_id, int obj_flags)
|
||||
{
|
||||
sc_pkcs15_prkey_info_t *info;
|
||||
|
||||
info = (sc_pkcs15_prkey_info_t *) calloc(1, sizeof(*info));
|
||||
info->id = *id;
|
||||
info->modulus_length = modulus_length;
|
||||
info->usage = usage;
|
||||
info->native = 1;
|
||||
info->access_flags = SC_PKCS15_PRKEY_ACCESS_SENSITIVE
|
||||
| SC_PKCS15_PRKEY_ACCESS_ALWAYSSENSITIVE
|
||||
| SC_PKCS15_PRKEY_ACCESS_NEVEREXTRACTABLE
|
||||
| SC_PKCS15_PRKEY_ACCESS_LOCAL;
|
||||
info->key_reference = ref;
|
||||
|
||||
if (path)
|
||||
info->path = *path;
|
||||
|
||||
return sc_pkcs15emu_add_object(p15card, type, label,
|
||||
info, auth_id, obj_flags);
|
||||
}
|
||||
|
||||
static int
|
||||
sc_pkcs15emu_add_pubkey(sc_pkcs15_card_t *p15card,
|
||||
const sc_pkcs15_id_t *id,
|
||||
const char *label, int type,
|
||||
unsigned int modulus_length, int usage,
|
||||
const sc_path_t *path, int ref,
|
||||
const sc_pkcs15_id_t *auth_id, int obj_flags)
|
||||
{
|
||||
sc_pkcs15_pubkey_info_t *info;
|
||||
|
||||
info = (sc_pkcs15_pubkey_info_t *) calloc(1, sizeof(*info));
|
||||
info->id = *id;
|
||||
info->modulus_length = modulus_length;
|
||||
info->usage = usage;
|
||||
info->access_flags = SC_PKCS15_PRKEY_ACCESS_EXTRACTABLE;
|
||||
info->key_reference = ref;
|
||||
|
||||
if (path)
|
||||
info->path = *path;
|
||||
|
||||
return sc_pkcs15emu_add_object(p15card, type, label, info, auth_id, obj_flags);
|
||||
}
|
||||
|
||||
//SC_IMPLEMENT_DRIVER_VERSION("0.9.4")
|
@ -44,6 +44,8 @@ extern int sc_pkcs15emu_piv_init_ex(sc_pkcs15_card_t *p15card,
|
||||
sc_pkcs15emu_opt_t *opts);
|
||||
extern int sc_pkcs15emu_gemsafeGPK_init_ex(sc_pkcs15_card_t *p15card,
|
||||
sc_pkcs15emu_opt_t *opts);
|
||||
extern int sc_pkcs15emu_gemsafeV1_init_ex(sc_pkcs15_card_t *p15card,
|
||||
sc_pkcs15emu_opt_t *opts);
|
||||
extern int sc_pkcs15emu_actalis_init_ex(sc_pkcs15_card_t *p15card,
|
||||
sc_pkcs15emu_opt_t *opts);
|
||||
extern int sc_pkcs15emu_atrust_acos_init_ex(sc_pkcs15_card_t *p15card,
|
||||
@ -62,6 +64,7 @@ static struct {
|
||||
{ "postecert", sc_pkcs15emu_postecert_init_ex },
|
||||
{ "PIV-II", sc_pkcs15emu_piv_init_ex },
|
||||
{ "gemsafeGPK", sc_pkcs15emu_gemsafeGPK_init_ex },
|
||||
{ "gemsafeV1", sc_pkcs15emu_gemsafeV1_init_ex },
|
||||
{ "actalis", sc_pkcs15emu_actalis_init_ex },
|
||||
{ "atrust-acos",sc_pkcs15emu_atrust_acos_init_ex},
|
||||
{ "tccardos", sc_pkcs15emu_tccardos_init_ex },
|
||||
|
Loading…
Reference in New Issue
Block a user