From 8d7bce4de23d216889234e26b72272cad6255011 Mon Sep 17 00:00:00 2001 From: alonbl Date: Fri, 18 Apr 2008 14:08:23 +0000 Subject: [PATCH] ruToken fixups http://www.opensc-project.org/pipermail/opensc-devel/2008-April/011057.html By Aktiv Co. Aleksey Samsonov git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@3478 c6295689-39f2-0310-b995-f0e70906c6a9 --- src/include/opensc/Makefile.am | 1 - src/libopensc/Makefile.am | 5 +- src/libopensc/Makefile.mak | 4 +- src/libopensc/card-rutoken.c | 1263 +++++++++++++------------- src/libopensc/libopensc.exports | 2 - src/libopensc/pkcs15-prkey-rutoken.c | 377 -------- src/libopensc/pkcs15-rutoken.c | 46 +- src/libopensc/rutoken.h | 7 - src/pkcs15init/Makefile.am | 2 +- src/pkcs15init/pkcs15-rutoken.c | 196 ++-- src/pkcs15init/rutoken.profile | 36 +- src/tools/rutoken-tool.c | 1 - 12 files changed, 802 insertions(+), 1138 deletions(-) delete mode 100644 src/libopensc/pkcs15-prkey-rutoken.c delete mode 100644 src/libopensc/rutoken.h diff --git a/src/include/opensc/Makefile.am b/src/include/opensc/Makefile.am index a963b063..d58c49a9 100644 --- a/src/include/opensc/Makefile.am +++ b/src/include/opensc/Makefile.am @@ -13,7 +13,6 @@ all-local: @$(LN_S) $(top_srcdir)/src/libopensc/pkcs15.h pkcs15.h @$(LN_S) $(top_srcdir)/src/libopensc/types.h types.h @$(LN_S) $(top_srcdir)/src/libopensc/ui.h ui.h - @$(LN_S) $(top_srcdir)/src/libopensc/rutoken.h rutoken.h @$(LN_S) $(top_srcdir)/src/pkcs11/pkcs11.h pkcs11.h @$(LN_S) $(top_srcdir)/src/pkcs11/pkcs11-opensc.h pkcs11-opensc.h @$(LN_S) $(top_srcdir)/src/pkcs15init/keycache.h keycache.h diff --git a/src/libopensc/Makefile.am b/src/libopensc/Makefile.am index 9b9f45d0..1f5ba599 100644 --- a/src/libopensc/Makefile.am +++ b/src/libopensc/Makefile.am @@ -10,8 +10,7 @@ lib_LTLIBRARIES = libopensc.la openscinclude_HEADERS = \ opensc.h pkcs15.h emv.h \ cardctl.h asn1.h log.h ui.h \ - errors.h types.h compression.h \ - rutoken.h + errors.h types.h compression.h noinst_HEADERS = cards.h ctbcs.h internal.h esteid.h muscle.h muscle-filesystem.h \ internal-winscard.h p15card-helper.h pkgconfig_DATA = libopensc.pc libpkcs15init.pc libscconf.pc @@ -43,7 +42,7 @@ libopensc_la_SOURCES = \ 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-rutoken.c pkcs15-prkey-rutoken.c \ + pkcs15-rutoken.c \ compression.c p15card-helper.c \ \ libopensc.exports diff --git a/src/libopensc/Makefile.mak b/src/libopensc/Makefile.mak index cfb3e132..91b8bfe9 100644 --- a/src/libopensc/Makefile.mak +++ b/src/libopensc/Makefile.mak @@ -5,7 +5,7 @@ TARGET = opensc.dll opensc_a.lib HEADERS = \ asn1.h cardctl.h cards.h emv.h errors.h \ - log.h opensc.h pkcs15.h rutoken.h types.h ui.h + log.h opensc.h pkcs15.h types.h ui.h HEADERSDIR = $(TOPDIR)\src\include\opensc @@ -32,7 +32,7 @@ OBJECTS = \ 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 \ - pkcs15-rutoken.obj pkcs15-prkey-rutoken.obj \ + pkcs15-rutoken.obj \ compression.obj p15card-helper.obj \ versioninfo.res diff --git a/src/libopensc/card-rutoken.c b/src/libopensc/card-rutoken.c index ace45421..2e197880 100644 --- a/src/libopensc/card-rutoken.c +++ b/src/libopensc/card-rutoken.c @@ -1,5 +1,5 @@ /* - * card-rutoken.c: Support for ruToken cards + * card-rutoken.c: Support for Rutoken cards * * Copyright (C) 2007 Pavel Mironchik * Copyright (C) 2007 Eugene Hermann @@ -18,13 +18,10 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "internal.h" -#include "cardctl.h" -#include -#include -#include -#include -#include "pkcs15.h" + +#ifdef HAVE_CONFIG_H +#include +#endif #if defined(HAVE_INTTYPES_H) #include #elif defined(HAVE_STDINT_H) @@ -35,8 +32,14 @@ typedef unsigned __int16 uint16_t; #else #warning no uint32_t type available, please contact opensc-devel@opensc-project.org #endif - -#define BIG_ENDIAN_RUTOKEN +#include +#include +#include +#include +#include "opensc.h" +#include "pkcs15.h" +#include "internal.h" +#include "cardctl.h" #ifdef ENABLE_OPENSSL #include @@ -45,19 +48,11 @@ typedef unsigned __int16 uint16_t; #include #include #include -#include "rutoken.h" #endif -#define FDESCR_DF 0x38 /*00111000b*/ +#define FDESCR_DF 0x38 /*00111000b*/ #define FDESCR_EF 0x01 - -#define ID_RESERVED_CURDF 0x3FFF /*Reserved ID for current DF*/ - -#ifdef BIG_ENDIAN_RUTOKEN -#define MF_PATH "\x3F\x00" -#else -#define MF_PATH "\x00\x3F" -#endif +#define ID_RESERVED_CURDF 0x3FFF /*Reserved ID for current DF*/ struct auth_senv { unsigned int algorithm; @@ -70,12 +65,10 @@ static const sc_SecAttrV2_t default_sec_attr = { 0, 2, 0, 0, 0, 0, 2 }; -static const struct sc_card_operations *iso_ops = NULL; - static struct sc_card_operations rutoken_ops; static struct sc_card_driver rutoken_drv = { - "ruToken driver", + "Rutoken driver", "rutoken", &rutoken_ops, NULL, 0, NULL @@ -86,7 +79,7 @@ static struct sc_atr_table rutoken_atrs[] = { { NULL, NULL, NULL, 0, 0, NULL } }; -const char *hexdump(const void *data, size_t len) +static const char *hexdump(const void *data, size_t len) { static char string[1024]; unsigned char *d = (unsigned char *)data; @@ -106,255 +99,203 @@ static int rutoken_finish(sc_card_t *card) { SC_FUNC_CALLED(card->ctx, 1); free(card->drv_data); - return 0; + SC_FUNC_RETURN(card->ctx, 1, SC_SUCCESS); } static int rutoken_match_card(sc_card_t *card) { - int i; - SC_FUNC_CALLED(card->ctx, 1); - - i = _sc_match_atr(card, rutoken_atrs, &card->type); - if (i < 0) - return 0; - - sc_debug(card->ctx, "atr recognized as ruToken\n"); - return 1; + if (_sc_match_atr(card, rutoken_atrs, &card->type) >= 0) + { + sc_debug(card->ctx, "ATR recognized as Rutoken\n"); + SC_FUNC_RETURN(card->ctx, 1, 1); + } + SC_FUNC_RETURN(card->ctx, 1, 0); } -static int rutoken_init(sc_card_t *card) +static int token_init(sc_card_t *card, const char *card_name) { - int ret = SC_ERROR_MEMORY_FAILURE; - unsigned int flags = SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_PAD_PKCS1; - /* SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_HASH_SHA1 - | SC_ALGORITHM_RSA_HASH_MD5_SHA1 - | SC_ALGORITHM_RSA_PAD_NONE */ + unsigned int flags; sc_algorithm_info_t info; - SC_FUNC_CALLED(card->ctx, 1); + SC_FUNC_CALLED(card->ctx, 3); - card->name = "rutoken card"; - card->drv_data = malloc(sizeof(auth_senv_t)); + card->name = card_name; card->caps |= SC_CARD_CAP_RSA_2048 | SC_CARD_CAP_NO_FCI | SC_CARD_CAP_RNG; - if (card->drv_data) - { - memset(card->drv_data, 0, sizeof(auth_senv_t)); - ret = SC_NO_ERROR; - } - /* add algorithm - TODO: may nid som other flag */ + card->drv_data = calloc(1, sizeof(auth_senv_t)); + if (card->drv_data == NULL) + SC_FUNC_RETURN(card->ctx, 3, SC_ERROR_OUT_OF_MEMORY); + flags = SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_PAD_PKCS1; _sc_card_add_rsa_alg(card, 256, flags, 0); _sc_card_add_rsa_alg(card, 512, flags, 0); _sc_card_add_rsa_alg(card, 768, flags, 0); _sc_card_add_rsa_alg(card, 1024, flags, 0); _sc_card_add_rsa_alg(card, 2048, flags, 0); - flags = SC_ALGORITHM_GOST_CRYPT_PZ | SC_ALGORITHM_GOST_CRYPT_GAMM - | SC_ALGORITHM_GOST_CRYPT_GAMMOS; + memset(&info, 0, sizeof(info)); info.algorithm = SC_ALGORITHM_GOST; - info.flags = flags; + info.flags = SC_ALGORITHM_GOST_CRYPT_PZ | SC_ALGORITHM_GOST_CRYPT_GAMM + | SC_ALGORITHM_GOST_CRYPT_GAMMOS; info.key_length = 32; - if (_sc_card_add_algorithm(card, &info) < 0) - return -1; - return ret; + _sc_card_add_algorithm(card, &info); + + SC_FUNC_RETURN(card->ctx, 3, SC_SUCCESS); +} + +static int rutoken_init(sc_card_t *card) +{ + int ret; + + SC_FUNC_CALLED(card->ctx, 1); + ret = token_init(card, "Rutoken card"); + SC_FUNC_RETURN(card->ctx, 1, ret); } static const struct sc_card_error rutoken_errors[] = { - { 0x6300, SC_ERROR_PIN_CODE_INCORRECT,"authentication failed"}, - { 0x63C1, SC_ERROR_PIN_CODE_INCORRECT,"authentication failed"}, - { 0x63C2, SC_ERROR_PIN_CODE_INCORRECT,"authentication failed"}, - { 0x63C3, SC_ERROR_PIN_CODE_INCORRECT,"authentication failed"}, - { 0x63C4, SC_ERROR_PIN_CODE_INCORRECT,"authentication failed"}, - { 0x63C5, SC_ERROR_PIN_CODE_INCORRECT,"authentication failed"}, - { 0x63C6, SC_ERROR_PIN_CODE_INCORRECT,"authentication failed"}, - { 0x63C7, SC_ERROR_PIN_CODE_INCORRECT,"authentication failed"}, - { 0x63C8, SC_ERROR_PIN_CODE_INCORRECT,"authentication failed"}, - { 0x63C9, SC_ERROR_PIN_CODE_INCORRECT,"authentication failed"}, - { 0x63Ca, SC_ERROR_PIN_CODE_INCORRECT,"authentication failed"}, - { 0x63Cb, SC_ERROR_PIN_CODE_INCORRECT,"authentication failed"}, - { 0x63Cc, SC_ERROR_PIN_CODE_INCORRECT,"authentication failed"}, - { 0x63Cd, SC_ERROR_PIN_CODE_INCORRECT,"authentication failed"}, - { 0x63Ce, SC_ERROR_PIN_CODE_INCORRECT,"authentication failed"}, - { 0x63Cf, SC_ERROR_PIN_CODE_INCORRECT,"authentication failed"}, + { 0x6300, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"}, + { 0x63C1, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed. One tries left"}, + { 0x63C2, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed. Two tries left"}, + { 0x63C3, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"}, + { 0x63C4, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"}, + { 0x63C5, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"}, + { 0x63C6, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"}, + { 0x63C7, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"}, + { 0x63C8, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"}, + { 0x63C9, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"}, + { 0x63CA, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"}, + { 0x63CB, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"}, + { 0x63CC, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"}, + { 0x63CD, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"}, + { 0x63CE, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"}, + { 0x63CF, SC_ERROR_PIN_CODE_INCORRECT, "Authentication failed"}, - { 0x6400, SC_ERROR_CARD_CMD_FAILED,"Aborting"}, + { 0x6400, SC_ERROR_CARD_CMD_FAILED, "Aborting"}, - { 0x6500, SC_ERROR_MEMORY_FAILURE, "Memory failure"}, - { 0x6581, SC_ERROR_MEMORY_FAILURE, "Memory failure"}, + { 0x6500, SC_ERROR_MEMORY_FAILURE, "Memory failure"}, + { 0x6581, SC_ERROR_MEMORY_FAILURE, "Memory failure"}, - { 0x6700, SC_ERROR_WRONG_LENGTH, "Lc or Le invalid"}, + { 0x6700, SC_ERROR_WRONG_LENGTH, "Lc or Le invalid"}, - { 0x6883, SC_ERROR_CARD_CMD_FAILED, "The finishing command of a chain is expected"}, + { 0x6883, SC_ERROR_CARD_CMD_FAILED, "The finishing command of a chain is expected"}, - { 0x6982, SC_ERROR_SECURITY_STATUS_NOT_SATISFIED,"required access right not granted"}, - { 0x6983, SC_ERROR_AUTH_METHOD_BLOCKED, "bs object blocked"}, - { 0x6985, SC_ERROR_CARD_CMD_FAILED, "command not allowed (unsuitable conditions)"}, - { 0x6986, SC_ERROR_INCORRECT_PARAMETERS,"no current ef selected"}, + { 0x6982, SC_ERROR_SECURITY_STATUS_NOT_SATISFIED, "Required access right not granted"}, + { 0x6983, SC_ERROR_AUTH_METHOD_BLOCKED, "DO blocked"}, + { 0x6985, SC_ERROR_CARD_CMD_FAILED, "Command not allowed (unsuitable conditions)"}, + { 0x6986, SC_ERROR_INCORRECT_PARAMETERS,"No current EF selected"}, - { 0x6a80, SC_ERROR_INCORRECT_PARAMETERS,"invalid parameters in data field"}, - { 0x6a81, SC_ERROR_NOT_SUPPORTED, "function/mode not supported"}, - { 0x6a82, SC_ERROR_FILE_NOT_FOUND, "file (DO) not found"}, - { 0x6a84, SC_ERROR_CARD_CMD_FAILED, "not enough memory"}, - { 0x6a86, SC_ERROR_INCORRECT_PARAMETERS,"p1/p2 invalid"}, - { 0x6a89, SC_ERROR_FILE_ALREADY_EXISTS,"file (DO) already exists"}, + { 0x6A80, SC_ERROR_INCORRECT_PARAMETERS,"Invalid parameters in data field"}, + { 0x6A81, SC_ERROR_NOT_SUPPORTED, "Function/mode not supported"}, + { 0x6A82, SC_ERROR_FILE_NOT_FOUND, "File (DO) not found"}, + { 0x6A84, SC_ERROR_CARD_CMD_FAILED, "Not enough memory space in the token"}, + { 0x6A86, SC_ERROR_INCORRECT_PARAMETERS,"P1 or P2 invalid"}, + { 0x6A89, SC_ERROR_FILE_ALREADY_EXISTS, "File (DO) already exists"}, - { 0x6b00, SC_ERROR_INCORRECT_PARAMETERS,"Out of file length"}, + { 0x6B00, SC_ERROR_INCORRECT_PARAMETERS,"Out of maximum file length"}, - { 0x6c00, SC_ERROR_WRONG_LENGTH, "le does not fit the data to be sent"}, + { 0x6C00, SC_ERROR_WRONG_LENGTH, "Le does not fit the data to be sent"}, - { 0x6d00, SC_ERROR_INS_NOT_SUPPORTED, "ins invalid (not supported)"}, + { 0x6D00, SC_ERROR_INS_NOT_SUPPORTED, "Ins invalid (not supported)"}, /* Own class of an error*/ - { 0x6f01, SC_ERROR_CARD_CMD_FAILED, "ruToken has the exchange protocol which is not supported by the USB-driver (newer, than in the driver)"}, - { 0x6f83, SC_ERROR_CARD_CMD_FAILED, "Infringement of the exchange protocol with ruToken is revealed"}, - { 0x6f84, SC_ERROR_CARD_CMD_FAILED, "ruToken is busy by processing of other command"}, - { 0x6f85, SC_ERROR_CARD_CMD_FAILED, "In the current folder the maximum quantity of file system objects is already created."}, - { 0x6f86, SC_ERROR_CARD_CMD_FAILED, "The token works not with access rights 'Visitor'"}, + { 0x6F01, SC_ERROR_CARD_CMD_FAILED, "Rutoken has the exchange protocol which is not supported by the USB-driver (newer, than in the driver)"}, + { 0x6F83, SC_ERROR_CARD_CMD_FAILED, "Infringement of the exchange protocol with Rutoken is revealed"}, + { 0x6F84, SC_ERROR_CARD_CMD_FAILED, "Rutoken is busy by processing of other command"}, + { 0x6F85, SC_ERROR_CARD_CMD_FAILED, "In the current folder the maximum quantity of file system objects is already created"}, + { 0x6F86, SC_ERROR_CARD_CMD_FAILED, "Invalid access right. Already login"}, - { 0x9000, SC_NO_ERROR, NULL} + { 0x9000, SC_NO_ERROR, NULL} }; -int rutoken_check_sw(sc_card_t *card, unsigned int sw1, unsigned int sw2) +static int rutoken_check_sw(sc_card_t *card, unsigned int sw1, unsigned int sw2) { - const int err_count = sizeof(rutoken_errors)/sizeof(rutoken_errors[0]); - int i; + size_t i; - sc_debug(card->ctx, "sw1 = %x, sw2 = %x", sw1, sw2); - - for (i = 0; i < err_count; i++) { + for (i = 0; i < sizeof(rutoken_errors)/sizeof(rutoken_errors[0]); ++i) { if (rutoken_errors[i].SWs == ((sw1 << 8) | sw2)) { if ( rutoken_errors[i].errorstr ) - sc_debug(card->ctx, rutoken_errors[i].errorstr); - /*SC_FUNC_RETURN(card->ctx, 1, rutoken_errors[i].errorno);*/ + sc_error(card->ctx, "%s\n", rutoken_errors[i].errorstr); + sc_debug(card->ctx, "sw1 = %x, sw2 = %x", sw1, sw2); return rutoken_errors[i].errorno; } } - - sc_error(card->ctx, "Unknown SWs; SW1=%02X, SW2=%02X\n", sw1, sw2); - SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_CARD_CMD_FAILED); + sc_error(card->ctx, "Unknown SWs; SW1=%02X, SW2=%02X\n", sw1, sw2); + return SC_ERROR_CARD_CMD_FAILED; } static int rutoken_dir_up(sc_card_t *card) { - u8 rbuf[256]; - int r = 0; - sc_apdu_t apdu; - SC_FUNC_CALLED(card->ctx, 1); - /*sc_debug(card->ctx, "\n\tpath = %s\n\ttype = %d", hexdump(path, pathlen), in_path->type); - prepare & transmit APDU - 00 a4 00 04 20 - first*/ - sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xA4, 0x03, 0x00); - apdu.cla = 0x00; - apdu.resplen = 256; - apdu.resp = rbuf; - apdu.le = 256; - r = sc_transmit_apdu(card, &apdu); - SC_TEST_RET(card->ctx, r, "APDU transmit failed"); - sc_debug(card->ctx, "rbuf = %s len %d", hexdump(apdu.resp, apdu.resplen), apdu.resplen); - sc_debug(card->ctx, "sw1 = %x, sw2 = %x", apdu.sw1, apdu.sw2); - return 0; -} + u8 rbuf[256]; + sc_apdu_t apdu; + int ret; -/* make little endian path from normal path. - return 1 if right len, otherwise 0 */ -static int make_le_path(u8 *hPath, size_t len) -{ -#ifdef BIG_ENDIAN_RUTOKEN - /* we don't need it any more */ - return 1; -#else - int i, ret = (len > 1) && !(len & 1); /* && (len <= SC_MAX_PATH_SIZE); */ - if (ret) - { - for(i = 0; i < len; i += 2) - { - u8 b = hPath[i]; - hPath[i] = hPath[i+1]; - hPath[i+1] = b; - } - } - return ret; -#endif + SC_FUNC_CALLED(card->ctx, 3); + + sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xA4, 0x03, 0x00); + apdu.cla = 0x00; + apdu.resplen = sizeof(rbuf); + apdu.resp = rbuf; + apdu.le = sizeof(rbuf); + + ret = sc_transmit_apdu(card, &apdu); + SC_TEST_RET(card->ctx, ret, "APDU transmit failed"); + ret = sc_check_sw(card, apdu.sw1, apdu.sw2); + SC_FUNC_RETURN(card->ctx, 3, ret); } static int rutoken_list_files(sc_card_t *card, u8 *buf, size_t buflen) { u8 rbuf[256]; u8 previd[2]; - int r = 0, len=0; sc_apdu_t apdu; + size_t len = 0; + int ret, first = 1; SC_FUNC_CALLED(card->ctx, 1); - /* sc_debug(card->ctx, "\n\tpath = %s\n\ttype = %d", hexdump(path, pathlen), in_path->type); */ - /* prepare & transmit APDU */ - /* 00 a4 00 04 20 - first */ - - sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xA4, 0x00, 0x00); - apdu.cla = 0x00; - apdu.resplen = 256; - apdu.resp = rbuf; - apdu.le = 256; - r = sc_transmit_apdu(card, &apdu); - SC_TEST_RET(card->ctx, r, "APDU transmit failed"); - sc_debug(card->ctx, "rbuf = %s len %d", hexdump(apdu.resp, apdu.resplen), apdu.resplen); - sc_debug(card->ctx, "sw1 = %x, sw2 = %x", apdu.sw1, apdu.sw2); - if((apdu.sw1 == 0x6a) ) + while (1) { - /* empty dir */ - return 0; - } - /* todo: add check buflen */ - /* save first file(dir) ID */ - memcpy(buf+len, rbuf+6, 2); - memcpy(previd, rbuf+6, 2); - len += 2; - if(rbuf[4] == FDESCR_DF) - rutoken_dir_up(card); - - /* 00 a4 00 02 02 prev id - next */ - while(1) - { - sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0x00, 0x06); - apdu.cla = 0x00; - apdu.lc = 2; - apdu.data = previd; - apdu.datalen = 2; - apdu.resplen = 256; - apdu.resp = rbuf; - apdu.le = 256; - r = sc_transmit_apdu(card, &apdu); - SC_TEST_RET(card->ctx, r, "APDU transmit failed"); - sc_debug(card->ctx, "rbuf = %s len %d", hexdump(apdu.resp, apdu.resplen), apdu.resplen); - sc_debug(card->ctx, "sw1 = %x, sw2 = %x", apdu.sw1, apdu.sw2); - if((apdu.sw1 == 0x6a) ) - { - /* end list */ - break; - } - /* todo: add check buflen */ - /* save first file(dir) ID */ - memcpy(buf+len, rbuf+6, 2); - memcpy(previd, rbuf+6, 2); - len += 2; - if(rbuf[4] == FDESCR_DF) + if (first) + sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xA4, 0x00, 0x00); + else + { + /* 00 a4 00 02 02 prev id - next */ + sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0x00, 0x02); + apdu.lc = sizeof(previd); + apdu.data = previd; + apdu.datalen = sizeof(previd); + } + apdu.cla = 0x00; + apdu.resplen = sizeof(rbuf); + apdu.resp = rbuf; + apdu.le = sizeof(rbuf); + ret = sc_transmit_apdu(card, &apdu); + SC_TEST_RET(card->ctx, ret, "APDU transmit failed"); + + if (apdu.sw1 == 0x6A && apdu.sw2 == 0x82) + break; /* if (first) "end list" else "empty dir" */ + + ret = sc_check_sw(card, apdu.sw1, apdu.sw2); + SC_TEST_RET(card->ctx, ret, "Get list files failed"); + + /* save first file(dir) ID */ + if (len + 2 <= buflen) + { + buf[len++] = rbuf[6]; + buf[len++] = rbuf[7]; + } + memcpy(previd, rbuf+6, sizeof(previd)); + if (rbuf[4] == FDESCR_DF) rutoken_dir_up(card); + first = 0; } - make_le_path(buf, len); - return len; + SC_FUNC_RETURN(card->ctx, 1, len); } static void rutoken_process_fcp(sc_card_t *card, u8 *pIn, sc_file_t *file) { -#ifdef BIG_ENDIAN_RUTOKEN file->size = pIn[3] + ((uint16_t)pIn[2])*256; file->id = pIn[7] + ((uint16_t)pIn[6])*256; -#else - file->size = pIn[2] + ((uint16_t)pIn[3])*256; - file->id = pIn[6] + ((uint16_t)pIn[7])*256; -#endif if (pIn[4] == FDESCR_DF) { @@ -366,65 +307,124 @@ static void rutoken_process_fcp(sc_card_t *card, u8 *pIn, sc_file_t *file) file->ef_structure = SC_FILE_EF_TRANSPARENT; } sc_file_set_sec_attr(file, pIn + 17, SEC_ATTR_SIZE); + + if (file->sec_attr && file->sec_attr_len == SEC_ATTR_SIZE +#ifndef SET_ACL_FOR_EF_LENLESS8_RUTOKEN +/* + * No set ACL for EF: + * PrKDF_path: "3F00FF000001" - SC_PKCS15_PRKDF + * PuKDF_path: "3F00FF000002" - SC_PKCS15_PUKDF + * CDF_path: "3F00FF000003" - SC_PKCS15_CDF + * DODF_path: "3F00FF000004" - SC_PKCS15_DODF + * (see files: src/libopensc/pkcs15-rutoken.c, src/pkcs15init/rutoken.profile) + */ + && (file->type != SC_FILE_TYPE_WORKING_EF || file->path.len >= 8) +#endif + ) + { + sc_file_add_acl_entry(file, SC_AC_OP_SELECT, + SC_AC_NONE, SC_AC_KEY_REF_NONE); + if (file->sec_attr[0] & 0x40) /* if AccessMode.6 */ + { + sc_debug(card->ctx, "SC_AC_OP_DELETE %i %i", + (int)(*(int8_t*)&file->sec_attr[1 +6]), + file->sec_attr[1+7 +6]); + sc_file_add_acl_entry(file, SC_AC_OP_DELETE, + (int)(*(int8_t*)&file->sec_attr[1 +6]), + file->sec_attr[1+7 +6]); + } + if (file->sec_attr[0] & 0x01) /* if AccessMode.0 */ + { + sc_debug(card->ctx, (file->type == SC_FILE_TYPE_DF) ? + "SC_AC_OP_CREATE %i %i" : "SC_AC_OP_READ %i %i", + (int)(*(int8_t*)&file->sec_attr[1 +0]), + file->sec_attr[1+7 +0]); + sc_file_add_acl_entry(file, + (file->type == SC_FILE_TYPE_DF) ? + SC_AC_OP_CREATE : SC_AC_OP_READ, + (int)(*(int8_t*)&file->sec_attr[1 +0]), + file->sec_attr[1+7 +0]); + } + if (file->type == SC_FILE_TYPE_DF) + { + sc_file_add_acl_entry(file, SC_AC_OP_LIST_FILES, + SC_AC_NONE, SC_AC_KEY_REF_NONE); + } + else + if (file->sec_attr[0] & 0x02) /* if AccessMode.1 */ + { + sc_debug(card->ctx, "SC_AC_OP_UPDATE %i %i", + (int)(*(int8_t*)&file->sec_attr[1 +1]), + file->sec_attr[1+7 +1]); + sc_file_add_acl_entry(file, SC_AC_OP_UPDATE, + (int)(*(int8_t*)&file->sec_attr[1 +1]), + file->sec_attr[1+7 +1]); + sc_debug(card->ctx, "SC_AC_OP_WRITE %i %i", + (int)(*(int8_t*)&file->sec_attr[1 +1]), + file->sec_attr[1+7 +1]); + sc_file_add_acl_entry(file, SC_AC_OP_WRITE, + (int)(*(int8_t*)&file->sec_attr[1 +1]), + file->sec_attr[1+7 +1]); + } + } } static int rutoken_select_file(sc_card_t *card, - const sc_path_t *in_path, - sc_file_t **file) + const sc_path_t *in_path, sc_file_t **file) { - int ret = SC_ERROR_INVALID_ARGUMENTS; + int ret; u8 pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf; - int pathlen = in_path->len; + int pathlen; u8 buf[SC_MAX_APDU_BUFFER_SIZE]; sc_apdu_t apdu; SC_FUNC_CALLED(card->ctx, 1); + if (!in_path || in_path->len < 2) + SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INVALID_ARGUMENTS); + pathlen = in_path->len; memcpy(path, in_path->value, pathlen); - sc_debug(card->ctx, "\n\tpath = %s\n\ttype = %d", hexdump(path, pathlen), in_path->type); - /* prepare & transmit APDU */ - if (make_le_path(path, pathlen)) + sc_debug(card->ctx, "\n\tpath = %s\n\ttype = %d", + hexdump(path, pathlen), in_path->type); + + ret = SC_ERROR_INVALID_ARGUMENTS; + sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0, 0); + switch (in_path->type) { - sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0, 0); - - switch (in_path->type) + case SC_PATH_TYPE_FILE_ID: + if (pathlen == 2) /* select file in current df */ { - case SC_PATH_TYPE_FILE_ID: - if (pathlen == 2) /* select file in current df */ - { - apdu.p1 = 2; - ret = SC_SUCCESS; - } - break; - case SC_PATH_TYPE_PATH: - apdu.p1 = 8; - if (memcmp(path, MF_PATH, 2) == 0) - { - if (pathlen == 2) /* select MF */ - { - apdu.p1 = 0; - } - else /* select DF */ - { - path += 2; - pathlen -= 2; - } - } + apdu.p1 = 2; ret = SC_SUCCESS; - break; - default: - ret = SC_ERROR_NOT_SUPPORTED; - break; } + break; + case SC_PATH_TYPE_PATH: + apdu.p1 = 8; + if (path[0] == 0x3F && path[1] == 0x00) + { + if (pathlen == 2) /* select MF */ + { + apdu.p1 = 0; + } + else /* select DF */ + { + path += 2; + pathlen -= 2; + } + } + ret = SC_SUCCESS; + break; + default: + ret = SC_ERROR_NOT_SUPPORTED; + break; } if (ret == SC_SUCCESS) { - ret = SC_ERROR_CARD_CMD_FAILED; apdu.lc = pathlen; apdu.data = path; apdu.datalen = pathlen; - + if (file != NULL) { apdu.resp = buf; apdu.resplen = sizeof(buf); @@ -434,107 +434,85 @@ static int rutoken_select_file(sc_card_t *card, apdu.le = 0; apdu.cse = SC_APDU_CASE_3_SHORT; } - if(sc_transmit_apdu(card, &apdu) >= 0) - ret = rutoken_check_sw(card, apdu.sw1, apdu.sw2); + ret = sc_transmit_apdu(card, &apdu); + SC_TEST_RET(card->ctx, ret, "APDU transmit failed"); + ret = sc_check_sw(card, apdu.sw1, apdu.sw2); - sc_debug(card->ctx, "file = %x", file); - if (file == NULL) + if (file == NULL) { /* We don't need file info */ - if (apdu.sw1 == 0x61) + if (apdu.sw1 == 0x61) SC_FUNC_RETURN(card->ctx, 2, SC_NO_ERROR); - SC_FUNC_RETURN(card->ctx, 2, ret); + SC_FUNC_RETURN(card->ctx, 1, ret); + } + /* New file structure */ + if ((ret == SC_SUCCESS) && (apdu.resplen == 32)) + { + *file = sc_file_new(); + if (*file == NULL) + SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_OUT_OF_MEMORY); + (*file)->path = *in_path; + /* what about selecting EF by ID (SC_PATH_TYPE_FILE_ID)? */ + + rutoken_process_fcp(card, buf, *file); + + sc_debug(card->ctx, + "nfile ID = %04X, path = %s, type = %02X, len = %d", + (*file)->id, hexdump((*file)->path.value, (*file)->path.len), + (*file)->type, (*file)->size); + sc_debug(card->ctx, "sec attr = %s", + hexdump((*file)->sec_attr, (*file)->sec_attr_len)); } } - /* New file structure */ - if ((ret == SC_SUCCESS) && (apdu.resplen == 32)) - { - /* sc_file_t *tmp_ */ - *file = sc_file_new(); - if (*file == NULL) - SC_FUNC_RETURN(card->ctx, 0, SC_ERROR_OUT_OF_MEMORY); - (*file)->path = *in_path; /* what about selecting EF by ID (SC_PATH_TYPE_FILE_ID)? */ - - rutoken_process_fcp(card, buf, *file); - /* *file = tmp_file; */ - - sc_debug(card->ctx, - "nfile ID = %04X, path = %s, type = %02X, len = %d", - (*file)->id, hexdump((*file)->path.value, (*file)->path.len), - (*file)->type, (*file)->size); - sc_debug(card->ctx, "sec attr = %s", - hexdump((*file)->sec_attr, (*file)->sec_attr_len)); - } - SC_FUNC_RETURN(card->ctx, 2, ret); + SC_FUNC_RETURN(card->ctx, 1, ret); } -/* -static int rutoken_set_file_attributes(sc_card_t *card, sc_file_t *file) -{ - int ret = SC_ERROR_NOT_SUPPORTED; - return ret; -} -*/ - static int rutoken_construct_fcp(sc_card_t *card, const sc_file_t *file, u8 *out) { - SC_FUNC_CALLED(card->ctx, 1); - + SC_FUNC_CALLED(card->ctx, 3); + if ((!file) || (file->id == ID_RESERVED_CURDF)) - SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INVALID_ARGUMENTS); + SC_FUNC_RETURN(card->ctx, 3, SC_ERROR_INVALID_ARGUMENTS); memset(out, 0, 32); switch (file->type) { case SC_FILE_TYPE_DF: out[4] = 0x38; -#ifdef BIG_ENDIAN_RUTOKEN out[0] = file->size / 256; out[1] = file->size % 256; -#else - out[1] = file->size / 256; - out[0] = file->size % 256; -#endif break; case SC_FILE_TYPE_WORKING_EF: out[4] = 0x01; /* set the length (write to wBodyLen) */ -#ifdef BIG_ENDIAN_RUTOKEN out[2] = file->size / 256; out[3] = file->size % 256; -#else - out[3] = file->size / 256; - out[2] = file->size % 256; -#endif break; case SC_FILE_TYPE_INTERNAL_EF: default: - SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_NOT_SUPPORTED); + SC_FUNC_RETURN(card->ctx, 3, SC_ERROR_NOT_SUPPORTED); } /* set file ID */ -#ifdef BIG_ENDIAN_RUTOKEN out[6] = file->id / 256; out[7] = file->id % 256; -#else - out[7] = file->id / 256; - out[6] = file->id % 256; -#endif + /* set sec_attr */ - if(file->sec_attr_len == SEC_ATTR_SIZE) + if (file->sec_attr_len == SEC_ATTR_SIZE) memcpy(out + 17, file->sec_attr, SEC_ATTR_SIZE); else memcpy(out + 17, &default_sec_attr, SEC_ATTR_SIZE); - - SC_FUNC_RETURN(card->ctx, 1, SC_NO_ERROR); + + SC_FUNC_RETURN(card->ctx, 3, SC_NO_ERROR); } static int rutoken_create_file(sc_card_t *card, sc_file_t *file) { - int ret = SC_ERROR_CARD_CMD_FAILED; + int ret; sc_apdu_t apdu; - u8 sbuf[32]; + u8 sbuf[32] = { 0 }; + SC_FUNC_CALLED(card->ctx, 1); - memset(sbuf, 0, 32); - if((ret = rutoken_construct_fcp(card, file, sbuf)) == SC_NO_ERROR) + ret = rutoken_construct_fcp(card, file, sbuf); + if (ret == SC_NO_ERROR) { sc_debug(card->ctx, "fcp = %s", hexdump(sbuf, 32)); sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE0, 0x00, 0x00); @@ -542,8 +520,9 @@ static int rutoken_create_file(sc_card_t *card, sc_file_t *file) apdu.datalen = 32; apdu.lc = 32; - if(sc_transmit_apdu(card, &apdu) >= 0) - ret = rutoken_check_sw(card, apdu.sw1, apdu.sw2); + ret = sc_transmit_apdu(card, &apdu); + SC_TEST_RET(card->ctx, ret, "APDU transmit failed"); + ret = sc_check_sw(card, apdu.sw1, apdu.sw2); } SC_FUNC_RETURN(card->ctx, 1, ret); } @@ -552,60 +531,64 @@ static int rutoken_delete_file(sc_card_t *card, const sc_path_t *path) { u8 sbuf[2]; sc_apdu_t apdu; - + SC_FUNC_CALLED(card->ctx, 1); if (!path || path->type != SC_PATH_TYPE_FILE_ID || (path->len != 0 && path->len != 2)) { sc_error(card->ctx, "File type has to be SC_PATH_TYPE_FILE_ID\n"); SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INVALID_ARGUMENTS); } - if (path->len == 2) + if (path->len == sizeof(sbuf)) { -#ifdef BIG_ENDIAN_RUTOKEN sbuf[0] = path->value[0]; sbuf[1] = path->value[1]; -#else - sbuf[0] = path->value[1]; - sbuf[1] = path->value[0]; -#endif sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE4, 0x00, 0x00); - apdu.lc = 2; - apdu.datalen = 2; + apdu.lc = sizeof(sbuf); + apdu.datalen = sizeof(sbuf); apdu.data = sbuf; } else /* No file ID given: means currently selected file */ sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0xE4, 0x00, 0x00); - SC_TEST_RET(card->ctx, sc_transmit_apdu(card, &apdu), "APDU transmit failed"); - SC_FUNC_RETURN(card->ctx, 1, rutoken_check_sw(card, apdu.sw1, apdu.sw2)); + SC_FUNC_RETURN(card->ctx, 1, sc_check_sw(card, apdu.sw1, apdu.sw2)); } static int rutoken_verify(sc_card_t *card, unsigned int type, int ref_qualifier, const u8 *data, size_t data_len, int *tries_left) { - int ret = SC_ERROR_CARD_CMD_FAILED; sc_apdu_t apdu; + int ret; SC_FUNC_CALLED(card->ctx, 1); + sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x20, 0x00, ref_qualifier); + ret = sc_transmit_apdu(card, &apdu); + if (ret == SC_SUCCESS && apdu.sw1 == 0x90 && apdu.sw2 == 0x00) + { + /* already login */ + /* RESET ACCESS RIGHTS */ + sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x40, 0x00, 0x00); + apdu.cla = 0x80; + ret = sc_transmit_apdu(card, &apdu); + SC_TEST_RET(card->ctx, ret, "APDU transmit failed"); + ret = sc_check_sw(card, apdu.sw1, apdu.sw2); + SC_TEST_RET(card->ctx, ret, "Reset access rights failed"); + } + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x20, 0x00, ref_qualifier); apdu.lc = data_len; apdu.datalen = data_len; apdu.data = data; - if(sc_transmit_apdu(card, &apdu) >= 0) + ret = sc_transmit_apdu(card, &apdu); + SC_TEST_RET(card->ctx, ret, "APDU transmit failed"); + ret = sc_check_sw(card, apdu.sw1, apdu.sw2); + if (ret == SC_ERROR_PIN_CODE_INCORRECT && tries_left) { - ret = rutoken_check_sw(card, apdu.sw1, apdu.sw2); - if(ret == SC_ERROR_PIN_CODE_INCORRECT && tries_left) - { - sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x20, 0x00, - ref_qualifier); - ret = sc_transmit_apdu(card, &apdu); - if(ret >= 0) - { - ret = rutoken_check_sw(card, apdu.sw1, apdu.sw2); - if(ret == SC_ERROR_PIN_CODE_INCORRECT) - *tries_left = (int)(apdu.sw2 & 0x0f); - } - } + sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x20, 0x00, ref_qualifier); + ret = sc_transmit_apdu(card, &apdu); + SC_TEST_RET(card->ctx, ret, "APDU transmit failed"); + ret = sc_check_sw(card, apdu.sw1, apdu.sw2); + if (ret == SC_ERROR_PIN_CODE_INCORRECT) + *tries_left = (int)(apdu.sw2 & 0x0f); } SC_FUNC_RETURN(card->ctx, 1, ret); } @@ -613,18 +596,19 @@ static int rutoken_verify(sc_card_t *card, unsigned int type, int ref_qualifier, static int rutoken_logout(sc_card_t *card) { sc_apdu_t apdu; - int ret = SC_ERROR_CARD_CMD_FAILED; sc_path_t path; + int ret; SC_FUNC_CALLED(card->ctx, 1); sc_format_path("3F00", &path); - if (rutoken_select_file(card, &path, NULL) == SC_SUCCESS) - { - sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x40, 0x00, 0x00); - apdu.cla = 0x80; - if(sc_transmit_apdu(card, &apdu) >= 0) - ret = rutoken_check_sw(card, apdu.sw1, apdu.sw2); - } + ret = rutoken_select_file(card, &path, NULL); + SC_TEST_RET(card->ctx, ret, "Select MF failed"); + + sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x40, 0x00, 0x00); + apdu.cla = 0x80; + ret = sc_transmit_apdu(card, &apdu); + SC_TEST_RET(card->ctx, ret, "APDU transmit failed"); + ret = sc_check_sw(card, apdu.sw1, apdu.sw2); SC_FUNC_RETURN(card->ctx, 1, ret); } @@ -632,32 +616,22 @@ static int rutoken_change_reference_data(sc_card_t *card, unsigned int type, int ref_qualifier, const u8 *old, size_t oldlen, const u8 *newref, size_t newlen, int *tries_left) { - int left; - int ret = SC_ERROR_CARD_CMD_FAILED; sc_apdu_t apdu; + int ret; SC_FUNC_CALLED(card->ctx, 1); - - if(old && oldlen) + if (old && oldlen) { - sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x20, 0x00, ref_qualifier); - if(sc_transmit_apdu(card, &apdu) >= 0 - && apdu.sw1 != 0x90 && apdu.sw2 != 0x00) - { - rutoken_logout(card); - rutoken_verify(card, type, ref_qualifier, old, oldlen, &left); - } + ret = rutoken_verify(card, type, ref_qualifier, old, oldlen, tries_left); + SC_TEST_RET(card->ctx, ret, "Invalid 'old' pass"); } sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x24, 0x01, ref_qualifier); apdu.lc = newlen; apdu.datalen = newlen; apdu.data = newref; - if(sc_transmit_apdu(card, &apdu) >= 0) - { - ret = rutoken_check_sw(card, apdu.sw1, apdu.sw2); - if(ret == SC_ERROR_PIN_CODE_INCORRECT && tries_left) - *tries_left = (int)(apdu.sw2 & 0x0f); - } + ret = sc_transmit_apdu(card, &apdu); + SC_TEST_RET(card->ctx, ret, "APDU transmit failed"); + ret = sc_check_sw(card, apdu.sw1, apdu.sw2); SC_FUNC_RETURN(card->ctx, 1, ret); } @@ -668,111 +642,97 @@ static int rutoken_reset_retry_counter(sc_card_t *card, unsigned int type, #ifdef FORCE_VERIFY_RUTOKEN int left; #endif - int ret = SC_ERROR_CARD_CMD_FAILED; sc_apdu_t apdu; + int ret; SC_FUNC_CALLED(card->ctx, 1); #ifdef FORCE_VERIFY_RUTOKEN - if(puk && puklen) + if (puk && puklen) { - sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x20, 0x00, ref_qualifier); - if(sc_transmit_apdu(card, &apdu) >= 0 - && apdu.sw1 != 0x90 && apdu.sw2 != 0x00) - { - rutoken_logout(card); - rutoken_verify(card, type, ref_qualifier, puk, puklen, &left); - } + ret = rutoken_verify(card, type, ref_qualifier, puk, puklen, &left); + sc_error(card->ctx, "Tries left: %i\n", left); + SC_TEST_RET(card->ctx, ret, "Invalid 'puk' pass"); } #endif sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x2c, 0x03, ref_qualifier); - if(sc_transmit_apdu(card, &apdu) >= 0) - ret = rutoken_check_sw(card, apdu.sw1, apdu.sw2); + ret = sc_transmit_apdu(card, &apdu); + SC_TEST_RET(card->ctx, ret, "APDU transmit failed"); + ret = sc_check_sw(card, apdu.sw1, apdu.sw2); SC_FUNC_RETURN(card->ctx, 1, ret); } static int rutoken_restore_security_env(sc_card_t *card, int se_num) { - int ret = SC_ERROR_CARD_CMD_FAILED; sc_apdu_t apdu; + int ret; SC_FUNC_CALLED(card->ctx, 1); sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x22, 3, se_num); - if(sc_transmit_apdu(card, &apdu) >= 0) - ret = rutoken_check_sw(card, apdu.sw1, apdu.sw2); + ret = sc_transmit_apdu(card, &apdu); + SC_TEST_RET(card->ctx, ret, "APDU transmit failed"); + ret = sc_check_sw(card, apdu.sw1, apdu.sw2); SC_FUNC_RETURN(card->ctx, 1, ret); } static int rutoken_set_security_env(sc_card_t *card, - const sc_security_env_t *env, - int se_num) + const sc_security_env_t *env, + int se_num) { sc_apdu_t apdu; - auth_senv_t *senv = (auth_senv_t*)card->drv_data; - u8 data[3] = {0x83, 0x01, env->key_ref[0]}; - int ret = SC_NO_ERROR; + auth_senv_t *senv; + u8 data[3] = { 0x83, 0x01 }; + int ret; SC_FUNC_CALLED(card->ctx, 1); - if (!senv || !env) return SC_ERROR_INVALID_ARGUMENTS; - if(env->algorithm == SC_ALGORITHM_RSA) + if (!env) + SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INVALID_ARGUMENTS); + senv = (auth_senv_t*)card->drv_data; + if (!senv) + SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INTERNAL); + if (env->algorithm == SC_ALGORITHM_RSA) { senv->algorithm = SC_ALGORITHM_RSA_RAW; - return ret; + SC_FUNC_RETURN(card->ctx, 1, SC_SUCCESS); } - else - senv->algorithm = SC_ALGORITHM_GOST; + senv->algorithm = SC_ALGORITHM_GOST; if (env->key_ref_len != 1) { sc_error(card->ctx, "No or invalid key reference\n"); - ret = SC_ERROR_INVALID_ARGUMENTS; + SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INVALID_ARGUMENTS); } - else + data[2] = env->key_ref[0]; /* select component */ + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 1, 0); + apdu.lc = apdu.datalen = sizeof(data); + apdu.data = data; + switch (env->operation) { - sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 1, 0); - apdu.lc = apdu.datalen = 3; - apdu.data = data; - switch (env->operation) - { - case SC_SEC_OPERATION_AUTHENTICATE: - { - apdu.p2 = 0xA4; - } + case SC_SEC_OPERATION_AUTHENTICATE: + apdu.p2 = 0xA4; break; - case SC_SEC_OPERATION_DECIPHER: - { - apdu.p2 = 0xB8; - } + case SC_SEC_OPERATION_DECIPHER: + apdu.p2 = 0xB8; break; - case SC_SEC_OPERATION_SIGN: - { - apdu.p2 = 0xAA; - } + case SC_SEC_OPERATION_SIGN: + apdu.p2 = 0xAA; break; - default: - ret = SC_ERROR_INVALID_ARGUMENTS; - } + default: + SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INVALID_ARGUMENTS); } /* set SE */ - if (ret == SC_NO_ERROR) - { - if(sc_transmit_apdu(card, &apdu) >= 0) - ret = rutoken_check_sw(card, apdu.sw1, apdu.sw2); - } + ret = sc_transmit_apdu(card, &apdu); + SC_TEST_RET(card->ctx, ret, "APDU transmit failed"); + ret = sc_check_sw(card, apdu.sw1, apdu.sw2); SC_FUNC_RETURN(card->ctx, 1, ret); } static void rutoken_set_do_hdr(u8 *data, sc_DOHdrV2_t *pHdr) { - if(data) + if (data) { -#ifdef BIG_ENDIAN_RUTOKEN data[0] = (u8)(pHdr->wDOBodyLen / 0x100); data[1] = (u8)(pHdr->wDOBodyLen % 0x100); -#else - data[0] = (u8)(pHdr->wDOBodyLen % 0x100); - data[1] = (u8)(pHdr->wDOBodyLen / 0x100); -#endif data[2] = (u8)(pHdr->OTID.byObjectType); data[3] = (u8)(pHdr->OTID.byObjectID); data[4] = (u8)(pHdr->OP.byObjectOptions); @@ -786,9 +746,11 @@ static void rutoken_set_do_hdr(u8 *data, sc_DOHdrV2_t *pHdr) static int rutoken_key_gen(sc_card_t *card, sc_DOHdrV2_t *pHdr) { - int ret = SC_ERROR_CARD_CMD_FAILED; u8 data[SC_RUTOKEN_DO_HDR_LEN]; - sc_apdu_t apdu; + sc_apdu_t apdu; + int ret; + + SC_FUNC_CALLED(card->ctx, 3); if ( (pHdr->wDOBodyLen != SC_RUTOKEN_DEF_LEN_DO_GOST) || (pHdr->OTID.byObjectType != SC_RUTOKEN_TYPE_KEY) || @@ -804,22 +766,23 @@ static int rutoken_key_gen(sc_card_t *card, sc_DOHdrV2_t *pHdr) { pHdr->OP.byObjectTry = 0; rutoken_set_do_hdr(data, pHdr); - sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xda, 0x01, 0x65); - apdu.data= data; + apdu.data = data; apdu.datalen = apdu.lc = sizeof(data); - - if(sc_transmit_apdu(card, &apdu) >= 0) - ret = rutoken_check_sw(card, apdu.sw1, apdu.sw2); + ret = sc_transmit_apdu(card, &apdu); + SC_TEST_RET(card->ctx, ret, "APDU transmit failed"); + ret = sc_check_sw(card, apdu.sw1, apdu.sw2); } - SC_FUNC_RETURN(card->ctx, 1, ret); + SC_FUNC_RETURN(card->ctx, 3, ret); } static int rutoken_create_do(sc_card_t *card, sc_DO_V2_t * pDO) { - int ret = SC_ERROR_CARD_CMD_FAILED; u8 data[SC_RUTOKEN_DO_HDR_LEN + SC_RUTOKEN_DO_PART_BODY_LEN]; - sc_apdu_t apdu; + sc_apdu_t apdu; + int ret; + + SC_FUNC_CALLED(card->ctx, 3); if ( ((pDO->HDR.OTID.byObjectType & SC_RUTOKEN_TYPE_CHV) && (pDO->HDR.OTID.byObjectID != SC_RUTOKEN_DEF_ID_GCHV_USER) && @@ -841,23 +804,23 @@ static int rutoken_create_do(sc_card_t *card, sc_DO_V2_t * pDO) { rutoken_set_do_hdr(data, &pDO->HDR); memcpy(data + SC_RUTOKEN_DO_HDR_LEN, pDO->abyDOBody, pDO->HDR.wDOBodyLen); - sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xda, 0x01, 0x62); - apdu.data= data; + apdu.data = data; apdu.datalen = apdu.lc = SC_RUTOKEN_DO_HDR_LEN + pDO->HDR.wDOBodyLen; - - if(sc_transmit_apdu(card, &apdu) >= 0) - ret = rutoken_check_sw(card, apdu.sw1, apdu.sw2); + ret = sc_transmit_apdu(card, &apdu); + SC_TEST_RET(card->ctx, ret, "APDU transmit failed"); + ret = sc_check_sw(card, apdu.sw1, apdu.sw2); } - SC_FUNC_RETURN(card->ctx, 1, ret); + SC_FUNC_RETURN(card->ctx, 3, ret); } static int rutoken_get_do_info(sc_card_t *card, sc_DO_INFO_t * pInfo) { - int ret = SC_ERROR_CARD_CMD_FAILED; - u8 data[1] = {pInfo->DoId}; - sc_apdu_t apdu; + u8 data[1]; + sc_apdu_t apdu; + int ret; + SC_FUNC_CALLED(card->ctx, 3); if ((pInfo->SelType != select_first) && ((pInfo->DoId < SC_RUTOKEN_DO_ALL_MIN_ID) || (pInfo->DoId > SC_RUTOKEN_DO_NOCHV_MAX_ID_V2))) @@ -872,37 +835,37 @@ static int rutoken_get_do_info(sc_card_t *card, sc_DO_INFO_t * pInfo) apdu.resplen = sizeof(pInfo->pDoData); apdu.le = 255; memset(apdu.resp, 0, apdu.resplen); - switch(pInfo->SelType) { case select_first: apdu.cse = SC_APDU_CASE_2_SHORT; break; - case select_by_id: - apdu.data = data; - apdu.datalen = apdu.lc = 1; - break; case select_next: apdu.p2 = 0x02; + case select_by_id: + data[0] = pInfo->DoId; apdu.data = data; - apdu.datalen = apdu.lc = 1; + apdu.datalen = sizeof(data); + apdu.lc = sizeof(data); break; default: - SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INVALID_ARGUMENTS); + SC_FUNC_RETURN(card->ctx, 3, SC_ERROR_INVALID_ARGUMENTS); break; } - if(sc_transmit_apdu(card, &apdu) >= 0) - ret = rutoken_check_sw(card, apdu.sw1, apdu.sw2); + ret = sc_transmit_apdu(card, &apdu); + SC_TEST_RET(card->ctx, ret, "APDU transmit failed"); + ret = sc_check_sw(card, apdu.sw1, apdu.sw2); } - return ret; + SC_FUNC_RETURN(card->ctx, 3, ret); } static int rutoken_delete_do(sc_card_t *card, u8 *pId) { - int ret = SC_ERROR_CARD_CMD_FAILED; - u8 data[1] = {*pId}; - sc_apdu_t apdu; - + u8 data[1]; + sc_apdu_t apdu; + int ret; + + SC_FUNC_CALLED(card->ctx, 3); if ((*pId < SC_RUTOKEN_DO_ALL_MIN_ID) || (*pId > SC_RUTOKEN_DO_NOCHV_MAX_ID_V2)) { @@ -911,60 +874,39 @@ static int rutoken_delete_do(sc_card_t *card, u8 *pId) else { sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xda, 0x01, 0x64); + data[0] = *pId; apdu.data = data; - apdu.datalen = apdu.lc = 1; - if(sc_transmit_apdu(card, &apdu) >= 0) - ret = rutoken_check_sw(card, apdu.sw1, apdu.sw2); + apdu.datalen = sizeof(data); + apdu.lc = sizeof(data); + ret = sc_transmit_apdu(card, &apdu); + SC_TEST_RET(card->ctx, ret, "APDU transmit failed"); + ret = sc_check_sw(card, apdu.sw1, apdu.sw2); } - SC_FUNC_RETURN(card->ctx, 1, ret); -} - -static int rutoken_get_serial(sc_card_t *card, sc_serial_number_t *pSerial) -{ - int ret = SC_ERROR_CARD_CMD_FAILED; - sc_apdu_t apdu; - - sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xca, 0x01, 0x81); - apdu.resp = pSerial->value; - apdu.le = 4; - apdu.resplen = sizeof(pSerial->value); - - if(sc_transmit_apdu(card, &apdu) >= 0) - { - pSerial->len = apdu.le; - ret = rutoken_check_sw(card, apdu.sw1, apdu.sw2); - } - - SC_FUNC_RETURN(card->ctx, 1, ret); + SC_FUNC_RETURN(card->ctx, 3, ret); } /* Both direction GOST cipher */ static int rutoken_cipher_p(sc_card_t *card, const u8 * crgram, size_t crgram_len, - u8 * out, size_t outlen, int p1, int p2, int isIV) + u8 * out, size_t outlen, int p1, int p2, int isIV) { - const size_t cipher_chunk = 248; /* cipher_chunk <= SC_MAX_APDU_BUFFER_SIZE */ + u8 buf[248]; /* 248 (cipher_chunk) <= SC_MAX_APDU_BUFFER_SIZE */ size_t len, outlen_tail = outlen; - u8 *buf; int ret; sc_apdu_t apdu; - - SC_FUNC_CALLED(card->ctx, 1); - sc_debug(card->ctx, ": crgram_len %i; outlen %i\n", crgram_len, outlen); + + SC_FUNC_CALLED(card->ctx, 3); + sc_debug(card->ctx, ": crgram_len %i; outlen %i", crgram_len, outlen); if (!out) - return SC_ERROR_INVALID_ARGUMENTS; + SC_FUNC_RETURN(card->ctx, 3, SC_ERROR_INVALID_ARGUMENTS); if (crgram_len < 16 || ((crgram_len) % 8)) - return SC_ERROR_WRONG_LENGTH; + SC_FUNC_RETURN(card->ctx, 3, SC_ERROR_WRONG_LENGTH); - buf = malloc(cipher_chunk); - if (!buf) - return SC_ERROR_OUT_OF_MEMORY; - sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, p1, p2); do { - len = (crgram_len > cipher_chunk) ? cipher_chunk : crgram_len; + len = (crgram_len > sizeof(buf)) ? sizeof(buf) : crgram_len; apdu.lc = len; apdu.datalen = len; apdu.data = crgram; @@ -975,11 +917,10 @@ static int rutoken_cipher_p(sc_card_t *card, const u8 * crgram, size_t crgram_le apdu.le = len; apdu.resplen = len; apdu.resp = buf; - - if (sc_transmit_apdu(card, &apdu) >= 0) - ret = rutoken_check_sw(card, apdu.sw1, apdu.sw2); - else - ret = SC_ERROR_CARD_CMD_FAILED; + + ret = sc_transmit_apdu(card, &apdu); + SC_TEST_RET(card->ctx, ret, "APDU transmit failed"); + ret = sc_check_sw(card, apdu.sw1, apdu.sw2); if (ret == SC_NO_ERROR) { if (isIV) @@ -998,24 +939,20 @@ static int rutoken_cipher_p(sc_card_t *card, const u8 * crgram, size_t crgram_le } } } while (ret == SC_NO_ERROR && crgram_len != 0); - - free(buf); - sc_debug(card->ctx, "len out cipher %d\n", outlen - outlen_tail); if (ret == SC_NO_ERROR) ret = (outlen_tail == 0) ? (int)outlen : SC_ERROR_WRONG_LENGTH; - - SC_FUNC_RETURN(card->ctx, 1, ret); + SC_FUNC_RETURN(card->ctx, 3, ret); } -/* Launcher for chipher */ +/* Launcher for cipher */ static int rutoken_cipher_gost(sc_card_t *card, - struct sc_rutoken_decipherinfo *ptr, char is_enchiper) + struct sc_rutoken_decipherinfo *ptr, char is_encipher) { int ret; - if (is_enchiper) + if (is_encipher) ret = rutoken_cipher_p(card, ptr->inbuf, ptr->inlen, ptr->outbuf, ptr->outlen, 0x86, 0x80, 0); else @@ -1041,10 +978,9 @@ static int rutoken_compute_mac_gost(sc_card_t *card, int ret; sc_apdu_t apdu; - SC_FUNC_CALLED(card->ctx, 1); - + SC_FUNC_CALLED(card->ctx, 3); if (!in || !out || olen != 4 || ilen == 0) - return SC_ERROR_INVALID_ARGUMENTS; + SC_FUNC_RETURN(card->ctx, 3, SC_ERROR_INVALID_ARGUMENTS); do { sc_format_apdu(card, &apdu, @@ -1058,39 +994,132 @@ static int rutoken_compute_mac_gost(sc_card_t *card, in += len; ilen -= len; if (ilen == 0) - { + { apdu.cla = 0x00; apdu.le = olen; apdu.resplen = olen; apdu.resp = out; - } - else - apdu.cla = 0x10; - if (sc_transmit_apdu(card, &apdu) >= 0) - ret = rutoken_check_sw(card, apdu.sw1, apdu.sw2); + } else - ret = SC_ERROR_CARD_CMD_FAILED; + apdu.cla = 0x10; + ret = sc_transmit_apdu(card, &apdu); + SC_TEST_RET(card->ctx, ret, "APDU transmit failed"); + ret = sc_check_sw(card, apdu.sw1, apdu.sw2); } while (ret == SC_NO_ERROR && ilen != 0); - - SC_FUNC_RETURN(card->ctx, 1, ret); + SC_FUNC_RETURN(card->ctx, 3, ret); } - + /* RSA emulation */ #ifdef ENABLE_OPENSSL +static int rutoken_get_prkey_from_bin(const u8 *data, size_t datalen, + struct sc_pkcs15_prkey **key) +{ + uint32_t bitlen; + size_t i, len; + struct sc_pkcs15_prkey_rsa *key_rsa; + + if (!data || !key || *key != NULL) + return -1; + + if (datalen < 14 + sizeof(uint32_t)) + return -1; + + /* Check header */ + if ( data[0] != 2 || data[1] != 1 + || data[2] != 0x07 /* Type */ + || data[3] != 0x02 /* Version */ + /* aiKeyAlg */ + || data[6] != 0 || data[7] != 0xA4 || data[8] != 0 || data[9] != 0 + /* magic "RSA2" */ + || data[10] != 0x52 || data[11] != 0x53 + || data[12] != 0x41 || data[13] != 0x32 + ) + return -1; + + len = 14; + /* bitlen */ + bitlen = 0; + for (i = 0; i < sizeof(uint32_t); ++i) + bitlen += (uint32_t)data[len++] << i*8; + + if (bitlen % 16) + return -1; + if (datalen - len < sizeof(uint32_t) + bitlen/8 * 2 + bitlen/16 * 5) + return -1; + + *key = calloc(1, sizeof(struct sc_pkcs15_prkey)); + if (!*key) + return -1; + key_rsa = &(*key)->u.rsa; + + key_rsa->exponent.data = malloc(sizeof(uint32_t)); + key_rsa->modulus.data = malloc(bitlen/8); + key_rsa->p.data = malloc(bitlen/16); + key_rsa->q.data = malloc(bitlen/16); + key_rsa->dmp1.data = malloc(bitlen/16); + key_rsa->dmq1.data = malloc(bitlen/16); + key_rsa->iqmp.data = malloc(bitlen/16); + key_rsa->d.data = malloc(bitlen/8); + if (!key_rsa->exponent.data || !key_rsa->modulus.data + || !key_rsa->p.data || !key_rsa->q.data + || !key_rsa->dmp1.data || !key_rsa->dmq1.data + || !key_rsa->iqmp.data || !key_rsa->d.data + ) + { + free(key_rsa->exponent.data); + free(key_rsa->modulus.data); + free(key_rsa->p.data); + free(key_rsa->q.data); + free(key_rsa->dmp1.data); + free(key_rsa->dmq1.data); + free(key_rsa->iqmp.data); + free(key_rsa->d.data); + memset(key_rsa, 0, sizeof(*key_rsa)); + + free(*key); + *key = NULL; + return -1; + } + +#define MEMCPY_KEYRSA_REVERSE_DATA(NAME, size) /* set key_rsa->NAME.len */ \ + do { \ + for (i = 0; i < (size); ++i) \ + if (data[len + (size) - 1 - i] != 0) \ + break; \ + for (; i < (size); ++i) \ + key_rsa->NAME.data[key_rsa->NAME.len++] = data[len + (size) - 1 - i]; \ + len += (size); \ + } while (0) + + MEMCPY_KEYRSA_REVERSE_DATA(exponent, sizeof(uint32_t)); /* pubexp */ + MEMCPY_KEYRSA_REVERSE_DATA(modulus, bitlen/8); /* modulus */ + MEMCPY_KEYRSA_REVERSE_DATA(p, bitlen/16); /* prime1 */ + MEMCPY_KEYRSA_REVERSE_DATA(q, bitlen/16); /* prime2 */ + MEMCPY_KEYRSA_REVERSE_DATA(dmp1, bitlen/16); /* exponent1 */ + MEMCPY_KEYRSA_REVERSE_DATA(dmq1, bitlen/16); /* exponent2 */ + MEMCPY_KEYRSA_REVERSE_DATA(iqmp, bitlen/16); /* coefficient */ + MEMCPY_KEYRSA_REVERSE_DATA(d, bitlen/8); /* privateExponent */ + + (*key)->algorithm = SC_ALGORITHM_RSA; + return 0; +} + static int rutoken_get_current_fileid(sc_card_t *card, u8 id[2]) { sc_apdu_t apdu; - int ret = SC_ERROR_CARD_CMD_FAILED; + int ret; + SC_FUNC_CALLED(card->ctx, 3); sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xca, 0x01, 0x11); apdu.resp = id; apdu.resplen = sizeof(id); apdu.le = 2; - if(sc_transmit_apdu(card, &apdu) >= 0) - ret = rutoken_check_sw(card, apdu.sw1, apdu.sw2); - SC_FUNC_RETURN(card->ctx, 1, ret); + ret = sc_transmit_apdu(card, &apdu); + SC_TEST_RET(card->ctx, ret, "APDU transmit failed"); + ret = sc_check_sw(card, apdu.sw1, apdu.sw2); + SC_FUNC_RETURN(card->ctx, 3, ret); } static int rutoken_read_prkey(sc_card_t *card, struct sc_pkcs15_prkey **out) @@ -1100,32 +1129,32 @@ static int rutoken_read_prkey(sc_card_t *card, struct sc_pkcs15_prkey **out) u8 *data; sc_path_t path; sc_file_t *file = NULL; - + r = sc_lock(card); - if(r != SC_SUCCESS) + if (r != SC_SUCCESS) return r; r = rutoken_get_current_fileid(card, id); - if(r == SC_SUCCESS) + if (r == SC_SUCCESS) { sc_path_set(&path, SC_PATH_TYPE_FILE_ID, id, sizeof(id), 0, -1); r = rutoken_select_file(card, &path, &file); } - if(r == SC_SUCCESS && file) + if (r == SC_SUCCESS && file) { data = malloc(file->size); - if(data == NULL) + if (data == NULL) r = SC_ERROR_OUT_OF_MEMORY; else { r = sc_read_binary(card, 0, data, file->size, 0); - if(r > 0 && (size_t)r == file->size) - r = sc_rutoken_get_prkey_from_bin(data, file->size, out); + if (r > 0 && (size_t)r == file->size) + r = rutoken_get_prkey_from_bin(data, file->size, out); memset(data, 0, file->size); free(data); } } - if(file) + if (file) sc_file_free(file); sc_unlock(card); return r; @@ -1135,26 +1164,24 @@ static int rutoken_read_prkey(sc_card_t *card, struct sc_pkcs15_prkey **out) static int extract_key(sc_card_t *card, EVP_PKEY **pk) { - struct sc_pkcs15_prkey *key = NULL; - int r; + struct sc_pkcs15_prkey *key = NULL; + int r; - SC_FUNC_CALLED(card->ctx, 1); + SC_FUNC_CALLED(card->ctx, 3); r = rutoken_read_prkey(card, &key); - if (r < 0) - return r; + SC_FUNC_RETURN(card->ctx, 3, r); - if((*pk = EVP_PKEY_new()) == NULL) + if ((*pk = EVP_PKEY_new()) == NULL) r = SC_ERROR_OUT_OF_MEMORY; else { - switch (key->algorithm) + switch (key->algorithm) { case SC_ALGORITHM_RSA: { - RSA *rsa = RSA_new(); - + RSA *rsa = RSA_new(); EVP_PKEY_set1_RSA(*pk, rsa); rsa->n = GETBN(&key->u.rsa.modulus); rsa->e = GETBN(&key->u.rsa.exponent); @@ -1176,58 +1203,36 @@ static int extract_key(sc_card_t *card, EVP_PKEY **pk) EVP_PKEY_free(*pk); *pk = NULL; } - if(key) sc_pkcs15_free_prkey(key); - return r; + if (key) sc_pkcs15_free_prkey(key); + SC_FUNC_RETURN(card->ctx, 3, r); } -static int sign_ext(sc_card_t *card, const u8 *data, size_t len, u8 *out, size_t out_len) +static int cipher_ext(sc_card_t *card, const u8 *data, size_t len, + u8 *out, size_t out_len, + int sign /* sign==1 -> Sidn; sign==0 -> decipher */) { + char error[1024]; EVP_PKEY *pkey = NULL; int ret, r; - SC_FUNC_CALLED(card->ctx, 1); - + SC_FUNC_CALLED(card->ctx, 3); if (out_len < len) - return SC_ERROR_INVALID_ARGUMENTS; + SC_FUNC_RETURN(card->ctx, 3, SC_ERROR_INVALID_ARGUMENTS); ret = extract_key(card, &pkey); if (ret == SC_SUCCESS) { - r = RSA_private_encrypt(len, data, out, pkey->pkey.rsa, RSA_PKCS1_PADDING); + if (sign) + r = RSA_PKCS1_SSLeay()->rsa_priv_enc(len, data, out, + pkey->pkey.rsa, RSA_PKCS1_PADDING); + else + { + r = RSA_PKCS1_SSLeay()->rsa_priv_dec(len, data, out, + pkey->pkey.rsa, RSA_PKCS1_PADDING); + ret = r; + } if ( r < 0) - { - char error[1024]; - - ret = SC_ERROR_INTERNAL; - ERR_load_crypto_strings(); - ERR_error_string(ERR_get_error(), error); - sc_error(card->ctx, error); - ERR_free_strings(); - } - } - if(pkey) - EVP_PKEY_free(pkey); - return ret; -} - -static int decipher_ext(sc_card_t *card, const u8 *data, size_t len, u8 *out, size_t out_len) -{ - EVP_PKEY *pkey = NULL; - int ret; - - SC_FUNC_CALLED(card->ctx, 1); - - if (out_len < len) - return SC_ERROR_INVALID_ARGUMENTS; - - ret = extract_key(card, &pkey); - if (ret == SC_SUCCESS) - { - ret = RSA_private_decrypt(len, data, out, pkey->pkey.rsa, RSA_PKCS1_PADDING); - if ( ret < 0) - { - char error[1024]; - + { ret = SC_ERROR_INTERNAL; ERR_load_crypto_strings(); ERR_error_string(ERR_get_error(), error); @@ -1235,65 +1240,72 @@ static int decipher_ext(sc_card_t *card, const u8 *data, size_t len, u8 *out, si ERR_free_strings(); } } - if(pkey) + if (pkey) EVP_PKEY_free(pkey); - return ret; + SC_FUNC_RETURN(card->ctx, 3, ret); } static int rutoken_decipher(sc_card_t *card, const u8 * data, size_t datalen, u8 * out, size_t outlen) { + int ret; auth_senv_t *senv = (auth_senv_t *)card->drv_data; SC_FUNC_CALLED(card->ctx, 1); if (!senv) - return SC_ERROR_INTERNAL; + SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INTERNAL); - if(senv->algorithm == SC_ALGORITHM_GOST) + if (senv->algorithm == SC_ALGORITHM_GOST) { - return rutoken_cipher_p(card, data, datalen, out, outlen, 0x80, 0x86, 1); + ret = rutoken_cipher_p(card, data, datalen, out, outlen, 0x80, 0x86, 1); } else if (senv->algorithm == SC_ALGORITHM_RSA_RAW) { - return decipher_ext(card, data, datalen, out, outlen); + /* decipher */ + ret = cipher_ext(card, data, datalen, out, outlen, 0); } else - return SC_ERROR_NOT_SUPPORTED; + ret = SC_ERROR_NOT_SUPPORTED; + SC_FUNC_RETURN(card->ctx, 1, ret); } static int rutoken_compute_signature(struct sc_card *card, const u8 * data, size_t datalen, u8 * out, size_t outlen) { + int ret; auth_senv_t *senv = (auth_senv_t *)card->drv_data; - + SC_FUNC_CALLED(card->ctx, 1); - if (!senv) - return SC_ERROR_INTERNAL; + SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INTERNAL); - if (senv->algorithm == SC_ALGORITHM_GOST) + if (senv->algorithm == SC_ALGORITHM_GOST) { - return rutoken_compute_mac_gost(card, data, datalen, out, outlen); + ret = rutoken_compute_mac_gost(card, data, datalen, out, outlen); } else if (senv->algorithm == SC_ALGORITHM_RSA_RAW) { - return sign_ext(card, data, datalen, out, outlen); + /* sign */ + ret = cipher_ext(card, data, datalen, out, outlen, 1); } else - return SC_ERROR_NOT_SUPPORTED; + ret = SC_ERROR_NOT_SUPPORTED; + SC_FUNC_RETURN(card->ctx, 1, ret); } -#endif + +#endif /* ENABLE_OPENSSL */ static int rutoken_get_challenge(sc_card_t *card, u8 *rnd, size_t count) { - int ret = SC_NO_ERROR; sc_apdu_t apdu; u8 rbuf[32]; size_t n; + int ret = SC_ERROR_INVALID_ARGUMENTS; /* if count == 0 */ + SC_FUNC_CALLED(card->ctx, 1); sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x84, 0x00, 0x00); apdu.le = sizeof(rbuf); apdu.resp = rbuf; @@ -1303,14 +1315,10 @@ static int rutoken_get_challenge(sc_card_t *card, u8 *rnd, size_t count) { ret = sc_transmit_apdu(card, &apdu); SC_TEST_RET(card->ctx, ret, "APDU transmit failed"); - ret = rutoken_check_sw(card, apdu.sw1, apdu.sw2); - if (ret != SC_SUCCESS) - break; + ret = sc_check_sw(card, apdu.sw1, apdu.sw2); + SC_TEST_RET(card->ctx, ret, "Get challenge failed"); if (apdu.resplen != sizeof(rbuf)) - { - ret = SC_ERROR_UNKNOWN; - break; - } + SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_UNKNOWN); n = count < sizeof(rbuf) ? count : sizeof(rbuf); memcpy(rnd, rbuf, n); count -= n; @@ -1319,35 +1327,53 @@ static int rutoken_get_challenge(sc_card_t *card, u8 *rnd, size_t count) SC_FUNC_RETURN(card->ctx, 1, ret); } +static int rutoken_get_serial(sc_card_t *card, sc_serial_number_t *serial) +{ + sc_apdu_t apdu; + int ret; + + SC_FUNC_CALLED(card->ctx, 3); + sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xCA, 0x01, 0x81); + apdu.resp = serial->value; + apdu.resplen = sizeof(serial->value); + apdu.le = 4; + ret = sc_transmit_apdu(card, &apdu); + SC_TEST_RET(card->ctx, ret, "APDU transmit failed"); + serial->len = apdu.le; + ret = sc_check_sw(card, apdu.sw1, apdu.sw2); + SC_FUNC_RETURN(card->ctx, 3, ret); +} + static int rutoken_get_info(sc_card_t *card, void *buff) { sc_apdu_t apdu; - u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; - int r = SC_ERROR_CARD_CMD_FAILED; - - sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xca, 0x01, 0x89); + u8 rbuf[8]; + int ret; + + SC_FUNC_CALLED(card->ctx, 3); + sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xCA, 0x01, 0x89); apdu.resp = rbuf; apdu.resplen = sizeof(rbuf); - apdu.le = 256; - if(sc_transmit_apdu(card, &apdu) >= 0) - { - memcpy(buff, apdu.resp, apdu.resplen); - r = rutoken_check_sw(card, apdu.sw1, apdu.sw2); - } - SC_FUNC_RETURN(card->ctx, 1, r); + apdu.le = sizeof(rbuf); + ret = sc_transmit_apdu(card, &apdu); + SC_TEST_RET(card->ctx, ret, "APDU transmit failed"); + memcpy(buff, apdu.resp, apdu.resplen); + ret = sc_check_sw(card, apdu.sw1, apdu.sw2); + SC_FUNC_RETURN(card->ctx, 3, ret); } static int rutoken_format(sc_card_t *card, int apdu_ins) { - int ret = SC_ERROR_CARD_CMD_FAILED; + int ret; sc_apdu_t apdu; + SC_FUNC_CALLED(card->ctx, 3); sc_format_apdu(card, &apdu, SC_APDU_CASE_1, apdu_ins, 0x00, 0x00); apdu.cla = 0x80; - if(sc_transmit_apdu(card, &apdu) >= 0) - ret = rutoken_check_sw(card, apdu.sw1, apdu.sw2); - - SC_FUNC_RETURN(card->ctx, 1, ret); + ret = sc_transmit_apdu(card, &apdu); + SC_TEST_RET(card->ctx, ret, "APDU transmit failed"); + ret = sc_check_sw(card, apdu.sw1, apdu.sw2); + SC_FUNC_RETURN(card->ctx, 3, ret); } static int rutoken_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr) @@ -1359,8 +1385,8 @@ static int rutoken_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr) ) ? SC_NO_ERROR : SC_ERROR_INVALID_ARGUMENTS; SC_FUNC_CALLED(card->ctx, 1); - - if(ret == SC_NO_ERROR) + + if (ret == SC_NO_ERROR) { switch (cmd) { @@ -1403,16 +1429,19 @@ static int rutoken_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr) sc_debug(card->ctx, "cmd = %d", cmd); ret = SC_ERROR_NOT_SUPPORTED; break; + case SC_CARDCTL_LIFECYCLE_SET: + sc_debug(card->ctx, "SC_CARDCTL_LIFECYCLE_SET not supported"); + sc_debug(card->ctx, "returning SC_ERROR_NOT_SUPPORTED"); + /* no call sc_error (SC_FUNC_RETURN) */ + return SC_ERROR_NOT_SUPPORTED; } } - return ret; + SC_FUNC_RETURN(card->ctx, 1, ret); } -static struct sc_card_driver * sc_get_driver(void) +static struct sc_card_driver* get_rutoken_driver(void) { - if (iso_ops == NULL) - iso_ops = sc_get_iso7816_driver()->ops; - rutoken_ops = *iso_ops; + rutoken_ops = *sc_get_iso7816_driver()->ops; rutoken_ops.match_card = rutoken_match_card; rutoken_ops.init = rutoken_init; @@ -1424,7 +1453,6 @@ static struct sc_card_driver * sc_get_driver(void) rutoken_ops.list_files = rutoken_list_files; rutoken_ops.card_ctl = rutoken_card_ctl; rutoken_ops.get_challenge = rutoken_get_challenge; - #ifdef ENABLE_OPENSSL rutoken_ops.decipher = rutoken_decipher; rutoken_ops.compute_signature = rutoken_compute_signature; @@ -1434,24 +1462,21 @@ static struct sc_card_driver * sc_get_driver(void) #endif rutoken_ops.set_security_env = rutoken_set_security_env; rutoken_ops.restore_security_env = rutoken_restore_security_env; - rutoken_ops.verify = rutoken_verify; - rutoken_ops.logout = rutoken_logout; + rutoken_ops.logout = rutoken_logout; rutoken_ops.change_reference_data = rutoken_change_reference_data; rutoken_ops.reset_retry_counter = rutoken_reset_retry_counter; - rutoken_ops.pin_cmd = NULL; rutoken_ops.read_record = NULL; rutoken_ops.write_record = NULL; rutoken_ops.append_record = NULL; rutoken_ops.update_record = NULL; rutoken_ops.write_binary = NULL; - return &rutoken_drv; } struct sc_card_driver * sc_get_rutoken_driver(void) { - return sc_get_driver(); + return get_rutoken_driver(); } diff --git a/src/libopensc/libopensc.exports b/src/libopensc/libopensc.exports index c537c4e3..f00cd924 100644 --- a/src/libopensc/libopensc.exports +++ b/src/libopensc/libopensc.exports @@ -184,8 +184,6 @@ sc_release_context sc_reset sc_reset_retry_counter sc_restore_security_env -sc_rutoken_get_prkey_from_bin -sc_rutoken_get_bin_from_prkey sc_select_file sc_set_card_driver sc_set_security_env diff --git a/src/libopensc/pkcs15-prkey-rutoken.c b/src/libopensc/pkcs15-prkey-rutoken.c deleted file mode 100644 index ecacedef..00000000 --- a/src/libopensc/pkcs15-prkey-rutoken.c +++ /dev/null @@ -1,377 +0,0 @@ -/* - * ruToken specific operation for PKCS #15 private key functions - * - * Copyright (C) 2007 Pavel Mironchik - * Copyright (C) 2007 Eugene Hermann - * - * 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 "rutoken.h" -#if defined(HAVE_INTTYPES_H) -#include -#elif defined(HAVE_STDINT_H) -#include -#elif defined(_MSC_VER) -typedef unsigned __int32 uint32_t; -typedef unsigned __int16 uint16_t; -#else -#warning no uint32_t type available, please contact opensc-devel@opensc-project.org -#endif - -/* BLOB definition */ - -typedef struct _RURSAPUBKEY { - uint32_t magic; - uint32_t bitlen; - uint32_t pubexp; -} RURSAPUBKEY; - -typedef struct _RUPUBLICKEYSTRUC { - u8 bType; - u8 bVersion; - uint16_t reserved; - uint32_t aiKeyAlg; -} RUBLOBHEADER; - -typedef struct _RUPRIVATEKEYBLOB { - RUBLOBHEADER blobheader; - RURSAPUBKEY rsapubkey; - u8 *modulus; - u8 *prime1; - u8 *prime2; - u8 *exponent1; - u8 *exponent2; - u8 *coefficient; - u8 *privateExponent; -} RUPRIVATEKEYBLOB; - - -static void ArrayReverse(u8 *buf, size_t size) -{ - size_t i; - u8 tmp; - - for (i=0; i < size/2; ++i) - { - tmp = buf[i]; - buf[i] = buf[size-1-i]; - buf[size-1-i] = tmp; - } -} - -static int free_private_blob(RUPRIVATEKEYBLOB *pr_blob) -{ - free(pr_blob->modulus); - free(pr_blob->prime1); - free(pr_blob->prime2); - free(pr_blob->exponent1); - free(pr_blob->exponent2); - free(pr_blob->coefficient); - free(pr_blob->privateExponent); - return 0; -} - -static int bin_to_private_blob(RUPRIVATEKEYBLOB *pr_blob, const u8* buf, size_t buf_len) -{ - const u8 *tmp; - size_t len = 2 + sizeof(pr_blob->blobheader) + sizeof(pr_blob->rsapubkey); - uint32_t bitlen; - - if (buf_len < len) - return -1; - - tmp = buf + 2; - memcpy(&pr_blob->blobheader, tmp, sizeof(pr_blob->blobheader)); - tmp += sizeof(pr_blob->blobheader); - - memcpy(&pr_blob->rsapubkey, tmp, sizeof(pr_blob->rsapubkey)); - tmp += sizeof(pr_blob->rsapubkey); - - bitlen = pr_blob->rsapubkey.bitlen; - - len += bitlen/8 * 2 + bitlen/16 * 5; - if (buf_len < len) - return -1; - - pr_blob->modulus = malloc(bitlen/8); - pr_blob->prime1 = malloc(bitlen/16); - pr_blob->prime2 = malloc(bitlen/16); - pr_blob->exponent1 = malloc(bitlen/16); - pr_blob->exponent2 = malloc(bitlen/16); - pr_blob->coefficient = malloc(bitlen/16); - pr_blob->privateExponent = malloc(bitlen/8); - if (!pr_blob->modulus || !pr_blob->prime1 || !pr_blob->prime2 - || !pr_blob->exponent1 || !pr_blob->exponent2 - || !pr_blob->coefficient || !pr_blob->privateExponent - ) - { - free_private_blob(pr_blob); - return -1; - } - memcpy(pr_blob->modulus, tmp, bitlen/8); - tmp += bitlen/8; - memcpy(pr_blob->prime1, tmp, bitlen/16); - tmp += bitlen/16; - memcpy(pr_blob->prime2, tmp, bitlen/16); - tmp += bitlen/16; - memcpy(pr_blob->exponent1, tmp, bitlen/16); - tmp += bitlen/16; - memcpy(pr_blob->exponent2, tmp, bitlen/16); - tmp += bitlen/16; - memcpy(pr_blob->coefficient, tmp, bitlen/16); - tmp += bitlen/16; - memcpy(pr_blob->privateExponent, tmp, bitlen/8); - tmp += bitlen/8; - return 0; -} - -static int create_private_blob(RUPRIVATEKEYBLOB *pr_blob, const struct sc_pkcs15_prkey_rsa *key) -{ - size_t n; - const uint32_t bitlen = key->modulus.len*8; - - if ( key->modulus.len != bitlen/8 - || key->p.len != bitlen/16 - || key->q.len != bitlen/16 - || key->dmp1.len != bitlen/16 - || key->dmq1.len != bitlen/16 - || key->iqmp.len != bitlen/16 - || key->d.len != bitlen/8 - ) - return -1; - - /* blobheader */ - /* u8 bType; */ - pr_blob->blobheader.bType = 0x07; - /* u8 bVersion; */ - pr_blob->blobheader.bVersion = 0x02; - /* u16 reserved; */ - pr_blob->blobheader.reserved = 0; - /* u32 aiKeyAlg; */ - pr_blob->blobheader.aiKeyAlg = 0x0000a400; - - pr_blob->rsapubkey.magic = 0x32415352; /* "RSA2" */ - pr_blob->rsapubkey.bitlen = bitlen; - - pr_blob->rsapubkey.pubexp = 0; - for (n=0; n < key->exponent.len && n < sizeof(pr_blob->rsapubkey.pubexp); ++n) - pr_blob->rsapubkey.pubexp += - (uint32_t)key->exponent.data[key->exponent.len - n - 1] << 8*n; - - pr_blob->modulus = malloc(bitlen/8); - pr_blob->prime1 = malloc(bitlen/16); - pr_blob->prime2 = malloc(bitlen/16); - pr_blob->exponent1 = malloc(bitlen/16); - pr_blob->exponent2 = malloc(bitlen/16); - pr_blob->coefficient = malloc(bitlen/16); - pr_blob->privateExponent = malloc(bitlen/8); - if (!pr_blob->modulus || !pr_blob->prime1 || !pr_blob->prime2 - || !pr_blob->exponent1 || !pr_blob->exponent2 - || !pr_blob->coefficient || !pr_blob->privateExponent - ) - { - free_private_blob(pr_blob); - return -1; - } - - memcpy(pr_blob->modulus, key->modulus.data, key->modulus.len); - ArrayReverse(pr_blob->modulus, key->modulus.len); - memcpy(pr_blob->prime1, key->p.data, key->p.len); - ArrayReverse(pr_blob->prime1, key->p.len); - memcpy(pr_blob->prime2, key->q.data, key->q.len); - ArrayReverse(pr_blob->prime2, key->q.len); - memcpy(pr_blob->exponent1, key->dmp1.data, key->dmp1.len); - ArrayReverse(pr_blob->exponent1, key->dmp1.len); - memcpy(pr_blob->exponent2, key->dmq1.data, key->dmq1.len); - ArrayReverse(pr_blob->exponent2, key->dmq1.len); - memcpy(pr_blob->coefficient, key->iqmp.data, key->iqmp.len); - ArrayReverse(pr_blob->coefficient, key->iqmp.len); - memcpy(pr_blob->privateExponent, key->d.data, key->d.len); - ArrayReverse(pr_blob->privateExponent, key->d.len); - return 0; -} - -static int get_sc_pksc15_prkey_rsa(const RUPRIVATEKEYBLOB *pr_blob, struct sc_pkcs15_prkey_rsa *key) -{ - static const u8 Exp[3] = { 0x01, 0x00, 0x01 }; /* big endian */ - - const uint32_t bitlen = pr_blob->rsapubkey.bitlen; - - key->modulus.data = malloc(bitlen/8); - key->modulus.len = bitlen/8; - key->p.data = malloc(bitlen/16); - key->p.len = bitlen/16; - key->q.data = malloc(bitlen/16); - key->q.len = bitlen/16; - key->dmp1.data = malloc(bitlen/16); - key->dmp1.len = bitlen/16; - key->dmq1.data = malloc(bitlen/16); - key->dmq1.len = bitlen/16; /* ?! bitlen/16 - 1; */ - key->iqmp.data = malloc(bitlen/16); - key->iqmp.len = bitlen/16; - key->d.data = malloc(bitlen/8); - key->d.len = bitlen/8; - key->exponent.data = malloc(sizeof(Exp)); - key->exponent.len = sizeof(Exp); - if(!key->modulus.data || !key->p.data || !key->q.data || !key->dmp1.data - || !key->dmq1.data || !key->iqmp.data || !key->d.data - || !key->exponent.data - ) - { - free(key->modulus.data); - free(key->p.data); - free(key->q.data); - free(key->dmp1.data); - free(key->dmq1.data); - free(key->iqmp.data); - free(key->d.data); - free(key->exponent.data); - memset(key, 0, sizeof(*key)); - return -1; - } - - memcpy(key->exponent.data, &Exp, sizeof(Exp)); - memcpy(key->modulus.data, pr_blob->modulus, key->modulus.len); - ArrayReverse(key->modulus.data, key->modulus.len); - memcpy(key->p.data, pr_blob->prime1, key->p.len); - ArrayReverse(key->p.data, key->p.len); - memcpy(key->q.data, pr_blob->prime2, key->q.len); - ArrayReverse(key->q.data, key->q.len); - memcpy(key->dmp1.data, pr_blob->exponent1, key->dmp1.len); - ArrayReverse(key->dmp1.data, key->dmp1.len); - memcpy(key->dmq1.data, pr_blob->exponent2, key->dmq1.len); - ArrayReverse(key->dmq1.data, key->dmq1.len); - memcpy(key->iqmp.data, pr_blob->coefficient, key->iqmp.len); - ArrayReverse(key->iqmp.data, key->iqmp.len); - memcpy(key->d.data, pr_blob->privateExponent, key->d.len); - ArrayReverse(key->d.data, key->d.len); - return 0; -} - -static int private_blob_to_bin(const RUPRIVATEKEYBLOB *pr_blob, u8 *buf, size_t *buf_len) -{ - u8 *tmp; - size_t len = 2 + sizeof(pr_blob->blobheader) + sizeof(pr_blob->rsapubkey); - - if(*buf_len < len) - return -1; - - buf[0] = 2; - buf[1] = 1; - tmp = buf + 2; - memcpy(tmp, &pr_blob->blobheader, sizeof(pr_blob->blobheader)); - tmp += sizeof(pr_blob->blobheader); - - memcpy(tmp, &pr_blob->rsapubkey, sizeof(pr_blob->rsapubkey)); - tmp += sizeof(pr_blob->rsapubkey); - - len += pr_blob->rsapubkey.bitlen/8 * 2 + pr_blob->rsapubkey.bitlen/16 * 5; - if (*buf_len < len) - return -1; - - memcpy(tmp, pr_blob->modulus, pr_blob->rsapubkey.bitlen/8); - tmp += pr_blob->rsapubkey.bitlen/8; - - memcpy(tmp, pr_blob->prime1, pr_blob->rsapubkey.bitlen/16); - tmp += pr_blob->rsapubkey.bitlen/16; - - memcpy(tmp, pr_blob->prime2, pr_blob->rsapubkey.bitlen/16); - tmp += pr_blob->rsapubkey.bitlen/16; - - memcpy(tmp, pr_blob->exponent1, pr_blob->rsapubkey.bitlen/16); - tmp += pr_blob->rsapubkey.bitlen/16; - - memcpy(tmp, pr_blob->exponent2, pr_blob->rsapubkey.bitlen/16); - tmp += pr_blob->rsapubkey.bitlen/16; - - memcpy(tmp, pr_blob->coefficient, pr_blob->rsapubkey.bitlen/16); - tmp += pr_blob->rsapubkey.bitlen/16; - - memcpy(tmp, pr_blob->privateExponent, pr_blob->rsapubkey.bitlen/8); - tmp += pr_blob->rsapubkey.bitlen/8; - - *buf_len = len; - return 0; -} - -static int clean_prkey_private_blob(const RUPRIVATEKEYBLOB* pr_blob) -{ - const uint32_t bitlen = pr_blob->rsapubkey.bitlen; - - memset(pr_blob->modulus, 0, bitlen/8); - memset(pr_blob->prime1, 0, bitlen/16); - memset(pr_blob->prime2, 0, bitlen/16); - memset(pr_blob->exponent1, 0, bitlen/16); - memset(pr_blob->exponent2, 0, bitlen/16); - memset(pr_blob->coefficient, 0, bitlen/16); - memset(pr_blob->privateExponent, 0, bitlen/8); - return 0; -} - -int sc_rutoken_get_prkey_from_bin(const u8 *data, size_t len, struct sc_pkcs15_prkey **key) -{ - int ret = -1; - RUPRIVATEKEYBLOB pr_blob; - - if (data && key) - { - *key = malloc(sizeof(struct sc_pkcs15_prkey)); - if (*key) - { - memset(*key, 0, sizeof(**key)); - ret = bin_to_private_blob(&pr_blob, data, len); - if (ret == 0) - { - ret = get_sc_pksc15_prkey_rsa(&pr_blob, &(*key)->u.rsa); - if (ret == 0) - (*key)->algorithm = SC_ALGORITHM_RSA; - clean_prkey_private_blob(&pr_blob); - free_private_blob(&pr_blob); - memset(&pr_blob, 0, sizeof(pr_blob)); - } - } - } - return ret; -} - -int sc_rutoken_get_bin_from_prkey(const struct sc_pkcs15_prkey_rsa *rsa, u8 *key, size_t *keysize) -{ - int r = -1; - RUPRIVATEKEYBLOB prkeyblob; - - if (rsa && key && keysize) - { - r = create_private_blob(&prkeyblob, rsa); - if (r == 0) - { - r = private_blob_to_bin(&prkeyblob, key, keysize); - clean_prkey_private_blob(&prkeyblob); - free_private_blob(&prkeyblob); - memset(&prkeyblob, 0, sizeof(prkeyblob)); - } - } - return r; -} - diff --git a/src/libopensc/pkcs15-rutoken.c b/src/libopensc/pkcs15-rutoken.c index 47377056..ad19f65f 100644 --- a/src/libopensc/pkcs15-rutoken.c +++ b/src/libopensc/pkcs15-rutoken.c @@ -1,5 +1,5 @@ /* - * PKCS15 emulation layer for ruToken + * PKCS15 emulation layer for Rutoken * * Copyright (C) 2007 Pavel Mironchik * Copyright (C) 2007 Eugene Hermann @@ -28,17 +28,15 @@ #include #include #include -#include "cardctl.h" #include #include - -#define RUT_LABEL "ruToken card" +#include "cardctl.h" #define PrKDF_path "3F00FF000001" #define PuKDF_path "3F00FF000002" #define CDF_path "3F00FF000003" #define DODF_path "3F00FF000004" -#define AODF_path "3F00FF00A0DF" +#define AODF_path "3F00FF000000" static const struct { @@ -82,8 +80,8 @@ static int add_predefined_pin(sc_pkcs15_card_t *p15card, sc_path_t *adf_path) { free(pin_info); free(pin_obj); - return SC_ERROR_OUT_OF_MEMORY; - } + return SC_ERROR_OUT_OF_MEMORY; + } pin_info->auth_id.len = 1; pin_info->auth_id.value[0] = (u8)pinlist[i].reference; pin_info->reference = pinlist[i].reference; @@ -97,8 +95,7 @@ static int add_predefined_pin(sc_pkcs15_card_t *p15card, sc_path_t *adf_path) pin_info->path = *adf_path; strncpy(pin_obj->label, pinlist[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1); - pin_obj->flags = SC_PKCS15_CO_FLAG_PRIVATE; - + pin_obj->flags = SC_PKCS15_CO_FLAG_PRIVATE; sc_pkcs15emu_add_pin_obj(p15card, pin_obj, pin_info); free(pin_obj); free(pin_info); @@ -119,7 +116,7 @@ static int set_card_info(sc_pkcs15_card_t *p15card) sc_serial_number_t serialnr; char serial[30] = {0}; u8 info[8]; - + /* get the card serial number */ if (sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serialnr) < 0) { @@ -128,21 +125,19 @@ static int set_card_info(sc_pkcs15_card_t *p15card) } sc_bin_to_hex(serialnr.value, serialnr.len , serial, sizeof(serial), 0); set_string(&p15card->serial_number, serial); - /* get ruToken information */ if (sc_card_ctl(card, SC_CARDCTL_RUTOKEN_GET_INFO, info) < 0) { sc_debug(ctx, "Unable to get token information\n"); return SC_ERROR_WRONG_CARD; } - set_string(&p15card->label, RUT_LABEL); + set_string(&p15card->label, card->name); p15card->version = (info[1] >> 4)*10 + (info[1] & 0x0f); sc_bin_to_hex(info + 3, 3 , serial, sizeof(serial), 0); set_string(&p15card->manufacturer_id, serial); - return SC_SUCCESS; } - + static int sc_pkcs15_rutoken_init_func(sc_pkcs15_card_t *p15card) { sc_context_t *ctx; @@ -152,25 +147,23 @@ static int sc_pkcs15_rutoken_init_func(sc_pkcs15_card_t *p15card) size_t i; int r; unsigned int added_pin = 0; - + if (!p15card || !p15card->card || !p15card->card->ctx || !p15card->card->ops || !p15card->card->ops->select_file ) return SC_ERROR_INVALID_ARGUMENTS; - card = p15card->card; ctx = card->ctx; - r = set_card_info(p15card); if (r != SC_SUCCESS) - { + { sc_error(ctx, "Unable to set card info: %s\n", sc_strerror(r)); r = SC_SUCCESS; - } + } for (i = 0; i < sizeof(arr_profile_df)/sizeof(arr_profile_df[0]); ++i) - { + { df = NULL; sc_format_path(arr_profile_df[i].path, &path); if (card->ops->select_file(card, &path, &df) == SC_ERROR_FILE_NOT_FOUND) @@ -181,7 +174,7 @@ static int sc_pkcs15_rutoken_init_func(sc_pkcs15_card_t *p15card) if (r == SC_SUCCESS) r = sc_pkcs15_add_df(p15card, arr_profile_df[i].type, &path, df); if (df) - sc_file_free(df); + sc_file_free(df); if (r != SC_SUCCESS) break; @@ -199,17 +192,16 @@ static int sc_pkcs15_rutoken_init_func(sc_pkcs15_card_t *p15card) return r; } -int sc_pkcs15emu_rutoken_init_ex(sc_pkcs15_card_t *p15card, - sc_pkcs15emu_opt_t *opts) +int sc_pkcs15emu_rutoken_init_ex(sc_pkcs15_card_t *p15card, + sc_pkcs15emu_opt_t *opts) { struct sc_card *card = p15card->card; - + SC_FUNC_CALLED(card->ctx, 1); - /* check if we have the correct card OS */ - if (strcmp(card->name, "rutoken card")) + if (strcmp(card->name, "Rutoken card")) return SC_ERROR_WRONG_CARD; - sc_debug(card->ctx, "%s found", card->name); return sc_pkcs15_rutoken_init_func(p15card); } + diff --git a/src/libopensc/rutoken.h b/src/libopensc/rutoken.h deleted file mode 100644 index f3fd6308..00000000 --- a/src/libopensc/rutoken.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef RUTOKEN_H -#define RUTOKEN_H - -int sc_rutoken_get_prkey_from_bin(const u8 *data, size_t len, struct sc_pkcs15_prkey **key); -int sc_rutoken_get_bin_from_prkey(const struct sc_pkcs15_prkey_rsa *rsa, u8 *key, size_t *keysize); - -#endif diff --git a/src/pkcs15init/Makefile.am b/src/pkcs15init/Makefile.am index 6663204a..407cef9e 100644 --- a/src/pkcs15init/Makefile.am +++ b/src/pkcs15init/Makefile.am @@ -24,7 +24,7 @@ dist_pkgdata_DATA = \ rutoken.profile \ asepcos.profile -DEFS = -DSC_PKCS15_PROFILE_DIRECTORY=\"$(pkgdatadir)\" +AM_CPPFLAGS = -DSC_PKCS15_PROFILE_DIRECTORY=\"$(pkgdatadir)\" AM_CFLAGS = $(OPTIONAL_OPENSSL_CFLAGS) $(LTLIB_CFLAGS) INCLUDES = -I$(top_srcdir)/src/common -I$(top_builddir)/src/include diff --git a/src/pkcs15init/pkcs15-rutoken.c b/src/pkcs15init/pkcs15-rutoken.c index c48857f3..3d717427 100644 --- a/src/pkcs15init/pkcs15-rutoken.c +++ b/src/pkcs15init/pkcs15-rutoken.c @@ -1,5 +1,5 @@ /* - * ruToken specific operation for PKCS15 initialization + * Rutoken specific operation for PKCS15 initialization * * Copyright (C) 2007 Pavel Mironchik * Copyright (C) 2007 Eugene Hermann @@ -18,10 +18,20 @@ * 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 +#if defined(HAVE_INTTYPES_H) +#include +#elif defined(HAVE_STDINT_H) +#include +#elif defined(_MSC_VER) +typedef unsigned __int32 uint32_t; +typedef unsigned __int16 uint16_t; +#else +#warning no uint32_t type available, please contact opensc-devel@opensc-project.org +#endif #include #include #include @@ -31,11 +41,14 @@ #include #include #include -#include #include "pkcs15-init.h" #include "profile.h" -#define MAX_ID 255 +#define RUTOKEN_MIN_ID_PRKEY 0x0000 +#define RUTOKEN_MAX_ID_PRKEY 0x00FF +#define RUTOKEN_MIN_ID_OTHER (RUTOKEN_MAX_ID_PRKEY + 1) +#define RUTOKEN_MAX_ID_OTHER 0x0FFF +#define RUTOKEN_BUFLEN_LISTFILES (2 * (RUTOKEN_MAX_ID_OTHER + 1)) static const sc_SecAttrV2_t pr_sec_attr = {0x43, 1, 1, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 2}; static const sc_SecAttrV2_t pb_sec_attr = {0x42, 0, 1, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 2}; @@ -47,10 +60,10 @@ static const sc_SecAttrV2_t p1_sec_attr = {0x43, 1, 1, 0, 0, 0, 0,-1, 1, 1, 0, 0 enum DF_IDs { - PrKDFid = 0x1001, - PuKDFid = 0x1002, - CDFid = 0x1003, - DODFid = 0x1004, + PrKDFid = 0x0000, + PuKDFid = 0x0000, + CDFid = 0x0000, + DODFid = 0x0000, AODFid = 0xFFFF }; @@ -75,40 +88,76 @@ static const struct { AODF_name, AODFid, SC_PKCS15_AODF } }; -/* - * Create/override new EF. - */ -static int rutoken_create_file(sc_card_t *card, sc_path_t *path, sc_file_t *ef) + +static int rutoken_get_bin_from_prkey(const struct sc_pkcs15_prkey_rsa *rsa, + u8 *bufkey, size_t *bufkey_size) { - int ret = SC_SUCCESS; - sc_path_t path_dir; + const uint32_t bitlen = rsa->modulus.len * 8; + size_t i, len; - SC_FUNC_CALLED(card->ctx, 1); + if ( rsa->modulus.len != bitlen/8 + || rsa->p.len != bitlen/16 + || rsa->q.len != bitlen/16 + || rsa->dmp1.len != bitlen/16 + || rsa->dmq1.len != bitlen/16 + || rsa->iqmp.len != bitlen/16 + || rsa->d.len != bitlen/8 + || rsa->exponent.len > sizeof(uint32_t) + ) + return -1; - if (path) - { - sc_ctx_suppress_errors_on(card->ctx); - ret = card->ops->select_file(card, path, NULL); - sc_ctx_suppress_errors_off(card->ctx); - if (ret == SC_SUCCESS) - { - sc_path_t del_path; - del_path.len = 2; - del_path.type = SC_PATH_TYPE_FILE_ID; - del_path.value[0] = (u8)(ef->id / 256); - del_path.value[1] = (u8)(ef->id % 256); - if (card->ops->select_file(card, &del_path, NULL) == SC_SUCCESS) - ret = card->ops->delete_file(card, &del_path); - } - path_dir = *path; - path_dir.len -= 2; - ret = card->ops->select_file(card, &path_dir, NULL); - } - if (ret == SC_SUCCESS) - { - ret = card->ops->create_file(card, ef); - } - return ret; + if (*bufkey_size < 14 + sizeof(uint32_t) * 2 + bitlen/8 * 2 + bitlen/16 * 5) + return -1; + + bufkey[0] = 2; + bufkey[1] = 1; + + /* BLOB header */ + bufkey[2] = 0x07; /* Type */ + bufkey[3] = 0x02; /* Version */ + /* reserve */ + bufkey[4] = 0; + bufkey[5] = 0; + /* aiKeyAlg */ + bufkey[6] = 0; + bufkey[7] = 0xA4; + bufkey[8] = 0; + bufkey[9] = 0; + + /* RSAPUBKEY */ + /* magic "RSA2" */ + bufkey[10] = 0x52; + bufkey[11] = 0x53; + bufkey[12] = 0x41; + bufkey[13] = 0x32; + len = 14; + /* bitlen */ + for (i = 0; i < sizeof(uint32_t); ++i) + bufkey[len++] = (bitlen >> i*8) & 0xff; + /* pubexp */ + for (i = 0; i < sizeof(uint32_t); ++i) + if (i < rsa->exponent.len) + bufkey[len++] = rsa->exponent.data[rsa->exponent.len - 1 - i]; + else + bufkey[len++] = 0; + +#define MEMCPY_BUF_REVERSE_RSA(NAME) \ + do { \ + for (i = 0; i < rsa->NAME.len; ++i) \ + bufkey[len++] = rsa->NAME.data[rsa->NAME.len - 1 - i]; \ + } while (0) + + /* PRIVATEKEYBLOB tail */ + MEMCPY_BUF_REVERSE_RSA(modulus); /* modulus */ + MEMCPY_BUF_REVERSE_RSA(p); /* prime1 */ + MEMCPY_BUF_REVERSE_RSA(q); /* prime2 */ + MEMCPY_BUF_REVERSE_RSA(dmp1); /* exponent1 */ + MEMCPY_BUF_REVERSE_RSA(dmq1); /* exponent2 */ + MEMCPY_BUF_REVERSE_RSA(iqmp); /* coefficient */ + MEMCPY_BUF_REVERSE_RSA(d); /* privateExponent */ + + *bufkey_size = len; + return 0; } /* @@ -177,7 +226,8 @@ rutoken_select_key_reference(sc_profile_t *profile, sc_card_t *card, } sc_append_file_id(&key_info->path, key_info->key_reference); - return key_info->key_reference >= 0 && key_info->key_reference <= MAX_ID ? + return key_info->key_reference >= RUTOKEN_MIN_ID_PRKEY + && key_info->key_reference <= RUTOKEN_MAX_ID_PRKEY ? SC_SUCCESS : SC_ERROR_TOO_MANY_OBJECTS; } @@ -195,36 +245,6 @@ rutoken_create_key(sc_profile_t *profile, sc_card_t *card, return SC_SUCCESS; } -/* - * Create private key files - */ -static int rutoken_create_prkeyfile(sc_card_t *card, - sc_pkcs15_prkey_info_t *key_info, size_t prsize) -{ - sc_path_t path; - sc_file_t *file; - int ret; - - SC_FUNC_CALLED(card->ctx, 1); - - file = sc_file_new(); - if (file) - { - /* create key file */ - path = key_info->path; - file->type = SC_FILE_TYPE_WORKING_EF; - file->id = key_info->key_reference; - file->size = prsize; - sc_file_set_sec_attr(file, (u8*)&pr_sec_attr, SEC_ATTR_SIZE); - ret = rutoken_create_file(card, &path, file); - if (file) - sc_file_free(file); - } - else - ret = SC_ERROR_OUT_OF_MEMORY; - return ret; -} - /* * Store a private key object. */ @@ -237,6 +257,7 @@ rutoken_store_key(sc_profile_t *profile, sc_card_t *card, const int nKeyBufSize = 2048; u8 *prkeybuf = NULL; size_t prsize; + sc_file_t *file; int ret; if (!profile || !profile->ops || !card || !card->ctx @@ -264,12 +285,21 @@ rutoken_store_key(sc_profile_t *profile, sc_card_t *card, ret = profile->ops->encode_private_key(profile, card, &key->u.rsa, prkeybuf, &prsize, 0); if (ret == 0) { - ret = rutoken_create_prkeyfile(card, key_info, prsize); - if (ret == 0) + file = sc_file_new(); + if (!file) + ret = SC_ERROR_OUT_OF_MEMORY; + else { - ret = sc_update_binary(card, 0, prkeybuf, prsize, 0); - if (ret < 0 || (size_t)ret != prsize) - sc_debug(card->ctx, "ret=%i (%u)\n", ret, prsize); + /* create (or update) key file */ + file->path = key_info->path; + file->type = SC_FILE_TYPE_WORKING_EF; + file->id = key_info->key_reference; + file->size = prsize; + sc_file_set_sec_attr(file, (u8*)&pr_sec_attr, SEC_ATTR_SIZE); + + ret = sc_pkcs15init_update_file(profile, card, + file, prkeybuf, prsize); + sc_file_free(file); } memset(prkeybuf, 0, prsize); } @@ -291,7 +321,7 @@ rutoken_encode_private_key(sc_profile_t *profile, sc_card_t *card, return SC_ERROR_INVALID_ARGUMENTS; SC_FUNC_CALLED(card->ctx, 1); - r = sc_rutoken_get_bin_from_prkey(rsa, key, keysize); + r = rutoken_get_bin_from_prkey(rsa, key, keysize); sc_debug(card->ctx, "sc_rutoken_get_bin_from_prkey returned %i\n", r); return r; } @@ -299,7 +329,7 @@ rutoken_encode_private_key(sc_profile_t *profile, sc_card_t *card, static int rutoken_id_in(int id, const u8 *buf, int buflen) { int i; - for (i = 0; i*2 < buflen; i++) + for (i = 0; i*2 + 1 < buflen; i++) if (id == (int)buf[i*2] * 0x100 + buf[i*2 + 1]) return 1; return 0; } @@ -308,7 +338,7 @@ static int rutoken_find_id(sc_card_t *card, const sc_path_t *path) { int ret = SC_SUCCESS; sc_file_t *file = NULL; - u8 *files = malloc(2048); + u8 *files = malloc(RUTOKEN_BUFLEN_LISTFILES); if (!files) return SC_ERROR_OUT_OF_MEMORY; if(path) { @@ -317,11 +347,11 @@ static int rutoken_find_id(sc_card_t *card, const sc_path_t *path) } if(ret == SC_SUCCESS) { - ret = card->ops->list_files(card, files, 2048); + ret = card->ops->list_files(card, files, RUTOKEN_BUFLEN_LISTFILES); if(ret >= 0) { int i; - for (i = 0; i < MAX_ID; i++) + for (i = RUTOKEN_MIN_ID_OTHER; i <= RUTOKEN_MAX_ID_OTHER; i++) if(!rutoken_id_in(i, files, ret)) {ret = i; break;} } } @@ -600,7 +630,13 @@ static int rutoken_init(sc_profile_t *profile, sc_card_t *card) df->id = arr_def_df[i].dir; r = sc_append_file_id(&df->path, df->id); if (r == SC_SUCCESS) + { + sc_ctx_suppress_errors_on(card->ctx); r = card->ops->create_file(card, df); + sc_ctx_suppress_errors_off(card->ctx); + if (r == SC_ERROR_FILE_ALREADY_EXISTS) + r = SC_SUCCESS; + } if (r != SC_SUCCESS) sc_error(card->ctx, "Failed to create df, %s\n", sc_strerror(r)); diff --git a/src/pkcs15init/rutoken.profile b/src/pkcs15init/rutoken.profile index 9f4063d3..fe94f370 100644 --- a/src/pkcs15init/rutoken.profile +++ b/src/pkcs15init/rutoken.profile @@ -13,20 +13,20 @@ pkcs15 { # Put the DF length into the ODF file? encode-df-length = no; # Have a lastUpdate field in the EF(TokenInfo)? - do-last-update = yes; + do-last-update = no; } # Default settings. # This option block will always be processed. option default_32k { - macros { + macros { odf-size = 0; aodf-size = 0; dodf-size = 2048; cdf-size = 2048; prkdf-size = 2048; pukdf-size = 2048; - } + } } # This option is for cards with very little memory. @@ -45,45 +45,45 @@ option default { } filesystem { - DF MF { + DF MF { path = 3F00; - type = DF; - + type = DF; + # Here comes the application DF DF PKCS15-AppDF { - type = DF; + type = DF; file-id = FF00; EF PKCS15-ODF { file-id = 00DF; size = $odf-size; - } - + } + EF PKCS15-AODF { file-id = A0DF; size = $aodf-size; } EF PKCS15-PrKDF { - file-id = 0001; + file-id = 0001; size = $prkdf-size; - } - + } + EF PKCS15-PuKDF { - file-id = 0002; + file-id = 0002; size = $pukdf-size; - } + } EF PKCS15-CDF { file-id = 0003; size = $cdf-size; - } - + } + EF PKCS15-DODF { file-id = 0004; size = $dodf-size; } - } - } + } + } } diff --git a/src/tools/rutoken-tool.c b/src/tools/rutoken-tool.c index afd72cbb..6530fed2 100644 --- a/src/tools/rutoken-tool.c +++ b/src/tools/rutoken-tool.c @@ -34,7 +34,6 @@ #include #include #include -#include #include "util.h" #define IV_SIZE 8