r3717:3719 from trunk

git-svn-id: https://www.opensc-project.org/svnp/opensc/branches/martin/0.12@3720 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
martin 2009-09-12 11:46:00 +00:00
parent 89e18e51dd
commit d3201511c7
20 changed files with 3388 additions and 6 deletions

3
NEWS
View File

@ -6,6 +6,9 @@ http://www.opensc-project.org/opensc/wiki/WhatsNew
Also see the svn changelog using svn command
or doc/nonpersistent/ChangeLog.
New in 0.??.==; 200?-??-??; ??
* New westcos driver by François Leblanc
New in 0.11.9; 2009-07-29; Andreas Jellinghaus
* New rutoken_ecp driver by Aktiv Co. / Aleksey Samsonov
* Allow more keys/certificates/files etc. with entersafe tokens

View File

@ -19,6 +19,7 @@
<xi:include href="cardos-tool.xml"/>
<xi:include href="cryptoflex-tool.xml"/>
<xi:include href="netkey-tool.xml"/>
<xi:include href="westcos-tool.xml"/>
</reference>
</book>

140
doc/tools/westcos-tool.xml Normal file
View File

@ -0,0 +1,140 @@
<?xml version="1.0" encoding="UTF-8"?>
<refentry id="westcos-tool">
<refmeta>
<refentrytitle>westcos-tool</refentrytitle>
<manvolnum>1</manvolnum>
<refmiscinfo>opensc</refmiscinfo>
</refmeta>
<refnamediv>
<refname>westcos-tool</refname>
<refpurpose>utility for manipulating data structure
on westcos smart card and similar security tokens</refpurpose>
</refnamediv>
<refsect1>
<title>Synopsis</title>
<para>
<command>westcos-tool</command> [OPTIONS]
</para>
</refsect1>
<refsect1>
<title>Description</title>
<para>
The <command>westcos-tool</command> utility is used to manipulate
the westcos data structures on 2 Ko smart cards. Users can create PINs,
keys and certificates stored on the token. User PIN authentication is
performed for those operations that require it.
</para>
</refsect1>
<refsect1>
<title>Options</title>
<para>
<variablelist>
<varlistentry>
<term><option>-G</option></term>
<listitem><para>Generate a private key on smart card. The smart card must be
not finalized and pin installed (ig. file for pin must be created, see option
-i). By default key length is 1536 bits. User authentication is required for
this operation. </para></listitem>
</varlistentry>
<varlistentry>
<term><option>-L</option> <varname>length</varname></term>
<listitem><para>Change the length of private key, use with <option>-G</option>.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-i</option></term>
<listitem><para>Install pin file in token, you must provide pin value
with <option>-pin</option>.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-pin</option> <varname>value</varname></term>
<listitem><para>set value of pin.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-puk</option> <varname>value</varname></term>
<listitem><para>set value of puk (or value of new pin for change pin
command see <option>-n</option>).</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-n</option></term>
<listitem><para>Changes a PIN stored on the token. User authentication
is required for this operation.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-u</option></term>
<listitem><para>Unblocks a PIN stored on the token. Knowledge of the Pin
Unblock Key (PUK) is required for this operation.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-cert</option> <varname>file</varname> </term>
<listitem><para>Write certificate <varname>file</varname> in pem format on the
card. User authentication is required for this operation.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-F</option></term>
<listitem><para>Finalize the card, once finalize default key is invalidate so pin and puk
can'be changed anymore without user authentification. Warning, smart cards not finalized are
unsecure because pin can be changed without user authentification (knowledge of default key
is enougth).</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-r</option> <varname>n</varname></term>
<listitem><para>Forces <command>westcos-tool</command> to use reader
number <varname>n</varname> for operations.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-gf</option> <varname>path</varname></term>
<listitem><para>Get the file <varname>path</varname> the file is written
on disk with <varname>path</varname> name. User authentication
is required for this operation.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-pf</option> <varname>path</varname></term>
<listitem><para>Put the file with name <varname>path</varname> from disk
to card the file is written in <varname>path</varname>. User authentication
is required for this operation.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-v</option></term>
<listitem><para>Causes <command>westcos-tool</command> to be more
verbose. Specify this flag several times to enable debug output
in the OpenSC library.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-h</option></term>
<listitem><para>Print help message on screen.</para></listitem>
</varlistentry>
</variablelist>
</para>
</refsect1>
<refsect1>
<title>See also</title>
<para>opensc(7)</para>
</refsect1>
<refsect1>
<title>Authors</title>
<para><command>westcos-tool</command> was written by
Francois Leblanc <email>francois.leblanc@cev-sa.com</email>.</para>
</refsect1>
</refentry>

View File

@ -40,12 +40,12 @@ libopensc_la_SOURCES = \
card-oberthur.c card-belpic.c card-atrust-acos.c card-entersafe.c \
card-incrypto34.c card-piv.c card-muscle.c card-acos5.c \
card-asepcos.c card-akis.c card-gemsafeV1.c card-rutoken.c \
card-rtecp.c \
card-rtecp.c card-westcos.c \
\
pkcs15-openpgp.c pkcs15-infocamere.c pkcs15-starcert.c \
pkcs15-tcos.c pkcs15-esteid.c pkcs15-postecert.c pkcs15-gemsafeGPK.c \
pkcs15-actalis.c pkcs15-atrust-acos.c pkcs15-tccardos.c pkcs15-piv.c \
pkcs15-esinit.c \
pkcs15-esinit.c p15emu-westcos.c \
compression.c p15card-helper.c \
\
libopensc.exports

View File

@ -22,6 +22,7 @@ OBJECTS = \
\
ctbcs.obj reader-ctapi.obj reader-pcsc.obj reader-openct.obj \
\
card-westcos.obj crc_AetB.obj \
card-setcos.obj card-miocos.obj card-flex.obj card-gpk.obj \
card-cardos.obj card-tcos.obj card-emv.obj card-default.obj \
card-mcrd.obj card-starcos.obj card-openpgp.obj card-jcop.obj \
@ -30,6 +31,7 @@ OBJECTS = \
card-asepcos.obj card-akis.obj card-gemsafeV1.obj card-rutoken.obj \
card-rtecp.obj \
\
p15emu-westcos.obj \
pkcs15-openpgp.obj pkcs15-infocamere.obj pkcs15-starcert.obj \
pkcs15-tcos.obj pkcs15-esteid.obj pkcs15-postecert.obj pkcs15-gemsafeGPK.obj \
pkcs15-actalis.obj pkcs15-atrust-acos.obj pkcs15-tccardos.obj pkcs15-piv.obj \

1355
src/libopensc/card-westcos.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -175,6 +175,19 @@ enum {
SC_CARDCTL_RTECP_INIT,
SC_CARDCTL_RTECP_INIT_END,
SC_CARDCTL_RTECP_GENERATE_KEY,
/*
* Westcos specific
*/
SC_CARDCTL_WESTCOS_FREEZE = _CTL_PREFIX('W', 'T', 'C'),
SC_CARDCTL_WESTCOS_CREATE_MF,
SC_CARDCTL_WESTCOS_COMMIT,
SC_CARDCTL_WESTCOS_ROLLBACK,
SC_CARDCTL_WESTCOS_AUT_KEY,
SC_CARDCTL_WESTCOS_CHANGE_KEY,
SC_CARDCTL_WESTCOS_SET_DEFAULT_KEY,
SC_CARDCTL_WESTCOS_LOAD_DATA,
};
enum {
@ -461,6 +474,22 @@ typedef struct sc_cardctl_asepcos_activate_file {
#define OP_TYPE_GENERATE 0
#define OP_TYPE_STORE 1
/*
* Westcos
*/
typedef struct {
int key_reference;
int key_len; //8, 16 or 24
u8 key_value[24];
}sc_autkey_t;
typedef struct {
sc_autkey_t master_key;
sc_autkey_t new_key;
u8 key_template[7];
}sc_changekey_t;
/*
* RuToken types and constants
*/

View File

@ -174,6 +174,7 @@ extern sc_card_driver_t *sc_get_akis_driver(void);
extern sc_card_driver_t *sc_get_entersafe_driver(void);
extern sc_card_driver_t *sc_get_rutoken_driver(void);
extern sc_card_driver_t *sc_get_rtecp_driver(void);
extern sc_card_driver_t *sc_get_westcos_driver(void);
#ifdef __cplusplus
}

View File

@ -84,6 +84,7 @@ static const struct _sc_driver_entry internal_card_drivers[] = {
#endif
{ "rutoken", (void *(*)(void)) sc_get_rutoken_driver },
{ "rutoken_ecp",(void *(*)(void)) sc_get_rtecp_driver },
{ "westcos", (void *(*)(void)) sc_get_westcos_driver },
/* emv is not really used, not sure if it works, but it conflicts with
muscle and rutoken driver, thus has to be after them */
{ "emv", (void *(*)(void)) sc_get_emv_driver },

View File

@ -0,0 +1,251 @@
/*
* p15emu-westcos.c: pkcs15 emulation for westcos card
*
* Copyright (C) 2009 francois.leblanc@cev-sa.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 <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "pkcs15.h"
#include "cardctl.h"
#include "compat_strlcpy.h"
static int sc_pkcs15emu_westcos_init(sc_pkcs15_card_t * p15card)
{
int i, r;
int modulus_length = 0, usage = 0;
u8 buf[256];
sc_card_t *card = p15card->card;
sc_context_t *ctx = card->ctx;
sc_serial_number_t serial;
sc_path_t path;
sc_file_t *file = NULL;
sc_format_path("3F00", &path);
r = sc_select_file(card, &path, &file);
if (r)
goto out;
if (file)
sc_file_free(file);
file = NULL;
if (p15card->label != NULL)
free(p15card->label);
p15card->label = strdup("westcos");
if (p15card->manufacturer_id != NULL)
free(p15card->manufacturer_id);
p15card->manufacturer_id = strdup("CEV");
/* get serial number */
r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial);
r = sc_bin_to_hex(serial.value, serial.len, buf, sizeof(buf), 0);
if (r)
goto out;
if (p15card->serial_number != NULL)
free(p15card->serial_number);
p15card->serial_number = strdup(buf);
p15card->version = buf[6];
p15card->flags = SC_PKCS15_CARD_FLAG_LOGIN_REQUIRED;
sc_format_path("AAAA", &path);
sc_ctx_suppress_errors_on(ctx);
r = sc_select_file(card, &path, &file);
sc_ctx_suppress_errors_off(ctx);
if (!r) {
for (i = 0; i < 1; i++) {
unsigned int flags;
struct sc_pkcs15_pin_info pin_info;
struct sc_pkcs15_object pin_obj;
memset(&pin_info, 0, sizeof(pin_info));
memset(&pin_obj, 0, sizeof(pin_obj));
flags = SC_PKCS15_PIN_FLAG_INITIALIZED;
if (i == 1) {
flags |=
SC_PKCS15_PIN_FLAG_UNBLOCK_DISABLED |
SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN;
}
pin_info.auth_id.len = 1;
pin_info.auth_id.value[0] = i + 1;
pin_info.reference = i;
pin_info.flags = flags;
pin_info.type = SC_PKCS15_PIN_TYPE_BCD;
pin_info.min_length = 4;
pin_info.stored_length = 8;
pin_info.max_length = 8;
pin_info.pad_char = 0xff;
pin_info.path = path;
pin_info.tries_left = -1;
if (i == 1)
strlcpy(pin_obj.label, "Unblock",
sizeof(pin_obj.label));
else
strlcpy(pin_obj.label, "User",
sizeof(pin_obj.label));
pin_obj.flags =
SC_PKCS15_CO_FLAG_MODIFIABLE |
SC_PKCS15_CO_FLAG_PRIVATE;
r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj,
&pin_info);
if (r)
goto out;
}
}
if (file)
sc_file_free(file);
file = NULL;
sc_format_path("0002", &path);
sc_ctx_suppress_errors_on(ctx);
r = sc_select_file(card, &path, &file);
sc_ctx_suppress_errors_off(ctx);
if (!r) {
struct sc_pkcs15_cert_info cert_info;
struct sc_pkcs15_object cert_obj;
struct sc_pkcs15_pubkey_info pubkey_info;
struct sc_pkcs15_object pubkey_obj;
struct sc_pkcs15_pubkey *pkey = NULL;
memset(&cert_info, 0, sizeof(cert_info));
memset(&cert_obj, 0, sizeof(cert_obj));
cert_info.id.len = 1;
cert_info.id.value[0] = 0x45;
cert_info.authority = 0;
cert_info.path = path;
sc_ctx_suppress_errors_on(ctx);
r = sc_pkcs15_read_certificate(p15card, &cert_info,
(sc_pkcs15_cert_t
**) (&cert_obj.data));
sc_ctx_suppress_errors_off(ctx);
if (!r) {
sc_pkcs15_cert_t *cert =
(sc_pkcs15_cert_t *) (cert_obj.data);
strlcpy(cert_obj.label, "User certificat",
sizeof(cert_obj.label));
cert_obj.flags = SC_PKCS15_CO_FLAG_MODIFIABLE;
r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj,
&cert_info);
if (r)
goto out;
pkey = &cert->key;
}
memset(&pubkey_info, 0, sizeof(pubkey_info));
memset(&pubkey_obj, 0, sizeof(pubkey_obj));
pubkey_info.id.len = 1;
pubkey_info.id.value[0] = 0x45;
pubkey_info.modulus_length = modulus_length;
pubkey_info.key_reference = 1;
pubkey_info.native = 1;
pubkey_info.usage =
SC_PKCS15_PRKEY_USAGE_VERIFY |
SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER |
SC_PKCS15_PRKEY_USAGE_ENCRYPT |
SC_PKCS15_PRKEY_USAGE_WRAP;
pubkey_info.path = path;
strlcpy(pubkey_obj.label, "Public Key",
sizeof(pubkey_obj.label));
pubkey_obj.auth_id.len = 1;
pubkey_obj.auth_id.value[0] = 1;
pubkey_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE;
pubkey_obj.type = SC_PKCS15_TYPE_PUBKEY_RSA;
if (pkey == NULL) {
pubkey_obj.data = &pubkey_info;
r = sc_pkcs15_read_pubkey(p15card, &pubkey_obj, &pkey);
if (r)
goto out;
//force rechargement clef et maj infos lors de sc_pkcs15emu_add_rsa_pubkey (sinon modulus = 0)
pubkey_obj.flags = 0;
}
if (pkey->algorithm == SC_ALGORITHM_RSA) {
modulus_length = (int)(pkey->u.rsa.modulus.len * 8);
}
pubkey_info.modulus_length = modulus_length;
pubkey_obj.data = pkey;
r = sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj,
&pubkey_info);
if (r < 0)
goto out;
}
if (!usage) {
usage =
SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_DECRYPT |
SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
}
if (file)
sc_file_free(file);
file = NULL;
sc_format_path("0001", &path);
sc_ctx_suppress_errors_on(ctx);
r = sc_select_file(card, &path, &file);
sc_ctx_suppress_errors_off(ctx);
if (!r) {
struct sc_pkcs15_prkey_info prkey_info;
struct sc_pkcs15_object prkey_obj;
memset(&prkey_info, 0, sizeof(prkey_info));
memset(&prkey_obj, 0, sizeof(prkey_obj));
prkey_info.id.len = 1;
prkey_info.id.value[0] = 0x45;
prkey_info.usage =
SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_DECRYPT
| SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
prkey_info.native = 1;
prkey_info.key_reference = 1;
prkey_info.modulus_length = modulus_length;
prkey_info.path = path;
strlcpy(prkey_obj.label, "Private Key",
sizeof(prkey_obj.label));
prkey_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE;
prkey_obj.auth_id.len = 1;
prkey_obj.auth_id.value[0] = 1;
r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj,
&prkey_info);
if (r < 0)
goto out;
}
r = 0;
out:if (file)
sc_file_free(file);
return r;
}
static int westcos_detect_card(sc_pkcs15_card_t * p15card)
{
sc_card_t *card = p15card->card;
sc_context_t *ctx = card->ctx;
char *name = "WESTCOS";
if (ctx->debug >= 1)
sc_debug(ctx, "westcos_detect_card (%s)", card->name);
if (strncmp(card->name, name, strlen(name)))
return SC_ERROR_WRONG_CARD;
return SC_SUCCESS;
}
int sc_pkcs15emu_westcos_init_ex(sc_pkcs15_card_t * p15card,
sc_pkcs15emu_opt_t * opts)
{
int r;
sc_card_t *card = p15card->card;
sc_context_t *ctx = card->ctx;
if (ctx->debug >= 1)
sc_debug(ctx, "sc_pkcs15_init_func_ex westcos\n");
if (opts && opts->flags & SC_PKCS15EMU_FLAGS_NO_CHECK)
return sc_pkcs15emu_westcos_init(p15card);
r = westcos_detect_card(p15card);
if (r)
return SC_ERROR_WRONG_CARD;
return sc_pkcs15emu_westcos_init(p15card);
}

View File

@ -28,6 +28,8 @@
#include <assert.h>
#include <ltdl.h>
extern int sc_pkcs15emu_westcos_init_ex(sc_pkcs15_card_t *p15card,
sc_pkcs15emu_opt_t *opts);
extern int sc_pkcs15emu_openpgp_init_ex(sc_pkcs15_card_t *,
sc_pkcs15emu_opt_t *);
extern int sc_pkcs15emu_infocamere_init_ex(sc_pkcs15_card_t *,
@ -58,6 +60,7 @@ static struct {
const char * name;
int (*handler)(sc_pkcs15_card_t *, sc_pkcs15emu_opt_t *);
} builtin_emulators[] = {
{ "westcos", sc_pkcs15emu_westcos_init_ex },
{ "openpgp", sc_pkcs15emu_openpgp_init_ex },
{ "infocamere", sc_pkcs15emu_infocamere_init_ex },
{ "starcert", sc_pkcs15emu_starcert_init_ex },

View File

@ -24,7 +24,8 @@ dist_pkgdata_DATA = \
rutoken.profile \
asepcos.profile \
entersafe.profile \
rutoken_ecp.profile
rutoken_ecp.profile \
westcos.profile
AM_CPPFLAGS = -DSC_PKCS15_PROFILE_DIRECTORY=\"$(pkgdatadir)\"
AM_CFLAGS = $(OPTIONAL_OPENSSL_CFLAGS) $(LTLIB_CFLAGS)
@ -32,6 +33,7 @@ INCLUDES = -I$(top_srcdir)/src/common -I$(top_builddir)/src/include
libpkcs15init_la_SOURCES = \
pkcs15-lib.c profile.c keycache.c \
pkcs15-westcos.c \
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 \

View File

@ -10,7 +10,7 @@ OBJECTS = pkcs15-lib.obj profile.obj keycache.obj \
pkcs15-cardos.obj pkcs15-jcop.obj pkcs15-starcos.obj \
pkcs15-oberthur.obj pkcs15-setcos.obj pkcs15-incrypto34.obj \
pkcs15-muscle.obj pkcs15-asepcos.obj pkcs15-rutoken.obj \
pkcs15-entersafe.obj pkcs15-rtecp.obj \
pkcs15-entersafe.obj pkcs15-rtecp.obj pkcs15-westcos.obj \
versioninfo.res
all: install-headers $(TARGET)

View File

@ -404,6 +404,7 @@ extern struct sc_pkcs15init_operations *sc_pkcs15init_get_asepcos_ops(void);
extern struct sc_pkcs15init_operations *sc_pkcs15init_get_rutoken_ops(void);
extern struct sc_pkcs15init_operations *sc_pkcs15init_get_entersafe_ops(void);
extern struct sc_pkcs15init_operations *sc_pkcs15init_get_rtecp_ops(void);
extern struct sc_pkcs15init_operations *sc_pkcs15init_get_westcos_ops(void);
#ifdef __cplusplus
}

View File

@ -165,6 +165,7 @@ static struct profile_operations {
{ "asepcos", (void*) sc_pkcs15init_get_asepcos_ops },
{ "entersafe",(void*) sc_pkcs15init_get_entersafe_ops },
{ "rutoken_ecp", (void *) sc_pkcs15init_get_rtecp_ops },
{ "westcos", (void *) sc_pkcs15init_get_westcos_ops },
{ NULL, NULL },
};

View File

@ -0,0 +1,464 @@
/*
* pkcs15-westcos.c: pkcs15 support for westcos card
*
* Copyright (C) 2009 francois.leblanc@cev-sa.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 <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <opensc/opensc.h>
#include <opensc/cardctl.h>
#include "pkcs15-init.h"
#include "profile.h"
#ifdef ENABLE_OPENSSL
#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/bio.h>
#endif
extern int sc_check_sw(sc_card_t *card, unsigned int sw1, unsigned int sw2);
#if 0
/*
* Get private and public key file
*/
static int _westcos_get_keyfiles(sc_profile_t *profile, sc_card_t *card,
const sc_path_t *df_path,
sc_file_t **prkf, sc_file_t **pukf)
{
sc_path_t path = *df_path;
int r;
/* Get the private key file */
r = SC_ERROR_NOT_SUPPORTED; //sc_profile_get_file_by_path(profile, &path, prkf);
if (r < 0) {
char pbuf[SC_MAX_PATH_STRING_SIZE];
r = sc_path_print(pbuf, sizeof(pbuf), &path);
if (r != SC_SUCCESS)
pbuf[0] = '\0';
return r;
}
/* Get the public key file */
path.len -= 2;
sc_append_file_id(&path, 0x1012);
r = SC_ERROR_NOT_SUPPORTED; //sc_profile_get_file_by_path(profile, &path, pukf);
if (r < 0) {
sc_file_free(*prkf);
return r;
}
return 0;
}
#endif /* currently unused */
static int westcos_pkcs15init_init_card(sc_profile_t *profile,
sc_card_t *card)
{
int r;
struct sc_path path;
sc_format_path("3F00", &path);
r = sc_select_file(card, &path, NULL);
if(r) return (r);
return r;
}
static int westcos_pkcs15init_create_dir(sc_profile_t *profile,
sc_card_t *card,
sc_file_t *df)
{
int r;
/* Create the application DF */
r = sc_pkcs15init_create_file(profile, card, df);
//if(r) return r;
r = sc_select_file(card, &df->path, NULL);
if(r) return r;
return 0;
}
#if 0
/*
* Create a PIN domain (i.e. a sub-directory holding a user PIN)
*/
static int westcos_pkcs15init_create_domain(sc_profile_t *profile,
sc_card_t *card,
const sc_pkcs15_id_t *id,
sc_file_t **ret)
{
return SC_ERROR_NOT_SUPPORTED; //sc_pkcs15_create_pin_domain(profile, card, id, ret);
}
#endif /* currently unused */
/*
* Select the PIN reference
*/
static int westcos_pkcs15_select_pin_reference(sc_profile_t *profile,
sc_card_t *card,
sc_pkcs15_pin_info_t *pin_info)
{
if (pin_info->flags & SC_PKCS15_PIN_FLAG_SO_PIN) {
pin_info->reference = 1;
} else {
pin_info->reference = 0;
}
return 0;
}
/*
* Create a new PIN inside a DF
*/
static int westcos_pkcs15_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)
{
int r;
sc_file_t *file = sc_file_new();
sc_path_t path;
if(pin_len>9 || puk_len>9 || pin_len<0 || puk_len<0)
return SC_ERROR_INVALID_ARGUMENTS;
file->type = SC_FILE_TYPE_INTERNAL_EF;
file->ef_structure = SC_FILE_EF_TRANSPARENT;
file->shareable = 0;
file->id = 0xAAAA;
file->size = 37;
r = sc_file_add_acl_entry(file, SC_AC_OP_READ, SC_AC_NONE, 0);
if(r) return r;
r = sc_file_add_acl_entry(file, SC_AC_OP_UPDATE, SC_AC_NONE, 0);
if(r) return r;
r = sc_file_add_acl_entry(file, SC_AC_OP_ERASE, SC_AC_NONE, 0);
if(r) return r;
r = sc_create_file(card, file);
if(r)
{
if(r != SC_ERROR_FILE_ALREADY_EXISTS)
return (r);
sc_format_path("3F005015AAAA", &path);
r = sc_select_file(card, &path, NULL);
if(r) return (r);
}
//r = sc_pkcs15init_create_file(profile, card, file);
if(file)
sc_file_free(file);
if(pin != NULL)
{
sc_changekey_t ck;
struct sc_pin_cmd_pin pin_cmd;
memset(&pin_cmd, 0, sizeof(pin_cmd));
memset(&ck, 0, sizeof(ck));
memcpy(ck.key_template, "\x1e\x00\x00\x10", 4);
pin_cmd.encoding = SC_PIN_ENCODING_GLP;
pin_cmd.len = pin_len;
pin_cmd.data = pin;
pin_cmd.max_length = 8;
ck.new_key.key_len = sc_build_pin(ck.new_key.key_value,
sizeof(ck.new_key.key_value), &pin_cmd, 1);
if(ck.new_key.key_len<0)
return SC_ERROR_CARD_CMD_FAILED;
r = sc_card_ctl(card, SC_CARDCTL_WESTCOS_CHANGE_KEY, &ck);
if(r) return r;
}
if(puk != NULL)
{
sc_changekey_t ck;
struct sc_pin_cmd_pin puk_cmd;
memset(&puk_cmd, 0, sizeof(puk_cmd));
memset(&ck, 0, sizeof(ck));
memcpy(ck.key_template, "\x1e\x00\x00\x20", 4);
puk_cmd.encoding = SC_PIN_ENCODING_GLP;
puk_cmd.len = puk_len;
puk_cmd.data = puk;
puk_cmd.max_length = 8;
ck.new_key.key_len = sc_build_pin(ck.new_key.key_value,
sizeof(ck.new_key.key_value), &puk_cmd, 1);
if(ck.new_key.key_len<0)
return SC_ERROR_CARD_CMD_FAILED;
r = sc_card_ctl(card, SC_CARDCTL_WESTCOS_CHANGE_KEY, &ck);
if(r) return r;
}
return 0;
}
/*
* Create a new key file
*/
static int westcos_pkcs15init_create_key(sc_profile_t *profile,
sc_card_t *card,
sc_pkcs15_object_t *obj)
{
int r;
size_t size;
sc_file_t *keyfile = NULL;
sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data;
if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) {
return SC_ERROR_NOT_SUPPORTED;
}
switch (key_info->modulus_length) {
case 128: size = 112; break;
case 256: size = 184; break;
case 512: size = 336; break;
case 768: size = 480; break;
case 1024: size = 616; break;
case 1536: size = 912; break;
case 2048: size = 1200; break;
default:
r = SC_ERROR_INVALID_ARGUMENTS;
goto out;
}
keyfile = sc_file_new();
if(keyfile == NULL)
return SC_ERROR_OUT_OF_MEMORY;
keyfile->path = key_info->path;
keyfile->type = SC_FILE_TYPE_WORKING_EF;
keyfile->ef_structure = SC_FILE_EF_TRANSPARENT;
keyfile->shareable = 0;
keyfile->size = size;
r = sc_file_add_acl_entry(keyfile, SC_AC_OP_READ, SC_AC_CHV, 0);
if(r) goto out;
r = sc_file_add_acl_entry(keyfile, SC_AC_OP_UPDATE, SC_AC_CHV, 0);
if(r) goto out;
r = sc_file_add_acl_entry(keyfile, SC_AC_OP_ERASE, SC_AC_CHV, 0);
if(r) goto out;
r = sc_pkcs15init_create_file(profile, card, keyfile);
if(r)
{
if(r != SC_ERROR_FILE_ALREADY_EXISTS)
goto out;
r = 0;
}
out:
if(keyfile)
sc_file_free(keyfile);
return r;
}
/*
* Store a private key
*/
static int westcos_pkcs15init_store_key(sc_profile_t *profile,
sc_card_t *card,
sc_pkcs15_object_t *obj,
sc_pkcs15_prkey_t *key)
{
return SC_ERROR_NOT_SUPPORTED;
#if 0
int r;
sc_file_t *keyfile;
sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data;
if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) {
return SC_ERROR_NOT_SUPPORTED;
}
r = SC_ERROR_NOT_SUPPORTED; //sc_profile_get_file_by_path(profile, &key_info->path, &keyfile);
if (r < 0) return r;
//r = sc_pkcs15init_update_file(profile, card, keyfile, &key->der.data, &key->der.len);
//sc_file_free(keyfile);
return r;
#endif
}
/*
* Generate key
*/
static int westcos_pkcs15init_generate_key(sc_profile_t *profile,
sc_card_t *card,
sc_pkcs15_object_t *obj,
sc_pkcs15_pubkey_t *pubkey)
{
int r = SC_ERROR_UNKNOWN;
long lg;
char *p;
sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data;
#ifdef ENABLE_OPENSSL
RSA *rsa = RSA_new();
BIGNUM *bn = BN_new();
BIO *mem = BIO_new(BIO_s_mem());
#endif
#ifndef ENABLE_OPENSSL
r = SC_ERROR_NOT_SUPPORTED;
#else
sc_file_t *prkf = NULL;
if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) {
return SC_ERROR_NOT_SUPPORTED;
}
if(/*keyfile == NULL ||*/ rsa == NULL || bn == NULL || mem == NULL)
{
r = SC_ERROR_OUT_OF_MEMORY;
goto out;
}
/* pkcs11 re-route routine cryptage vers la carte fixe default to use openssl */
rsa->meth = RSA_PKCS1_SSLeay();
if(!BN_set_word(bn, RSA_F4) ||
!RSA_generate_key_ex(rsa, key_info->modulus_length, bn, NULL))
{
r = SC_ERROR_UNKNOWN;
goto out;
}
if(pubkey != NULL)
{
if(!i2d_RSAPublicKey_bio(mem, rsa))
{
r = SC_ERROR_UNKNOWN;
goto out;
}
lg = BIO_get_mem_data(mem, &p);
pubkey->algorithm = SC_ALGORITHM_RSA;
r = sc_pkcs15_decode_pubkey(card->ctx, pubkey, p, lg);
}
BIO_reset(mem);
if(!i2d_RSAPrivateKey_bio(mem, rsa))
{
r = SC_ERROR_UNKNOWN;
goto out;
}
lg = BIO_get_mem_data(mem, &p);
/* Get the private key file */
r = sc_profile_get_file_by_path(profile, &key_info->path, &prkf);
if (r < 0)
{
char pbuf[SC_MAX_PATH_STRING_SIZE];
r = sc_path_print(pbuf, sizeof(pbuf), &key_info->path);
if (r != SC_SUCCESS)
pbuf[0] = '\0';
return r;
}
r = sc_pkcs15init_update_file(profile, card, prkf, p, lg);
if(r) goto out;
out:
if(mem)
BIO_free(mem);
if(bn)
BN_free(bn);
if(rsa)
RSA_free(rsa);
if(prkf)
sc_file_free(prkf);
#endif
return r;
}
static int westcos_pkcs15init_finalize_card(sc_card_t *card)
{
int r;
/* be sure authentificate card */
r = sc_card_ctl(card, SC_CARDCTL_WESTCOS_AUT_KEY, NULL);
if(r) return (r);
return sc_pkcs15init_set_lifecycle(card, SC_CARDCTRL_LIFECYCLE_USER);
}
static struct sc_pkcs15init_operations sc_pkcs15init_westcos_operations = {
NULL, /* erase_card */
westcos_pkcs15init_init_card, /* init_card */
westcos_pkcs15init_create_dir, /* create_dir */
NULL, /* create_domain */
westcos_pkcs15_select_pin_reference,/* select_pin_reference */
westcos_pkcs15_create_pin, /* create_pin */
NULL, /* select_key_reference */
westcos_pkcs15init_create_key, /* create_key */
westcos_pkcs15init_store_key, /* store_key */
westcos_pkcs15init_generate_key, /* generate_key */
NULL, NULL, /* encode private/public key */
westcos_pkcs15init_finalize_card, /* finalize_card */
NULL,NULL,NULL,NULL, /* old style app */
NULL, /* old_generate_key */
NULL /* delete_object */
};
struct sc_pkcs15init_operations* sc_pkcs15init_get_westcos_ops(void)
{
return &sc_pkcs15init_westcos_operations;
}

View File

@ -0,0 +1,183 @@
cardinfo {
label = "westcos";
manufacturer = "CEV";
max-pin-length = 8;
min-pin-length = 4;
pin-encoding = BCD;
pin-pad-char = 0xff;
}
# Default settings.
# This option block will always be processed.
option default {
macros {
protected = *=$PIN, READ=NONE;
unprotected = *=NONE;
private = *=$PIN;
so-pin-flags = local, initialized, needs-padding; #, soPin;
so-min-pin-length = 6;
so-pin-attempts = 2;
so-auth-id = 1; #FF;
so-puk-attempts = 4;
so-min-puk-length = 6;
unusedspace-size = 128;
odf-size = 256;
aodf-size = 256;
cdf-size = 512;
prkdf-size = 256;
pukdf-size = 256;
dodf-size = 256;
}
}
PIN so-pin {
auth-id = 1;
reference = 1;
attempts = 3;
min-length = 4;
max-length = 8;
flags = local, initialized, needs-padding;
}
PIN so-puk {
auth-id = 2;
reference = 2;
attempts = 10;
min-length = 4;
max-length = 8;
flags = local, initialized, needs-padding;
}
PIN user-pin {
auth-id = 1;
reference = 1;
attempts = 3;
min-length = 4;
max-length = 8;
flags = local, initialized, needs-padding;
}
PIN user-puk {
auth-id = 2;
reference = 2;
attempts = 10;
min-length = 4;
max-length = 8;
flags = local, initialized, needs-padding;
}
filesystem {
DF MF {
path = 3F00;
type = DF;
# This is the DIR file
EF DIR {
type = EF;
file-id = 2F00;
size = 128;
acl = $unprotected;
}
# 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 = $unprotected;
size = 5000;
EF PKCS15-ODF {
file-id = 5031;
size = $odf-size;
acl = $unprotected;
}
EF PKCS15-TokenInfo {
file-id = 5032;
acl = $unprotected;
}
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;
}
# 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 {
EF private-key {
file-id = 0100;
structure = transparent;
acl = *=NEVER, READ=$PIN, UPDATE=$PIN, WRITE=$PIN, DELETE=$PIN;
}
EF public-key {
file-id = 0200;
structure = transparent;
acl = *=NEVER, READ=NONE, UPDATE=$PIN, WRITE=$PIN, DELETE=$PIN;
}
# Certificate template
EF certificate {
file-id = 0300;
structure = transparent;
acl = *=NEVER, READ=NONE, UPDATE=$PIN, WRITE=$PIN, DELETE=$PIN;
}
# data objects are stored in transparent EFs.
EF data {
file-id = 0400;
structure = transparent;
acl = *=NEVER, READ=NONE, UPDATE=$PIN, WRITE=$PIN, DELETE=$PIN;
}
# private data objects are stored in transparent EFs.
EF privdata {
file-id = 0500;
structure = transparent;
acl = *=NEVER, READ=$PIN, UPDATE=$PIN, WRITE=$PIN, DELETE=$PIN;
}
}
}
}
}

View File

@ -9,7 +9,7 @@ noinst_HEADERS = util.h
bin_PROGRAMS = opensc-tool opensc-explorer pkcs15-tool pkcs15-crypt \
pkcs11-tool cardos-tool eidenv rutoken-tool
if ENABLE_OPENSSL
bin_PROGRAMS += cryptoflex-tool pkcs15-init netkey-tool piv-tool
bin_PROGRAMS += cryptoflex-tool pkcs15-init netkey-tool piv-tool westcos-tool
endif
dist_bin_SCRIPTS = cardos-info
if WIN32
@ -44,6 +44,8 @@ netkey_tool_SOURCES = netkey-tool.c
netkey_tool_LDADD = $(OPTIONAL_OPENSSL_LIBS)
rutoken_tool_SOURCES = rutoken-tool.c util.c
rutoken_tool_LDADD = $(OPTIONAL_OPENSSL_LIBS)
westcos_tool_SOURCES = westcos-tool.c
westcos_tool_LDADD = $(OPTIONAL_OPENSSL_LIBS)
if WIN32
opensc_tool_SOURCES += versioninfo.rc
@ -58,6 +60,7 @@ cardos_tool_SOURCES += versioninfo.rc
eidenv_SOURCES += versioninfo.rc
netkey_tool_SOURCES += versioninfo.rc
rutoken_tool_SOURCES += versioninfo.rc
westcos_tool_SOURCES += versioninfo.rc
else
dist_noinst_DATA = versioninfo.rc
endif

View File

@ -5,7 +5,7 @@ TOPDIR = ..\..
TARGETS = opensc-tool.exe opensc-explorer.exe pkcs15-tool.exe pkcs15-crypt.exe \
pkcs11-tool.exe cardos-info.exe eidenv.exe rutoken-tool.exe \
netkey-tool.exe \
netkey-tool.exe westcos-tool.exe \
$(PROGRAMS_OPENSSL)
all: $(TARGETS)

942
src/tools/westcos-tool.c Normal file
View File

@ -0,0 +1,942 @@
/*
* westcos-tool.exe: tool for westcos card
*
* Copyright (C) 2009 francois.leblanc@cev-sa.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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <opensc/opensc.h>
#include <opensc/errors.h>
#include <opensc/pkcs15.h>
#include <opensc/cardctl.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/bio.h>
#include <openssl/x509v3.h>
#include <openssl/bn.h>
static char *version ="0.0.6";
static char *nom_card = "WESTCOS";
static int finalise = 0;
static int verbose = 0;
static int install_pin = 0;
static int remplace = 0;
static char *pin = NULL;
static char *puk = NULL;
static char *cert = NULL;
static int keylen = 0;
static int no_lecteur = -1;
static int new_pin = 0;
static int debloque = 0;
static char *get_filename = NULL;
static char *get_path = NULL;
static char *put_filename = NULL;
static char *put_path = NULL;
static int do_convert_bignum(sc_pkcs15_bignum_t *dst, BIGNUM *src)
{
if (src == 0) return 0;
dst->len = BN_num_bytes(src);
dst->data = (u8 *) malloc(dst->len);
BN_bn2bin(src, dst->data);
return 1;
}
static int charge = 0;
static void print_openssl_erreur(void)
{
long r;
if (!charge)
{
ERR_load_crypto_strings();
charge = 1;
}
while ((r = ERR_get_error()) != 0)
fprintf(stderr, "%s\n", ERR_error_string(r, NULL));
}
static verify_pin(sc_card_t *card, int pin_reference, char *pin_value)
{
int r, tries_left = -1;
struct sc_pin_cmd_data data;
memset(&data, 0, sizeof(data));
data.cmd = SC_PIN_CMD_VERIFY;
data.pin_type = SC_AC_CHV;
data.pin_reference = pin_reference;
data.flags = SC_PIN_CMD_NEED_PADDING;
if (card->slot->capabilities & SC_SLOT_CAP_PIN_PAD)
{
printf("Please enter PIN on the reader's pin pad.\n");
data.pin1.prompt = "Please enter PIN";
data.flags |= SC_PIN_CMD_USE_PINPAD;
}
else
{
if(pin_value == NULL)
{
return SC_ERROR_INVALID_ARGUMENTS;
}
data.pin1.data = pin_value;
data.pin1.len = strlen(pin_value);
}
r = sc_pin_cmd(card, &data, &tries_left);
if (r)
{
if (r == SC_ERROR_PIN_CODE_INCORRECT)
{
if (tries_left >= 0)
printf("Error %d attemps left.\n", tries_left);
else
printf("Wrong pin.\n");
}
else
fprintf(stderr, "The pin can be verify: %s\n", sc_strerror(r));
return -1;
}
printf("Pin correct.\n");
return 0;
}
static change_pin(sc_card_t *card,
int pin_reference,
char *pin_value1,
char *pin_value2)
{
int r, tries_left = -1;
struct sc_pin_cmd_data data;
memset(&data, 0, sizeof(data));
data.cmd = SC_PIN_CMD_CHANGE;
data.pin_type = SC_AC_CHV;
data.pin_reference = pin_reference;
data.flags = SC_PIN_CMD_NEED_PADDING;
if (card->slot->capabilities & SC_SLOT_CAP_PIN_PAD)
{
printf("Please enter PIN on the reader's pin pad.\n");
data.pin1.prompt = "Please enter PIN";
data.flags |= SC_PIN_CMD_USE_PINPAD;
}
else
{
if(pin_value1 == NULL || pin_value2 == NULL)
{
return SC_ERROR_INVALID_ARGUMENTS;
}
data.pin1.data = pin_value1;
data.pin1.len = strlen(pin_value1);
data.pin2.data = pin_value2;
data.pin2.len = strlen(pin_value2);
}
r = sc_pin_cmd(card, &data, &tries_left);
if (r)
{
if (r == SC_ERROR_PIN_CODE_INCORRECT)
{
if (tries_left >= 0)
printf("Error %d attemps left.\n", tries_left);
else
printf("Wrong pin.\n");
}
else
fprintf(stderr, "Can't change pin: %s\n",
sc_strerror(r));
return -1;
}
printf("Pin changed.\n");
return 0;
}
static debloque_pin(sc_card_t *card,
int pin_reference,
char *puk_value,
char *pin_value)
{
int r, tries_left = -1;
struct sc_pin_cmd_data data;
memset(&data, 0, sizeof(data));
data.cmd = SC_PIN_CMD_UNBLOCK;
data.pin_type = SC_AC_CHV;
data.pin_reference = pin_reference;
data.flags = SC_PIN_CMD_NEED_PADDING;
if (card->slot->capabilities & SC_SLOT_CAP_PIN_PAD)
{
printf("Please enter PIN on the reader's pin pad.\n");
data.pin1.prompt = "Please enter PIN";
data.flags |= SC_PIN_CMD_USE_PINPAD;
}
else
{
if(pin == NULL || puk == NULL)
{
return SC_ERROR_INVALID_ARGUMENTS;
}
data.pin1.data = puk_value;
data.pin1.len = strlen(puk_value);
data.pin2.data = pin_value;
data.pin2.len = strlen(pin_value);
}
r = sc_pin_cmd(card, &data, &tries_left);
if (r)
{
if (r == SC_ERROR_PIN_CODE_INCORRECT)
{
if (tries_left >= 0)
printf("Error %d attemps left.\n", tries_left);
else
printf("Wrong pin.\n");
}
else
fprintf(stderr, "Can't unblock pin: %s\n",
sc_strerror(r));
return -1;
}
printf("Code debloque.\n");
return 0;
}
static int cert2der(X509 *cert, u8 **value)
{
int len;
u8 *p;
len = i2d_X509(cert, NULL);
p = *value = (u8*)malloc(len);
i2d_X509(cert, &p);
return len;
}
static int creation_fichier_cert(sc_card_t *card)
{
int r;
int size;
sc_path_t path;
sc_file_t *file = NULL;
sc_context_t *ctx = card->ctx;
sc_format_path("3F00", &path);
r = sc_select_file(card, &path, &file);
if(r) goto out;
size = (file->size) - 32;
if(file)
{
sc_file_free(file);
file = NULL;
}
sc_format_path("0002", &path);
sc_ctx_suppress_errors_on(ctx);
r = sc_select_file(card, &path, NULL);
sc_ctx_suppress_errors_off(ctx);
if(r)
{
if(r != SC_ERROR_FILE_NOT_FOUND) goto out;
file = sc_file_new();
if(file == NULL)
{
fprintf(stderr, "memory error.\n");
goto out;
}
file->type = SC_FILE_TYPE_WORKING_EF;
file->ef_structure = SC_FILE_EF_TRANSPARENT;
file->shareable = 0;
file->size = size;
r = sc_file_add_acl_entry(file, SC_AC_OP_READ, SC_AC_NONE, 0);
if(r) goto out;
r = sc_file_add_acl_entry(file, SC_AC_OP_UPDATE, SC_AC_CHV, 0);
if(r) goto out;
r = sc_file_add_acl_entry(file, SC_AC_OP_ERASE, SC_AC_CHV, 0);
if(r) goto out;
file->path = path;
r = sc_create_file(card, file);
if(r) goto out;
}
out:
if(file)
sc_file_free(file);
return r;
}
void usage(void)
{
printf("Tools for westcos card.\n");
printf("version %s.\n\n", version);
printf("\t -G Generate key 1536 default.\n");
printf("\t -L [length] Key length 512,1024,1536.\n");
printf("\t -i Install pin.\n");
printf("\t -pin [value] Pin.\n");
printf("\t -puk [value] Puk.\n");
printf("\t -n Change pin (new pin in puk option).\n");
printf("\t -u Unblock pin.\n");
printf("\t -cert [file] Write certificate (in pem format).\n");
printf("\t -F Finalize card "\
"(!!! MANDATORY FOR SECURITY !!!).\n");
printf("\t -r [n] Use reader number [n]"\
" (default: autodetect).\n");
printf("\t -gf [path] Read file [path].\n");
printf("\t -pf [path] Write file [path].\n");
printf("\t -v verbose.\n");
printf("\t -h This message.\n");
exit(0);
}
int main(int argc, char *argv[])
{
int r;
int i = 1;
u8 *p;
int card_presente = 0;
sc_context_param_t ctx_param;
sc_reader_t *lecteur = NULL;
sc_card_t *card = NULL;
sc_context_t *ctx = NULL;
sc_file_t *file = NULL;
sc_path_t path;
RSA *rsa = RSA_new();
BIGNUM *bn = BN_new();
BIO *mem = BIO_new(BIO_s_mem());
if(rsa == NULL || bn == NULL || mem == NULL)
{
fprintf(stderr,"Not enougth memory.\n");
goto out;
}
while(i<argc)
{
p = argv[i++];
if(strcmp(p, "-gf") == 0)
{
if(i<argc)
{
get_filename = argv[i++];
continue;
}
}
if(strcmp(p, "-pf") == 0)
{
if(i<argc)
{
put_filename = argv[i++];
continue;
}
}
if(strcmp(p, "-F") == 0)
{
finalise = 1;
continue;
}
if(strcmp(p, "-i") == 0)
{
install_pin = 1;
continue;
}
if(strcmp(p, "-R") == 0)
{
remplace = 1;
continue;
}
if(strcmp(p, "-G") == 0)
{
if(keylen == 0) keylen = 1536;
continue;
}
if(strcmp(p, "-L") == 0)
{
if(i<argc)
{
keylen = atoi(argv[i++]);
continue;
}
}
if(strcmp(p, "-pin") == 0)
{
if(i<argc)
{
pin = argv[i++];
continue;
}
}
if(strcmp(p, "-puk") == 0)
{
if(i<argc)
{
puk = argv[i++];
continue;
}
}
if(strcmp(p, "-cert") == 0)
{
if(i<argc)
{
cert = argv[i++];
continue;
}
}
if(strcmp(p, "-n") == 0)
{
new_pin = 1;
continue;
}
if(strcmp(p, "-u") == 0)
{
debloque = 1;
continue;
}
if(strcmp(p, "-r") == 0)
{
if(i<argc)
{
no_lecteur = atoi(argv[i++]);
continue;
}
}
if(!strcmp(p, "-h") || !strcmp(p,"--help"))
{
usage();
}
if(!strncmp(p, "-v", 2))
{
char *n = p+1;
while(*n++ == 'v') verbose++;
continue;
}
printf("Unknown %s \n", p);
usage();
exit(-1);
}
memset(&ctx_param, 0, sizeof(ctx_param));
ctx_param.ver = 0;
ctx_param.app_name = argv[0];
r = sc_context_create(&ctx, &ctx_param);
if (r)
{
fprintf(stderr, "Failed to establish context: %s\n", sc_strerror(r));
return 1;
}
if (verbose > 1)
ctx->debug = verbose-1;
if(no_lecteur == -1)
{
for(i = 0; i<sc_ctx_get_reader_count(ctx); i++)
{
lecteur = sc_ctx_get_reader(ctx, i);
if(sc_detect_card_presence(lecteur, 0))
{
r = sc_connect_card(lecteur, 0, &card);
if(r>=0)
{
printf("card->name = %s\n", card->name);
if(strncmp(card->name, nom_card, strlen(nom_card)) == 0)
{
card_presente = 1;
break;
}
sc_disconnect_card(card,0);
card = NULL;
}
}
}
}
else
{
if(no_lecteur < sc_ctx_get_reader_count(ctx))
{
lecteur = sc_ctx_get_reader(ctx, no_lecteur);
r = sc_connect_card(lecteur, 0, &card);
if(r>=0)
{
card_presente = 1;
}
else
{
sc_disconnect_card(card,0);
}
}
}
if(!card_presente) goto out;
sc_lock(card);
sc_format_path("3F00", &path);
r = sc_select_file(card, &path, NULL);
if(r) goto out;
if(install_pin)
{
sc_format_path("AAAA", &path);
sc_ctx_suppress_errors_on(ctx);
r = sc_select_file(card, &path, NULL);
sc_ctx_suppress_errors_off(ctx);
if(r)
{
if(r != SC_ERROR_FILE_NOT_FOUND) goto out;
file = sc_file_new();
if(file == NULL)
{
fprintf(stderr, "Not enougth memory.\n");
goto out;
}
file->type = SC_FILE_TYPE_INTERNAL_EF;
file->ef_structure = SC_FILE_EF_TRANSPARENT;
file->shareable = 0;
file->id = 0xAAAA;
file->size = 37;
r = sc_file_add_acl_entry(file, SC_AC_OP_READ, SC_AC_NONE, 0);
if(r) goto out;
r = sc_file_add_acl_entry(file, SC_AC_OP_UPDATE, SC_AC_NONE, 0);
if(r) goto out;
r = sc_file_add_acl_entry(file, SC_AC_OP_ERASE, SC_AC_NONE, 0);
if(r) goto out;
//sc_format_path("3F00AAAA", &(file->path));
file->path = path;
r = sc_create_file(card, file);
if(r) goto out;
}
if(pin != NULL)
{
sc_changekey_t ck;
struct sc_pin_cmd_pin pin_cmd;
memset(&pin_cmd, 0, sizeof(pin_cmd));
memset(&ck, 0, sizeof(ck));
memcpy(ck.key_template, "\x1e\x00\x00\x10", 4);
pin_cmd.encoding = SC_PIN_ENCODING_GLP;
pin_cmd.len = strlen(pin);
pin_cmd.data = pin;
pin_cmd.max_length = 8;
ck.new_key.key_len = sc_build_pin(ck.new_key.key_value,
sizeof(ck.new_key.key_value), &pin_cmd, 1);
if(ck.new_key.key_len<0)
goto out;
r = sc_card_ctl(card, SC_CARDCTL_WESTCOS_CHANGE_KEY, &ck);
if(r) goto out;
}
if(puk != NULL)
{
sc_changekey_t ck;
struct sc_pin_cmd_pin puk_cmd;
memset(&puk_cmd, 0, sizeof(puk_cmd));
memset(&ck, 0, sizeof(ck));
memcpy(ck.key_template, "\x1e\x00\x00\x20", 4);
puk_cmd.encoding = SC_PIN_ENCODING_GLP;
puk_cmd.len = strlen(puk);
puk_cmd.data = puk;
puk_cmd.max_length = 8;
ck.new_key.key_len = sc_build_pin(ck.new_key.key_value,
sizeof(ck.new_key.key_value), &puk_cmd, 1);
if(ck.new_key.key_len<0)
goto out;
r = sc_card_ctl(card, SC_CARDCTL_WESTCOS_CHANGE_KEY, &ck);
if(r) goto out;
}
}
if(new_pin)
{
if(change_pin(card, 0, pin, puk))
printf("Wrong pin.\n");
goto out;
}
if(debloque)
{
if(debloque_pin(card, 0, puk, pin))
printf("Error unblocking pin.\n");
goto out;
}
printf("verify pin.\n");
{
if(verify_pin(card, 0, pin))
{
printf("Wrong pin.\n");
goto out;
}
}
if(keylen)
{
int lg;
struct sc_pkcs15_pubkey key;
struct sc_pkcs15_pubkey_rsa *dst = &(key.u.rsa);
memset(&key, 0, sizeof(key));
key.algorithm = SC_ALGORITHM_RSA;
printf("Generate key of length %d.\n", keylen);
if(!BN_set_word(bn, RSA_F4) ||
!RSA_generate_key_ex(rsa, keylen, bn, NULL))
{
fprintf(stderr,
"RSA_generate_key_ex return %d\n", ERR_get_error());
goto out;
}
rsa->meth = RSA_PKCS1_SSLeay();
if(!i2d_RSAPrivateKey_bio(mem, rsa))
{
fprintf(stderr,
"i2d_RSAPrivateKey_bio return %d\n", ERR_get_error());
goto out;
}
lg = BIO_get_mem_data(mem, &p);
sc_format_path("0001", &path);
sc_ctx_suppress_errors_on(ctx);
r = sc_select_file(card, &path, NULL);
sc_ctx_suppress_errors_off(ctx);
if(r)
{
if(r != SC_ERROR_FILE_NOT_FOUND) goto out;
file = sc_file_new();
if(file == NULL)
{
fprintf(stderr, "Not enougth memory.\n");
goto out;
}
file->type = SC_FILE_TYPE_WORKING_EF;
file->ef_structure = SC_FILE_EF_TRANSPARENT;
file->shareable = 0;
file->size = ((lg/4)+1)*4;
r = sc_file_add_acl_entry(file, SC_AC_OP_READ, SC_AC_CHV, 0);
if(r) goto out;
r = sc_file_add_acl_entry(file, SC_AC_OP_UPDATE, SC_AC_CHV, 0);
if(r) goto out;
r = sc_file_add_acl_entry(file, SC_AC_OP_ERASE, SC_AC_CHV, 0);
if(r) goto out;
file->path = path;
printf("File key creation %s, size %d.\n", file->path.value,
file->size);
r = sc_create_file(card, file);
if(r) goto out;
}
else
{
if(!remplace)
{
fprintf(stderr,
"Key file already exist,"\
" use -R to replace it.\n");
goto out;
}
}
printf("Private key length is %d\n", lg);
printf("Write private key.\n");
r = sc_update_binary(card,0,p,lg,0);
if(r<0) goto out;
printf("Private key correctly written.\n");
r = creation_fichier_cert(card);
if(r) goto out;
if (!do_convert_bignum(&dst->modulus, rsa->n)
|| !do_convert_bignum(&dst->exponent, rsa->e))
goto out;
r = sc_pkcs15_encode_pubkey(ctx, &key, &p, &lg);
if(r) goto out;
printf("Public key length %d\n", lg);
sc_format_path("3F000002", &path);
r = sc_select_file(card, &path, NULL);
if(r) goto out;
printf("Write public key.\n");
r = sc_update_binary(card,0,p,lg,0);
if(r<0) goto out;
printf("Public key correctly written.\n");
}
if(cert)
{
BIO *bio;
X509 *xp;
bio = BIO_new(BIO_s_file());
if (BIO_read_filename(bio, cert) <= 0)
{
BIO_free(bio);
fprintf(stderr, "Can't open file %s.\n", cert);
goto out;
}
xp = PEM_read_bio_X509(bio, NULL, NULL, NULL);
BIO_free(bio);
if (xp == NULL)
{
print_openssl_erreur();
goto out;
}
else
{
int lg = cert2der(xp, &p);
sc_format_path("0002", &path);
r = sc_select_file(card, &path, NULL);
if(r) goto out;
/* FIXME: verifier taille fichier compatible... */
printf("Write certificate %s.\n", cert);
r = sc_update_binary(card,0,p,lg,0);
if(r<0)
{
if(p) free(p);
goto out;
}
if(xp) X509_free(xp);
if(p) free(p);
printf("Certificate correctly written.\n");
}
}
if(finalise)
{
int mode = SC_CARDCTRL_LIFECYCLE_USER;
if(card->atr[10] != 0x82)
{
sc_format_path("0001", &path);
r = sc_select_file(card, &path, NULL);
if(r)
{
printf("This card don't have private key"\
" and can't be finalize.\n");
goto out;
}
printf("Finalize card...\n");
if(sc_card_ctl(card, SC_CARDCTL_WESTCOS_AUT_KEY, NULL) ||
sc_card_ctl(card, SC_CARDCTL_LIFECYCLE_SET, &mode))
{
printf("Error finalizing card,"\
" card isn't secure.\n");
goto out;
}
}
printf("Card correctly finalized.\n");
}
if(get_filename)
{
FILE *fp;
u8 *b;
if(file)
{
sc_file_free(file);
file = NULL;
}
sc_format_path(get_filename, &path);
r = sc_select_file(card, &path, &file);
if(r)
{
printf("Error file not found.\n");
goto out;
}
b = (u8*)malloc(file->size);
if(b == NULL)
{
fprintf(stderr, "Not enougth memory.\n");
goto out;
}
r = sc_read_binary(card, 0, b, file->size, 0);
if(r<0)
{
printf("Error reading file.\n");
goto out;
}
fp = fopen(get_filename, "wb");
fwrite(b, 1, file->size, fp);
fclose(fp);
free(b);
}
if(put_filename)
{
FILE *fp;
u8 *b;
if(file)
{
sc_file_free(file);
file = NULL;
}
sc_format_path(put_filename, &path);
r = sc_select_file(card, &path, &file);
if(r)
{
printf("File not found.\n");
goto out;
}
b = (u8*)malloc(file->size);
if(b == NULL)
{
fprintf(stderr, "Not enougth memory.\n");
goto out;
}
memset(b, 0, file->size);
fp = fopen(put_filename, "rb");
fread(b, 1, file->size, fp);
fclose(fp);
r = sc_update_binary(card, 0, b, file->size, 0);
if(r<0)
{
free(b);
printf("Error writing file.\n");
goto out;
}
free(b);
}
out:
if(mem)
BIO_free(mem);
if(bn)
BN_free(bn);
if(rsa)
RSA_free(rsa);
if(file)
sc_file_free(file);
if (card)
{
sc_unlock(card);
sc_disconnect_card(card, 0);
}
if (ctx)
sc_release_context(ctx);
}