diff --git a/NEWS b/NEWS index b1cb579e..36bf26f4 100644 --- a/NEWS +++ b/NEWS @@ -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 diff --git a/doc/tools/tools.xml b/doc/tools/tools.xml index c1246010..6bdc675e 100644 --- a/doc/tools/tools.xml +++ b/doc/tools/tools.xml @@ -19,6 +19,7 @@ + diff --git a/doc/tools/westcos-tool.xml b/doc/tools/westcos-tool.xml new file mode 100644 index 00000000..fc2cc278 --- /dev/null +++ b/doc/tools/westcos-tool.xml @@ -0,0 +1,140 @@ + + + + westcos-tool + 1 + opensc + + + + westcos-tool + utility for manipulating data structure + on westcos smart card and similar security tokens + + + + Synopsis + + westcos-tool [OPTIONS] + + + + + Description + + The westcos-tool 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. + + + + + Options + + + + + 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. + + + + length + Change the length of private key, use with . + + + + + + Install pin file in token, you must provide pin value + with . + + + + value + set value of pin. + + + + value + set value of puk (or value of new pin for change pin + command see ). + + + + + Changes a PIN stored on the token. User authentication + is required for this operation. + + + + + Unblocks a PIN stored on the token. Knowledge of the Pin + Unblock Key (PUK) is required for this operation. + + + + file + Write certificate file in pem format on the + card. User authentication is required for this operation. + + + + + 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). + + + + n + Forces westcos-tool to use reader + number n for operations. + + + + path + Get the file path the file is written + on disk with path name. User authentication + is required for this operation. + + + + path + Put the file with name path from disk + to card the file is written in path. User authentication + is required for this operation. + + + + + Causes westcos-tool to be more + verbose. Specify this flag several times to enable debug output + in the OpenSC library. + + + + + Print help message on screen. + + + + + + + + See also + opensc(7) + + + + Authors + westcos-tool was written by + Francois Leblanc francois.leblanc@cev-sa.com. + + + diff --git a/src/libopensc/Makefile.am b/src/libopensc/Makefile.am index 16b4f67f..ae3542b9 100644 --- a/src/libopensc/Makefile.am +++ b/src/libopensc/Makefile.am @@ -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 diff --git a/src/libopensc/Makefile.mak b/src/libopensc/Makefile.mak index 5acccce6..a06fa827 100644 --- a/src/libopensc/Makefile.mak +++ b/src/libopensc/Makefile.mak @@ -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 \ diff --git a/src/libopensc/card-westcos.c b/src/libopensc/card-westcos.c new file mode 100644 index 00000000..77091dc1 --- /dev/null +++ b/src/libopensc/card-westcos.c @@ -0,0 +1,1355 @@ +/* + * card-westcos.c: 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 + */ + +#include "internal.h" +#include +#include +#include +#include +#include "cardctl.h" +#include "asn1.h" + +#ifdef ENABLE_OPENSSL +#include +#include +#include +#include +#include +#include +#endif + +#ifndef min +#define min(a,b) (((a)<(b))?(a):(b)) +#endif + +#ifndef min +#define max(a,b) (((a)>(b))?(a):(b)) +#endif + +#define DEFAULT_TRANSPORT_KEY "6f:59:b0:ed:6e:62:46:4a:5d:25:37:68:23:a8:a2:2d" + +#define JAVACARD (0x01) + +#ifdef ENABLE_OPENSSL +#define DEBUG_SSL +#ifdef DEBUG_SSL +static void print_openssl_erreur(void) +{ + static int charge = 0; + 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)); +} +#endif +#endif + +typedef struct { + sc_security_env_t env; + sc_autkey_t default_key; + int flags; + int file_id; +} priv_data_t; + +static const struct sc_card_operations *iso_ops = NULL; +static struct sc_card_operations westcos_ops; + +static struct sc_card_driver westcos_drv = { + "WESTCOS compatible cards", "westcos", &westcos_ops, NULL, 0, NULL +}; + +static int westcos_get_default_key(sc_card_t * card, + struct sc_cardctl_default_key *data) +{ + const char *default_key; + if (card->ctx->debug >= 1) + sc_debug(card->ctx, + "westcos_get_default_key:data->method=%d, data->key_ref=%d\n", + data->method, data->key_ref); + if (data->method != SC_AC_AUT || data->key_ref != 0) + return SC_ERROR_NO_DEFAULT_KEY; + default_key = + scconf_get_str(card->ctx->conf_blocks[0], "westcos_default_key", + DEFAULT_TRANSPORT_KEY); + return sc_hex_to_bin(default_key, data->key_data, &data->len); +} + +#define CRC_A 1 +#define CRC_B 2 + +static unsigned short westcos_update_crc(unsigned char ch, unsigned short *lpwCrc) +{ + ch = (ch ^ (unsigned char)((*lpwCrc) & 0x00FF)); + ch = (ch ^ (ch << 4)); + *lpwCrc = + (*lpwCrc >> 8) ^ ((unsigned short)ch << 8) ^ ((unsigned short)ch << + 3) ^ ((unsigned short) + ch >> 4); + return (*lpwCrc); +} + +static void westcos_compute_aetb_crc(int CRCType, + unsigned char *Data, + size_t Length, + unsigned char * TransmitFirst, + unsigned char * TransmitSecond) +{ + unsigned char chBlock; + unsigned short wCrc; + switch (CRCType) { + case CRC_A: + wCrc = 0x6363; // ITU-V.41 + break; + case CRC_B: + wCrc = 0xFFFF; // ISO 3309 + break; + default: + return; + } + + do { + chBlock = *Data++; + westcos_update_crc(chBlock, &wCrc); + } while (--Length); + if (CRCType == CRC_B) + wCrc = ~wCrc; // ISO 3309 + *TransmitFirst = (unsigned char) (wCrc & 0xFF); + *TransmitSecond = (unsigned char) ((wCrc >> 8) & 0xFF); + return; +} + +static int westcos_check_sw(sc_card_t * card, unsigned int sw1, + unsigned int sw2) +{ + if ((sw1 == 0x69) && (sw2 == 0x88)) + return SC_ERROR_SECURITY_STATUS_NOT_SATISFIED; + assert(iso_ops && iso_ops->check_sw); + return iso_ops->check_sw(card, sw1, sw2); +} + +typedef struct mon_atr { + size_t len; + int flags; + u8 *atr, *mask; +} mon_atr_t; + +static mon_atr_t atrs[] = { + {13, 0x00, + "\x3f\x69\x00\x00\x00\x64\x01\x00\x00\x00\x80\x90\x00", + "\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\xf0\xff\xff"}, + {12, JAVACARD, + "\x3b\x95\x94\x80\x1F\xC3\x80\x73\xC8\x21\x13\x54", + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"} +}; + +static int westcos_finish(sc_card_t * card) +{ + if (card->algorithms) + free(card->algorithms); + card->algorithms = NULL; + card->algorithm_count = 0; + if (card->drv_data) + free(card->drv_data); + return 0; +} + +static int westcos_match_card(sc_card_t * card) +{ + u8 *p, j; + size_t i; + mon_atr_t *matr; + if (card->ctx->debug >= 1) + sc_debug(card->ctx, "westcos_match_card %d, %X:%X:%X\n", + card->atr_len, card->atr[0], card->atr[1], + card->atr[2]); + for (i = 0; i < sizeof(atrs) / sizeof(*atrs); i++) { + matr = &atrs[i]; + if (matr->len != card->atr_len) + continue; + p = card->atr; + for (j = 0; j < card->atr_len; j++) { + if (((matr->mask[j]) & (*p)) != (matr->atr[j])) + break; + p++; + if (*p == ':') + p++; + } + if (j >= card->atr_len) { + if (matr->flags & JAVACARD) { + int r; + sc_apdu_t apdu; + u8 aid[] = { + 0xA0, 0x00, 0xCE, 0x00, 0x07, 0x01 + }; + sc_format_apdu(card, &apdu, + SC_APDU_CASE_3_SHORT, 0xA4, 0x04, + 0); + apdu.cla = 0x00; + apdu.lc = sizeof(aid); + apdu.datalen = sizeof(aid); + apdu.data = aid; + sc_ctx_suppress_errors_on(card->ctx); + r = sc_transmit_apdu(card, &apdu); + sc_ctx_suppress_errors_off(card->ctx); + if (r) + continue; + sc_ctx_suppress_errors_on(card->ctx); + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + sc_ctx_suppress_errors_off(card->ctx); + if (r) + continue; + } + card->drv_data = malloc(sizeof(priv_data_t)); + if (card->drv_data == NULL) + return SC_ERROR_OUT_OF_MEMORY; + memset(card->drv_data, 0, sizeof(card->drv_data)); + if (matr->flags & JAVACARD) { + priv_data_t *priv_data = + (priv_data_t *) card->drv_data; + priv_data->flags |= JAVACARD; + } + return 1; + } + } + return 0; +} + +static int westcos_init(sc_card_t * card) +{ + int r; + const char *default_key; + unsigned long exponent, flags; + if (card == NULL || card->drv_data == NULL) + return SC_ERROR_INVALID_ARGUMENTS; + card->cla = 0x00; + card->max_send_size = 240; + card->max_recv_size = 240; + exponent = 0; + flags = SC_ALGORITHM_RSA_RAW; + flags |= SC_ALGORITHM_RSA_HASH_NONE; + flags |= SC_ALGORITHM_RSA_PAD_NONE | SC_ALGORITHM_RSA_PAD_PKCS1; + flags |= SC_ALGORITHM_ONBOARD_KEY_GEN; + _sc_card_add_rsa_alg(card, 128, flags, exponent); + _sc_card_add_rsa_alg(card, 256, flags, exponent); + _sc_card_add_rsa_alg(card, 512, flags, exponent); + _sc_card_add_rsa_alg(card, 768, flags, exponent); + _sc_card_add_rsa_alg(card, 1024, flags, exponent); + _sc_card_add_rsa_alg(card, 1100, flags, exponent); + _sc_card_add_rsa_alg(card, 1200, flags, exponent); + _sc_card_add_rsa_alg(card, 1300, flags, exponent); + _sc_card_add_rsa_alg(card, 1400, flags, exponent); + _sc_card_add_rsa_alg(card, 1536, flags, exponent); + _sc_card_add_rsa_alg(card, 2048, flags, exponent); + default_key = + scconf_get_str(card->ctx->conf_blocks[0], "westcos_default_key", + DEFAULT_TRANSPORT_KEY); + if (default_key) { + priv_data_t *priv_data = (priv_data_t *) (card->drv_data); + priv_data->default_key.key_reference = 0; + priv_data->default_key.key_len = + sizeof(priv_data->default_key.key_value); + r = sc_hex_to_bin(default_key, priv_data->default_key.key_value, + &(priv_data->default_key.key_len)); + if (r) + return (r); + } + return 0; +} + +static int westcos_select_file(sc_card_t * card, const sc_path_t * in_path, + sc_file_t ** file_out) +{ + sc_context_t *ctx; + sc_apdu_t apdu; + u8 buf[SC_MAX_APDU_BUFFER_SIZE]; + u8 pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf; + int r, pathlen; + sc_file_t *file = NULL; + priv_data_t *priv_data = NULL; + if (card->ctx->debug >= 1) + sc_debug(card->ctx, "westcos_select_file\n"); + if (card == NULL) + return SC_ERROR_INVALID_ARGUMENTS; + priv_data = (priv_data_t *) card->drv_data; + priv_data->file_id = 0; + ctx = card->ctx; + memcpy(path, in_path->value, in_path->len); + pathlen = (int)in_path->len; + sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0, 0); + switch (in_path->type) { + case SC_PATH_TYPE_FILE_ID: + apdu.p1 = 0; + if (pathlen != 2) + return SC_ERROR_INVALID_ARGUMENTS; + break; + case SC_PATH_TYPE_DF_NAME: + apdu.p1 = 4; + break; + case SC_PATH_TYPE_PATH: + apdu.p1 = 9; + if (pathlen == 2 && memcmp(path, "\x3F\x00", 2) == 0) { + apdu.p1 = 0; + } + + else if (pathlen > 2 && memcmp(path, "\x3F\x00", 2) == 0) { + apdu.p1 = 8; + pathlen -= 2; + memcpy(path, &in_path->value[2], pathlen); + } + break; + case SC_PATH_TYPE_FROM_CURRENT: + apdu.p1 = 9; + break; + case SC_PATH_TYPE_PARENT: + apdu.p1 = 3; + pathlen = 0; + apdu.cse = SC_APDU_CASE_3_SHORT; + break; + default: + return SC_ERROR_INVALID_ARGUMENTS; + } + apdu.p2 = 0; /* first record, return FCI */ + apdu.lc = pathlen; + apdu.data = path; + apdu.datalen = pathlen; + if (file_out != NULL) { + apdu.resp = buf; + apdu.resplen = sizeof(buf); + apdu.le = 255; + } else { + apdu.resplen = 0; + apdu.le = 0; + apdu.cse = SC_APDU_CASE_3_SHORT; + } + r = sc_transmit_apdu(card, &apdu); + if (r) + return (r); + if (file_out == NULL) { + if (apdu.sw1 == 0x61) + return 0; + return sc_check_sw(card, apdu.sw1, apdu.sw2); + } + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + if (r) + return (r); + switch (apdu.resp[0]) { + case 0x6F: + file = sc_file_new(); + if (file == NULL) + return SC_ERROR_OUT_OF_MEMORY; + file->path = *in_path; + if (card->ops->process_fci == NULL) { + sc_file_free(file); + return SC_ERROR_NOT_SUPPORTED; + } + if (apdu.resp[1] <= apdu.resplen) + card->ops->process_fci(card, file, apdu.resp + 2, + apdu.resp[1]); + *file_out = file; + break; + case 0x00: /* proprietary coding */ + return SC_ERROR_UNKNOWN_DATA_RECEIVED; + default: + return SC_ERROR_UNKNOWN_DATA_RECEIVED; + } + return 0; +} + +static int _westcos2opensc_ac(u8 flag) +{ + if (flag == 0) + return SC_AC_NEVER; + else if (flag == 1) + return SC_AC_CHV; + else if (flag == 2) + return SC_AC_AUT; + else if (flag == 15) + return SC_AC_NONE; + return SC_AC_UNKNOWN; +} + +static int westcos_process_fci(sc_card_t * card, sc_file_t * file, + const u8 * buf, size_t buflen) +{ + sc_context_t *ctx = card->ctx; + size_t taglen, len = buflen; + const u8 *tag = NULL, *p = buf; + if (card->ctx->debug >= 5) + sc_debug(card->ctx, "processing FCI bytes\n"); + tag = sc_asn1_find_tag(ctx, p, len, 0x83, &taglen); + if (tag != NULL && taglen == 2) { + file->id = (tag[0] << 8) | tag[1]; + if (card->ctx->debug >= 5) + sc_debug(card->ctx, " file identifier: 0x%02X%02X\n", + tag[0], tag[1]); + } + tag = sc_asn1_find_tag(ctx, p, len, 0x80, &taglen); + if (tag != NULL && taglen >= 2) { + int bytes = (tag[0] << 8) + tag[1]; + if (card->ctx->debug >= 5) + sc_debug(card->ctx, " bytes in file: %d\n", bytes); + file->size = bytes; + } + if (tag == NULL) { + tag = sc_asn1_find_tag(ctx, p, len, 0x81, &taglen); + if (tag != NULL && taglen >= 2) { + int bytes = (tag[0] << 8) + tag[1]; + if (card->ctx->debug >= 5) + sc_debug(card->ctx, " bytes in file: %d\n", + bytes); + file->size = bytes; + } + } + tag = sc_asn1_find_tag(ctx, p, len, 0x82, &taglen); + if (tag != NULL) { + if (taglen > 0) { + unsigned char byte = tag[0]; + const char *type; + file->shareable = 0; + if (card->ctx->debug >= 5) + sc_debug(card->ctx, " shareable: %s\n", + (file->shareable) ? "yes" : "no"); + file->ef_structure = SC_FILE_EF_UNKNOWN; + switch (byte) { + case 0x38: + type = "DF"; + file->type = SC_FILE_TYPE_DF; + break; + case 0x01: + type = "working or internal EF"; + file->type = SC_FILE_TYPE_WORKING_EF; + file->ef_structure = SC_FILE_EF_TRANSPARENT; + break; + case 0x02: + type = "working or internal EF"; + file->type = SC_FILE_TYPE_WORKING_EF; + file->ef_structure = SC_FILE_EF_LINEAR_FIXED; + break; + case 0x06: + type = "working or internal EF"; + file->type = SC_FILE_TYPE_WORKING_EF; + file->ef_structure = SC_FILE_EF_CYCLIC; + break; + default: + type = "unknow"; + } + if (card->ctx->debug >= 5) + sc_debug(card->ctx, " type: %s\n", type); + if (card->ctx->debug >= 5) + sc_debug(card->ctx, " EF structure: %d\n", + file->ef_structure); + } + } + tag = sc_asn1_find_tag(ctx, p, len, 0x84, &taglen); + if (tag != NULL && taglen > 0 && taglen <= 16) { + memcpy(file->name, tag, taglen); + file->namelen = taglen; + if (card->ctx->debug >= 5) { + char tbuf[128]; + sc_hex_dump(ctx, file->name, file->namelen, tbuf, + sizeof(tbuf)); + sc_debug(card->ctx, " File name: %s\n", tbuf); + } + } + if (file->type == SC_FILE_TYPE_DF) { + tag = sc_asn1_find_tag(ctx, p, len, 0x85, &taglen); + if (tag != NULL && taglen == 3) { + file->size = tag[1] * 256 + tag[2]; + } else + file->size = 0; + } + tag = sc_asn1_find_tag(ctx, p, len, 0xA5, &taglen); + if (tag != NULL && taglen) { + sc_file_set_prop_attr(file, tag, taglen); + } + tag = sc_asn1_find_tag(ctx, p, len, 0x86, &taglen); + if (tag != NULL && taglen) { + sc_file_set_sec_attr(file, tag, taglen); + + /* FIXME: compact file system only */ + if (file->type == SC_FILE_TYPE_DF) { + sc_file_add_acl_entry(file, SC_AC_OP_SELECT, + _westcos2opensc_ac(tag[0] >> + 4), + tag[0 + 4] >> 4); + sc_file_add_acl_entry(file, SC_AC_OP_CREATE, + _westcos2opensc_ac(tag[0] & + 0x0f), + tag[0 + 4] & 0x0f); + sc_file_add_acl_entry(file, SC_AC_OP_INVALIDATE, + _westcos2opensc_ac(tag[1] >> + 4), + tag[1 + 4] >> 4); + } + + else { + if (file->ef_structure == SC_FILE_EF_TRANSPARENT) { + sc_file_add_acl_entry(file, SC_AC_OP_READ, + _westcos2opensc_ac(tag[0] + >> + 4), + tag[0 + 4] >> 4); + sc_file_add_acl_entry(file, SC_AC_OP_UPDATE, + _westcos2opensc_ac(tag[0] + & + 0x0f), + tag[0 + 4] & 0x0f); + sc_file_add_acl_entry(file, + SC_AC_OP_INVALIDATE, + _westcos2opensc_ac(tag[1] + >> + 4), + tag[1 + 4] >> 4); + sc_file_add_acl_entry(file, SC_AC_OP_ERASE, + _westcos2opensc_ac(tag[1] + & + 0x0f), + tag[1 + 4] & 0x0f); + } + + else { + sc_file_add_acl_entry(file, SC_AC_OP_READ, + _westcos2opensc_ac(tag[0] + >> + 4), + tag[0 + 4] >> 4); + sc_file_add_acl_entry(file, SC_AC_OP_UPDATE, + _westcos2opensc_ac(tag[0] + & + 0x0f), + tag[0 + 4] & 0x0f); + sc_file_add_acl_entry(file, + SC_AC_OP_INVALIDATE, + _westcos2opensc_ac(tag[1] + >> + 4), + tag[1 + 4] >> 4); + } + } + } + return 0; +} + +#define HIGH (0) +#define LOW (1) +static int _convertion_ac_methode(sc_file_t * file, int low, + unsigned int operation, u8 * buf, + u8 * buf_key) +{ + const struct sc_acl_entry *acl; + acl = sc_file_get_acl_entry(file, operation); + if (acl == NULL) { + + /* par defaut always */ + *buf = 0xff; + *buf_key = 0x00; + return 0; + } + switch (acl->method) { + case SC_AC_NONE: + if (low) + *buf |= 0x0f; + + else + *buf |= 0xf0; + break; + case SC_AC_CHV: /* Card Holder Verif. */ + if (low) + *buf |= 0x01; + + else + *buf |= 0x10; + break; + case SC_AC_TERM: /* Terminal auth. */ + return SC_ERROR_NOT_SUPPORTED; + case SC_AC_PRO: /* Secure Messaging */ + return SC_ERROR_NOT_SUPPORTED; + case SC_AC_AUT: /* Key auth. */ + if (low) + *buf |= 0x02; + + else + *buf |= 0x20; + if (acl->key_ref > 15) + return SC_ERROR_NOT_SUPPORTED; + if (low) + *buf_key |= acl->key_ref; + + else + *buf_key |= (acl->key_ref) << 4; + break; + case SC_AC_NEVER: + *buf |= 0; + break; + default: + return SC_ERROR_NOT_SUPPORTED; + } + return 0; +} + +static int westcos_create_file(sc_card_t *card, struct sc_file *file) +{ + int r; + sc_apdu_t apdu; + u8 buf[12], p1 = 0, p2 = 0; + int buflen; + if (card == NULL) + return SC_ERROR_INVALID_ARGUMENTS; + if (card->ctx->debug >= 1) + sc_debug(card->ctx, "westcos_create_file\n"); + memset(buf, 0, sizeof(buf)); + + /* clef de transport */ + r = sc_card_ctl(card, SC_CARDCTL_WESTCOS_AUT_KEY, NULL); + if (r) + return (r); + buflen = sizeof(buf); + switch (file->type) { + case SC_FILE_TYPE_DF: + buf[0] = 0x00; + buf[1] = 0x01; + _convertion_ac_methode(file, HIGH, SC_AC_OP_SELECT, &buf[2], + &buf[2 + 4]); + _convertion_ac_methode(file, LOW, SC_AC_OP_CREATE, &buf[2], + &buf[2 + 4]); + _convertion_ac_methode(file, HIGH, SC_AC_OP_INVALIDATE, + &buf[3], &buf[3 + 4]); + buflen = 10; + break; + case SC_FILE_TYPE_INTERNAL_EF: + buf[0] |= 0x80; + case SC_FILE_TYPE_WORKING_EF: + switch (file->ef_structure) { + case SC_FILE_EF_TRANSPARENT: + buf[0] |= 0x20; /* pas de support transaction */ + buf[1] |= 0; + _convertion_ac_methode(file, HIGH, SC_AC_OP_READ, + &buf[2], &buf[2 + 4]); + _convertion_ac_methode(file, LOW, SC_AC_OP_UPDATE, + &buf[2], &buf[2 + 4]); + _convertion_ac_methode(file, HIGH, SC_AC_OP_INVALIDATE, + &buf[3], &buf[3 + 4]); + _convertion_ac_methode(file, LOW, SC_AC_OP_ERASE, + &buf[3], &buf[3 + 4]); + buf[10] = (u8) ((file->size) / 256); + buf[11] = (u8) ((file->size) % 256); + break; + case SC_FILE_EF_LINEAR_FIXED: + buf[0] |= 0x40; /* pas de support transaction */ + buf[1] |= 0; + _convertion_ac_methode(file, HIGH, SC_AC_OP_READ, + &buf[2], &buf[2 + 4]); + _convertion_ac_methode(file, LOW, SC_AC_OP_UPDATE, + &buf[2], &buf[2 + 4]); + _convertion_ac_methode(file, HIGH, SC_AC_OP_INVALIDATE, + &buf[3], &buf[3 + 4]); + buf[10] = file->record_count; + buf[11] = file->record_length; + break; + case SC_FILE_EF_CYCLIC: + buf[0] |= 0x60; /* pas de support transaction */ + buf[1] |= 0; + _convertion_ac_methode(file, HIGH, SC_AC_OP_READ, + &buf[2], &buf[2 + 4]); + _convertion_ac_methode(file, LOW, SC_AC_OP_UPDATE, + &buf[2], &buf[2 + 4]); + _convertion_ac_methode(file, HIGH, SC_AC_OP_INVALIDATE, + &buf[3], &buf[3 + 4]); + buf[10] = file->record_count; + buf[11] = file->record_length; + break; + case SC_FILE_EF_LINEAR_VARIABLE: + case SC_FILE_EF_UNKNOWN: + case SC_FILE_EF_LINEAR_FIXED_TLV: + case SC_FILE_EF_LINEAR_VARIABLE_TLV: + case SC_FILE_EF_CYCLIC_TLV: + default: + return SC_ERROR_NOT_SUPPORTED; + } + break; + default: + return SC_ERROR_NOT_SUPPORTED; + } + if (file->shareable) + buf[0] |= 0x08; + if (file->path.len >= 2) { + p1 = file->path.value[file->path.len - 2]; + p2 = file->path.value[file->path.len - 1]; + } + + else if (file->id) { + p1 = (file->id) / 256; + p2 = (file->id) % 256; + } + if (card->ctx->debug >= 3) + sc_debug(card->ctx, "create file %s, id %X size %d\n", + file->path.value, file->id, file->size); + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE0, p1, p2); + apdu.cla = 0x80; + apdu.lc = buflen; + apdu.datalen = buflen; + apdu.data = buf; + r = sc_transmit_apdu(card, &apdu); + if (r) + return (r); + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + return r; +} + +static int westcos_delete_file(sc_card_t * card, const sc_path_t * path_in) +{ + int r; + sc_apdu_t apdu; + if (card == NULL || path_in == NULL || path_in->len < 2) + return SC_ERROR_INVALID_ARGUMENTS; + if (card->ctx->debug >= 1) + sc_debug(card->ctx, "westcos_delete_file\n"); + if (path_in->len > 2) { + r = sc_select_file(card, path_in, NULL); + if (r) + return (r); + } + sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0xE4, + path_in->value[path_in->len - 2], + path_in->value[path_in->len - 1]); + apdu.cla = 0x80; + r = sc_transmit_apdu(card, &apdu); + if (r) + return (r); + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + if (r) + return (r); + return 0; +} + +static int westcos_list_files(sc_card_t * card, u8 * buf, size_t buflen) +{ + int r; + sc_apdu_t apdu; + if (card == NULL) + return SC_ERROR_INVALID_ARGUMENTS; + if (card->ctx->debug >= 1) + sc_debug(card->ctx, "westcos_list_files\n"); + sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x34, 0x00, 0x00); + apdu.cla = 0x80; + apdu.le = buflen; + apdu.resplen = buflen; + apdu.resp = buf; + r = sc_transmit_apdu(card, &apdu); + if (r) + return (r); + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + if (r) + return (r); + return apdu.resplen; +} + +static int westcos_get_crypte_challenge(sc_card_t * card, const u8 * key, + u8 * result, size_t * len) +{ + int r; + DES_key_schedule ks1, ks2; + u8 buf[8]; + if ((*len) < sizeof(buf)) + return SC_ERROR_INVALID_ARGUMENTS; + *len = 8; + r = sc_get_challenge(card, buf, *len); + if (r) + return r; + DES_set_key((const_DES_cblock *) & key[0], &ks1); + DES_set_key((const_DES_cblock *) & key[8], &ks2); + DES_ecb2_encrypt((const_DES_cblock *)buf, (DES_cblock*)result, &ks1, &ks2, DES_ENCRYPT); + return 0; +} + +static int westcos_pin_cmd(sc_card_t * card, struct sc_pin_cmd_data *data, + int *tries_left) +{ + int r; + u8 buf[20]; //, result[20]; + sc_apdu_t apdu; + size_t len = 0; + int pad = 0, use_pin_pad = 0, ins, p1 = 0; + if (card == NULL) + return SC_ERROR_INVALID_ARGUMENTS; + if (card->ctx->debug >= 1) + sc_debug(card->ctx, + "westcos_pin_cmd:data->pin_type=%X, data->cmd=%X\n", + data->pin_type, data->cmd); + if (tries_left) + *tries_left = -1; + switch (data->pin_type) { + case SC_AC_AUT: + len = sizeof(buf); + r = westcos_get_crypte_challenge(card, data->pin1.data, buf, + &len); + if (r) + return (r); + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x82, 0x00, + data->pin_reference); + apdu.lc = len; + apdu.datalen = len; + apdu.data = buf; + r = sc_transmit_apdu(card, &apdu); + if (r) + return (r); + return sc_check_sw(card, apdu.sw1, apdu.sw2); + break; + case SC_AC_CHV: + 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 = 0; + data->pin1.encoding = SC_PIN_ENCODING_GLP; + if (data->pin1.min_length == 0) + data->pin1.min_length = 4; + if (data->pin1.max_length == 0) + data->pin1.max_length = 12; + switch (data->cmd) { + case SC_PIN_CMD_VERIFY: + ins = 0x20; + if ((r = + sc_build_pin(buf, sizeof(buf), &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(buf, sizeof(buf), + &data->pin1, pad)) < 0) + return r; + len += r; + } else { + + /* implicit test */ + p1 = 1; + } + data->pin2.offset = data->pin1.offset + len; + data->pin2.encoding = SC_PIN_ENCODING_GLP; + if ((r = + sc_build_pin(buf + len, sizeof(buf) - 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(buf, sizeof(buf), + &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; + data->pin2.encoding = SC_PIN_ENCODING_GLP; + if ((r = + sc_build_pin(buf + len, sizeof(buf) - 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 = buf; + apdu.resplen = 0; + apdu.sensitive = 1; + if (!use_pin_pad) { + + /* Transmit the APDU to the card */ + r = sc_transmit_apdu(card, &apdu); + + /* Clear the buffer - it may contain pins */ + sc_mem_clear(buf, sizeof(buf)); + } else { + data->apdu = &apdu; + if (card->reader + && card->reader->ops + && card->reader->ops->perform_verify) { + r = card->reader->ops->perform_verify(card-> + reader, + card-> + slot, + data); + } else { + r = SC_ERROR_NOT_SUPPORTED; + } + } + if (r) + return (r); + return sc_check_sw(card, apdu.sw1, apdu.sw2); + default: + return SC_ERROR_NOT_SUPPORTED; + } +} + +static int sc_get_atr(sc_card_t * card) +{ + int r; + sc_apdu_t apdu; + u8 buf[sizeof(card->atr)]; + if (card == NULL) + return SC_ERROR_INVALID_ARGUMENTS; + sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xEC, 0x00, 0x00); + apdu.cla = 0x80; + apdu.le = 0x0d; + apdu.resplen = 0x0d; + apdu.resp = buf; + r = sc_transmit_apdu(card, &apdu); + if (r) + return (r); + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + if (r) + return (r); + memcpy(card->atr, buf, sizeof(card->atr)); + card->atr_len = apdu.resplen; + return r; +} + +static int sc_lock_phase(sc_card_t * card, u8 phase) +{ + int r; + sc_apdu_t apdu; + if (card == NULL) + return SC_ERROR_INVALID_ARGUMENTS; + sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x16, phase, 0x00); + apdu.cla = 0x80; + r = sc_transmit_apdu(card, &apdu); + if (r) + return (r); + return sc_check_sw(card, apdu.sw1, apdu.sw2); +} + +static int westcos_card_ctl(sc_card_t * card, unsigned long cmd, void *ptr) +{ + int r; + size_t buflen; + u8 buf[256]; + sc_apdu_t apdu; + struct sc_pin_cmd_data data; + sc_serial_number_t *serialnr; + priv_data_t *priv_data = NULL; + if (card == NULL) + return SC_ERROR_INVALID_ARGUMENTS; + if (card->ctx->debug >= 1) + sc_debug(card->ctx, "westcos_card_ctl cmd = %X\n", cmd); + priv_data = (priv_data_t *) card->drv_data; + switch (cmd) { + case SC_CARDCTL_GET_DEFAULT_KEY: + return westcos_get_default_key(card, + (struct sc_cardctl_default_key + *)ptr); + break; + case SC_CARDCTL_LIFECYCLE_SET: + if (1) { + int mode = *((int *)ptr); + switch (mode) { + case SC_CARDCTRL_LIFECYCLE_ADMIN: + if (priv_data->flags & JAVACARD) { + return 0; + } + if (card->atr[10] == 0x80 + || card->atr[10] == 0x81) + return 0; + return SC_ERROR_CARD_CMD_FAILED; + case SC_CARDCTRL_LIFECYCLE_USER: + if (card->atr[10] == 0x80) { + r = sc_lock_phase(card, 0x02); + if (r) + return (r); + r = sc_get_atr(card); + if (r) + return (r); + r = sc_card_ctl(card, + SC_CARDCTL_WESTCOS_AUT_KEY, + NULL); + if (r) + return (r); + } + if (card->atr[10] == 0x81) { + r = sc_lock_phase(card, 0x01); + if (r) + return (r); + r = sc_get_atr(card); + if (r) + return (r); + return 0; + } + return SC_ERROR_CARD_CMD_FAILED; + case SC_CARDCTRL_LIFECYCLE_OTHER: + default: + break; + } + } + break; + case SC_CARDCTL_GET_SERIALNR: + sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xEE, 0x00, + 0x00); + apdu.cla = 0xb0; + apdu.le = 8; + apdu.resp = buf; + apdu.resplen = 10; /* include SW's */ + r = sc_transmit_apdu(card, &apdu); + if (r) + return (r); + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + if (r) + return (r); + if (SC_MAX_SERIALNR < 8) + return SC_ERROR_NOT_SUPPORTED; + serialnr = (sc_serial_number_t *) ptr; + serialnr->len = 8; + memcpy(serialnr->value, buf, serialnr->len); + return 0; + case SC_CARDCTL_WESTCOS_CREATE_MF: + buf[0] = *((u8 *) ptr); + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE0, 0x3F, + 0x00); + apdu.cla = 0x80; + apdu.lc = 1; + apdu.datalen = 1; + apdu.data = buf; + apdu.le = 0; + r = sc_transmit_apdu(card, &apdu); + if (r) + return (r); + return sc_check_sw(card, apdu.sw1, apdu.sw2); + case SC_CARDCTL_WESTCOS_COMMIT: + sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x2C, 0x00, 0x00); + apdu.cla = 0x80; + r = sc_transmit_apdu(card, &apdu); + if (r) + return (r); + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + if (r) + return (r); + return r; + case SC_CARDCTL_WESTCOS_ROLLBACK: + sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x24, 0x00, 0x00); + apdu.cla = 0x80; + r = sc_transmit_apdu(card, &apdu); + if (r) + return (r); + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + if (r) + return (r); + return r; + case SC_CARDCTL_WESTCOS_AUT_KEY: + if (ptr != NULL) + priv_data->default_key = *((sc_autkey_t *) ptr); + memset(&data, 0, sizeof(data)); + data.pin_type = SC_AC_AUT; + data.pin_reference = priv_data->default_key.key_reference; + data.pin1.len = priv_data->default_key.key_len; + data.pin1.data = priv_data->default_key.key_value; + return sc_pin_cmd(card, &data, NULL); + case SC_CARDCTL_WESTCOS_CHANGE_KEY: + if (1) { + int lrc; + u8 temp[7]; + sc_changekey_t *ck = (sc_changekey_t *) ptr; + sc_autkey_t master_key; + if (ck->master_key.key_len != 0) + master_key = ck->master_key; + + else + master_key = priv_data->default_key; + memcpy(temp, ck->key_template, sizeof(temp)); + westcos_compute_aetb_crc(CRC_A, ck->new_key.key_value, + ck->new_key.key_len, &temp[5], &temp[6]); + for (r = 0, temp[4] = 0xAA, lrc = 0; r < sizeof(temp); + r++) + lrc += temp[r]; + temp[4] = (lrc % 256); + buflen = sizeof(buf); + r = westcos_get_crypte_challenge(card, + master_key.key_value, + buf, &buflen); + if (r) + return (r); + memcpy(&buf[buflen], temp, sizeof(temp)); + buflen += sizeof(temp); + memcpy(&buf[buflen], ck->new_key.key_value, + ck->new_key.key_len); + buflen += ck->new_key.key_len; + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, + 0xD8, ck->new_key.key_reference, + master_key.key_reference); + apdu.cla = 0x80; + apdu.lc = buflen; + apdu.datalen = buflen; + apdu.data = buf; + r = sc_transmit_apdu(card, &apdu); + if (r) + return (r); + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + if (r) + return (r); + return r; + } + case SC_CARDCTL_WESTCOS_SET_DEFAULT_KEY: + priv_data->default_key = *((sc_autkey_t *) ptr); + return 0; + case SC_CARDCTL_WESTCOS_LOAD_DATA: + + /* ptr[0] = 0x01 pour generique appli, 0x81 pour appli avec pme */ + buf[0] = *((u8 *) ptr); + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xB2, 0x80, + 0x14); + apdu.cla = 0xB0; + apdu.lc = 1; + apdu.datalen = 1; + apdu.data = buf; + r = sc_transmit_apdu(card, &apdu); + if (r) + return (r); + return sc_check_sw(card, apdu.sw1, apdu.sw2); + } + return SC_ERROR_NOT_SUPPORTED; +} +static int westcos_set_security_env(sc_card_t *card, + const struct sc_security_env *env, + int se_num) +{ + priv_data_t *priv_data = NULL; + if (card == NULL) + return SC_ERROR_INVALID_ARGUMENTS; + if (card->ctx->debug >= 1) + sc_debug(card->ctx, "westcos_set_security_env\n"); + priv_data = (priv_data_t *) card->drv_data; + priv_data->env = *env; + return 0; +} + +static int westcos_restore_security_env(sc_card_t *card, int se_num) +{ + if (card == NULL) + return SC_ERROR_INVALID_ARGUMENTS; + if (card->ctx->debug >= 1) + sc_debug(card->ctx, "westcos_restore_security_env\n"); + return 0; +} + +static int westcos_sign_decipher(int mode, sc_card_t *card, + const u8 * data, size_t data_len, u8 * out, + size_t outlen) +{ + int r; + int idx = 0; + u8 buf[180]; + sc_file_t *keyfile = sc_file_new(); + priv_data_t *priv_data = NULL; + int pad; + +#ifdef ENABLE_OPENSSL + RSA *rsa = NULL; + BIO *mem = BIO_new(BIO_s_mem()); + +#endif + if (card == NULL) + return SC_ERROR_INVALID_ARGUMENTS; + if (card->ctx->debug >= 1) + sc_debug(card->ctx, "westcos_sign_decipher\n"); + priv_data = (priv_data_t *) card->drv_data; + if (keyfile == NULL || mem == NULL || priv_data == NULL) { + r = SC_ERROR_OUT_OF_MEMORY; + goto out; + } +#ifndef ENABLE_OPENSSL + r = SC_ERROR_NOT_SUPPORTED; + +#else + if ((priv_data->env.flags) & SC_ALGORITHM_RSA_PAD_PKCS1) + pad = RSA_PKCS1_PADDING; + + else if ((priv_data->env.flags) & SC_ALGORITHM_RSA_RAW) + pad = RSA_NO_PADDING; + + else { + r = SC_ERROR_INVALID_ARGUMENTS; + goto out; + } + r = sc_select_file(card, &(priv_data->env.file_ref), &keyfile); + if (r) + goto out; + + do { + int alire; + alire = min(((keyfile->size) - idx), sizeof(buf)); + if (alire <= 0) + break; + if (card->ctx->debug >= 5) + sc_debug(card->ctx, "idx = %d, alire=%d\n", idx, alire); + r = sc_read_binary(card, idx, buf, alire, 0); + if (r < 0) + goto out; + BIO_write(mem, buf, r); + idx += r; + } while (1); + BIO_set_mem_eof_return(mem, -1); + if (!d2i_RSAPrivateKey_bio(mem, &rsa)) { + if (card->ctx->debug >= 5) + sc_debug(card->ctx, "RSA clef invalide, %d\n", + ERR_get_error()); + r = SC_ERROR_UNKNOWN; + goto out; + } + + /* pkcs11 reroute routine cryptage vers la carte */ + rsa->meth = RSA_PKCS1_SSLeay(); + if (RSA_size(rsa) > outlen) { + if (card->ctx->debug >= 5) + sc_debug(card->ctx, "Buffer too small\n"); + r = SC_ERROR_OUT_OF_MEMORY; + goto out; + } +#if 1 + if (mode) { /* decipher */ + r = RSA_private_decrypt(data_len, data, out, rsa, pad); + if (r == -1) { + +#ifdef DEBUG_SSL + print_openssl_erreur(); + +#endif + if (card->ctx->debug >= 5) + sc_debug(card->ctx, "Decipher error %d\n", + ERR_get_error()); + r = SC_ERROR_UNKNOWN; + goto out; + } + } + + else { /* signature */ + + r = RSA_private_encrypt(data_len, data, out, rsa, pad); + if (r == -1) { + +#ifdef DEBUG_SSL + print_openssl_erreur(); + +#endif + if (card->ctx->debug >= 5) + sc_debug(card->ctx, "Signature error %d\n", + ERR_get_error()); + r = SC_ERROR_UNKNOWN; + goto out; + } + } + +#else + if (RSA_sign(nid, data, data_len, out, &outlen, rsa) != 1) { + if (card->ctx->debug >= 5) + sc_debug(card->ctx, "RSA_sign error %d \n", + ERR_get_error()); + r = SC_ERROR_UNKNOWN; + goto out; + } + r = outlen; + +#endif +#endif /* ENABLE_OPENSSL */ + out: +#ifdef ENABLE_OPENSSL + if (mem) + BIO_free(mem); + if (rsa) + RSA_free(rsa); + +#endif + if (keyfile) + sc_file_free(keyfile); + return r; +} + +static int westcos_compute_signature(sc_card_t *card, const u8 * data, + size_t data_len, u8 * out, size_t outlen) +{ + return westcos_sign_decipher(0, card, data, data_len, out, outlen); +} + +static int westcos_decipher(sc_card_t *card, const u8 * crgram, + size_t crgram_len, u8 * out, size_t outlen) +{ + return westcos_sign_decipher(1, card, crgram, crgram_len, out, outlen); +} + +struct sc_card_driver *sc_get_westcos_driver(void) +{ + if (iso_ops == NULL) + iso_ops = sc_get_iso7816_driver()->ops; + westcos_ops = *iso_ops; + + westcos_ops.match_card = westcos_match_card; + westcos_ops.init = westcos_init; + westcos_ops.finish = westcos_finish; + /* read_binary */ + /* write_binary */ + /* update_binary */ + westcos_ops.erase_binary = NULL; + /* read_record */ + /* write_record */ + /* append_record */ + /* update_record */ + westcos_ops.select_file = westcos_select_file; + /* get_response */ + /* get_challenge */ + westcos_ops.verify = NULL; + westcos_ops.logout = NULL; + westcos_ops.restore_security_env = westcos_restore_security_env; + westcos_ops.set_security_env = westcos_set_security_env; + westcos_ops.decipher = westcos_decipher; + westcos_ops.compute_signature = westcos_compute_signature; + westcos_ops.change_reference_data = NULL; + westcos_ops.reset_retry_counter = NULL; + westcos_ops.create_file = westcos_create_file; + westcos_ops.delete_file = westcos_delete_file; + westcos_ops.list_files = westcos_list_files; + westcos_ops.check_sw = westcos_check_sw; + westcos_ops.card_ctl = westcos_card_ctl; + westcos_ops.process_fci = westcos_process_fci; + westcos_ops.construct_fci = NULL; + westcos_ops.pin_cmd = westcos_pin_cmd; + westcos_ops.get_data = NULL; + westcos_ops.put_data = NULL; + westcos_ops.delete_record = NULL; + + return &westcos_drv; +} + diff --git a/src/libopensc/cardctl.h b/src/libopensc/cardctl.h index 9483f773..657fa185 100644 --- a/src/libopensc/cardctl.h +++ b/src/libopensc/cardctl.h @@ -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 */ diff --git a/src/libopensc/cards.h b/src/libopensc/cards.h index 044a19fb..465059ba 100644 --- a/src/libopensc/cards.h +++ b/src/libopensc/cards.h @@ -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 } diff --git a/src/libopensc/ctx.c b/src/libopensc/ctx.c index db9953b5..9b2fb872 100644 --- a/src/libopensc/ctx.c +++ b/src/libopensc/ctx.c @@ -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 }, diff --git a/src/libopensc/p15emu-westcos.c b/src/libopensc/p15emu-westcos.c new file mode 100644 index 00000000..69e58908 --- /dev/null +++ b/src/libopensc/p15emu-westcos.c @@ -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 +#include +#include + +#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); +} diff --git a/src/libopensc/pkcs15-syn.c b/src/libopensc/pkcs15-syn.c index b0546f56..801f747c 100644 --- a/src/libopensc/pkcs15-syn.c +++ b/src/libopensc/pkcs15-syn.c @@ -28,6 +28,8 @@ #include #include +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 }, diff --git a/src/pkcs15init/Makefile.am b/src/pkcs15init/Makefile.am index 5ffdbba6..7f41e86f 100644 --- a/src/pkcs15init/Makefile.am +++ b/src/pkcs15init/Makefile.am @@ -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 \ diff --git a/src/pkcs15init/Makefile.mak b/src/pkcs15init/Makefile.mak index 1626668e..ca23a37f 100644 --- a/src/pkcs15init/Makefile.mak +++ b/src/pkcs15init/Makefile.mak @@ -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) diff --git a/src/pkcs15init/pkcs15-init.h b/src/pkcs15init/pkcs15-init.h index 80dd83b6..8c37a186 100644 --- a/src/pkcs15init/pkcs15-init.h +++ b/src/pkcs15init/pkcs15-init.h @@ -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 } diff --git a/src/pkcs15init/pkcs15-lib.c b/src/pkcs15init/pkcs15-lib.c index 03dbeaa9..6bc05473 100644 --- a/src/pkcs15init/pkcs15-lib.c +++ b/src/pkcs15init/pkcs15-lib.c @@ -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 }, }; diff --git a/src/pkcs15init/pkcs15-westcos.c b/src/pkcs15init/pkcs15-westcos.c new file mode 100644 index 00000000..321647d7 --- /dev/null +++ b/src/pkcs15init/pkcs15-westcos.c @@ -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 +#endif + +#include +#include +#include + +#include +#include +#include "pkcs15-init.h" +#include "profile.h" + +#ifdef ENABLE_OPENSSL +#include +#include +#include + + +#include +#include +#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; +} + + + diff --git a/src/pkcs15init/westcos.profile b/src/pkcs15init/westcos.profile new file mode 100644 index 00000000..957912fd --- /dev/null +++ b/src/pkcs15init/westcos.profile @@ -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; + } + } + + } + } +} + + + diff --git a/src/tools/Makefile.am b/src/tools/Makefile.am index cac0e06c..20af2088 100644 --- a/src/tools/Makefile.am +++ b/src/tools/Makefile.am @@ -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 diff --git a/src/tools/Makefile.mak b/src/tools/Makefile.mak index ef2c8c66..e4325874 100644 --- a/src/tools/Makefile.mak +++ b/src/tools/Makefile.mak @@ -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) diff --git a/src/tools/westcos-tool.c b/src/tools/westcos-tool.c new file mode 100644 index 00000000..3ddc2471 --- /dev/null +++ b/src/tools/westcos-tool.c @@ -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 +#endif + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +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 1) + ctx->debug = verbose-1; + + if(no_lecteur == -1) + { + for(i = 0; i=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); + +} +