add support for asepcos

git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@3200 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
nils 2007-07-03 20:44:34 +00:00
parent 7c5fe33cfe
commit 8770859315
13 changed files with 2112 additions and 8 deletions

View File

@ -30,6 +30,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 \
\
pkcs15-openpgp.c pkcs15-infocamere.c pkcs15-starcert.c \
pkcs15-tcos.c pkcs15-esteid.c pkcs15-postecert.c pkcs15-gemsafe.c \

View File

@ -27,7 +27,7 @@ OBJECTS = \
card-cardos.obj card-tcos.obj card-emv.obj card-default.obj \
card-mcrd.obj card-starcos.obj card-openpgp.obj card-jcop.obj \
card-oberthur.obj card-belpic.obj card-atrust-acos.obj \
card-incrypto34.obj card-piv.obj card-acos5.obj \
card-incrypto34.obj card-piv.obj card-acos5.obj card-asepcos.obj \
muscle.obj card-muscle.obj muscle-filesystem.obj \
compression.obj p15card-helper.obj \
\

1112
src/libopensc/card-asepcos.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -130,7 +130,16 @@ enum {
SC_CARDCTL_MUSCLE_GENERATE_KEY,
SC_CARDCTL_MUSCLE_EXTRACT_KEY,
SC_CARDCTL_MUSCLE_IMPORT_KEY,
SC_CARDCTL_MUSCLE_VERIFIED_PINS
SC_CARDCTL_MUSCLE_VERIFIED_PINS,
/*
* ASEPCOS specific calls
*/
SC_CARDCTL_ASEPCOS_BASE = _CTL_PREFIX('A','S','E'),
SC_CARDCTL_ASEPCOS_CHANGE_KEY,
SC_CARDCTL_ASEPCOS_AKN2FILEID,
SC_CARDCTL_ASEPCOS_SET_SATTR,
SC_CARDCTL_ASEPCOS_ACTIVATE_FILE
};
enum {
@ -400,6 +409,23 @@ typedef struct sc_cardctl_muscle_key_info {
typedef struct sc_cardctl_muscle_verified_pins_info {
unsigned verifiedPins;
} sc_cardctl_muscle_verified_pins_info_t;
/* ASEPCOS ctl specific structures */
typedef struct sc_cardctl_asepcos_change_key {
const u8 *data;
size_t datalen;
} sc_cardctl_asepcos_change_key_t;
typedef struct sc_cardctl_asepcos_akn2fileid {
int akn;
int fileid;
} sc_cardctl_asepcos_akn2fileid_t;
typedef struct sc_cardctl_asepcos_activate_file {
int fileid;
int is_ef;
} sc_cardctl_asepcos_activate_file_t;
#ifdef __cplusplus
}
#endif

View File

@ -125,7 +125,12 @@ enum {
/* ACOS5 driver */
SC_CARD_TYPE_ACOS5_BASE = 16000,
SC_CARD_TYPE_ACOS5_GENERIC
SC_CARD_TYPE_ACOS5_GENERIC,
/* Athena APCOS cards */
SC_CARD_TYPE_ASEPCOS_BASE = 17000,
SC_CARD_TYPE_ASEPCOS_GENERIC,
SC_CARD_TYPE_ASEPCOS_JAVA
};
#ifdef __cplusplus

View File

@ -60,6 +60,7 @@ static const struct _sc_driver_entry internal_card_drivers[] = {
#endif
{ "miocos", (void *(*)(void)) sc_get_miocos_driver },
{ "mcrd", (void *(*)(void)) sc_get_mcrd_driver },
{ "asepcos", (void *(*)(void)) sc_get_asepcos_driver },
{ "setcos", (void *(*)(void)) sc_get_setcos_driver },
{ "starcos", (void *(*)(void)) sc_get_starcos_driver },
{ "tcos", (void *(*)(void)) sc_get_tcos_driver },
@ -69,7 +70,7 @@ static const struct _sc_driver_entry internal_card_drivers[] = {
{ "oberthur", (void *(*)(void)) sc_get_oberthur_driver },
#endif
{ "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 },
{ "incrypto34", (void *(*)(void)) sc_get_incrypto34_driver },

View File

@ -1175,6 +1175,7 @@ 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_muscle_driver(void);
extern sc_card_driver_t *sc_get_acos5_driver(void);
extern sc_card_driver_t *sc_get_asepcos_driver(void);
#ifdef __cplusplus
}

View File

@ -19,7 +19,8 @@ PROFILES = \
starcos.profile \
setcos.profile \
pkcs15.profile \
muscle.profile
muscle.profile \
asepcos.profile
EXTRA_DIST = $(PROFILES) Makefile.mak
@ -31,7 +32,7 @@ libpkcs15init_la_SOURCES = \
pkcs15-gpk.c pkcs15-miocos.c pkcs15-cflex.c \
pkcs15-cardos.c pkcs15-jcop.c pkcs15-starcos.c \
pkcs15-oberthur.c pkcs15-setcos.c pkcs15-incrypto34.c \
pkcs15-muscle.c
pkcs15-muscle.c pkcs15-asepcos.c
libpkcs15init_la_LDFLAGS = -version-info @OPENSC_LT_CURRENT@:@OPENSC_LT_REVISION@:@OPENSC_LT_AGE@

View File

@ -9,7 +9,7 @@ OBJECTS = profile.obj pkcs15-lib.obj keycache.obj \
pkcs15-miocos.obj pkcs15-gpk.obj pkcs15-cflex.obj \
pkcs15-cardos.obj pkcs15-jcop.obj pkcs15-starcos.obj \
pkcs15-oberthur.obj pkcs15-setcos.obj pkcs15-incrypto34.obj \
pkcs15-muscle.obj
pkcs15-muscle.obj pkcs15-asepcos.obj
all: install-headers $(TARGET)

View File

@ -0,0 +1,110 @@
#
# PKCS15 r/w profile for Athena APCOS cards
#
cardinfo {
max-pin-length = 16;
pin-encoding = ascii-numeric;
pin-pad-char = 0x00;
}
# Default settings.
# This option block will always be processed.
option default {
macros {
so-pin-flags = local, initialized, soPin;
df_acl = *=$SOPIN;
}
}
# This option sets up the card so that a single
# user PIN protects all files
option onepin {
macros {
so-pin-flags = local, initialized;
df_acl = *=$PIN;
}
}
# Define reasonable limits for PINs and PUK
PIN so-pin {
reference = 1;
flags = $so-pin-flags;
}
PIN so-puk {
reference = 2;
}
PIN user-pin {
attempts = 3;
flags = local, initialized;
}
PIN user-puk {
attempts = 10;
flags = local, initialized;
}
# Additional filesystem info.
# This is added to the file system info specified in the
# main profile.
filesystem {
DF MF {
ACL = *=AUT0;
DF PKCS15-AppDF {
size = 8192;
ACL = $df_acl;
EF PKCS15-PrKDF {
size = 384;
}
EF PKCS15-PuKDF {
size = 384;
}
# This template defines files for keys, certificates etc.
#
# When instantiating the template, each file id will be
# combined with the last octet of the object's pkcs15 id
# to form a unique file ID.
template key-domain {
# This is a dummy entry - pkcs15-init insists that
# this is present
EF private-key {
file-id = 0100;
ACL = *=NEVER, CRYPTO=$PIN, UPDATE=$PIN;
}
# public keys
EF public-key {
file-id = 3003;
structure = transparent;
ACL = *=NEVER,
READ=NONE,
UPDATE=$PIN,
ERASE=$PIN;
}
# Certificate template
EF certificate {
file-id = 3104;
structure = transparent;
ACL = *=NEVER,
READ=NONE,
UPDATE=$PIN,
ERASE=$PIN;
}
# data objects are stored in transparent EFs.
EF data {
file-id = 3302;
structure = transparent;
ACL = *=NEVER,
READ=NONE,
UPDATE=$PIN,
ERASE=$PIN;
}
}
}
}
}

View File

@ -0,0 +1,846 @@
/*
* Copyright (c) 2007 Athena Smartcard Solutions Inc.
*
* 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 <opensc/opensc.h>
#include <opensc/cardctl.h>
#include <opensc/log.h>
#include "pkcs15-init.h"
#include "profile.h"
/* delete a EF/DF if present. This function does not return an
* error if the requested file is not present.
*/
static int asepcos_cond_delete(sc_profile_t *pro, sc_card_t *card,
const sc_path_t *path)
{
int r;
sc_file_t *tfile = NULL;
sc_ctx_suppress_errors_on(card->ctx);
r = sc_select_file(card, path, &tfile);
sc_ctx_suppress_errors_off(card->ctx);
if (r == SC_SUCCESS) {
r = sc_pkcs15init_authenticate(pro, card, tfile, SC_AC_OP_DELETE_SELF);
sc_file_free(tfile);
if (r != SC_SUCCESS)
return r;
r = sc_delete_file(card, path);
} else if (r == SC_ERROR_FILE_NOT_FOUND)
r = SC_SUCCESS;
return r;
}
/* checks whether the file with the transport key exists. If existent
* the transport key is verified and stored in the keycache (as a
* normal user PIN with the same reference).
* @param profile profile information for this card
* @param card sc_card_t object to use
* @return SC_SUCCESS on success and an error code otherwise
*/
static int asepcos_check_verify_tpin(sc_profile_t *profile, sc_card_t *card)
{
int r;
sc_path_t path;
/* check whether the file with the transport PIN exists */
sc_format_path("3f000001", &path);
sc_ctx_suppress_errors_on(card->ctx);
r = sc_select_file(card, &path, NULL);
sc_ctx_suppress_errors_off(card->ctx);
if (r == SC_SUCCESS) {
/* try to verify the transport key */
u8 pbuf[64];
size_t psize = sizeof(pbuf);
sc_file_t *tfile = NULL;
sc_format_path("3f00", &path);
r = sc_profile_get_file_by_path(profile, sc_get_mf_path(), &tfile);
if (r != SC_SUCCESS)
return r;
/* we need to temporarily disable the SC_CARD_CAP_USE_FCI_AC
* flag to trick sc_pkcs15init_authenticate() to use access
* information form the profile file */
card->caps &= ~SC_CARD_CAP_USE_FCI_AC;
r = sc_pkcs15init_authenticate(profile, card, tfile, SC_AC_OP_CRYPTO);
card->caps |= SC_CARD_CAP_USE_FCI_AC;
sc_file_free(tfile);
if (r != SC_SUCCESS) {
sc_error(card->ctx, "unable to authenticate");
return r;
}
/* store the transport key as a PIN */
r = sc_keycache_get_key(&path, SC_AC_AUT, 0, pbuf, psize);
if (r < 0) {
sc_error(card->ctx, "unable to get transport key");
return r;
}
r = sc_keycache_put_key(&path, SC_AC_CHV, 0, pbuf, (size_t)r);
if (r != SC_SUCCESS) {
sc_error(card->ctx, "unable to store transport key");
return r;
}
}
return SC_SUCCESS;
}
/* erase card: erase all EFs/DFs created by OpenSC
* @param profile the sc_profile_t object with the configurable profile
* information
* @param card the card from which the opensc application should be
* erased.
* @return SC_SUCCESS on success and an error code otherwise
*/
static int asepcos_erase(struct sc_profile *profile, sc_card_t *card)
{
int r;
sc_path_t path;
/* TODO: - only remove the OpenSC entry in EF(DIR)
* - use EF(DIR) to get the DF of the OpenSC
* pkcs15 application.
*/
/* EF(DIR) */
sc_format_path("3f002f00", &path);
r = asepcos_cond_delete(profile, card, &path);
if (r != SC_SUCCESS)
return r;
/* DF(PKCS15) */
sc_format_path("3f005015", &path);
r = asepcos_cond_delete(profile, card, &path);
if (r != SC_SUCCESS)
return r;
return SC_SUCCESS;
}
/* create application DF
* @param profile sc_profile_t object with the configurable profile
* information
* @param cardd sc_card_t object to be used
* @param df sc_file_t with the application DF to create
* @return SC_SUCCESS on success and an error value otherwise
*/
static int asepcos_create_dir(sc_profile_t *profile, sc_card_t *card,
sc_file_t *df)
{
int r;
static const u8 pa_acl[] = {0x80,0x01,0x5f,0x90,0x00};
sc_file_t *tfile;
/* Check wether a transport exists and verify it if present */
r = asepcos_check_verify_tpin(profile, card);
if (r != SC_SUCCESS)
return r;
/* As we don't know whether or not a SO-PIN is used to protect the AC
* in the application DF we set the preliminary security attributes
* of the DF(PKCS15) to allow everything. Once a SO-PIN is set
* we tighten security attributes to values specified in the profile.
*/
sc_file_dup(&tfile, df);
/* we use a separate copy of the sc_file_t object so we don't
* override the permissions specified in the profile */
if (tfile == NULL)
return SC_ERROR_OUT_OF_MEMORY;
r = sc_file_set_sec_attr(tfile, pa_acl, sizeof(pa_acl));
if (r != SC_SUCCESS) {
sc_file_free(tfile);
return r;
}
/* create application DF */
r = sc_pkcs15init_create_file(profile, card, tfile);
sc_file_free(tfile);
return r;
}
/* select PIN reference: do nothing special, the real PIN reference if
* determined when the PIN is created. This is just helper function to
* determine the next best file id of the PIN file.
*/
static int asepcos_select_pin_reference(sc_profile_t *profile, sc_card_t *card,
sc_pkcs15_pin_info_t *pinfo)
{
if (pinfo->flags & SC_PKCS15_PIN_FLAG_SO_PIN)
return SC_SUCCESS;
if (pinfo->reference <= 0)
pinfo->reference = 1;
/* as we want to use <fileid of PIN> + 1 for the PUK we need to
* ensure that all references are odd => if the reference is
* even add one */
if ((pinfo->reference & 1) == 0)
pinfo->reference++;
return SC_SUCCESS;
}
/* asepcos_pinid_to_akn: returns the AKN of a PIN EF
* This functions calls SELECT FILE and extracts the AKN from the
* proprietary FCP attributes.
* @param card sc_card_t object to use
* @param fileid IN file id of the PIN file
* @param akn OUT the AKN of the PIN
* @return SC_SUCCESS on success and an error code otherwise
*/
static int asepcos_pinid_to_akn(sc_card_t *card, int fileid, int *akn)
{
int r;
u8 fid[2];
sc_path_t path;
sc_file_t *nfile = NULL;
fid[0] = (fileid >> 8) & 0xff;
fid[1] = fileid & 0xff;
r = sc_path_set(&path, SC_PATH_TYPE_FILE_ID, fid, 2, 0, 0);
if (r != SC_SUCCESS)
return r;
r = sc_select_file(card, &path, &nfile);
if (r != SC_SUCCESS)
return r;
if (nfile->prop_attr == NULL || nfile->prop_attr_len != 11) {
sc_error(card->ctx, "unable to determine AKN");
sc_file_free(nfile);
return SC_ERROR_INTERNAL;
}
*akn = nfile->prop_attr[10];
sc_file_free(nfile);
return SC_SUCCESS;
}
static int asepcos_do_store_pin(sc_profile_t *profile, sc_card_t *card,
sc_pkcs15_pin_info_t *pinfo, const u8* pin, size_t pinlen,
int puk, int pinid)
{
sc_file_t *nfile = NULL;
u8 buf[64], sbuf[64], *p = buf, *q = sbuf;
int r, akn;
/* outter tag */
*p++ = 0x85;
p++;
/* as a file id for pin with use 0x00:<key id> */
*p++ = (pinid >> 8) & 0xff;
*p++ = pinid & 0xff;
/* pin length */
if (pinlen < 4 || pinlen > 16) {
sc_error(card->ctx, "invalid PIN length");
return SC_ERROR_INVALID_ARGUMENTS;
}
*p++ = 0x00;
*p++ = pinlen & 0xff;
/* max tries */
*p++ = pinfo->tries_left & 0xff;
/* algorithm id and key key usage and padding bytes */
*p++ = 0x00;
*p++ = 0x00;
/* key attributes (SO PIN) */
#if 0
*p++ = (pinfo->flags & SC_PKCS15_PIN_FLAG_SO_PIN) ? 0x08 : 0x00;
#else
*p++ = 0x00;
#endif
/* the PIN */
*p++ = 0x81;
*p++ = pinlen & 0xff;
memcpy(p, pin, pinlen);
p += pinlen;
/* set outer length */
buf[1] = p - buf - 2;
nfile = sc_file_new();
if (nfile == NULL)
return SC_ERROR_OUT_OF_MEMORY;
nfile->type = SC_FILE_TYPE_INTERNAL_EF;
nfile->id = pinid & 0xffff;
r = sc_file_set_prop_attr(nfile, buf, p - buf);
if (r != SC_SUCCESS) {
sc_file_free(nfile);
return r;
}
/* set security attributes */
*q++ = 0x80;
*q++ = 0x01;
*q++ = 0x92;
*q++ = 0xa0;
q++;
*q++ = 0x89;
*q++ = 0x03;
*q++ = (pinid >> 16) & 0xff;
*q++ = (pinid >> 8 ) & 0xff;
*q++ = pinid & 0xff;
if (puk != 0) {
*q++ = 0x89;
*q++ = 0x03;
*q++ = (puk >> 16) & 0xff;
*q++ = (puk >> 8 ) & 0xff;
*q++ = puk & 0xff;
}
sbuf[4] = q - sbuf - 5;
/* we need to set the security attributes separately as PIN itself
* is used to protect the UPDATE access permission.
*/
r = sc_file_set_sec_attr(nfile, sbuf, q - sbuf);
if (r != SC_SUCCESS) {
sc_file_free(nfile);
return r;
}
r = sc_create_file(card, nfile);
sc_file_free(nfile);
if (r != SC_SUCCESS) {
sc_error(card->ctx, "unable to create PIN file");
return r;
}
/* get AKN of the newly created PIN */
r = asepcos_pinid_to_akn(card, pinid, &akn);
if (r != SC_SUCCESS)
return r;
/* use the AKN as reference */
pinfo->reference = akn;
/* set the correct PIN length */
pinfo->min_length = 4;
pinfo->stored_length = pinlen;
pinfo->max_length = 16;
return r;
}
/* simple function to detect whether or not the "onepin" profile is used
* (copied from pkcs15-starcos.c).
*/
static int have_onepin(sc_profile_t *profile)
{
sc_pkcs15_pin_info_t sopin;
sc_profile_get_pin_info(profile, SC_PKCS15INIT_SO_PIN, &sopin);
if (!(sopin.flags & SC_PKCS15_PIN_FLAG_SO_PIN))
return 1;
else
return 0;
}
static void asepcos_fix_pin_reference(sc_pkcs15_pin_info_t *pinfo)
{
if (pinfo->flags & SC_PKCS15_PIN_FLAG_SO_PIN)
sc_keycache_set_pin_name(&pinfo->path, pinfo->reference, SC_PKCS15INIT_SO_PIN);
else
sc_keycache_set_pin_name(&pinfo->path, pinfo->reference, SC_PKCS15INIT_USER_PIN);
}
/* create PIN and, if specified, PUK files
* @param profile profile information for this card
* @param card sc_card_t object to use
* @param pin_obj sc_pkcs15_object_t for the PIN
* @param pin PIN value
* @param len_len PIN length
* @param puk PUK value (optional)
* @param puk_len PUK length (optional)
* @return SC_SUCCESS on success and an error code otherwise
*/
static int asepcos_create_pin(sc_profile_t *profile, sc_card_t *card,
sc_file_t *df, sc_pkcs15_object_t *pin_obj,
const u8 *pin, size_t pin_len, const u8 *puk, size_t puk_len)
{
sc_pkcs15_pin_info_t *pinfo = (sc_pkcs15_pin_info_t *) pin_obj->data;
int r, pid;
sc_path_t tpath = df->path;
sc_file_t *tfile = NULL;
if (!pin || !pin_len)
return SC_ERROR_INVALID_ARGUMENTS;
pid = (pinfo->reference & 0xff) | (((tpath.len >> 1) - 1) << 16);
/* get the ACL of the application DF */
r = sc_select_file(card, &df->path, &tfile);
if (r != SC_SUCCESS)
return r;
/* verify the PIN protecting the CREATE acl (if necessary) */
r = sc_pkcs15init_authenticate(profile, card, tfile, SC_AC_OP_CREATE);
sc_file_free(tfile);
if (r != SC_SUCCESS) {
sc_error(card->ctx, "unable to create PIN file, insufficent rights");
return r;
}
do {
sc_path_t pin_path;
memset(&pin_path, 0, sizeof(sc_path_t));
pin_path.type = SC_PATH_TYPE_FILE_ID;
/* XXX: check the pkcs15 structure whether this file id
* is already used */
r = sc_append_file_id(&pin_path, pid & 0xff);
if (r != SC_SUCCESS)
return r;
sc_ctx_suppress_errors_on(card->ctx);
r = sc_select_file(card, &pin_path, NULL);
sc_ctx_suppress_errors_off(card->ctx);
if (r == SC_SUCCESS)
pid += 2;
else if (r != SC_ERROR_FILE_NOT_FOUND) {
sc_error(card->ctx, "error selecting PIN file");
return r;
}
} while (r != SC_ERROR_FILE_NOT_FOUND);
if (puk != NULL && puk_len != 0) {
/* Create PUK (if specified). Note: we need to create the PUK
* the PIN as the PUK fileid is used in the PIN acl.
*/
struct sc_pkcs15_pin_info puk_info;
if (pinfo->flags & SC_PKCS15_PIN_FLAG_SO_PIN)
sc_profile_get_pin_info(profile, SC_PKCS15INIT_SO_PUK, &puk_info);
else
sc_profile_get_pin_info(profile, SC_PKCS15INIT_USER_PUK, &puk_info);
/* If a PUK we use "file id of the PIN" + 1 as the file id
* of the PUK.
*/
r = asepcos_do_store_pin(profile, card, &puk_info, puk, puk_len, 0, pid+1);
if (r != SC_SUCCESS)
return r;
}
r = asepcos_do_store_pin(profile, card, pinfo, pin, pin_len, pid+1, pid);
if (r != SC_SUCCESS)
return r;
#if 1
if (pinfo->flags & SC_PKCS15_PIN_FLAG_SO_PIN ||
(have_onepin(profile) && pid == 0x010001)) {
sc_cardctl_asepcos_activate_file_t st;
/* Once the SO PIN or ,in case of the "onepin" profile", the
* first USER PIN has been set we can tighten the ACLs of
* the application DF.
*/
sc_debug(card->ctx, "finalizing application DF");
/* first we need to fix the reference to pin in the key
* keycache as sc_pkcs15init_fixup_file() will otherwise
* mess up the ACLs */
asepcos_fix_pin_reference(pinfo);
r = sc_select_file(card, &df->path, NULL);
if (r != SC_SUCCESS)
return r;
/* remove symbolic references from the ACLs */
r = sc_pkcs15init_fixup_file(profile, df);
if (r != SC_SUCCESS)
return r;
r = sc_card_ctl(card, SC_CARDCTL_ASEPCOS_SET_SATTR, df);
if (r != SC_SUCCESS) {
sc_error(card->ctx, "unable to change the security attributes");
return r;
}
/* finally activate the application DF (fix ACLs) */
/* 1. select MF */
r = sc_select_file(card, sc_get_mf_path(), NULL);
if (r != SC_SUCCESS)
return r;
/* 2. activate the application DF */
st.fileid = df->id;
st.is_ef = 0;
r = sc_card_ctl(card, SC_CARDCTL_ASEPCOS_ACTIVATE_FILE, &st);
if (r != SC_SUCCESS) {
sc_error(card->ctx, "unable to activate DF");
return r;
}
}
#endif
#ifdef asepcos_USE_PIN_PATH
/* using the real path to the PIN file would be nice but unfortunately
* it currently causes some problems with the keycache code
*/
r = sc_append_file_id(&tpath, pid & 0xff);
if (r != SC_SUCCESS)
return r;
pinfo->path = tpath;
#endif
return r;
}
/* internal wrapper for sc_pkcs15init_authenticate()
* @param profile information for this card
* @param card sc_card_t object to use
* @param path path to the EF/DF for which the credential is required
* @param op the required access method
* @return SC_SUCCESS on success and an error code otherwise
*/
static int asepcos_do_authenticate(sc_profile_t *profile, sc_card_t *card,
const sc_path_t *path, int op)
{
int r;
sc_file_t *prkey = NULL;
r = sc_profile_get_file_by_path(profile, path, &prkey);
if (r != SC_SUCCESS) {
sc_error(card->ctx, "unable to find file in profile");
return r;
}
r = sc_pkcs15init_authenticate(profile, card, prkey, op);
sc_file_free(prkey);
if (r != SC_SUCCESS) {
sc_error(card->ctx, "unable to authenticate");
return r;
}
return SC_SUCCESS;
}
#define SET_TLV_LENGTH(p,l) do { \
if ((l) < 128) \
*(p)++ = (l) & 0x7f; \
else if ((l) < 256) { \
*(p)++ = 0x81; \
*(p)++ = (l) & 0xff; \
} else { \
*(p)++ = 0x82; \
*(p)++ = ((l) >> 8 ) & 0xff; \
*(p)++ = (l) & 0xff; \
} \
} while(0)
static int asepcos_do_create_key(sc_card_t *card, size_t ksize, int fileid,
const u8 *keydata, size_t kdlen)
{
int r;
size_t len;
sc_file_t *nfile = NULL;
u8 buf[512], *p = buf;
if (sizeof(buf) < kdlen + 11)
return SC_ERROR_BUFFER_TOO_SMALL;
*p++ = 0x85;
*p++ = 0x82;
p += 2;
/* file id */
*p++ = (fileid >> 8) && 0xff;
*p++ = fileid & 0xff;
/* key size */
*p++ = (ksize >> 8) & 0xff;
*p++ = ksize & 0xff;
/* max attempts */
*p++ = 0x03;
/* key attributes */
*p++ = 0xc0;
*p++ = 0x80;
*p++ = 0x00;
/* key parts */
memcpy(p, keydata, kdlen);
p += kdlen;
/* set outer TLV length */
len = p - buf - 4;
buf[2] = (len >> 8) & 0xff;
buf[3] = len & 0xff;
nfile = sc_file_new();
if (nfile == NULL)
return SC_ERROR_OUT_OF_MEMORY;
nfile->type = SC_FILE_TYPE_INTERNAL_EF;
nfile->id = fileid & 0xffff;
r = sc_file_set_prop_attr(nfile, buf, p - buf);
if (r != SC_SUCCESS) {
sc_error(card->ctx, "unable to set key prop. attributes");
sc_file_free(nfile);
return r;
}
r = sc_create_file(card, nfile);
sc_file_free(nfile);
if (r != SC_SUCCESS) {
sc_error(card->ctx, "unable to create key file");
return r;
}
return r;
}
/* creates a key file
*/
static int asepcos_create_key(sc_profile_t *profile, sc_card_t *card,
sc_pkcs15_object_t *obj)
{
sc_pkcs15_prkey_info_t *kinfo = (sc_pkcs15_prkey_info_t *) obj->data;
int r, len;
u8 buf[512], *p = buf;
size_t blen = kinfo->modulus_length / 8;
int afileid = -1,
fileid = (kinfo->path.value[kinfo->path.len-2]) << 8 |
kinfo->path.value[kinfo->path.len-1];
if (obj->auth_id.len != 0) {
/* the key is proctected by a PIN */
/* XXX use the pkcs15 structures for this */
sc_cardctl_asepcos_akn2fileid_t st;
st.akn = sc_keycache_find_named_pin(NULL, SC_PKCS15INIT_USER_PIN);
r = sc_card_ctl(card, SC_CARDCTL_ASEPCOS_AKN2FILEID, &st);
if (r != SC_SUCCESS) {
sc_error(card->ctx, "unable to determine file id of the PIN");
return r;
}
afileid = st.fileid;
}
#if 0
/* select the DF */
r = sc_select_file(card, &profile->df_info->file->path, NULL);
if (r != SC_SUCCESS)
return r;
#endif
/* authenticate if necessary */
r = asepcos_do_authenticate(profile, card, &profile->df_info->file->path, SC_AC_OP_CREATE);
if (r != SC_SUCCESS)
return r;
/* first: create private key (file id = 0x0100 | <ref & 0xff>) */
/* key parts */
*p++ = 0xc1;
*p++ = 0x82;
p += 2;
#if 0
/* private exponent */
*p++ = 0x92;
SET_TLV_LENGTH(p, blen);
memset(p, 0xff, blen);
p += blen;
#else
/* public exponent */
*p++ = 0x90;
SET_TLV_LENGTH(p, 3);
memset(p, 0xff, 3);
p += 3;
#endif
/* primes p, q */
*p++ = 0x93;
SET_TLV_LENGTH(p, blen);
memset(p, 0xff, blen);
p += blen;
/* key TLV length */
len = p - buf - 4;
buf[2] = (len >> 8) & 0xff;
buf[3] = len & 0xff;
/* security attributes */
*p++ = 0x80;
*p++ = 0x01;
*p++ = 0xa2; /* compute signature and generate key pair */
if (afileid > 0) {
*p++ = 0xa0;
*p++ = 0x05;
*p++ = 0x89;
*p++ = 0x03;
*p++ = (afileid >> 16) & 0xff;
*p++ = (afileid >> 8 ) & 0xff;
*p++ = afileid & 0xff;
} else {
*p++ = 0x90;
*p++ = 0x00;
}
r = asepcos_do_create_key(card, kinfo->modulus_length, fileid, buf, p - buf);
if (r != SC_SUCCESS) {
sc_error(card->ctx, "unable to create private key file");
return r;
}
return r;
}
/* stores a rsa private key in a internal EF
*/
static int asepcos_do_store_rsa_key(sc_card_t *card, sc_profile_t *profile,
sc_pkcs15_object_t *obj, sc_pkcs15_prkey_info_t *kinfo,
struct sc_pkcs15_prkey_rsa *key)
{
int r, klen;
u8 buf[512], *p = buf;
sc_path_t tpath;
sc_cardctl_asepcos_change_key_t ckdata;
/* authenticate if necessary */
if (obj->auth_id.len != 0) {
r = asepcos_do_authenticate(profile, card, &kinfo->path, SC_AC_OP_UPDATE);
if (r != SC_SUCCESS)
return r;
}
/* select the rsa private key */
tpath.type = SC_PATH_TYPE_FILE_ID;
tpath.len = 2;
tpath.value[0] = kinfo->path.value[kinfo->path.len-2];
tpath.value[1] = kinfo->path.value[kinfo->path.len-1];
r = sc_select_file(card, &tpath, NULL);
if (r != SC_SUCCESS) {
sc_error(card->ctx, "unable to select rsa key file");
return r;
}
/* store key parts in buffer */
*p++ = 0xc1;
*p++ = 0x82;
p += 2;
#if 0
/* private exponent */
*p++ = 0x92;
SET_TLV_LENGTH(p, key->d.len);
memcpy(p, key->d.data, key->d.len);
p += key->d.len;
#else
/* public exponent */
*p++ = 0x90;
SET_TLV_LENGTH(p, key->exponent.len);
memcpy(p, key->exponent.data, key->exponent.len);
p += key->exponent.len;
#endif
/* primes p, q */
*p++ = 0x93;
SET_TLV_LENGTH(p, (key->p.len + key->q.len));
memcpy(p, key->p.data, key->p.len);
p += key->p.len;
memcpy(p, key->q.data, key->q.len);
p += key->q.len;
/* key TLV length */
klen = p - buf - 4;
buf[2] = (klen >> 8) & 0xff;
buf[3] = klen & 0xff;
ckdata.data = buf;
ckdata.datalen = p - buf;
r = sc_card_ctl(card, SC_CARDCTL_ASEPCOS_CHANGE_KEY, &ckdata);
if (r != SC_SUCCESS) {
sc_error(card->ctx, "unable to change key data");
return r;
}
return SC_SUCCESS;
}
/* Stores an external (RSA) on the card.
* @param profile profile information for this card
* @param card sc_card_t object to use
* @param obj sc_pkcs15_object_t object with pkcs15 information
* @param key the private key
* @return SC_SUCCESS on success and an error code otherwise
*/
static int asepcos_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 *kinfo = (sc_pkcs15_prkey_info_t *) obj->data;
if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) {
sc_error(card->ctx, "only RSA is currently supported");
return SC_ERROR_NOT_SUPPORTED;
}
return asepcos_do_store_rsa_key(card, profile, obj, kinfo, &key->u.rsa);
}
/* Generates a new (RSA) key pair using an existing key file.
* @param profile IN profile information for this card
* @param card IN sc_card_t object to use
* @param obj IN sc_pkcs15_object_t object with pkcs15 information
* @param pukkey OUT the newly created public key
* @return SC_SUCCESS on success and an error code otherwise
*/
static int asepcos_generate_key(sc_profile_t *profile, sc_card_t *card,
sc_pkcs15_object_t *obj, sc_pkcs15_pubkey_t *pubkey)
{
int r;
sc_pkcs15_prkey_info_t *kinfo = (sc_pkcs15_prkey_info_t *) obj->data;
sc_apdu_t apdu;
sc_path_t tpath;
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE],
sbuf[SC_MAX_APDU_BUFFER_SIZE];
/* authenticate if necessary */
r = asepcos_do_authenticate(profile, card, &kinfo->path, SC_AC_OP_UPDATE);
if (r != SC_SUCCESS)
return r;
/* select the rsa private key */
tpath.type = SC_PATH_TYPE_FILE_ID;
tpath.len = 2;
tpath.value[0] = kinfo->path.value[kinfo->path.len-2];
tpath.value[1] = kinfo->path.value[kinfo->path.len-1];
r = sc_select_file(card, &tpath, NULL);
if (r != SC_SUCCESS) {
sc_error(card->ctx, "unable to select rsa key file");
return r;
}
sbuf[0] = 0x01;
sbuf[1] = 0x00;
sbuf[2] = 0x01;
sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x46, 0x00, 0x00);
apdu.lc = 3;
apdu.datalen = 3;
apdu.data = sbuf;
apdu.le = 256;
apdu.resplen = sizeof(rbuf);
apdu.resp = rbuf;
r = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00) {
sc_error(card->ctx, "error creating key");
return SC_ERROR_INTERNAL;
}
pubkey->u.rsa.modulus.len = apdu.resplen;
pubkey->u.rsa.modulus.data = malloc(apdu.resplen);
if (pubkey->u.rsa.modulus.data == NULL)
return SC_ERROR_OUT_OF_MEMORY;
memcpy(pubkey->u.rsa.modulus.data, apdu.resp, apdu.resplen);
pubkey->u.rsa.exponent.len = 3;
pubkey->u.rsa.exponent.data = malloc(3);
if (pubkey->u.rsa.exponent.data == NULL)
return SC_ERROR_OUT_OF_MEMORY;
memcpy(pubkey->u.rsa.exponent.data, sbuf, 3);
return SC_SUCCESS;
}
static struct sc_pkcs15init_operations sc_pkcs15init_asepcos_operations = {
asepcos_erase,
NULL, /* init_card */
asepcos_create_dir,
NULL, /* create_domain */
asepcos_select_pin_reference,
asepcos_create_pin,
NULL, /* select key reference */
asepcos_create_key,
asepcos_store_key,
asepcos_generate_key,
NULL, NULL, /* encode private/public key */
NULL, /* finalize_card */
NULL, NULL, NULL, NULL, NULL, /* old style api */
NULL /* delete_object */
};
struct sc_pkcs15init_operations * sc_pkcs15init_get_asepcos_ops(void)
{
return &sc_pkcs15init_asepcos_operations;
}

View File

@ -400,7 +400,7 @@ 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_incrypto34_ops(void);
extern struct sc_pkcs15init_operations *sc_pkcs15init_get_muscle_ops(void);
extern struct sc_pkcs15init_operations *sc_pkcs15init_get_apcos_ops(void);
extern struct sc_pkcs15init_operations *sc_pkcs15init_get_asepcos_ops(void);
#ifdef __cplusplus
}

View File

@ -161,6 +161,7 @@ static struct profile_operations {
{ "setcos", (void *) sc_pkcs15init_get_setcos_ops },
{ "incrypto34", (void *) sc_pkcs15init_get_incrypto34_ops },
{ "muscle", (void*) sc_pkcs15init_get_muscle_ops },
{ "asepcos", (void*) sc_pkcs15init_get_asepcos_ops },
{ NULL, NULL },
};