2007-12-17 13:39:20 +00:00
|
|
|
/*
|
2010-09-09 17:28:44 +00:00
|
|
|
* card-rutoken.c: Support for Rutoken S cards
|
2007-12-17 13:39:20 +00:00
|
|
|
*
|
|
|
|
* Copyright (C) 2007 Pavel Mironchik <rutoken@rutoken.ru>
|
|
|
|
* Copyright (C) 2007 Eugene Hermann <rutoken@rutoken.ru>
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*/
|
2008-04-18 14:08:23 +00:00
|
|
|
|
2010-03-04 08:14:36 +00:00
|
|
|
#include "config.h"
|
|
|
|
|
2008-04-18 14:08:23 +00:00
|
|
|
#include <sys/types.h>
|
2009-11-23 16:38:02 +00:00
|
|
|
#include <assert.h>
|
2008-04-18 14:08:23 +00:00
|
|
|
#include <ctype.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
2008-04-24 16:34:08 +00:00
|
|
|
#include <stdio.h>
|
2010-03-04 08:14:36 +00:00
|
|
|
|
|
|
|
#include "internal.h"
|
2008-04-18 14:08:23 +00:00
|
|
|
#include "opensc.h"
|
|
|
|
#include "pkcs15.h"
|
2009-11-23 16:38:02 +00:00
|
|
|
#include "asn1.h"
|
2010-03-04 08:14:36 +00:00
|
|
|
#include "cardctl.h"
|
2007-12-17 13:39:20 +00:00
|
|
|
|
|
|
|
struct auth_senv {
|
|
|
|
unsigned int algorithm;
|
|
|
|
};
|
|
|
|
typedef struct auth_senv auth_senv_t;
|
|
|
|
|
2009-01-28 12:10:13 +00:00
|
|
|
struct helper_acl_to_sec_attr
|
|
|
|
{
|
|
|
|
unsigned int ac_op;
|
|
|
|
size_t sec_attr_pos;
|
|
|
|
};
|
|
|
|
typedef struct helper_acl_to_sec_attr helper_acl_to_sec_attr_t;
|
|
|
|
|
|
|
|
static const helper_acl_to_sec_attr_t arr_convert_attr_df [] = {
|
|
|
|
{ SC_AC_OP_CREATE, 0 },
|
|
|
|
{ SC_AC_OP_CREATE, 1 },
|
|
|
|
{ SC_AC_OP_DELETE, 6 }
|
|
|
|
};
|
|
|
|
|
|
|
|
static const helper_acl_to_sec_attr_t arr_convert_attr_ef [] = {
|
|
|
|
{ SC_AC_OP_READ, 0 },
|
|
|
|
{ SC_AC_OP_UPDATE, 1 },
|
|
|
|
{ SC_AC_OP_WRITE, 1 },
|
|
|
|
{ SC_AC_OP_DELETE, 6 }
|
|
|
|
};
|
|
|
|
|
2007-12-17 13:39:20 +00:00
|
|
|
static const sc_SecAttrV2_t default_sec_attr = {
|
2008-01-03 08:59:14 +00:00
|
|
|
0x42,
|
|
|
|
0, 1, 0, 0, 0, 0, 1,
|
2009-11-23 16:38:02 +00:00
|
|
|
0, 0, 0, 0,
|
|
|
|
2, 0, 0, 0,
|
|
|
|
0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0,
|
|
|
|
2, 0, 0, 0,
|
|
|
|
0, 0, 0, 0 /* reserve */
|
2007-12-17 13:39:20 +00:00
|
|
|
};
|
|
|
|
|
2009-11-23 16:38:02 +00:00
|
|
|
static const struct sc_card_operations *iso_ops = NULL;
|
2008-01-03 08:59:14 +00:00
|
|
|
static struct sc_card_operations rutoken_ops;
|
|
|
|
|
2007-12-17 13:39:20 +00:00
|
|
|
static struct sc_card_driver rutoken_drv = {
|
2008-04-18 14:08:23 +00:00
|
|
|
"Rutoken driver",
|
2007-12-17 13:39:20 +00:00
|
|
|
"rutoken",
|
|
|
|
&rutoken_ops,
|
|
|
|
NULL, 0, NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct sc_atr_table rutoken_atrs[] = {
|
2009-11-13 09:45:21 +00:00
|
|
|
{ "3b:6f:00:ff:00:56:72:75:54:6f:6b:6e:73:30:20:00:00:90:00", NULL, NULL, SC_CARD_TYPE_GENERIC_BASE, 0, NULL }, /* Aktiv Rutoken S */
|
|
|
|
{ "3b:6f:00:ff:00:56:75:61:54:6f:6b:6e:73:30:20:00:00:90:00", NULL, NULL, SC_CARD_TYPE_GENERIC_BASE, 0, NULL }, /* Aktiv uaToken S */
|
2007-12-17 13:39:20 +00:00
|
|
|
{ NULL, NULL, NULL, 0, 0, NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
static int rutoken_finish(sc_card_t *card)
|
|
|
|
{
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
|
2009-11-23 16:38:02 +00:00
|
|
|
assert(card->drv_data);
|
2007-12-17 13:39:20 +00:00
|
|
|
free(card->drv_data);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_SUCCESS);
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int rutoken_match_card(sc_card_t *card)
|
|
|
|
{
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
|
2008-04-18 14:08:23 +00:00
|
|
|
if (_sc_match_atr(card, rutoken_atrs, &card->type) >= 0)
|
|
|
|
{
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "ATR recognized as Rutoken\n");
|
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, 1);
|
2008-04-18 14:08:23 +00:00
|
|
|
}
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, 0);
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
|
|
|
|
2008-04-18 14:08:23 +00:00
|
|
|
static int token_init(sc_card_t *card, const char *card_name)
|
2007-12-17 13:39:20 +00:00
|
|
|
{
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_NORMAL);
|
2008-01-03 08:59:14 +00:00
|
|
|
|
2008-04-18 14:08:23 +00:00
|
|
|
card->name = card_name;
|
2010-09-09 17:28:44 +00:00
|
|
|
card->caps |= SC_CARD_CAP_NO_FCI | SC_CARD_CAP_RNG;
|
2008-04-18 14:08:23 +00:00
|
|
|
card->drv_data = calloc(1, sizeof(auth_senv_t));
|
|
|
|
if (card->drv_data == NULL)
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_OUT_OF_MEMORY);
|
2007-12-17 13:39:20 +00:00
|
|
|
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS);
|
2008-04-18 14:08:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int rutoken_init(sc_card_t *card)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
|
2009-11-13 09:45:21 +00:00
|
|
|
/* &rutoken_atrs[1] : { uaToken S ATR, NULL ATR } */
|
|
|
|
if (_sc_match_atr(card, &rutoken_atrs[1], &card->type) >= 0)
|
|
|
|
ret = token_init(card, "uaToken S card");
|
|
|
|
else
|
|
|
|
ret = token_init(card, "Rutoken S card");
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, ret);
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static const struct sc_card_error rutoken_errors[] = {
|
|
|
|
|
2008-04-18 14:08:23 +00:00
|
|
|
{ 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"},
|
2007-12-17 13:39:20 +00:00
|
|
|
|
2008-04-18 14:08:23 +00:00
|
|
|
{ 0x6400, SC_ERROR_CARD_CMD_FAILED, "Aborting"},
|
2007-12-17 13:39:20 +00:00
|
|
|
|
2008-04-18 14:08:23 +00:00
|
|
|
{ 0x6500, SC_ERROR_MEMORY_FAILURE, "Memory failure"},
|
|
|
|
{ 0x6581, SC_ERROR_MEMORY_FAILURE, "Memory failure"},
|
2007-12-17 13:39:20 +00:00
|
|
|
|
2008-04-18 14:08:23 +00:00
|
|
|
{ 0x6700, SC_ERROR_WRONG_LENGTH, "Lc or Le invalid"},
|
2007-12-17 13:39:20 +00:00
|
|
|
|
2008-04-18 14:08:23 +00:00
|
|
|
{ 0x6883, SC_ERROR_CARD_CMD_FAILED, "The finishing command of a chain is expected"},
|
2007-12-17 13:39:20 +00:00
|
|
|
|
2008-04-18 14:08:23 +00:00
|
|
|
{ 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"},
|
2007-12-17 13:39:20 +00:00
|
|
|
|
2008-04-18 14:08:23 +00:00
|
|
|
{ 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"},
|
2007-12-17 13:39:20 +00:00
|
|
|
|
2008-04-18 14:08:23 +00:00
|
|
|
{ 0x6B00, SC_ERROR_INCORRECT_PARAMETERS,"Out of maximum file length"},
|
2007-12-17 13:39:20 +00:00
|
|
|
|
2008-04-18 14:08:23 +00:00
|
|
|
{ 0x6C00, SC_ERROR_WRONG_LENGTH, "Le does not fit the data to be sent"},
|
2007-12-17 13:39:20 +00:00
|
|
|
|
2008-04-18 14:08:23 +00:00
|
|
|
{ 0x6D00, SC_ERROR_INS_NOT_SUPPORTED, "Ins invalid (not supported)"},
|
2007-12-17 13:39:20 +00:00
|
|
|
|
|
|
|
/* Own class of an error*/
|
2008-04-18 14:08:23 +00:00
|
|
|
{ 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"},
|
2007-12-17 13:39:20 +00:00
|
|
|
|
2010-12-16 05:04:37 +00:00
|
|
|
{ 0x9000, SC_SUCCESS, NULL}
|
2007-12-17 13:39:20 +00:00
|
|
|
};
|
|
|
|
|
2008-04-18 14:08:23 +00:00
|
|
|
static int rutoken_check_sw(sc_card_t *card, unsigned int sw1, unsigned int sw2)
|
2007-12-17 13:39:20 +00:00
|
|
|
{
|
2008-04-18 14:08:23 +00:00
|
|
|
size_t i;
|
2007-12-17 13:39:20 +00:00
|
|
|
|
2008-04-18 14:08:23 +00:00
|
|
|
for (i = 0; i < sizeof(rutoken_errors)/sizeof(rutoken_errors[0]); ++i) {
|
2007-12-17 13:39:20 +00:00
|
|
|
if (rutoken_errors[i].SWs == ((sw1 << 8) | sw2)) {
|
2008-01-03 08:59:14 +00:00
|
|
|
if ( rutoken_errors[i].errorstr )
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "%s\n", rutoken_errors[i].errorstr);
|
|
|
|
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "sw1 = %x, sw2 = %x", sw1, sw2);
|
2007-12-17 13:39:20 +00:00
|
|
|
return rutoken_errors[i].errorno;
|
|
|
|
}
|
|
|
|
}
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Unknown SWs; SW1=%02X, SW2=%02X\n", sw1, sw2);
|
2008-04-18 14:08:23 +00:00
|
|
|
return SC_ERROR_CARD_CMD_FAILED;
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
|
|
|
|
2009-11-23 16:38:02 +00:00
|
|
|
static void swap_pair(u8 *buf, size_t len)
|
2007-12-17 13:39:20 +00:00
|
|
|
{
|
2009-11-23 16:38:02 +00:00
|
|
|
size_t i;
|
|
|
|
u8 tmp;
|
2007-12-17 13:39:20 +00:00
|
|
|
|
2009-11-23 16:38:02 +00:00
|
|
|
for (i = 0; i + 1 < len; i += 2)
|
|
|
|
{
|
|
|
|
tmp = buf[i];
|
|
|
|
buf[i] = buf[i + 1];
|
|
|
|
buf[i + 1] = tmp;
|
|
|
|
}
|
|
|
|
}
|
2008-04-18 14:08:23 +00:00
|
|
|
|
2009-11-23 16:38:02 +00:00
|
|
|
static void swap_four(u8 *buf, size_t len)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
u8 tmp;
|
2008-04-18 14:08:23 +00:00
|
|
|
|
2009-11-23 16:38:02 +00:00
|
|
|
for (i = 0; i + 3 < len; i += 4)
|
|
|
|
{
|
|
|
|
tmp = buf[i];
|
|
|
|
buf[i] = buf[i + 3];
|
|
|
|
buf[i + 3] = tmp;
|
|
|
|
swap_pair(&buf[i + 1], 2);
|
|
|
|
}
|
2008-01-03 08:59:14 +00:00
|
|
|
}
|
2007-12-17 13:39:20 +00:00
|
|
|
|
|
|
|
static int rutoken_list_files(sc_card_t *card, u8 *buf, size_t buflen)
|
|
|
|
{
|
|
|
|
sc_apdu_t apdu;
|
2009-11-23 16:38:02 +00:00
|
|
|
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE], previd[2];
|
|
|
|
const u8 *tag;
|
|
|
|
size_t taglen, len = 0;
|
|
|
|
int ret;
|
2008-04-07 19:25:21 +00:00
|
|
|
|
2009-11-23 16:38:02 +00:00
|
|
|
assert(card && card->ctx);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
|
2009-11-23 16:38:02 +00:00
|
|
|
assert(buf);
|
|
|
|
|
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xA4, 0, 0);
|
|
|
|
for (;;)
|
2008-01-03 08:59:14 +00:00
|
|
|
{
|
2008-04-18 14:08:23 +00:00
|
|
|
apdu.resp = rbuf;
|
2009-11-23 16:38:02 +00:00
|
|
|
apdu.resplen = sizeof(rbuf);
|
2011-03-11 17:57:46 +00:00
|
|
|
apdu.le = 256;
|
2008-04-18 14:08:23 +00:00
|
|
|
ret = sc_transmit_apdu(card, &apdu);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "APDU transmit failed");
|
2008-04-18 14:08:23 +00:00
|
|
|
if (apdu.sw1 == 0x6A && apdu.sw2 == 0x82)
|
2009-11-23 16:38:02 +00:00
|
|
|
break; /* Next file not found */
|
2008-04-18 14:08:23 +00:00
|
|
|
|
|
|
|
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "");
|
2009-11-23 16:38:02 +00:00
|
|
|
|
|
|
|
if (apdu.resplen <= 2)
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_WRONG_LENGTH);
|
2009-11-23 16:38:02 +00:00
|
|
|
|
|
|
|
/* save first file(dir) ID */
|
|
|
|
tag = sc_asn1_find_tag(card->ctx, apdu.resp + 2, apdu.resplen - 2,
|
|
|
|
0x83, &taglen);
|
|
|
|
if (!tag || taglen != sizeof(previd))
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_UNKNOWN_DATA_RECEIVED);
|
2009-11-23 16:38:02 +00:00
|
|
|
memcpy(previd, tag, sizeof(previd));
|
|
|
|
|
|
|
|
if (len + sizeof(previd) <= buflen)
|
|
|
|
{
|
|
|
|
buf[len++] = previd[1];
|
|
|
|
buf[len++] = previd[0];
|
|
|
|
}
|
2008-04-18 14:08:23 +00:00
|
|
|
|
2009-11-23 16:38:02 +00:00
|
|
|
tag = sc_asn1_find_tag(card->ctx, apdu.resp + 2, apdu.resplen - 2,
|
|
|
|
0x82, &taglen);
|
|
|
|
if (!tag || taglen != 2)
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_UNKNOWN_DATA_RECEIVED);
|
2009-11-23 16:38:02 +00:00
|
|
|
if (tag[0] == 0x38)
|
2008-04-18 14:08:23 +00:00
|
|
|
{
|
2009-11-23 16:38:02 +00:00
|
|
|
/* Select parent DF of the current DF */
|
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xA4, 0x03, 0);
|
|
|
|
apdu.resp = rbuf;
|
|
|
|
apdu.resplen = sizeof(rbuf);
|
2011-03-11 17:57:46 +00:00
|
|
|
apdu.le = 256;
|
2009-11-23 16:38:02 +00:00
|
|
|
ret = sc_transmit_apdu(card, &apdu);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "APDU transmit failed");
|
2009-11-23 16:38:02 +00:00
|
|
|
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "");
|
2008-04-18 14:08:23 +00:00
|
|
|
}
|
2009-11-23 16:38:02 +00:00
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0, 0x02);
|
|
|
|
apdu.lc = sizeof(previd);
|
|
|
|
apdu.data = previd;
|
|
|
|
apdu.datalen = sizeof(previd);
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, len);
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
|
|
|
|
2009-11-23 16:38:02 +00:00
|
|
|
static void set_acl_from_sec_attr(sc_card_t *card, sc_file_t *file)
|
2007-12-17 13:39:20 +00:00
|
|
|
{
|
2009-11-23 16:38:02 +00:00
|
|
|
if (file->sec_attr && file->sec_attr_len == sizeof(sc_SecAttrV2_t))
|
2008-04-18 14:08:23 +00:00
|
|
|
{
|
|
|
|
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 */
|
|
|
|
{
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "SC_AC_OP_DELETE %i %i",
|
2008-04-18 14:08:23 +00:00
|
|
|
(int)(*(int8_t*)&file->sec_attr[1 +6]),
|
2009-11-23 16:38:02 +00:00
|
|
|
file->sec_attr[1+7 +6*4]);
|
2008-04-18 14:08:23 +00:00
|
|
|
sc_file_add_acl_entry(file, SC_AC_OP_DELETE,
|
|
|
|
(int)(*(int8_t*)&file->sec_attr[1 +6]),
|
2009-11-23 16:38:02 +00:00
|
|
|
file->sec_attr[1+7 +6*4]);
|
2008-04-18 14:08:23 +00:00
|
|
|
}
|
|
|
|
if (file->sec_attr[0] & 0x01) /* if AccessMode.0 */
|
|
|
|
{
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, (file->type == SC_FILE_TYPE_DF) ?
|
2008-04-18 14:08:23 +00:00
|
|
|
"SC_AC_OP_CREATE %i %i" : "SC_AC_OP_READ %i %i",
|
|
|
|
(int)(*(int8_t*)&file->sec_attr[1 +0]),
|
2009-11-23 16:38:02 +00:00
|
|
|
file->sec_attr[1+7 +0*4]);
|
2008-04-18 14:08:23 +00:00
|
|
|
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]),
|
2009-11-23 16:38:02 +00:00
|
|
|
file->sec_attr[1+7 +0*4]);
|
2008-04-18 14:08:23 +00:00
|
|
|
}
|
|
|
|
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 */
|
|
|
|
{
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "SC_AC_OP_UPDATE %i %i",
|
2008-04-18 14:08:23 +00:00
|
|
|
(int)(*(int8_t*)&file->sec_attr[1 +1]),
|
2009-11-23 16:38:02 +00:00
|
|
|
file->sec_attr[1+7 +1*4]);
|
2008-04-18 14:08:23 +00:00
|
|
|
sc_file_add_acl_entry(file, SC_AC_OP_UPDATE,
|
|
|
|
(int)(*(int8_t*)&file->sec_attr[1 +1]),
|
2009-11-23 16:38:02 +00:00
|
|
|
file->sec_attr[1+7 +1*4]);
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "SC_AC_OP_WRITE %i %i",
|
2008-04-18 14:08:23 +00:00
|
|
|
(int)(*(int8_t*)&file->sec_attr[1 +1]),
|
2009-11-23 16:38:02 +00:00
|
|
|
file->sec_attr[1+7 +1*4]);
|
2008-04-18 14:08:23 +00:00
|
|
|
sc_file_add_acl_entry(file, SC_AC_OP_WRITE,
|
|
|
|
(int)(*(int8_t*)&file->sec_attr[1 +1]),
|
2009-11-23 16:38:02 +00:00
|
|
|
file->sec_attr[1+7 +1*4]);
|
2008-04-18 14:08:23 +00:00
|
|
|
}
|
|
|
|
}
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int rutoken_select_file(sc_card_t *card,
|
2009-11-23 16:38:02 +00:00
|
|
|
const sc_path_t *in_path, sc_file_t **file_out)
|
2007-12-17 13:39:20 +00:00
|
|
|
{
|
|
|
|
sc_apdu_t apdu;
|
2009-11-23 16:38:02 +00:00
|
|
|
u8 buf[SC_MAX_APDU_BUFFER_SIZE], pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf;
|
|
|
|
sc_file_t *file = NULL;
|
|
|
|
size_t pathlen;
|
|
|
|
u8 t0, t1;
|
|
|
|
int ret;
|
2007-12-17 13:39:20 +00:00
|
|
|
|
2009-11-23 16:38:02 +00:00
|
|
|
assert(card && card->ctx);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
|
2007-12-17 13:39:20 +00:00
|
|
|
|
2009-11-23 16:38:02 +00:00
|
|
|
assert(in_path && sizeof(pathbuf) >= in_path->len);
|
|
|
|
memcpy(path, in_path->value, in_path->len);
|
2008-04-18 14:08:23 +00:00
|
|
|
pathlen = in_path->len;
|
|
|
|
|
2009-11-23 16:38:02 +00:00
|
|
|
/* p2 = 0; first record, return FCP */
|
2008-04-18 14:08:23 +00:00
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0, 0);
|
|
|
|
switch (in_path->type)
|
2007-12-17 13:39:20 +00:00
|
|
|
{
|
2008-04-18 14:08:23 +00:00
|
|
|
case SC_PATH_TYPE_FILE_ID:
|
2009-11-23 16:38:02 +00:00
|
|
|
if (pathlen != 2)
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INVALID_ARGUMENTS);
|
2008-04-18 14:08:23 +00:00
|
|
|
break;
|
|
|
|
case SC_PATH_TYPE_PATH:
|
2009-11-23 16:38:02 +00:00
|
|
|
if (pathlen >= 2 && memcmp(path, "\x3F\x00", 2) == 0)
|
2007-12-17 13:39:20 +00:00
|
|
|
{
|
2009-11-23 16:38:02 +00:00
|
|
|
if (pathlen == 2)
|
|
|
|
break; /* only 3F00 supplied */
|
|
|
|
path += 2;
|
|
|
|
pathlen -= 2;
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
2009-11-23 16:38:02 +00:00
|
|
|
apdu.p1 = 0x08;
|
2008-04-18 14:08:23 +00:00
|
|
|
break;
|
2009-11-23 16:38:02 +00:00
|
|
|
case SC_PATH_TYPE_DF_NAME:
|
|
|
|
case SC_PATH_TYPE_FROM_CURRENT:
|
|
|
|
case SC_PATH_TYPE_PARENT:
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_NOT_SUPPORTED);
|
2008-04-18 14:08:23 +00:00
|
|
|
default:
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INVALID_ARGUMENTS);
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
2009-11-23 16:38:02 +00:00
|
|
|
swap_pair(path, pathlen);
|
|
|
|
apdu.lc = pathlen;
|
|
|
|
apdu.data = path;
|
|
|
|
apdu.datalen = pathlen;
|
|
|
|
|
|
|
|
apdu.resp = buf;
|
|
|
|
apdu.resplen = sizeof(buf);
|
2011-03-11 17:57:46 +00:00
|
|
|
apdu.le = 256;
|
2009-11-23 16:38:02 +00:00
|
|
|
|
|
|
|
ret = sc_transmit_apdu(card, &apdu);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "APDU transmit failed");
|
2009-11-23 16:38:02 +00:00
|
|
|
if (file_out == NULL)
|
2007-12-17 13:39:20 +00:00
|
|
|
{
|
2009-11-23 16:38:02 +00:00
|
|
|
if (apdu.sw1 == 0x61)
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, 0);
|
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));
|
2009-11-23 16:38:02 +00:00
|
|
|
}
|
|
|
|
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "");
|
2007-12-17 13:39:20 +00:00
|
|
|
|
2009-11-23 16:38:02 +00:00
|
|
|
if (apdu.resplen > 0 && apdu.resp[0] != 0x62) /* Tag 0x62 - FCP */
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_UNKNOWN_DATA_RECEIVED);
|
2009-11-23 16:38:02 +00:00
|
|
|
|
|
|
|
file = sc_file_new();
|
|
|
|
if (file == NULL)
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY);
|
2009-11-23 16:38:02 +00:00
|
|
|
file->path = *in_path;
|
|
|
|
if (card->ops->process_fci == NULL)
|
|
|
|
{
|
|
|
|
sc_file_free(file);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_NOT_SUPPORTED);
|
2009-11-23 16:38:02 +00:00
|
|
|
}
|
|
|
|
if (apdu.resplen > 1 && apdu.resplen >= (size_t)apdu.resp[1] + 2)
|
|
|
|
{
|
|
|
|
ret = card->ops->process_fci(card, file, apdu.resp+2, apdu.resp[1]);
|
|
|
|
if (ret == SC_SUCCESS)
|
2008-04-18 14:08:23 +00:00
|
|
|
{
|
2009-11-23 16:38:02 +00:00
|
|
|
t0 = file->id & 0xFF;
|
|
|
|
t1 = (file->id >> 8) & 0xFF;
|
|
|
|
file->id = (t0 << 8) | t1;
|
|
|
|
t0 = file->size & 0xFF;
|
|
|
|
t1 = (file->size >> 8) & 0xFF;
|
|
|
|
file->size = (t0 << 8) | t1;
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
|
|
|
}
|
2009-11-23 16:38:02 +00:00
|
|
|
if (file->sec_attr && file->sec_attr_len == sizeof(sc_SecAttrV2_t))
|
|
|
|
set_acl_from_sec_attr(card, file);
|
|
|
|
else
|
|
|
|
ret = SC_ERROR_UNKNOWN_DATA_RECEIVED;
|
|
|
|
if (ret != SC_SUCCESS)
|
|
|
|
sc_file_free(file);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
assert(file_out);
|
|
|
|
*file_out = file;
|
|
|
|
}
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, ret);
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
|
|
|
|
2009-11-23 16:38:02 +00:00
|
|
|
static int rutoken_construct_fci(sc_card_t *card, const sc_file_t *file,
|
|
|
|
u8 *out, size_t *outlen)
|
2007-12-17 13:39:20 +00:00
|
|
|
{
|
2009-11-23 16:38:02 +00:00
|
|
|
u8 buf[64], *p = out;
|
|
|
|
|
|
|
|
assert(card && card->ctx);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_NORMAL);
|
2008-04-18 14:08:23 +00:00
|
|
|
|
2009-11-23 16:38:02 +00:00
|
|
|
assert(file && out && outlen);
|
|
|
|
assert(*outlen >= (size_t)(p - out) + 2);
|
|
|
|
*p++ = 0x62; /* FCP template */
|
|
|
|
p++; /* for length */
|
|
|
|
|
|
|
|
/* 0x80 - Number of data bytes in the file, excluding structural information */
|
|
|
|
buf[1] = (file->size >> 8) & 0xFF;
|
|
|
|
buf[0] = file->size & 0xFF;
|
|
|
|
sc_asn1_put_tag(0x80, buf, 2, p, *outlen - (p - out), &p);
|
|
|
|
|
|
|
|
/* 0x82 - File descriptor byte */
|
|
|
|
if (file->type_attr_len)
|
2007-12-17 13:39:20 +00:00
|
|
|
{
|
2009-11-23 16:38:02 +00:00
|
|
|
assert(sizeof(buf) >= file->type_attr_len);
|
|
|
|
memcpy(buf, file->type_attr, file->type_attr_len);
|
|
|
|
sc_asn1_put_tag(0x82, buf, file->type_attr_len,
|
|
|
|
p, *outlen - (p - out), &p);
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
|
|
|
else
|
2009-01-28 12:10:13 +00:00
|
|
|
{
|
2009-11-23 16:38:02 +00:00
|
|
|
switch (file->type)
|
|
|
|
{
|
|
|
|
case SC_FILE_TYPE_WORKING_EF:
|
|
|
|
buf[0] = 0x01;
|
|
|
|
break;
|
|
|
|
case SC_FILE_TYPE_DF:
|
|
|
|
buf[0] = 0x38;
|
|
|
|
break;
|
|
|
|
case SC_FILE_TYPE_INTERNAL_EF:
|
|
|
|
default:
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_NOT_SUPPORTED);
|
2009-11-23 16:38:02 +00:00
|
|
|
}
|
|
|
|
buf[1] = 0;
|
|
|
|
sc_asn1_put_tag(0x82, buf, 2, p, *outlen - (p - out), &p);
|
2009-01-28 12:10:13 +00:00
|
|
|
}
|
2009-11-23 16:38:02 +00:00
|
|
|
/* 0x83 - File identifier */
|
|
|
|
buf[1] = (file->id >> 8) & 0xFF;
|
|
|
|
buf[0] = file->id & 0xFF;
|
|
|
|
sc_asn1_put_tag(0x83, buf, 2, p, *outlen - (p - out), &p);
|
|
|
|
|
|
|
|
if (file->prop_attr_len)
|
|
|
|
{
|
|
|
|
assert(sizeof(buf) >= file->prop_attr_len);
|
|
|
|
memcpy(buf, file->prop_attr, file->prop_attr_len);
|
|
|
|
sc_asn1_put_tag(0x85, buf, file->prop_attr_len,
|
|
|
|
p, *outlen - (p - out), &p);
|
|
|
|
}
|
|
|
|
if (file->sec_attr_len)
|
|
|
|
{
|
|
|
|
assert(sizeof(buf) >= file->sec_attr_len);
|
|
|
|
memcpy(buf, file->sec_attr, file->sec_attr_len);
|
|
|
|
sc_asn1_put_tag(0x86, buf, file->sec_attr_len,
|
|
|
|
p, *outlen - (p - out), &p);
|
|
|
|
}
|
|
|
|
out[1] = p - out - 2; /* length */
|
|
|
|
*outlen = p - out;
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, 0);
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
|
|
|
|
2009-01-28 12:10:13 +00:00
|
|
|
static int set_sec_attr_from_acl(sc_card_t *card, sc_file_t *file)
|
|
|
|
{
|
|
|
|
const helper_acl_to_sec_attr_t *conv_attr;
|
|
|
|
size_t i, n_conv_attr;
|
|
|
|
const sc_acl_entry_t *entry;
|
|
|
|
sc_SecAttrV2_t attr = { 0 };
|
2010-12-16 05:04:37 +00:00
|
|
|
int ret = SC_SUCCESS;
|
2009-01-28 12:10:13 +00:00
|
|
|
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_NORMAL);
|
2009-01-28 12:10:13 +00:00
|
|
|
|
|
|
|
if (file->type == SC_FILE_TYPE_DF)
|
|
|
|
{
|
|
|
|
conv_attr = arr_convert_attr_df;
|
|
|
|
n_conv_attr = sizeof(arr_convert_attr_df)/sizeof(arr_convert_attr_df[0]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
conv_attr = arr_convert_attr_ef;
|
|
|
|
n_conv_attr = sizeof(arr_convert_attr_ef)/sizeof(arr_convert_attr_ef[0]);
|
|
|
|
}
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "file->type = %i", file->type);
|
2009-01-28 12:10:13 +00:00
|
|
|
|
|
|
|
for (i = 0; i < n_conv_attr; ++i)
|
|
|
|
{
|
|
|
|
entry = sc_file_get_acl_entry(file, conv_attr[i].ac_op);
|
|
|
|
if (entry && (entry->method == SC_AC_CHV || entry->method == SC_AC_NONE
|
|
|
|
|| entry->method == SC_AC_NEVER)
|
|
|
|
)
|
|
|
|
{
|
|
|
|
/* AccessMode.[conv_attr[i].sec_attr_pos] */
|
|
|
|
attr[0] |= 1 << conv_attr[i].sec_attr_pos;
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "AccessMode.%u, attr[0]=0x%x",
|
2009-01-28 12:10:13 +00:00
|
|
|
conv_attr[i].sec_attr_pos, attr[0]);
|
|
|
|
attr[1 + conv_attr[i].sec_attr_pos] = (u8)entry->method;
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "method %u", (u8)entry->method);
|
2009-01-28 12:10:13 +00:00
|
|
|
if (entry->method == SC_AC_CHV)
|
|
|
|
{
|
2009-11-23 16:38:02 +00:00
|
|
|
attr[1+7 + conv_attr[i].sec_attr_pos*4] = (u8)entry->key_ref;
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "key_ref %u", (u8)entry->key_ref);
|
2009-01-28 12:10:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "ACL (%u) not set, set default sec_attr",
|
2009-11-23 16:38:02 +00:00
|
|
|
conv_attr[i].ac_op);
|
|
|
|
memcpy(attr, default_sec_attr, sizeof(attr));
|
2009-01-28 12:10:13 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2009-11-23 16:38:02 +00:00
|
|
|
ret = sc_file_set_sec_attr(file, attr, sizeof(attr));
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, ret);
|
2009-01-28 12:10:13 +00:00
|
|
|
}
|
|
|
|
|
2007-12-17 13:39:20 +00:00
|
|
|
static int rutoken_create_file(sc_card_t *card, sc_file_t *file)
|
|
|
|
{
|
2008-04-18 14:08:23 +00:00
|
|
|
int ret;
|
|
|
|
|
2009-11-23 16:38:02 +00:00
|
|
|
assert(card && card->ctx);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
|
2009-01-28 12:10:13 +00:00
|
|
|
|
2009-11-23 16:38:02 +00:00
|
|
|
assert(file);
|
|
|
|
if (file->sec_attr_len == 0)
|
2007-12-17 13:39:20 +00:00
|
|
|
{
|
2009-11-23 16:38:02 +00:00
|
|
|
ret = set_sec_attr_from_acl(card, file);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "Set sec_attr from ACL failed");
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
2009-11-23 16:38:02 +00:00
|
|
|
assert(iso_ops && iso_ops->create_file);
|
|
|
|
ret = iso_ops->create_file(card, file);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, ret);
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int rutoken_delete_file(sc_card_t *card, const sc_path_t *path)
|
|
|
|
{
|
|
|
|
u8 sbuf[2];
|
|
|
|
sc_apdu_t apdu;
|
2008-04-18 14:08:23 +00:00
|
|
|
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
|
2007-12-17 13:39:20 +00:00
|
|
|
if (!path || path->type != SC_PATH_TYPE_FILE_ID || (path->len != 0 && path->len != 2))
|
|
|
|
{
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "File type has to be SC_PATH_TYPE_FILE_ID\n");
|
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INVALID_ARGUMENTS);
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
2008-04-18 14:08:23 +00:00
|
|
|
if (path->len == sizeof(sbuf))
|
2007-12-17 13:39:20 +00:00
|
|
|
{
|
2009-11-23 16:38:02 +00:00
|
|
|
sbuf[1] = path->value[0];
|
|
|
|
sbuf[0] = path->value[1];
|
2007-12-17 13:39:20 +00:00
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE4, 0x00, 0x00);
|
2008-04-18 14:08:23 +00:00
|
|
|
apdu.lc = sizeof(sbuf);
|
|
|
|
apdu.datalen = sizeof(sbuf);
|
2007-12-17 13:39:20 +00:00
|
|
|
apdu.data = sbuf;
|
|
|
|
}
|
|
|
|
else /* No file ID given: means currently selected file */
|
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0xE4, 0x00, 0x00);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, sc_transmit_apdu(card, &apdu), "APDU transmit failed");
|
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, sc_check_sw(card, apdu.sw1, apdu.sw2));
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
|
|
|
|
2008-01-03 08:59:14 +00:00
|
|
|
static int rutoken_verify(sc_card_t *card, unsigned int type, int ref_qualifier,
|
|
|
|
const u8 *data, size_t data_len, int *tries_left)
|
|
|
|
{
|
|
|
|
sc_apdu_t apdu;
|
2008-04-18 14:08:23 +00:00
|
|
|
int ret;
|
2008-01-03 08:59:14 +00:00
|
|
|
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
|
2008-04-18 14:08:23 +00:00
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x20, 0x00, ref_qualifier);
|
|
|
|
ret = sc_transmit_apdu(card, &apdu);
|
2009-01-28 12:10:13 +00:00
|
|
|
if (ret == SC_SUCCESS && ((apdu.sw1 == 0x90 && apdu.sw2 == 0x00)
|
|
|
|
|| apdu.sw1 == 0x63)
|
|
|
|
)
|
2008-04-18 14:08:23 +00:00
|
|
|
{
|
2009-01-28 12:10:13 +00:00
|
|
|
/* sw1 == 0x63 - may be already login with other ref_qualifier
|
|
|
|
* sw1 == 0x90 && sw2 == 0x00 - already login with ref_qualifier
|
|
|
|
*/
|
2008-04-18 14:08:23 +00:00
|
|
|
/* RESET ACCESS RIGHTS */
|
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x40, 0x00, 0x00);
|
|
|
|
apdu.cla = 0x80;
|
|
|
|
ret = sc_transmit_apdu(card, &apdu);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "APDU transmit failed");
|
2008-04-18 14:08:23 +00:00
|
|
|
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "Reset access rights failed");
|
2008-04-18 14:08:23 +00:00
|
|
|
}
|
|
|
|
|
2008-01-03 08:59:14 +00:00
|
|
|
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;
|
2008-04-18 14:08:23 +00:00
|
|
|
ret = sc_transmit_apdu(card, &apdu);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "APDU transmit failed");
|
2008-04-18 14:08:23 +00:00
|
|
|
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
|
|
|
if (ret == SC_ERROR_PIN_CODE_INCORRECT && tries_left)
|
2008-01-03 08:59:14 +00:00
|
|
|
{
|
2008-04-18 14:08:23 +00:00
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x20, 0x00, ref_qualifier);
|
|
|
|
ret = sc_transmit_apdu(card, &apdu);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "APDU transmit failed");
|
2008-04-18 14:08:23 +00:00
|
|
|
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
|
|
|
if (ret == SC_ERROR_PIN_CODE_INCORRECT)
|
|
|
|
*tries_left = (int)(apdu.sw2 & 0x0f);
|
2008-01-03 08:59:14 +00:00
|
|
|
}
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, ret);
|
2008-01-03 08:59:14 +00:00
|
|
|
}
|
|
|
|
|
2007-12-17 13:39:20 +00:00
|
|
|
static int rutoken_logout(sc_card_t *card)
|
|
|
|
{
|
|
|
|
sc_apdu_t apdu;
|
|
|
|
sc_path_t path;
|
2008-04-18 14:08:23 +00:00
|
|
|
int ret;
|
2007-12-17 13:39:20 +00:00
|
|
|
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
|
2007-12-17 13:39:20 +00:00
|
|
|
sc_format_path("3F00", &path);
|
2008-04-18 14:08:23 +00:00
|
|
|
ret = rutoken_select_file(card, &path, NULL);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "Select MF failed");
|
2008-04-18 14:08:23 +00:00
|
|
|
|
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x40, 0x00, 0x00);
|
|
|
|
apdu.cla = 0x80;
|
|
|
|
ret = sc_transmit_apdu(card, &apdu);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "APDU transmit failed");
|
2008-04-18 14:08:23 +00:00
|
|
|
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, ret);
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
|
|
|
|
2008-01-03 08:59:14 +00:00
|
|
|
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)
|
2007-12-17 13:39:20 +00:00
|
|
|
{
|
|
|
|
sc_apdu_t apdu;
|
2008-04-18 14:08:23 +00:00
|
|
|
int ret;
|
2008-01-03 08:59:14 +00:00
|
|
|
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
|
2008-04-18 14:08:23 +00:00
|
|
|
if (old && oldlen)
|
2008-01-03 08:59:14 +00:00
|
|
|
{
|
2008-04-18 14:08:23 +00:00
|
|
|
ret = rutoken_verify(card, type, ref_qualifier, old, oldlen, tries_left);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "Invalid 'old' pass");
|
2008-01-03 08:59:14 +00:00
|
|
|
}
|
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x24, 0x01, ref_qualifier);
|
|
|
|
apdu.lc = newlen;
|
|
|
|
apdu.datalen = newlen;
|
|
|
|
apdu.data = newref;
|
2008-04-18 14:08:23 +00:00
|
|
|
ret = sc_transmit_apdu(card, &apdu);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "APDU transmit failed");
|
2008-04-18 14:08:23 +00:00
|
|
|
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, ret);
|
2008-01-03 08:59:14 +00:00
|
|
|
}
|
2007-12-17 13:39:20 +00:00
|
|
|
|
2008-01-03 08:59:14 +00:00
|
|
|
static int rutoken_reset_retry_counter(sc_card_t *card, unsigned int type,
|
|
|
|
int ref_qualifier, const u8 *puk, size_t puklen,
|
|
|
|
const u8 *newref, size_t newlen)
|
|
|
|
{
|
|
|
|
#ifdef FORCE_VERIFY_RUTOKEN
|
|
|
|
int left;
|
|
|
|
#endif
|
|
|
|
sc_apdu_t apdu;
|
2008-04-18 14:08:23 +00:00
|
|
|
int ret;
|
2008-01-03 08:59:14 +00:00
|
|
|
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
|
2008-01-03 08:59:14 +00:00
|
|
|
#ifdef FORCE_VERIFY_RUTOKEN
|
2008-04-18 14:08:23 +00:00
|
|
|
if (puk && puklen)
|
2008-01-03 08:59:14 +00:00
|
|
|
{
|
2008-04-18 14:08:23 +00:00
|
|
|
ret = rutoken_verify(card, type, ref_qualifier, puk, puklen, &left);
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Tries left: %i\n", left);
|
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "Invalid 'puk' pass");
|
2008-01-03 08:59:14 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x2c, 0x03, ref_qualifier);
|
2008-04-18 14:08:23 +00:00
|
|
|
ret = sc_transmit_apdu(card, &apdu);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "APDU transmit failed");
|
2008-04-18 14:08:23 +00:00
|
|
|
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, ret);
|
2008-01-03 08:59:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int rutoken_restore_security_env(sc_card_t *card, int se_num)
|
|
|
|
{
|
|
|
|
sc_apdu_t apdu;
|
2008-04-18 14:08:23 +00:00
|
|
|
int ret;
|
2008-01-03 08:59:14 +00:00
|
|
|
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
|
2008-01-03 08:59:14 +00:00
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x22, 3, se_num);
|
2008-04-18 14:08:23 +00:00
|
|
|
ret = sc_transmit_apdu(card, &apdu);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "APDU transmit failed");
|
2008-04-18 14:08:23 +00:00
|
|
|
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, ret);
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
|
|
|
|
2008-01-03 08:59:14 +00:00
|
|
|
static int rutoken_set_security_env(sc_card_t *card,
|
2008-04-18 14:08:23 +00:00
|
|
|
const sc_security_env_t *env,
|
|
|
|
int se_num)
|
2007-12-17 13:39:20 +00:00
|
|
|
{
|
|
|
|
sc_apdu_t apdu;
|
2008-04-18 14:08:23 +00:00
|
|
|
auth_senv_t *senv;
|
|
|
|
u8 data[3] = { 0x83, 0x01 };
|
|
|
|
int ret;
|
2008-04-07 19:25:21 +00:00
|
|
|
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
|
2008-04-18 14:08:23 +00:00
|
|
|
if (!env)
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INVALID_ARGUMENTS);
|
2008-04-18 14:08:23 +00:00
|
|
|
senv = (auth_senv_t*)card->drv_data;
|
|
|
|
if (!senv)
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INTERNAL);
|
2010-09-09 17:28:44 +00:00
|
|
|
if (env->algorithm != SC_ALGORITHM_GOST)
|
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_NOT_SUPPORTED);
|
2008-01-03 08:59:14 +00:00
|
|
|
|
2008-04-18 14:08:23 +00:00
|
|
|
senv->algorithm = SC_ALGORITHM_GOST;
|
2007-12-17 13:39:20 +00:00
|
|
|
if (env->key_ref_len != 1)
|
|
|
|
{
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "No or invalid key reference\n");
|
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INVALID_ARGUMENTS);
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
2008-04-18 14:08:23 +00:00
|
|
|
data[2] = env->key_ref[0];
|
2007-12-17 13:39:20 +00:00
|
|
|
/* select component */
|
2008-04-18 14:08:23 +00:00
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 1, 0);
|
|
|
|
apdu.lc = apdu.datalen = sizeof(data);
|
|
|
|
apdu.data = data;
|
2009-01-28 12:10:13 +00:00
|
|
|
switch (env->operation)
|
2007-12-17 13:39:20 +00:00
|
|
|
{
|
2008-04-18 14:08:23 +00:00
|
|
|
case SC_SEC_OPERATION_AUTHENTICATE:
|
|
|
|
apdu.p2 = 0xA4;
|
2007-12-17 13:39:20 +00:00
|
|
|
break;
|
2008-04-18 14:08:23 +00:00
|
|
|
case SC_SEC_OPERATION_DECIPHER:
|
|
|
|
apdu.p2 = 0xB8;
|
2007-12-17 13:39:20 +00:00
|
|
|
break;
|
2008-04-18 14:08:23 +00:00
|
|
|
case SC_SEC_OPERATION_SIGN:
|
|
|
|
apdu.p2 = 0xAA;
|
2007-12-17 13:39:20 +00:00
|
|
|
break;
|
2008-04-18 14:08:23 +00:00
|
|
|
default:
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INVALID_ARGUMENTS);
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
|
|
|
/* set SE */
|
2008-04-18 14:08:23 +00:00
|
|
|
ret = sc_transmit_apdu(card, &apdu);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "APDU transmit failed");
|
2008-04-18 14:08:23 +00:00
|
|
|
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, ret);
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
|
|
|
|
2009-11-23 16:38:02 +00:00
|
|
|
static void rutoken_set_do_hdr(u8 *data, size_t *data_len, sc_DOHdrV2_t *hdr)
|
2007-12-17 13:39:20 +00:00
|
|
|
{
|
2009-11-23 16:38:02 +00:00
|
|
|
u8 buf[64], *p = data;
|
|
|
|
|
|
|
|
assert(hdr && data && data_len);
|
|
|
|
|
|
|
|
/* 0x80 - Number of data bytes in the file, excluding structural information */
|
|
|
|
buf[1] = (hdr->wDOBodyLen >> 8) & 0xFF;
|
|
|
|
buf[0] = hdr->wDOBodyLen & 0xFF;
|
|
|
|
sc_asn1_put_tag(0x80, buf, 2, p, *data_len - (p - data), &p);
|
|
|
|
|
|
|
|
/* 0x83 - Type and ID */
|
|
|
|
buf[0] = hdr->OTID.byObjectType;
|
|
|
|
buf[1] = hdr->OTID.byObjectID;
|
|
|
|
sc_asn1_put_tag(0x83, buf, 2, p, *data_len - (p - data), &p);
|
|
|
|
|
|
|
|
/* 0x85 - Options, Flags and Max count of try */
|
|
|
|
buf[0] = hdr->OP.byObjectOptions;
|
|
|
|
buf[1] = hdr->OP.byObjectFlags;
|
|
|
|
buf[2] = hdr->OP.byObjectTry;
|
|
|
|
sc_asn1_put_tag(0x85, buf, 3, p, *data_len - (p - data), &p);
|
|
|
|
|
|
|
|
assert(sizeof(buf) >= sizeof(hdr->SA_V2));
|
|
|
|
memcpy(buf, hdr->SA_V2, sizeof(hdr->SA_V2));
|
|
|
|
sc_asn1_put_tag(0x86, buf, sizeof(hdr->SA_V2), p, *data_len - (p - data), &p);
|
|
|
|
|
|
|
|
assert(*data_len >= (size_t)(p - data));
|
|
|
|
*data_len = p - data;
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int rutoken_key_gen(sc_card_t *card, sc_DOHdrV2_t *pHdr)
|
|
|
|
{
|
2009-11-23 16:38:02 +00:00
|
|
|
u8 data[SC_MAX_APDU_BUFFER_SIZE];
|
|
|
|
size_t data_len = sizeof(data);
|
2008-04-18 14:08:23 +00:00
|
|
|
sc_apdu_t apdu;
|
|
|
|
int ret;
|
|
|
|
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_NORMAL);
|
2007-12-17 13:39:20 +00:00
|
|
|
if (
|
|
|
|
(pHdr->wDOBodyLen != SC_RUTOKEN_DEF_LEN_DO_GOST) ||
|
|
|
|
(pHdr->OTID.byObjectType != SC_RUTOKEN_TYPE_KEY) ||
|
|
|
|
(pHdr->OP.byObjectFlags & SC_RUTOKEN_FLAGS_COMPACT_DO) ||
|
|
|
|
(pHdr->OP.byObjectFlags & SC_RUTOKEN_FLAGS_FULL_OPEN_DO) ||
|
|
|
|
(pHdr->OTID.byObjectID < SC_RUTOKEN_DO_ALL_MIN_ID) ||
|
|
|
|
(pHdr->OTID.byObjectID > SC_RUTOKEN_DO_NOCHV_MAX_ID_V2)
|
|
|
|
)
|
|
|
|
{
|
|
|
|
ret = SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pHdr->OP.byObjectTry = 0;
|
2009-11-23 16:38:02 +00:00
|
|
|
rutoken_set_do_hdr(data, &data_len, pHdr);
|
2007-12-17 13:39:20 +00:00
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xda, 0x01, 0x65);
|
2008-04-18 14:08:23 +00:00
|
|
|
apdu.data = data;
|
2009-11-23 16:38:02 +00:00
|
|
|
apdu.datalen = apdu.lc = data_len;
|
2008-04-18 14:08:23 +00:00
|
|
|
ret = sc_transmit_apdu(card, &apdu);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "APDU transmit failed");
|
2008-04-18 14:08:23 +00:00
|
|
|
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, ret);
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int rutoken_create_do(sc_card_t *card, sc_DO_V2_t * pDO)
|
|
|
|
{
|
2009-11-23 16:38:02 +00:00
|
|
|
u8 data[SC_MAX_APDU_BUFFER_SIZE];
|
|
|
|
size_t data_len = sizeof(data);
|
2008-04-18 14:08:23 +00:00
|
|
|
sc_apdu_t apdu;
|
|
|
|
int ret;
|
|
|
|
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_NORMAL);
|
2007-12-17 13:39:20 +00:00
|
|
|
if (
|
|
|
|
((pDO->HDR.OTID.byObjectType & SC_RUTOKEN_TYPE_CHV) &&
|
|
|
|
(pDO->HDR.OTID.byObjectID != SC_RUTOKEN_DEF_ID_GCHV_USER) &&
|
|
|
|
(pDO->HDR.OTID.byObjectID != SC_RUTOKEN_DEF_ID_GCHV_ADMIN)) ||
|
|
|
|
((pDO->HDR.OTID.byObjectType == SC_RUTOKEN_ALLTYPE_GOST) &&
|
|
|
|
(pDO->HDR.wDOBodyLen != SC_RUTOKEN_DEF_LEN_DO_GOST)) ||
|
|
|
|
((pDO->HDR.OTID.byObjectType == SC_RUTOKEN_ALLTYPE_SE) &&
|
|
|
|
(pDO->HDR.wDOBodyLen != SC_RUTOKEN_DEF_LEN_DO_SE)) ||
|
|
|
|
(pDO->HDR.OTID.byObjectID < SC_RUTOKEN_DO_ALL_MIN_ID) ||
|
|
|
|
(pDO->HDR.OTID.byObjectID > SC_RUTOKEN_DO_NOCHV_MAX_ID_V2) ||
|
|
|
|
((pDO->HDR.OP.byObjectFlags & SC_RUTOKEN_FLAGS_COMPACT_DO) &&
|
|
|
|
(pDO->HDR.wDOBodyLen > SC_RUTOKEN_COMPACT_DO_MAX_LEN)) ||
|
|
|
|
(pDO->HDR.wDOBodyLen > SC_RUTOKEN_DO_PART_BODY_LEN)
|
|
|
|
)
|
|
|
|
{
|
|
|
|
ret = SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-11-23 16:38:02 +00:00
|
|
|
rutoken_set_do_hdr(data, &data_len, &pDO->HDR);
|
|
|
|
assert(sizeof(data) >= data_len + pDO->HDR.wDOBodyLen + 2);
|
|
|
|
ret = sc_asn1_put_tag(0xA5, pDO->abyDOBody, pDO->HDR.wDOBodyLen,
|
|
|
|
data + data_len, sizeof(data) - data_len, NULL);
|
|
|
|
if (ret == SC_SUCCESS)
|
|
|
|
data_len += pDO->HDR.wDOBodyLen + 2;
|
2007-12-17 13:39:20 +00:00
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xda, 0x01, 0x62);
|
2008-04-18 14:08:23 +00:00
|
|
|
apdu.data = data;
|
2009-11-23 16:38:02 +00:00
|
|
|
apdu.datalen = apdu.lc = data_len;
|
2008-04-18 14:08:23 +00:00
|
|
|
ret = sc_transmit_apdu(card, &apdu);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "APDU transmit failed");
|
2008-04-18 14:08:23 +00:00
|
|
|
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, ret);
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int rutoken_get_do_info(sc_card_t *card, sc_DO_INFO_t * pInfo)
|
|
|
|
{
|
2008-04-18 14:08:23 +00:00
|
|
|
u8 data[1];
|
|
|
|
sc_apdu_t apdu;
|
|
|
|
int ret;
|
2007-12-17 13:39:20 +00:00
|
|
|
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_NORMAL);
|
2007-12-17 13:39:20 +00:00
|
|
|
if ((pInfo->SelType != select_first) &&
|
|
|
|
((pInfo->DoId < SC_RUTOKEN_DO_ALL_MIN_ID) ||
|
|
|
|
(pInfo->DoId > SC_RUTOKEN_DO_NOCHV_MAX_ID_V2)))
|
|
|
|
{
|
|
|
|
ret = SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x30, 0x00, 0x00);
|
|
|
|
apdu.cla = 0x80;
|
|
|
|
apdu.resp = pInfo->pDoData;
|
|
|
|
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_next:
|
|
|
|
apdu.p2 = 0x02;
|
2008-04-18 14:08:23 +00:00
|
|
|
case select_by_id:
|
|
|
|
data[0] = pInfo->DoId;
|
2007-12-17 13:39:20 +00:00
|
|
|
apdu.data = data;
|
2008-04-18 14:08:23 +00:00
|
|
|
apdu.datalen = sizeof(data);
|
|
|
|
apdu.lc = sizeof(data);
|
2007-12-17 13:39:20 +00:00
|
|
|
break;
|
|
|
|
default:
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
|
2007-12-17 13:39:20 +00:00
|
|
|
break;
|
|
|
|
}
|
2008-04-18 14:08:23 +00:00
|
|
|
ret = sc_transmit_apdu(card, &apdu);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "APDU transmit failed");
|
2008-04-18 14:08:23 +00:00
|
|
|
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, ret);
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int rutoken_delete_do(sc_card_t *card, u8 *pId)
|
|
|
|
{
|
2008-04-18 14:08:23 +00:00
|
|
|
u8 data[1];
|
|
|
|
sc_apdu_t apdu;
|
|
|
|
int ret;
|
|
|
|
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_NORMAL);
|
2007-12-17 13:39:20 +00:00
|
|
|
if ((*pId < SC_RUTOKEN_DO_ALL_MIN_ID) ||
|
|
|
|
(*pId > SC_RUTOKEN_DO_NOCHV_MAX_ID_V2))
|
|
|
|
{
|
|
|
|
ret = SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xda, 0x01, 0x64);
|
2008-04-18 14:08:23 +00:00
|
|
|
data[0] = *pId;
|
2007-12-17 13:39:20 +00:00
|
|
|
apdu.data = data;
|
2008-04-18 14:08:23 +00:00
|
|
|
apdu.datalen = sizeof(data);
|
|
|
|
apdu.lc = sizeof(data);
|
|
|
|
ret = sc_transmit_apdu(card, &apdu);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "APDU transmit failed");
|
2008-04-18 14:08:23 +00:00
|
|
|
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, ret);
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Both direction GOST cipher */
|
|
|
|
|
|
|
|
static int rutoken_cipher_p(sc_card_t *card, const u8 * crgram, size_t crgram_len,
|
2008-04-18 14:08:23 +00:00
|
|
|
u8 * out, size_t outlen, int p1, int p2, int isIV)
|
2007-12-17 13:39:20 +00:00
|
|
|
{
|
2008-04-18 14:08:23 +00:00
|
|
|
u8 buf[248]; /* 248 (cipher_chunk) <= SC_MAX_APDU_BUFFER_SIZE */
|
2008-01-03 08:59:14 +00:00
|
|
|
size_t len, outlen_tail = outlen;
|
|
|
|
int ret;
|
2007-12-17 13:39:20 +00:00
|
|
|
sc_apdu_t apdu;
|
2008-04-18 14:08:23 +00:00
|
|
|
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_NORMAL);
|
|
|
|
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, ": crgram_len %i; outlen %i", crgram_len, outlen);
|
2008-01-03 08:59:14 +00:00
|
|
|
|
|
|
|
if (!out)
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
|
2008-01-03 08:59:14 +00:00
|
|
|
if (crgram_len < 16 || ((crgram_len) % 8))
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_WRONG_LENGTH);
|
2008-01-03 08:59:14 +00:00
|
|
|
|
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, p1, p2);
|
|
|
|
do
|
2007-12-17 13:39:20 +00:00
|
|
|
{
|
2008-04-18 14:08:23 +00:00
|
|
|
len = (crgram_len > sizeof(buf)) ? sizeof(buf) : crgram_len;
|
2008-01-03 08:59:14 +00:00
|
|
|
apdu.lc = len;
|
|
|
|
apdu.datalen = len;
|
|
|
|
apdu.data = crgram;
|
|
|
|
crgram += len;
|
|
|
|
crgram_len -= len;
|
|
|
|
|
|
|
|
apdu.cla = (crgram_len == 0) ? 0x00 : 0x10;
|
|
|
|
apdu.le = len;
|
|
|
|
apdu.resplen = len;
|
|
|
|
apdu.resp = buf;
|
2008-04-18 14:08:23 +00:00
|
|
|
|
|
|
|
ret = sc_transmit_apdu(card, &apdu);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "APDU transmit failed");
|
2008-04-18 14:08:23 +00:00
|
|
|
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2010-12-16 05:04:37 +00:00
|
|
|
if (ret == SC_SUCCESS)
|
2007-12-17 13:39:20 +00:00
|
|
|
{
|
2008-01-03 08:59:14 +00:00
|
|
|
if (isIV)
|
2007-12-17 13:39:20 +00:00
|
|
|
{
|
2008-01-03 08:59:14 +00:00
|
|
|
apdu.resp += 8;
|
|
|
|
apdu.resplen -= 8;
|
|
|
|
isIV = 0;
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
2008-01-03 08:59:14 +00:00
|
|
|
if (apdu.resplen > outlen_tail)
|
|
|
|
ret = SC_ERROR_BUFFER_TOO_SMALL;
|
2007-12-17 13:39:20 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
memcpy(out, apdu.resp, apdu.resplen);
|
|
|
|
out += apdu.resplen;
|
2008-01-03 08:59:14 +00:00
|
|
|
outlen_tail -= apdu.resplen;
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
|
|
|
}
|
2010-12-16 05:04:37 +00:00
|
|
|
} while (ret == SC_SUCCESS && crgram_len != 0);
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "len out cipher %d\n", outlen - outlen_tail);
|
2010-12-16 05:04:37 +00:00
|
|
|
if (ret == SC_SUCCESS)
|
2008-01-03 08:59:14 +00:00
|
|
|
ret = (outlen_tail == 0) ? (int)outlen : SC_ERROR_WRONG_LENGTH;
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, ret);
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
|
|
|
|
2008-04-18 14:08:23 +00:00
|
|
|
/* Launcher for cipher */
|
2007-12-17 13:39:20 +00:00
|
|
|
|
2008-01-03 08:59:14 +00:00
|
|
|
static int rutoken_cipher_gost(sc_card_t *card,
|
2008-04-18 14:08:23 +00:00
|
|
|
struct sc_rutoken_decipherinfo *ptr, char is_encipher)
|
2007-12-17 13:39:20 +00:00
|
|
|
{
|
2008-01-03 08:59:14 +00:00
|
|
|
int ret;
|
|
|
|
|
2008-04-18 14:08:23 +00:00
|
|
|
if (is_encipher)
|
2008-01-03 08:59:14 +00:00
|
|
|
ret = rutoken_cipher_p(card, ptr->inbuf, ptr->inlen,
|
|
|
|
ptr->outbuf, ptr->outlen, 0x86, 0x80, 0);
|
|
|
|
else
|
|
|
|
ret = rutoken_cipher_p(card, ptr->inbuf, ptr->inlen,
|
|
|
|
ptr->outbuf, ptr->outlen, 0x80, 0x86, 1);
|
|
|
|
if (ret > 0)
|
|
|
|
{
|
|
|
|
if ((size_t)ret == ptr->outlen)
|
|
|
|
ret = SC_SUCCESS;
|
|
|
|
else
|
|
|
|
ret = SC_ERROR_INTERNAL; /* SC_ERROR_DECRYPT_FAILED; */
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
|
|
|
|
2008-01-03 08:59:14 +00:00
|
|
|
static int rutoken_compute_mac_gost(sc_card_t *card,
|
|
|
|
const u8 *in, size_t ilen,
|
|
|
|
u8 *out, size_t olen)
|
2007-12-17 13:39:20 +00:00
|
|
|
{
|
2008-01-03 08:59:14 +00:00
|
|
|
const size_t signing_chunk = 248;
|
|
|
|
size_t len;
|
|
|
|
int ret;
|
|
|
|
sc_apdu_t apdu;
|
|
|
|
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_NORMAL);
|
2008-01-03 08:59:14 +00:00
|
|
|
if (!in || !out || olen != 4 || ilen == 0)
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
|
2008-01-03 08:59:14 +00:00
|
|
|
do
|
2007-12-17 13:39:20 +00:00
|
|
|
{
|
2008-01-03 08:59:14 +00:00
|
|
|
sc_format_apdu(card, &apdu,
|
|
|
|
ilen > signing_chunk ?
|
|
|
|
SC_APDU_CASE_3_SHORT : SC_APDU_CASE_4_SHORT,
|
|
|
|
0x2A, 0x90, 0x80);
|
|
|
|
len = (ilen > signing_chunk) ? signing_chunk : ilen;
|
|
|
|
apdu.lc = len;
|
|
|
|
apdu.datalen = len;
|
|
|
|
apdu.data = in;
|
|
|
|
in += len;
|
|
|
|
ilen -= len;
|
|
|
|
if (ilen == 0)
|
2008-04-18 14:08:23 +00:00
|
|
|
{
|
2008-01-03 08:59:14 +00:00
|
|
|
apdu.cla = 0x00;
|
|
|
|
apdu.le = olen;
|
|
|
|
apdu.resplen = olen;
|
|
|
|
apdu.resp = out;
|
2008-04-18 14:08:23 +00:00
|
|
|
}
|
2008-01-03 08:59:14 +00:00
|
|
|
else
|
2008-04-18 14:08:23 +00:00
|
|
|
apdu.cla = 0x10;
|
|
|
|
ret = sc_transmit_apdu(card, &apdu);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "APDU transmit failed");
|
2008-04-18 14:08:23 +00:00
|
|
|
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2010-12-16 05:04:37 +00:00
|
|
|
} while (ret == SC_SUCCESS && ilen != 0);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, ret);
|
2008-01-03 08:59:14 +00:00
|
|
|
}
|
2008-04-18 14:08:23 +00:00
|
|
|
|
2008-01-03 08:59:14 +00:00
|
|
|
static int rutoken_compute_signature(struct sc_card *card,
|
|
|
|
const u8 * data, size_t datalen,
|
|
|
|
u8 * out, size_t outlen)
|
2007-12-17 13:39:20 +00:00
|
|
|
{
|
2008-04-18 14:08:23 +00:00
|
|
|
int ret;
|
2008-01-03 08:59:14 +00:00
|
|
|
auth_senv_t *senv = (auth_senv_t *)card->drv_data;
|
2007-12-17 13:39:20 +00:00
|
|
|
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
|
2008-01-03 08:59:14 +00:00
|
|
|
if (!senv)
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INTERNAL);
|
2007-12-17 13:39:20 +00:00
|
|
|
|
2008-04-18 14:08:23 +00:00
|
|
|
if (senv->algorithm == SC_ALGORITHM_GOST)
|
|
|
|
ret = rutoken_compute_mac_gost(card, data, datalen, out, outlen);
|
2008-01-03 08:59:14 +00:00
|
|
|
else
|
2008-04-18 14:08:23 +00:00
|
|
|
ret = SC_ERROR_NOT_SUPPORTED;
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, ret);
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
2008-04-18 14:08:23 +00:00
|
|
|
|
2008-01-03 08:59:14 +00:00
|
|
|
static int rutoken_get_challenge(sc_card_t *card, u8 *rnd, size_t count)
|
|
|
|
{
|
|
|
|
sc_apdu_t apdu;
|
|
|
|
u8 rbuf[32];
|
|
|
|
size_t n;
|
2008-04-18 14:08:23 +00:00
|
|
|
int ret = SC_ERROR_INVALID_ARGUMENTS; /* if count == 0 */
|
2007-12-17 13:39:20 +00:00
|
|
|
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
|
2008-01-03 08:59:14 +00:00
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x84, 0x00, 0x00);
|
|
|
|
apdu.le = sizeof(rbuf);
|
|
|
|
apdu.resp = rbuf;
|
|
|
|
apdu.resplen = sizeof(rbuf);
|
|
|
|
|
|
|
|
while (count > 0)
|
|
|
|
{
|
|
|
|
ret = sc_transmit_apdu(card, &apdu);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "APDU transmit failed");
|
2008-04-18 14:08:23 +00:00
|
|
|
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "Get challenge failed");
|
2008-01-03 08:59:14 +00:00
|
|
|
if (apdu.resplen != sizeof(rbuf))
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_UNKNOWN);
|
2008-01-03 08:59:14 +00:00
|
|
|
n = count < sizeof(rbuf) ? count : sizeof(rbuf);
|
|
|
|
memcpy(rnd, rbuf, n);
|
|
|
|
count -= n;
|
|
|
|
rnd += n;
|
|
|
|
}
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, ret);
|
2008-01-03 08:59:14 +00:00
|
|
|
}
|
2007-12-17 13:39:20 +00:00
|
|
|
|
2008-04-18 14:08:23 +00:00
|
|
|
static int rutoken_get_serial(sc_card_t *card, sc_serial_number_t *serial)
|
|
|
|
{
|
|
|
|
sc_apdu_t apdu;
|
|
|
|
int ret;
|
|
|
|
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_NORMAL);
|
2008-04-18 14:08:23 +00:00
|
|
|
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);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "APDU transmit failed");
|
2008-04-18 14:08:23 +00:00
|
|
|
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2009-11-23 16:38:02 +00:00
|
|
|
serial->len = apdu.resplen;
|
|
|
|
swap_four(serial->value, serial->len);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, ret);
|
2008-04-18 14:08:23 +00:00
|
|
|
}
|
|
|
|
|
2007-12-17 13:39:20 +00:00
|
|
|
static int rutoken_get_info(sc_card_t *card, void *buff)
|
|
|
|
{
|
|
|
|
sc_apdu_t apdu;
|
2008-04-18 14:08:23 +00:00
|
|
|
u8 rbuf[8];
|
|
|
|
int ret;
|
|
|
|
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_NORMAL);
|
2008-04-18 14:08:23 +00:00
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xCA, 0x01, 0x89);
|
2007-12-17 13:39:20 +00:00
|
|
|
apdu.resp = rbuf;
|
|
|
|
apdu.resplen = sizeof(rbuf);
|
2008-04-18 14:08:23 +00:00
|
|
|
apdu.le = sizeof(rbuf);
|
|
|
|
ret = sc_transmit_apdu(card, &apdu);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "APDU transmit failed");
|
2008-04-18 14:08:23 +00:00
|
|
|
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2009-11-23 16:38:02 +00:00
|
|
|
if (ret == SC_SUCCESS)
|
|
|
|
memcpy(buff, apdu.resp, apdu.resplen);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, ret);
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
|
|
|
|
2008-01-03 08:59:14 +00:00
|
|
|
static int rutoken_format(sc_card_t *card, int apdu_ins)
|
2007-12-17 13:39:20 +00:00
|
|
|
{
|
2008-04-18 14:08:23 +00:00
|
|
|
int ret;
|
2007-12-17 13:39:20 +00:00
|
|
|
sc_apdu_t apdu;
|
2008-01-03 08:59:14 +00:00
|
|
|
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_NORMAL);
|
2008-01-03 08:59:14 +00:00
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, apdu_ins, 0x00, 0x00);
|
|
|
|
apdu.cla = 0x80;
|
2008-04-18 14:08:23 +00:00
|
|
|
ret = sc_transmit_apdu(card, &apdu);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, ret, "APDU transmit failed");
|
2008-04-18 14:08:23 +00:00
|
|
|
ret = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, ret);
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int rutoken_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr)
|
|
|
|
{
|
2008-01-03 08:59:14 +00:00
|
|
|
int ret = (ptr != NULL
|
|
|
|
/*|| cmd == SC_CARDCTL_ERASE_CARD */
|
|
|
|
|| cmd == SC_CARDCTL_RUTOKEN_FORMAT_INIT
|
|
|
|
|| cmd == SC_CARDCTL_RUTOKEN_FORMAT_END
|
2010-12-16 05:04:37 +00:00
|
|
|
) ? SC_SUCCESS : SC_ERROR_INVALID_ARGUMENTS;
|
2008-01-03 08:59:14 +00:00
|
|
|
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
|
2008-04-18 14:08:23 +00:00
|
|
|
|
2010-12-16 05:04:37 +00:00
|
|
|
if (ret == SC_SUCCESS)
|
2007-12-17 13:39:20 +00:00
|
|
|
{
|
|
|
|
switch (cmd)
|
|
|
|
{
|
|
|
|
case SC_CARDCTL_RUTOKEN_CREATE_DO:
|
|
|
|
ret = rutoken_create_do(card, ptr);
|
|
|
|
break;
|
|
|
|
case SC_CARDCTL_RUTOKEN_GENERATE_KEY_DO:
|
|
|
|
ret = rutoken_key_gen(card, ptr);
|
|
|
|
break;
|
|
|
|
case SC_CARDCTL_RUTOKEN_DELETE_DO:
|
|
|
|
ret = rutoken_delete_do(card, ptr);
|
|
|
|
break;
|
|
|
|
case SC_CARDCTL_RUTOKEN_GET_DO_INFO:
|
|
|
|
ret = rutoken_get_do_info(card, ptr);
|
|
|
|
break;
|
|
|
|
case SC_CARDCTL_GET_SERIALNR:
|
|
|
|
ret = rutoken_get_serial(card, ptr);
|
|
|
|
break;
|
|
|
|
case SC_CARDCTL_RUTOKEN_CHANGE_DO:
|
|
|
|
ret = SC_ERROR_NOT_SUPPORTED;
|
|
|
|
break;
|
|
|
|
case SC_CARDCTL_RUTOKEN_GET_INFO:
|
|
|
|
ret = rutoken_get_info(card, ptr);
|
|
|
|
break;
|
|
|
|
case SC_CARDCTL_RUTOKEN_GOST_ENCIPHER:
|
2008-01-03 08:59:14 +00:00
|
|
|
ret = rutoken_cipher_gost(card, ptr, 1);
|
2007-12-17 13:39:20 +00:00
|
|
|
break;
|
|
|
|
case SC_CARDCTL_RUTOKEN_GOST_DECIPHER:
|
2008-01-03 08:59:14 +00:00
|
|
|
ret = rutoken_cipher_gost(card, ptr, 0);
|
2007-12-17 13:39:20 +00:00
|
|
|
break;
|
2008-01-03 08:59:14 +00:00
|
|
|
/* case SC_CARDCTL_ERASE_CARD: */
|
|
|
|
case SC_CARDCTL_RUTOKEN_FORMAT_INIT:
|
|
|
|
/* ret = rutoken_format(card, 0x7a); *//* APDU: INIT RUTOKEN */
|
|
|
|
ret = rutoken_format(card, 0x8a); /* APDU: NEW INIT RUTOKEN */
|
|
|
|
break;
|
|
|
|
case SC_CARDCTL_RUTOKEN_FORMAT_END:
|
|
|
|
ret = rutoken_format(card, 0x7b); /* APDU: FORMAT END */
|
2007-12-17 13:39:20 +00:00
|
|
|
break;
|
|
|
|
default:
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "cmd = %d", cmd);
|
2007-12-17 13:39:20 +00:00
|
|
|
ret = SC_ERROR_NOT_SUPPORTED;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, ret);
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
|
|
|
|
2008-04-18 14:08:23 +00:00
|
|
|
static struct sc_card_driver* get_rutoken_driver(void)
|
2007-12-17 13:39:20 +00:00
|
|
|
{
|
2009-11-23 16:38:02 +00:00
|
|
|
if (iso_ops == NULL)
|
|
|
|
iso_ops = sc_get_iso7816_driver()->ops;
|
|
|
|
rutoken_ops = *iso_ops;
|
2007-12-17 13:39:20 +00:00
|
|
|
|
|
|
|
rutoken_ops.match_card = rutoken_match_card;
|
|
|
|
rutoken_ops.init = rutoken_init;
|
|
|
|
rutoken_ops.finish = rutoken_finish;
|
2009-11-23 16:38:02 +00:00
|
|
|
/* read_binary */
|
|
|
|
rutoken_ops.write_binary = NULL;
|
|
|
|
/* update_binary */
|
|
|
|
rutoken_ops.read_record = NULL;
|
|
|
|
rutoken_ops.write_record = NULL;
|
|
|
|
rutoken_ops.append_record = NULL;
|
|
|
|
rutoken_ops.update_record = NULL;
|
2007-12-17 13:39:20 +00:00
|
|
|
rutoken_ops.select_file = rutoken_select_file;
|
2009-11-23 16:38:02 +00:00
|
|
|
rutoken_ops.get_response = NULL;
|
2008-01-03 08:59:14 +00:00
|
|
|
rutoken_ops.get_challenge = rutoken_get_challenge;
|
2009-11-23 16:38:02 +00:00
|
|
|
rutoken_ops.verify = rutoken_verify;
|
|
|
|
rutoken_ops.logout = rutoken_logout;
|
|
|
|
rutoken_ops.restore_security_env = rutoken_restore_security_env;
|
|
|
|
rutoken_ops.set_security_env = rutoken_set_security_env;
|
2008-01-03 08:59:14 +00:00
|
|
|
rutoken_ops.decipher = NULL;
|
2010-09-09 17:28:44 +00:00
|
|
|
rutoken_ops.compute_signature = rutoken_compute_signature;
|
2008-01-03 08:59:14 +00:00
|
|
|
rutoken_ops.change_reference_data = rutoken_change_reference_data;
|
|
|
|
rutoken_ops.reset_retry_counter = rutoken_reset_retry_counter;
|
2009-11-23 16:38:02 +00:00
|
|
|
rutoken_ops.create_file = rutoken_create_file;
|
|
|
|
rutoken_ops.delete_file = rutoken_delete_file;
|
|
|
|
rutoken_ops.list_files = rutoken_list_files;
|
|
|
|
rutoken_ops.check_sw = rutoken_check_sw;
|
|
|
|
rutoken_ops.card_ctl = rutoken_card_ctl;
|
|
|
|
/* process_fci */
|
|
|
|
rutoken_ops.construct_fci = rutoken_construct_fci;
|
2008-01-03 08:59:14 +00:00
|
|
|
rutoken_ops.pin_cmd = NULL;
|
2009-11-23 16:38:02 +00:00
|
|
|
|
2007-12-17 13:39:20 +00:00
|
|
|
return &rutoken_drv;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct sc_card_driver * sc_get_rutoken_driver(void)
|
|
|
|
{
|
2008-04-18 14:08:23 +00:00
|
|
|
return get_rutoken_driver();
|
2007-12-17 13:39:20 +00:00
|
|
|
}
|
|
|
|
|