new patch for ruToken support

Thanks to Andrew V. Stepanov
http://www.opensc-project.org/pipermail/opensc-devel/2007-December/010631.html


git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@3310 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
ludovic.rousseau 2008-01-03 08:59:14 +00:00
parent 513a3dde0a
commit bf9d6beaac
8 changed files with 1015 additions and 1486 deletions

View File

@ -36,7 +36,8 @@ 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 \
compression.c p15card-helper.c pkcs15-rutoken.c
pkcs15-rutoken.c pkcs15-prkey-rutoken.c \
compression.c p15card-helper.c
libopensc_la_LDFLAGS = -version-info @OPENSC_LT_CURRENT@:@OPENSC_LT_REVISION@:@OPENSC_LT_AGE@
libopensc_la_LIBADD = @LIBSCCONF@ $(OPENSSL_LIBS) $(OPENCT_LIBS) $(PCSC_LIBS) $(LTLIB_LIBS)

File diff suppressed because it is too large Load Diff

View File

@ -142,8 +142,8 @@ enum {
SC_CARDCTL_ASEPCOS_ACTIVATE_FILE,
/*
* ruToken specific calls
*/
* ruToken specific calls
*/
SC_CARDCTL_RUTOKEN_BASE = _CTL_PREFIX('R', 'T', 'K'),
/* PUT_DATA */
SC_CARDCTL_RUTOKEN_CREATE_DO,
@ -155,7 +155,8 @@ enum {
SC_CARDCTL_RUTOKEN_GET_DO_INFO,
SC_CARDCTL_RUTOKEN_GOST_ENCIPHER,
SC_CARDCTL_RUTOKEN_GOST_DECIPHER,
SC_CARDCTL_RUTOKEN_TRIES_LEFT
SC_CARDCTL_RUTOKEN_FORMAT_INIT,
SC_CARDCTL_RUTOKEN_FORMAT_END
};
enum {
@ -544,8 +545,8 @@ typedef struct sc_DO_INFO_V2 {
u8 pDoData[256];
} sc_DO_INFO_t;
struct sc_rutoken_decipherinfo{
u8 *inbuf;
struct sc_rutoken_decipherinfo {
const u8 *inbuf;
size_t inlen;
u8 *outbuf;
size_t outlen;

View File

@ -1,5 +1,5 @@
/*
* ruToken specific operation for PKCS15 initialization
* PKCS15 emulation layer for ruToken
*
* Copyright (C) 2007 Pavel Mironchik <rutoken@rutoken.ru>
* Copyright (C) 2007 Eugene Hermann <rutoken@rutoken.ru>
@ -30,756 +30,71 @@
#include <opensc/opensc.h>
#include <opensc/cardctl.h>
#include <opensc/log.h>
#include "../pkcs15init/pkcs15-init.h"
#include "../pkcs15init/profile.h"
#include <opensc/pkcs15.h>
#define USAGE_AUT SC_PKCS15_PRKEY_USAGE_ENCRYPT | \
SC_PKCS15_PRKEY_USAGE_DECRYPT | \
SC_PKCS15_PRKEY_USAGE_WRAP | \
SC_PKCS15_PRKEY_USAGE_UNWRAP | \
SC_PKCS15_PRKEY_USAGE_SIGN
#define P15_DF(T) T & SC_PKCS15_TYPE_CERT ? SC_PKCS15_CDF \
: T & SC_PKCS15_TYPE_PUBKEY ? SC_PKCS15_PUKDF : \
T & SC_PKCS15_TYPE_PRKEY_RSA ? SC_PKCS15_PRKDF : SC_PKCS15_DODF
int rutoken_erase(struct sc_profile *, sc_card_t *);
#define MAX_ID 255
const sc_SecAttrV2_t map_sec_attr = {0x42, 0, 1, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 2};
const sc_SecAttrV2_t pr_sec_attr = {0x43, 1, 1, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 2};
const sc_SecAttrV2_t pb_sec_attr = {0x42, 0, 1, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 2};
const char GCHV_DF[] = "3F0000000000";
const char APP_DF[] = "3F0000000000FF00";
const char PRK_DF[] = "3F0000000000FF001001";
const char PUK_DF[] = "3F0000000000FF001002";
const char C_DF[] = "3F0000000000FF001003";
enum DF_IDs
{
PrKDFid = 0x1001,
PuKDFid = 0x1002,
CDFid = 0x1003,
DFsId = 0xefff,
DFsSize = 2048
};
/* BLOB definition */
typedef struct _RSAPUBKEY {
int magic;
int bitlen;
int pubexp;
} RSAPUBKEY;
typedef struct _PUBLICKEYSTRUC {
u8 bType;
u8 bVersion;
u_int16_t reserved;
u_int32_t aiKeyAlg;
} BLOBHEADER;
typedef struct _PRIVATEKEYBLOB {
BLOBHEADER blobheader;
RSAPUBKEY rsapubkey;
u8 *modulus;
u8 *prime1;
u8 *prime2;
u8 *exponent1;
u8 *exponent2;
u8 *coefficient;
u8 *privateExponent;
} PRIVATEKEYBLOB;
void ArrayReverse(u8 *buf, int size);
int bin_to_privite_blob(PRIVATEKEYBLOB *pr_blob, u8 *buf, int buf_len);
/* BLOB */
int create_privite_blob(PRIVATEKEYBLOB *pr_blob, const struct sc_pkcs15_prkey_rsa *key){
int bitlen = key->modulus.len*8;
/* 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;
int n = key->exponent.len;
while (n > 0)
{
((u8*)&pr_blob->rsapubkey.pubexp)[key->exponent.len - n] = key->exponent.data[n - 1];
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);
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;
}
int get_sc_pksc15_prkey_rsa(const PRIVATEKEYBLOB *pr_blob, struct sc_pkcs15_prkey_rsa *key){
int bitlen = pr_blob->rsapubkey.bitlen;
long exp = 0x00010001;
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 - 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(3);
memcpy(key->exponent.data, &exp, 3);
key->exponent.len = 3;
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;
}
int get_privite_blob_len(const PRIVATEKEYBLOB *pr_blob){
return sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + 9*(pr_blob->rsapubkey.bitlen/16);
}
int free_privite_blob(PRIVATEKEYBLOB *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;
}
int privite_blob_to_bin(const PRIVATEKEYBLOB *pr_blob, u8 *buf, size_t *buf_len){
if(*buf_len < get_privite_blob_len(pr_blob) + 2)
return -1;
buf[0] = 2;
buf[1] = 1;
u8 *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);
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 = get_privite_blob_len(pr_blob) + 2;
return 0;
}
int get_prkey_from_bin(u8* data, int len, struct sc_pkcs15_prkey **key)
{
int ret = -1;
*key = malloc(sizeof(struct sc_pkcs15_prkey));
if(data && *key)
{
PRIVATEKEYBLOB pr_blob;
memset(*key, 0, sizeof(struct sc_pkcs15_prkey));
bin_to_privite_blob(&pr_blob, data, len);
ret = get_sc_pksc15_prkey_rsa(&pr_blob, &(*key)->u.rsa);
(*key)->algorithm = SC_ALGORITHM_RSA;
free_privite_blob(&pr_blob);
}
return ret;
}
void ArrayReverse(u8 *buf, int size)
{
int i, j;
u8 *tmp = malloc(size);
if (tmp)
{
for(i = 0, j = size - 1; i < size; i++, j--)
tmp[i] = buf[j];
memcpy(buf, tmp, size);
free(tmp);
}
}
int bin_to_privite_blob(PRIVATEKEYBLOB *pr_blob, u8 *buf, int buf_len){
u8 *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);
int bitlen = pr_blob->rsapubkey.bitlen;
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);
memcpy(pr_blob->modulus, tmp, pr_blob->rsapubkey.bitlen/8);
tmp += pr_blob->rsapubkey.bitlen/8;
memcpy(pr_blob->prime1, tmp, pr_blob->rsapubkey.bitlen/16);
tmp += pr_blob->rsapubkey.bitlen/16;
memcpy(pr_blob->prime2, tmp, pr_blob->rsapubkey.bitlen/16);
tmp += pr_blob->rsapubkey.bitlen/16;
memcpy(pr_blob->exponent1, tmp, pr_blob->rsapubkey.bitlen/16);
tmp += pr_blob->rsapubkey.bitlen/16;
memcpy(pr_blob->exponent2, tmp, pr_blob->rsapubkey.bitlen/16);
tmp += pr_blob->rsapubkey.bitlen/16;
memcpy(pr_blob->coefficient, tmp, pr_blob->rsapubkey.bitlen/16);
tmp += pr_blob->rsapubkey.bitlen/16;
memcpy(pr_blob->privateExponent, tmp, pr_blob->rsapubkey.bitlen/8);
tmp += pr_blob->rsapubkey.bitlen/8;
return 0;
}
/*
* Create/override new EF.
*/
int rutoken_create_file(sc_card_t *card, sc_path_t *path, sc_file_t *ef)
{
int ret = SC_SUCCESS;
if(path)
{
ret = card->ops->select_file(card, path, NULL);
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);
}
}
if (ret == SC_SUCCESS)
{
ret = card->ops->create_file(card, ef);
}
return ret;
}
/*
* Create a DF
*/
static int
rutoken_create_dir(sc_profile_t *profile, sc_card_t *card, sc_file_t *df)
{
int ret = SC_SUCCESS;
sc_file_t *file = NULL;
SC_FUNC_CALLED(card->ctx, 1);
ret = card->ops->select_file(card, &df->path, &file);
if (ret == SC_ERROR_FILE_NOT_FOUND)
ret = card->ops->create_file(card, df);
else if(file && file->type != SC_FILE_TYPE_DF)
ret = SC_ERROR_WRONG_CARD;
if(file)
sc_file_free(file);
return ret;
}
/*
* Select a key reference
*/
static int
rutoken_select_key_reference(sc_profile_t *profile, sc_card_t *card,
sc_pkcs15_prkey_info_t *key_info)
{
SC_FUNC_CALLED(card->ctx, 1);
/* hocus-pocus :) */
sc_format_path(PRK_DF, &key_info->path);
sc_append_file_id(&key_info->path, key_info->key_reference);
//g_nKeyRef = key_info->key_reference;
return key_info->key_reference >= 0 && key_info->key_reference <= MAX_ID ? SC_SUCCESS : SC_ERROR_TOO_MANY_OBJECTS;
}
/*
* Create a private key object.
* This is a no-op.
*/
static int
rutoken_create_key(sc_profile_t *profile, sc_card_t *card,
sc_pkcs15_object_t *obj)
{
SC_FUNC_CALLED(card->ctx, 1);
return 0;
}
/* Send the pkcs15 profile to its doom. NOTE:This change current DF! */
static void fix_pkcs15(sc_profile_t *profile, sc_card_t *card, int type, int x)
{
sc_file_t *df;
if(profile->df[type])
df = profile->df[type];
else
{
df = sc_file_new();
profile->df[type] = df;
}
switch(type)
{
case SC_PKCS15_PRKDF:
sc_format_path(PRK_DF, &df->path);
break;
case SC_PKCS15_PUKDF:
sc_format_path(PUK_DF, &df->path);
break;
case SC_PKCS15_CDF:
sc_format_path(C_DF, &df->path);
break;
default:
return;
}
df->id = DFsId;
df->size = DFsSize;
df->type = SC_FILE_TYPE_WORKING_EF;
df->ef_structure = SC_FILE_EF_TRANSPARENT;
sc_append_file_id(&df->path, df->id);
sc_path_t odf_path;
sc_format_path("3f0000000000dfff", &odf_path);
if(card->ops->select_file(card, &odf_path, NULL) == SC_SUCCESS)
{
odf_path.len = 0;
odf_path.type = SC_PATH_TYPE_FILE_ID;
card->ops->delete_file(card, &odf_path);
}
}
int rutoken_check_df(sc_card_t *card, int df_id)
{
int ret = -1;
sc_path_t path;
sc_file_t *file = sc_file_new();
if(file)
{
sc_format_path(GCHV_DF, &path);
ret = card->ops->select_file(card, &path, NULL);
}
else
ret = SC_ERROR_OUT_OF_MEMORY;
if (ret == SC_SUCCESS)
{
sc_format_path(APP_DF, &file->path);
file->type = SC_FILE_TYPE_DF;
// FIXME: change to 'df' secattr
sc_file_set_sec_attr(file, (u8*)&pb_sec_attr, SEC_ATTR_SIZE);
/* appdf (ff00) */
file->id = 0xff00;
ret = rutoken_create_dir(NULL, card, file);
}
if (ret == SC_SUCCESS)
{
/* p15df */
sc_format_path(APP_DF, &path);
card->ops->select_file(card, &path, NULL);
file->id = df_id;
file->path = path;
sc_append_file_id(&file->path, df_id);
ret = rutoken_create_dir(NULL, card, file);
}
if(file) sc_file_free(file);
return ret;
}
/*
* create private key files
*/
int rutoken_create_prkeyfile(sc_card_t *card,
sc_pkcs15_prkey_info_t *key_info,
sc_file_t **prkf, size_t prsize)
{
int ret;
SC_FUNC_CALLED(card->ctx, 1);
sc_path_t path;
int id = key_info->key_reference;
{
sc_file_t *file = sc_file_new();
if (file) ret = rutoken_check_df(card, PrKDFid);
else ret = SC_ERROR_OUT_OF_MEMORY;
if (ret == SC_SUCCESS)
{
/* create key file */
sc_format_path(PRK_DF, &path);
file->type = SC_FILE_TYPE_WORKING_EF;
file->id = id;
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);
}
return ret;
}
/* Store a private key object. */
static int
rutoken_store_key(sc_profile_t *profile, sc_card_t *card,
sc_pkcs15_object_t *obj,
sc_pkcs15_prkey_t *key)
{
SC_FUNC_CALLED(card->ctx, 1);
sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data;
const int nKeyBufSize = 2048;
u8 *prkeybuf = NULL;
size_t prsize;
int ret;
if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA)
return SC_ERROR_NOT_SUPPORTED;
prkeybuf = calloc(nKeyBufSize, 1);
if(!prkeybuf)
return SC_ERROR_OUT_OF_MEMORY;
/* encode private key
* create key file
* write a key */
prsize = nKeyBufSize;
if((ret = profile->ops->encode_private_key(profile, card, &key->u.rsa, prkeybuf, &prsize, 0)) == 0 &&
( ret = rutoken_create_prkeyfile(card, key_info, NULL, prsize)) == 0)
{
if((ret = sc_update_binary(card, 0, prkeybuf, prsize, 0)) == prsize)
{
fix_pkcs15(profile, card, P15_DF(obj->type), 0);
}
}
free(prkeybuf);
return ret;
}
static int
rutoken_encode_private_key(sc_profile_t *profile, sc_card_t *card,
struct sc_pkcs15_prkey_rsa *rsa,
u8 *key, size_t *keysize, int key_ref)
{
PRIVATEKEYBLOB prkeyblob;
create_privite_blob(&prkeyblob, rsa);
int r = privite_blob_to_bin(&prkeyblob, key, keysize);
free_privite_blob(&prkeyblob);
return r;
}
int rutoken_id_in(int id, const u8 *buf, int buflen)
{
int i;
for (i = 0; i*2 < buflen; i++)
if (id == (int)buf[i*2] * 0x100 + buf[i*2 + 1]) return 1;
return 0;
}
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);
if (!files) return SC_ERROR_OUT_OF_MEMORY;
if(path)
{
if((ret = card->ops->select_file(card, path, &file)) == SC_SUCCESS)
ret = file->type == SC_FILE_TYPE_DF ? SC_SUCCESS : SC_ERROR_NOT_ALLOWED;
}
if(ret == SC_SUCCESS)
{
ret = card->ops->list_files(card, files, 2048);
if(ret >= 0)
{
int i;
for (i = 0; i < MAX_ID; i++)
if(!rutoken_id_in(i, files, ret)) {ret = i; break;}
}
}
free(files);
if(file)sc_file_free(file);
return ret;
}
int rutoken_new_file(struct sc_profile *profile, struct sc_card *card,
unsigned int type, unsigned int idx, struct sc_file **file)
{
SC_FUNC_CALLED(card->ctx, 1);
int ret = SC_SUCCESS, id;
sc_path_t path;
switch (type & SC_PKCS15_TYPE_CLASS_MASK)
{
case SC_PKCS15_TYPE_CERT:
ret = rutoken_check_df(card, CDFid);
/* find first unlished file id */
if (ret == SC_SUCCESS) ret = (id = rutoken_find_id(card, NULL)) >= 0 ? SC_SUCCESS : SC_ERROR_TOO_MANY_OBJECTS;
sc_format_path(C_DF, &path);
break;
case SC_PKCS15_TYPE_PUBKEY:
ret = rutoken_check_df(card, PuKDFid);
if (ret == SC_SUCCESS) ret = (id = rutoken_find_id(card, NULL)) >= 0 ? SC_SUCCESS : SC_ERROR_TOO_MANY_OBJECTS;
sc_format_path(PUK_DF, &path);
break;
case SC_PKCS15_TYPE_PRKEY_RSA:
default:
ret = SC_ERROR_NOT_SUPPORTED;
}
if(ret == SC_SUCCESS)
{
*file = sc_file_new();
(*file)->size = 0;
(*file)->id = id;
sc_append_file_id(&path, (*file)->id);
(*file)->path = path;
sc_file_set_sec_attr(*file, (u8*)&pb_sec_attr, SEC_ATTR_SIZE);
(*file)->type = SC_FILE_TYPE_WORKING_EF;
/* If target file exist than remove it */
if (card->ops->select_file(card, &(*file)->path, NULL) == SC_SUCCESS)
{
sc_path_t del_path;
del_path.len = 0;
del_path.type = SC_PATH_TYPE_FILE_ID;
card->ops->delete_file(card, &del_path);
}
fix_pkcs15(profile, card, P15_DF(type), 0);
}
return ret;
}
int rutoken_delete_object(struct sc_profile *profile, struct sc_card *card,
unsigned int type, const void *data, const sc_path_t *path)
{
int ret = -1, tries_left = 2;
/* try to logon as user*/
card->ops->logout(card);
u8 *pin;
ret = card->ops->card_ctl(card, SC_CARDCTL_RUTOKEN_TRIES_LEFT, &tries_left);
while(ret == SC_ERROR_PIN_CODE_INCORRECT && tries_left > 0)
{
pin = (u8*)getpass("Please enter User PIN: ");
ret = sc_verify(card, SC_AC_CHV, 2, pin, 8, NULL);
if(ret != SC_SUCCESS)
{
tries_left = 2;
card->ops->card_ctl(card, SC_CARDCTL_RUTOKEN_TRIES_LEFT, &tries_left);
fprintf(stderr, "PIN code verification failed: %s\n%d tries left\n", sc_strerror(ret), tries_left);
}
}
if( (ret == SC_SUCCESS) &&
(ret = card->ops->select_file(card, path, NULL) == SC_SUCCESS))
{
sc_path_t del_path;
memset(&del_path, 0, sizeof(del_path));
del_path.type = SC_PATH_TYPE_FILE_ID;
del_path.value[0] = path->value[path->len - 2];
del_path.value[1] = path->value[path->len - 1];
del_path.len = 2;
ret = sc_delete_file(card, &del_path);
}
return ret;
}
/*
* Inicialization routine
*/
/* Complete initialization */
int rutoken_check_sw(sc_card_t *, unsigned int, unsigned int);
int rutoken_finalize_card(sc_card_t *card)
{
int ret = SC_ERROR_CARD_CMD_FAILED;
SC_FUNC_CALLED(card->ctx, 1);
sc_apdu_t apdu = {0};
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x7b, 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);
}
/* Try to delete pkcs15 structure */
int rutoken_erase(struct sc_profile *profile, sc_card_t *card)
{
int ret = SC_ERROR_CARD_CMD_FAILED;
SC_FUNC_CALLED(card->ctx, 1);
sc_apdu_t apdu = {0};
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x7a, 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);
return ret;
}
/* create pkcs15 structure */
int rutoken_init(sc_profile_t *profile, sc_card_t *card)
{
return SC_ERROR_NOT_SUPPORTED;
}
static struct sc_pkcs15init_operations sc_pkcs15init_rutoken_operations = {
rutoken_erase,
rutoken_init, /* init_card */
rutoken_create_dir,
NULL, /* create_domain */
NULL/*rutoken_select_pin_reference*/,
NULL/*rutoken_create_pin*/,
rutoken_select_key_reference,
rutoken_create_key,
rutoken_store_key,
NULL, /* rutoken_generate_key, */
rutoken_encode_private_key,
NULL, /* encode private/public key */
rutoken_finalize_card, /* finalize_card */
NULL, NULL, NULL,
rutoken_new_file,
NULL, /* old style api */
rutoken_delete_object /* delete_object */
};
struct sc_pkcs15init_operations *
sc_pkcs15init_get_rutoken_ops(void)
{
return &sc_pkcs15init_rutoken_operations;
}
static void set_string(char **strp, const char *value)
{
if (*strp) free(*strp);
*strp = value ? strdup(value) : NULL;
}
#define KEY_LABEL "GOST 28.147-89 KEY"
#define OBJ_LABEL "SE object"
#define RUT_LABEL "ruToken card"
#define PrKDF_path "3F00FF000001"
#define PuKDF_path "3F00FF000002"
#define CDF_path "3F00FF000003"
#define DODF_path "3F00FF000004"
#define AODF_path "3F00FF00A0DF"
static const struct
{
char const* path;
unsigned int type;
} arr_profile_df[] =
{
{ PrKDF_path, SC_PKCS15_PRKDF },
{ PuKDF_path, SC_PKCS15_PUKDF },
{ CDF_path, SC_PKCS15_CDF },
{ DODF_path, SC_PKCS15_DODF },
{ AODF_path, SC_PKCS15_AODF }
};
static const struct {
int type, id, auth_id, min_length;
unsigned char reference;
const char *path;
int reference;
const char *label;
int flags;
unsigned int flags;
} pinlist[]=
{
{1, 2, 2, 1, 0x02, "3f0000000000", "User PIN",
SC_PKCS15_PIN_FLAG_LOCAL|SC_PKCS15_PIN_FLAG_CASE_SENSITIVE /*| SC_PKCS15_PIN_FLAG_INITIALIZED | SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN*/},
{0, 0, 0, 0, 0, NULL, NULL, 0}
{ SC_RUTOKEN_DEF_ID_GCHV_USER, "User PIN",
SC_PKCS15_PIN_FLAG_LOCAL | SC_PKCS15_PIN_FLAG_CASE_SENSITIVE
},
{ SC_RUTOKEN_DEF_ID_GCHV_ADMIN, "SO PIN",
SC_PKCS15_PIN_FLAG_LOCAL | SC_PKCS15_PIN_FLAG_CASE_SENSITIVE
| SC_PKCS15_PIN_FLAG_SO_PIN
}
};
int sc_pkcs15emu_rutoken_init_ex(sc_pkcs15_card_t *p15card, sc_pkcs15emu_opt_t *opts);
void add_predefined_pin(sc_pkcs15_card_t *p15card)
static int add_predefined_pin(sc_pkcs15_card_t *p15card, sc_path_t *adf_path)
{
int i;
sc_path_t path;
sc_pkcs15_pin_info_t *pin_info = (sc_pkcs15_pin_info_t *) calloc(1, sizeof(*pin_info));
sc_pkcs15_object_t *pin_obj = (sc_pkcs15_object_t *) calloc(1, sizeof(*pin_obj));
for(i=0; pinlist[i].id; ++i)
size_t i;
sc_pkcs15_pin_info_t *pin_info;
sc_pkcs15_object_t *pin_obj;
for (i = 0; i < sizeof(pinlist)/sizeof(pinlist[0]); ++i)
{
sc_format_path(pinlist[i].path, &path);
pin_info = calloc(1, sizeof(*pin_info));
pin_obj = calloc(1, sizeof(*pin_obj));
if (!pin_info || !pin_obj)
{
free(pin_info);
free(pin_obj);
return SC_ERROR_OUT_OF_MEMORY;
}
pin_info->auth_id.len = 1;
pin_info->auth_id.value[0] = 1;
pin_info->auth_id.value[0] = (u8)pinlist[i].reference;
pin_info->reference = pinlist[i].reference;
pin_info->flags = pinlist[i].flags;
pin_info->type = SC_PKCS15_PIN_TYPE_ASCII_NUMERIC;
pin_info->min_length = pinlist[i].min_length;
pin_info->min_length = 1;
pin_info->stored_length = 16;
pin_info->max_length = 16;
pin_info->pad_char = -1;
pin_info->tries_left = 1;
sc_format_path(pinlist[i].path, &pin_info->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;
@ -788,15 +103,19 @@ void add_predefined_pin(sc_pkcs15_card_t *p15card)
free(pin_obj);
free(pin_info);
}
return SC_SUCCESS;
}
static int sc_pkcs15_rutoken_init_func(sc_pkcs15_card_t *p15card)
static void set_string(char **strp, const char *value)
{
if (*strp) free(*strp);
*strp = value ? strdup(value) : NULL;
}
static int set_card_info(sc_pkcs15_card_t *p15card)
{
int ret = SC_ERROR_WRONG_CARD;
sc_card_t *card = p15card->card;
sc_context_t *ctx = p15card->card->ctx;
sc_path_t path;
sc_file_t *odf;
sc_serial_number_t serialnr;
char serial[30] = {0};
u8 info[8];
@ -804,76 +123,80 @@ static int sc_pkcs15_rutoken_init_func(sc_pkcs15_card_t *p15card)
/* get the card serial number */
if (sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serialnr) < 0)
{
sc_debug(ctx, "unable to get ICCSN");
goto failed;
sc_debug(ctx, "Unable to get ICCSN\n");
return SC_ERROR_WRONG_CARD;
}
sc_bin_to_hex(serialnr.value, serialnr.len , serial, sizeof(serial), 0);
set_string(&p15card->serial_number, serial);
/* ct_debug("serial_number = %s", serial); */
/* get ruToken information */
if (sc_card_ctl(card, SC_CARDCTL_RUTOKEN_GET_INFO, info) < 0)
{
sc_debug(ctx, "unable to get token information");
goto failed;
sc_debug(ctx, "Unable to get token information\n");
return SC_ERROR_WRONG_CARD;
}
set_string(&p15card->label, RUT_LABEL);
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);
odf = sc_file_new();
if(odf)
{
sc_format_path("3f0000000000dfff", &odf->path);
odf->id = 0xdfff;
odf->type = SC_FILE_TYPE_WORKING_EF;
odf->ef_structure = SC_FILE_EF_TRANSPARENT;
odf->size = 1024;
p15card->file_odf = odf;
}
return SC_SUCCESS;
}
add_predefined_pin(p15card);
static int sc_pkcs15_rutoken_init_func(sc_pkcs15_card_t *p15card)
{
sc_context_t *ctx;
sc_file_t *df;
sc_card_t *card;
sc_path_t path;
size_t i;
int r;
unsigned int added_pin = 0;
while (p15card->df_list)
sc_pkcs15_remove_df(p15card, p15card->df_list);
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;
sc_file_t *df = sc_file_new();
if (df)
{
df->id = DFsId;
df->size = 0;
df->type = SC_FILE_TYPE_WORKING_EF;
df->ef_structure = SC_FILE_EF_TRANSPARENT;
sc_format_path(PRK_DF, &path);
sc_append_file_id(&path, df->id);
if(card->ops->select_file(card, &path, NULL) == SC_SUCCESS)
r = set_card_info(p15card);
if (r != SC_SUCCESS)
{
df->path = path;
sc_pkcs15_add_df(p15card, SC_PKCS15_PRKDF, &path, df);
sc_error(ctx, "Unable to set card info: %s\n", sc_strerror(r));
r = SC_SUCCESS;
}
sc_format_path(PUK_DF, &path);
sc_append_file_id(&path, df->id);
if(card->ops->select_file(card, &path, NULL) == SC_SUCCESS)
for (i = 0; i < sizeof(arr_profile_df)/sizeof(arr_profile_df[0]); ++i)
{
df->path = path;
sc_pkcs15_add_df(p15card, SC_PKCS15_PUKDF, &path, df);
}
sc_format_path(C_DF, &path);
sc_append_file_id(&path, df->id);
if(card->ops->select_file(card, &path, NULL) == SC_SUCCESS)
df = NULL;
sc_format_path(arr_profile_df[i].path, &path);
if (card->ops->select_file(card, &path, &df) == SC_ERROR_FILE_NOT_FOUND)
{
df->path = path;
sc_pkcs15_add_df(p15card, SC_PKCS15_CDF, &path, df);
sc_error(ctx, "File system mismatch\n");
r = SC_ERROR_OBJECT_NOT_FOUND;
}
if (r == SC_SUCCESS)
r = sc_pkcs15_add_df(p15card, arr_profile_df[i].type, &path, df);
if (df)
sc_file_free(df);
if (r != SC_SUCCESS) break;
if (arr_profile_df[i].type == SC_PKCS15_AODF
&& add_predefined_pin(p15card, &path) == SC_SUCCESS
)
added_pin = 1;
}
ret = SC_SUCCESS;
failed:
return ret;
if (!added_pin)
{
sc_debug(ctx, "Use formating token!\n");
sc_format_path("", &path);
r = add_predefined_pin(p15card, &path);
}
return r;
}
int sc_pkcs15emu_rutoken_init_ex(sc_pkcs15_card_t *p15card,

View File

@ -2445,7 +2445,18 @@ static int pkcs15_dobj_get_value(struct sc_pkcs11_session *session,
return rv;
}
static CK_RV data_value_to_attr(CK_ATTRIBUTE_PTR attr, struct sc_pkcs15_data *data)
{
if (!attr || !data)
return CKR_ATTRIBUTE_VALUE_INVALID;
sc_debug(context, "data %p\n", data);
sc_debug(context, "data_len %i\n", data->data_len);
check_attribute_buffer(attr, data->data_len);
memcpy(attr->pValue, data->data, data->data_len);
return CKR_OK;
}
static CK_RV pkcs15_dobj_get_attribute(struct sc_pkcs11_session *session,
void *object,
@ -2503,16 +2514,14 @@ static CK_RV pkcs15_dobj_get_attribute(struct sc_pkcs11_session *session,
struct sc_pkcs15_data *data = NULL;
rv = pkcs15_dobj_get_value(session, dobj, &data);
if (rv!=CKR_OK)
if (rv == CKR_OK)
rv = data_value_to_attr(attr, data);
if (data) {
free(data->data);
free(data);
}
if (rv != CKR_OK)
return rv;
else if (!data)
return CKR_ATTRIBUTE_VALUE_INVALID;
sc_debug(context, "data %p\n", data);
sc_debug(context, "data_len %i\n", data->data_len);
check_attribute_buffer(attr, data->data_len);
memcpy(attr->pValue, data->data, data->data_len);
free(data);
}
break;
default:

View File

@ -33,7 +33,7 @@ libpkcs15init_la_SOURCES = \
pkcs15-gpk.c pkcs15-miocos.c pkcs15-cflex.c \
pkcs15-cardos.c pkcs15-jcop.c pkcs15-starcos.c \
pkcs15-oberthur.c pkcs15-setcos.c pkcs15-incrypto34.c \
pkcs15-muscle.c pkcs15-asepcos.c
pkcs15-muscle.c pkcs15-asepcos.c pkcs15-rutoken.c
libpkcs15init_la_LDFLAGS = -version-info @OPENSC_LT_CURRENT@:@OPENSC_LT_REVISION@:@OPENSC_LT_AGE@ $(AM_LDFLAGS)

View File

@ -1,75 +1,88 @@
#
# PKCS15 profile, generic information.
# This profile is loaded before any card specific profile.
#
cardinfo {
max-pin-length = 8;
pin-encoding = ascii-numeric;
pin-pad-char = 0x00;
#
# The following controls some aspects of the PKCS15 we put onto
# the card.
#
pkcs15 {
# Put certificates into the CDF itself?
direct-certificates = no;
# Put the DF length into the ODF file?
encode-df-length = no;
# Have a lastUpdate field in the EF(TokenInfo)?
do-last-update = yes;
}
option default {
# Default settings.
# This option block will always be processed.
option default_32k {
macros {
so-pin-flags = initialized, needs-padding, soPin;
isf_acl = WRITE=$SOPIN;
df_acl = *=$SOPIN;
odf-size = 0;
aodf-size = 0;
dodf-size = 2048;
cdf-size = 2048;
prkdf-size = 2048;
pukdf-size = 2048;
}
}
# Define reasonable limits for PINs and PUK
# We set the reference for SO pin+puk here, because
# those are hard-coded (if a PUK us assigned).
PIN so-pin {
reference = 0;
# This option is for cards with very little memory.
# It sets the size of various PKCS15 directory files
# to 128 or 256, respectively.
#option small {
option default {
macros {
odf-size = 0;
aodf-size = 0;
dodf-size = 512;
cdf-size = 512;
prkdf-size = 512;
pukdf-size = 512;
}
}
PIN so-puk {
reference = 1;
}
PIN user-pin {
attempts = 15;
}
PIN user-puk {
attempts = 15;
}
# Additional filesystem info.
# This is added to the file system info specified in the
# main profile.
filesystem {
DF MF {
DF {
path = 3F00;
type = DF;
file-id = 0000;
acl = *=NONE;
DF {
type = DF;
file-id = 0000;
acl = *=NONE;
DF {
# Here comes the application DF
DF PKCS15-AppDF {
type = DF;
file-id = 0000;
acl = *=NONE;
file-id = FF00;
EF PKCS15-ODF {
file-id = 00DF;
size = $odf-size;
}
DF {
type = DF;
EF PKCS15-AODF {
file-id = A0DF;
size = $aodf-size;
}
EF PKCS15-PrKDF {
file-id = 0001;
acl = *=NONE;
size = $prkdf-size;
}
DF {
type = DF;
EF PKCS15-PuKDF {
file-id = 0002;
acl = *=NONE;
size = $pukdf-size;
}
}
DF {
type = DF;
file-id = 0001;
acl = *=NONE;
EF PKCS15-CDF {
file-id = 0003;
size = $cdf-size;
}
EF PKCS15-DODF {
file-id = 0004;
size = $dodf-size;
}
}
}
}

View File

@ -28,446 +28,505 @@
#include <unistd.h>
#endif
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <sys/stat.h>
#include <limits.h>
#include <sys/types.h>
#include <fcntl.h>
#include <opensc/opensc.h>
#include <opensc/cardctl.h>
#include "util.h"
//#define _DEBUG
#ifdef _DEBUG
#define trace(fmt) printf("%s, %s line %d: " fmt, __FUNCTION__, __FILE__, __LINE__)
#define trace2(fmt,a) printf("%s, %s line %d: " fmt, __FUNCTION__, __FILE__, __LINE__, a)
#define trace2(fmt,a,b) printf("%s, %s line %d: " fmt, __FUNCTION__, __FILE__, __LINE__, a, b)
#else
#define trace(fmt)
#define trace2(fmt,a)
#define trace3(fmt,a,b)
#endif
#define IV_SIZE 8
#define HASH_SIZE 4
/* globals */
const char *app_name = "rutoken-tool";
sc_context_t *g_ctx = NULL;
static const char *app_name = "rutoken-tool";
enum {
OP_NONE,
OP_GET_INFO,
OP_ENCIPHER,
OP_DECIPHER,
OP_SIGN,
OP_FORMAT
OP_GEN_KEY,
OP_ENCRYPT,
OP_DECRYPT,
OP_MAC
};
enum {
OPT_BASE = 0x100,
OPT_PIN,
OPT_SOPIN
static const struct option options[] = {
{"reader", 1, NULL, 'r'},
{"wait", 0, NULL, 'w'},
{"pin", 1, NULL, 'p'},
{"key", 1, NULL, 'k'},
{"IV", 1, NULL, 'I'},
{"type", 1, NULL, 't'},
{"input", 1, NULL, 'i'},
{"output", 1, NULL, 'o'},
{"info", 0, NULL, 's'},
{"genkey", 0, NULL, 'g'},
{"encrypt", 0, NULL, 'e'},
{"decrypt", 0, NULL, 'd'},
{"mac", 0, NULL, 'm'},
{"verbose", 0, NULL, 'v'},
{NULL, 0, NULL, 0 }
};
const struct option options[] = {
{"reader", 1, 0, 'r'},
{"card-driver", 1, 0, 'c'},
{"wait", 0, 0, 'w'},
{"verbose", 0, 0, 'v'},
{"getinfo", 0, 0, 'g'},
{"encrypt", 0, 0, 'e'},
{"decrypt", 0, 0, 'u'},
{"sign", 0, 0, 's'},
{"key", 1, 0, 'k'},
{"i-vector",1, 0, 'I'},
{"pin", 1, 0, OPT_PIN},
{"so-pin", 1, 0, OPT_SOPIN},
{"input", 1, 0, 'i'},
{"output", 1, 0, 'o'},
{"format", 0, 0, 'F'},
{0, 0, 0, 0}
};
const char *option_help[] = {
static const char *option_help[] = {
"Uses reader number <arg> [0]",
"Forces the use of driver <arg> [auto-detect]",
"Wait for a card to be inserted",
"Verbose operation. Use several times to enable debug output.",
"Get RuToken info",
"GOST encrypt",
"GOST decrypt",
"sign",
"use GOST key",
"use initialization vector (synchro posylka)",
"user pin",
"admin pin",
"input file path",
"output file path",
"format card"
"Specify PIN",
"Selects the GOST key ID to use",
"Initialization vector of the encryption to use",
"Specify a new GOST key type: ECB (default), SM or CFB",
"Selects the input file to cipher",
"Selects the output file to cipher",
"Show ruToken information",
"Generate new GOST key",
"Performs GOST encryption operation",
"Performs GOST decryption operation",
"Performs MAC computation with GOST key",
"Verbose operation. Use several times to enable debug output."
};
/* Get ruToken device information */
int rutoken_info(sc_card_t *card)
static int rutoken_info(sc_card_t *card)
{
trace("enter\n");
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
char szInfo[SC_MAX_APDU_BUFFER_SIZE*4];
sc_serial_number_t serial;
int r;
r = card->ops->card_ctl(card, SC_CARDCTL_RUTOKEN_GET_INFO, rbuf);
r = sc_card_ctl(card, SC_CARDCTL_RUTOKEN_GET_INFO, rbuf);
if (r) {
fprintf(stderr, "get info failed: %s\n",
sc_strerror(r));
return 1;
}
sc_bin_to_hex(rbuf, 8, szInfo, sizeof(szInfo), 0);
printf("Type: %d\n", *((char *)rbuf));
printf("Version: %d.%d\n", (*((char *)rbuf+1))>>4, (*((char *)rbuf+1))&0x0F );
printf("Memory: %d Kb\n", *((char *)rbuf+2)*8);
printf("Protocol version: %d\n", *((char *)rbuf+3));
printf("Software version: %d\n", *((char *)rbuf+4));
printf("Order: %d\n", *((char *)rbuf+5));
sc_serial_number_t serial;
r = card->ops->card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial);
if (r) {
fprintf(stderr, "get serial failed: %s\n",
sc_strerror(r));
return 1;
}
sc_bin_to_hex(serial.value, serial.len , szInfo, sizeof(szInfo), 0);
printf("Serial number : %s\n", szInfo);
return 0;
}
/* Cryptografic routine */
/* Size of file */
off_t get_file_size(int fd)
{
off_t cur_pos;
off_t file_size;
cur_pos = lseek(fd, 0, SEEK_CUR);
file_size = lseek(fd, 0, SEEK_END);
lseek(fd, cur_pos, SEEK_SET);
return file_size;
}
/* Allocate buffer and read file, insert initialization vector if needIV
return buffer size */
int get_file(sc_card_t *card, const char *filepath, u8 **ppBuf, int needIV, u8 *IV)
{
int file = open(filepath, O_RDONLY);
int ret = -1, size = -1;
if(file > 0)
{
size = get_file_size(file);
trace2("size = %d\n", size);
if(size > 0) *ppBuf = realloc(*ppBuf, needIV ? size + 8 : size);
if(*ppBuf)
{
trace3("needIV %d, %p\n", needIV, IV);
if (needIV)
{
if (IV)
ret = memcpy(*ppBuf, IV, 8) != *ppBuf;
else
{
trace("get_challenge\n");
ret = card->ops->get_challenge(card, *ppBuf, 8);
}
if (ret == SC_SUCCESS)
{
ret = read(file, *ppBuf + 8, size) + 8;
size += 8;
}
else
ret = -1;
}
else
ret = read(file, *ppBuf, size);
}
trace3("ret = %d, size = %d\n", ret, size);
if( ret != size)
{
printf("Read error!!!\n");
free(*ppBuf);
ret = -1;
}
close(file);
}
else
printf("File %s not found\n", filepath);
return ret;
}
/* Write buffer to a file
sync = NULL if not sync decrypt */
int write_file(const char *filepath, u8 *buff, size_t len)
{
int file, r;
file = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR|S_IWUSR | S_IRGRP|S_IWGRP | S_IROTH|S_IWOTH);
if( file < 0 ) {
printf("File %s not found\n", filepath);
fprintf(stderr, "Error: Get info failed: %s\n", sc_strerror(r));
return -1;
}
r = write(file, buff, len);
if( r < 0) {
printf("Write error!!!\n");
return r;
};
return r;
printf("Type: %d\n", rbuf[0]);
printf("Version: %d.%d\n", rbuf[1]>>4, rbuf[1] & 0x0F);
printf("Memory: %d Kb\n", rbuf[2]*8);
printf("Protocol version: %d\n", rbuf[3]);
printf("Software version: %d\n", rbuf[4]);
printf("Order: %d\n", rbuf[5]);
r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial);
if (r) {
fprintf(stderr, "Error: Get serial failed: %s\n", sc_strerror(r));
return -1;
}
printf("Serial number: ");
hex_dump(stdout, serial.value, serial.len, NULL);
putchar('\n');
return 0;
}
/* Decrypt a buffer */
int rutoken_decipher(sc_card_t *card, u8 keyid, u8 *in, size_t inlen, u8 *out, size_t outlen, int oper)
/* Cipher/Decipher a buffer on token (used GOST key chosen by ID) */
static int rutoken_cipher(sc_card_t *card, u8 keyid,
const u8 *in, size_t inlen,
u8 *out, size_t outlen, int oper)
{
int r;/*
u8 buff[24] = {0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31,
0x4E, 0x4F, 0xEB, 0x69, 0x5B, 0xFF, 0x01, 0x20, 0xE1, 0xA9, 0x2D, 0xAE, 0x59, 0xD4, 0xD1, 0xCA};
u8 outbuff[24] = {0};*/
int r;
struct sc_rutoken_decipherinfo inf = { in, inlen, out, outlen };
sc_security_env_t env;
int cmd = (oper == OP_ENCRYPT) ?
SC_CARDCTL_RUTOKEN_GOST_ENCIPHER :
SC_CARDCTL_RUTOKEN_GOST_DECIPHER;
memset(&env, 0, sizeof(env));
env.key_ref[0] = keyid;
env.key_ref_len = 1;
env.algorithm = SC_ALGORITHM_GOST;
env.algorithm_flags = SC_RUTOKEN_OPTIONS_GOST_CRYPT_GAMM;
env.operation = SC_SEC_OPERATION_DECIPHER;
/* set security env */
trace2("try to set SE key = %02X\n", keyid);
r = card->ops->set_security_env(card, &env, 0);
r = sc_set_security_env(card, &env, 0);
if (r) {
fprintf(stderr, "decipher failed: %d : %s\n",
r, sc_strerror(r));
return 1;
}
trace("set SE - ok\n");
/* cipher */
r = card->ops->card_ctl(card, oper, &inf);
if (r < 0) {
fprintf(stderr, "decipher failed: %s\n",
fprintf(stderr, "Error: Cipher failed (set security environment): %s\n",
sc_strerror(r));
return 1;
return -1;
}
trace2("return %d\n", r);
return r;
}
/* Decrypt a file */
int crypt_file(sc_card_t *card, u8 keyid, const char *szInFile, const char *szOutFile, int oper, u8* IV)
{
int ret = SC_ERROR_CARD_CMD_FAILED;
int size = -1;
u8 *pBuf = NULL, *pOut = NULL;
size = get_file(card, szInFile, &pBuf, oper == OP_ENCIPHER, IV);
trace3("size of %s is %d\n", szInFile, size);
if(size > 0)
{
pOut = malloc(size);
size = rutoken_decipher
(card, keyid, pBuf, size, pOut, size,
oper == OP_ENCIPHER ? SC_CARDCTL_RUTOKEN_GOST_ENCIPHER : SC_CARDCTL_RUTOKEN_GOST_DECIPHER);
if ((size > 0) && (write_file(szOutFile, pOut, size) == size)) ret = SC_SUCCESS;
free(pBuf);
free(pOut);
/* cipher */
r = sc_card_ctl(card, cmd, &inf);
if (r) {
fprintf(stderr, "Error: Cipher failed: %s\n", sc_strerror(r));
return -1;
}
return ret;
return 0;
}
/* external definitions */
struct sc_profile_t;
extern int rutoken_erase(struct sc_profile_t *, sc_card_t *);
extern int rutoken_finalize_card(sc_card_t *);
extern int rutoken_init(struct sc_profile_t *, sc_card_t *);
/* Format and initialize file system */
int format_card(sc_card_t *card)
/* Compute MAC a buffer on token (used GOST key chosen by ID) */
static int rutoken_mac(sc_card_t *card, u8 keyid,
const u8 *in, size_t inlen,
u8 *out, size_t outlen)
{
int ret = SC_ERROR_CARD_CMD_FAILED;
trace("enter\n");
if (( ret = (rutoken_erase(NULL, card)) == SC_SUCCESS) &&
( ret = (rutoken_init(NULL, card)) == SC_SUCCESS)
)
ret = rutoken_finalize_card(card);
return ret;
int r;
sc_security_env_t env;
memset(&env, 0, sizeof(env));
env.key_ref[0] = keyid;
env.key_ref_len = 1;
env.algorithm = SC_ALGORITHM_GOST;
env.operation = SC_SEC_OPERATION_SIGN;
/* set security env */
r = sc_set_security_env(card, &env, 0);
if (r) {
fprintf(stderr, "Error: Computation signature (MAC) failed"
" (set security environment): %s\n", sc_strerror(r));
return -1;
}
/* calculate hash */
r = sc_compute_signature(card, in, inlen, out, outlen);
if (r) {
fprintf(stderr, "Error: Computation signature (MAC) failed: %s\n",
sc_strerror(r));
return -1;
}
return 0;
}
int main(int argc, char *const argv[])
/* Encrypt/Decrupt infile to outfile */
static int do_crypt(sc_card_t *card, u8 keyid,
const char *path_infile, const char *path_outfile,
const u8 IV[IV_SIZE], int oper)
{
int err = 0, r, c, long_optind = 0;
const char *opt_driver = NULL;
sc_context_param_t ctx_param;
int opt_reader = -1, opt_debug = 0, opt_wait = 0, opt_key = 0, opt_is_IV,
opt_is_pin = 0, opt_is_sopin = 0, opt_is_input = 0, opt_is_output = 0;
char opt_pin[100] = {0}, opt_input[PATH_MAX] = {0}, opt_output[PATH_MAX] = {0}, opt_IV[16] = {0};
int operation = 0;
int err;
int fd_in, fd_out;
struct stat st;
size_t insize, outsize, readsize;
u8 *inbuf = NULL, *outbuf = NULL, *p;
fd_in = open(path_infile, O_RDONLY);
if (fd_in < 0) {
fprintf(stderr, "Error: Cannot open file '%s'\n", path_infile);
return -1;
}
err = fstat(fd_in, &st);
if (err || (oper == OP_DECRYPT && st.st_size < IV_SIZE)) {
fprintf(stderr, "Error: File '%s' is invalid\n", path_infile);
close(fd_in);
return -1;
}
insize = st.st_size;
if (oper == OP_ENCRYPT)
insize += IV_SIZE;
outsize = insize;
if (oper == OP_DECRYPT) /* !(stat.st_size < IV_SIZE) already true */
outsize -= IV_SIZE;
inbuf = malloc(insize);
outbuf = malloc(outsize);
if (!inbuf || !outbuf) {
fprintf(stderr, "Error: File '%s' is too big (allocate memory)\n",
path_infile);
err = -1;
}
if (err == 0) {
p = inbuf;
readsize = insize;
if (oper == OP_ENCRYPT) {
memcpy(inbuf, IV, IV_SIZE); /* Set IV in first bytes buf */
/* insize >= IV_SIZE already true */
p += IV_SIZE;
readsize -= IV_SIZE;
}
err = read(fd_in, p, readsize);
if (err < 0 || (size_t)err != readsize) {
fprintf(stderr, "Error: Read file '%s' failed\n", path_infile);
err = -1;
}
else
err = 0;
}
close(fd_in);
if (err == 0) {
fd_out = open(path_outfile, O_WRONLY | O_CREAT | O_TRUNC,
S_IRUSR | S_IWUSR);
if (fd_out < 0) {
fprintf(stderr, "Error: Cannot create file '%s'\n",path_outfile);
err = -1;
}
else {
err = rutoken_cipher(card, keyid, inbuf, insize,
outbuf, outsize, oper);
if (err == 0) {
err = write(fd_out, outbuf, outsize);
if (err < 0 || (size_t)err != outsize) {
fprintf(stderr,"Error: Write file '%s' failed\n",
path_outfile);
err = -1;
}
else
err = 0;
}
close(fd_out);
}
}
if (outbuf)
free(outbuf);
if (inbuf)
free(inbuf);
return err;
}
/* Cipher/Decipher
(for cipher IV is parameters or random generated on token) */
static int gostchiper(sc_card_t *card, u8 keyid,
const char *path_infile, const char *path_outfile,
const char IV[IV_SIZE], int is_iv, int op_oper)
{
int r;
u8 iv[IV_SIZE];
if (op_oper == OP_ENCRYPT) {
if (!is_iv) {
/* generated random on token */
r = sc_get_challenge(card, iv, IV_SIZE);
if (r) {
fprintf(stderr, "Error: Generate IV"
" (get challenge) failed: %s\n",
sc_strerror(r));
return -1;
}
}
else
memcpy(iv, IV, IV_SIZE);
}
return do_crypt(card, keyid, path_infile, path_outfile, iv, op_oper);
}
/* Print MAC infile (used GOST key chosen by ID) */
static int gostmac(sc_card_t *card, u8 keyid, const char *path_infile)
{
int err;
int fd;
struct stat st;
size_t insize;
u8 *inbuf = NULL;
u8 outbuf[HASH_SIZE];
fd = open(path_infile, O_RDONLY);
if (fd < 0) {
fprintf(stderr, "Error: Cannot open file '%s'\n", path_infile);
return -1;
}
err = fstat(fd, &st);
if (err) {
fprintf(stderr, "Error: File '%s' is invalid\n", path_infile);
close(fd);
return -1;
}
insize = st.st_size;
inbuf = malloc(insize);
if (!inbuf) {
fprintf(stderr, "Error: File '%s' is too big (allocate memory)\n",
path_infile);
err = -1;
}
if (err == 0) {
err = read(fd, inbuf, insize);
if (err < 0 || (size_t)err != insize) {
fprintf(stderr, "Error: Read file '%s' failed\n", path_infile);
err = -1;
}
else
err = rutoken_mac(card, keyid, inbuf, insize,
outbuf, sizeof(outbuf));
}
if (err == 0) {
hex_dump(stdout, outbuf, sizeof(outbuf), NULL);
putchar('\n');
}
if (inbuf)
free(inbuf);
close(fd);
return err;
}
/* Generate GOST key on ruToken card */
static int generate_gostkey(sc_card_t *card, u8 keyid, u8 keyoptions)
{
const sc_SecAttrV2_t gk_sec_attr =
{0x44, 0, 0, 1, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 2};
sc_DOHdrV2_t paramkey;
int r;
memset(&paramkey, 0, sizeof(paramkey));
paramkey.wDOBodyLen = SC_RUTOKEN_DEF_LEN_DO_GOST;
paramkey.OTID.byObjectType = SC_RUTOKEN_TYPE_KEY;
paramkey.OTID.byObjectID = keyid;
paramkey.OP.byObjectOptions = keyoptions;
/* assert(sizeof(*gk_sec_attr)); */
/* assert(sizeof(*paramkey.SA_V2)); */
/* assert(sizeof(paramkey.SA_V2) == sizeof(gk_sec_attr)); */
memcpy(paramkey.SA_V2, gk_sec_attr, sizeof(gk_sec_attr));
r = sc_card_ctl(card, SC_CARDCTL_RUTOKEN_GENERATE_KEY_DO, &paramkey);
if (r) {
fprintf(stderr, "Error: Generate GOST key failed: %s\n", sc_strerror(r));
return -1;
}
return 0;
}
int main(int argc, char* argv[])
{
int opt_reader = -1;
int opt_wait = 0;
const char *opt_pin = NULL;
int opt_key = 0;
int opt_is_iv = 0;
u8 opt_keytype = SC_RUTOKEN_OPTIONS_GOST_CRYPT_PZ;
const char *opt_input = NULL;
const char *opt_output = NULL;
int opt_operation = OP_NONE;
int opt_debug = 0;
char IV[IV_SIZE];
int err = 0;
sc_context_t *ctx = NULL;
sc_context_param_t ctx_param;
sc_card_t *card = NULL;
int c, long_optind, r, tries_left;
while (1)
{
c = getopt_long(argc, argv, "r:vc:wgeusk:i:o:p:I:F", options,
&long_optind);
while (1) {
c = getopt_long(argc, argv, "r:wp:k:I:t:i:o:sgedmv",
options, &long_optind);
if (c == -1)
break;
switch (c) {
case 'h':
case '?':
print_usage_and_die(app_name, options, option_help);
case 'r':
opt_reader = atoi(optarg);
break;
case 'v':
opt_debug++;
break;
case 'c':
opt_driver = optarg;
break;
case 'w':
opt_wait = 1;
break;
case 'g':
operation = OP_GET_INFO;
case 'p':
opt_pin = optarg;
break;
case 'k':
opt_key = atoi(optarg);
opt_key = (opt_key / 10) * 0x10 + opt_key % 10;
if (opt_key <= 0 || opt_key < SC_RUTOKEN_DO_ALL_MIN_ID
|| opt_key > SC_RUTOKEN_DO_NOCHV_MAX_ID) {
fprintf(stderr, "Error: Key ID is invalid"
" (%d <= ID <= %d)\n",
SC_RUTOKEN_DO_ALL_MIN_ID > 0 ?
SC_RUTOKEN_DO_ALL_MIN_ID : 1,
SC_RUTOKEN_DO_NOCHV_MAX_ID);
return -1;
}
break;
case 'I':
opt_is_IV = 1;
strncpy(opt_IV, optarg, 8);
opt_is_iv = 1;
strncpy(IV, optarg, sizeof(IV));
break;
case 'u':
operation = OP_DECIPHER;
break;
case 'e':
operation = OP_ENCIPHER;
break;
case 's':
operation = OP_SIGN;
break;
case OPT_PIN:
if(opt_is_sopin || opt_is_pin)
{
fprintf(stderr, "You must specify only one pin\n");
goto end;
case 't':
if (strcmp(optarg, "CFB") == 0)
opt_keytype = SC_RUTOKEN_OPTIONS_GOST_CRYPT_GAMMOS;
else if (strcmp(optarg, "SM") == 0)
opt_keytype = SC_RUTOKEN_OPTIONS_GOST_CRYPT_GAMM;
else if (strcmp(optarg, "ECB") != 0) {
fprintf(stderr, "Error: Key type must be either"
" ECB, SM or CFB\n");
return -1;
}
opt_is_pin = 1;
strcpy(opt_pin, optarg);
break;
case OPT_SOPIN:
if(opt_is_sopin || opt_is_pin)
{
fprintf(stderr, "You must specify only one pin\n");
goto end;
}
opt_is_sopin = 1;
strcpy(opt_pin, optarg);
break;
case 'i':
opt_is_input = 1;
strcpy(opt_input, optarg);
opt_input = optarg;
break;
case 'o':
opt_is_output = 1;
strcpy(opt_output, optarg);
opt_output = optarg;
break;
case 'F':
operation = OP_FORMAT;
case 's':
opt_operation = OP_GET_INFO;
break;
case 'g':
opt_operation = OP_GEN_KEY;
break;
case 'e':
opt_operation = OP_ENCRYPT;
break;
case 'd':
opt_operation = OP_DECRYPT;
break;
case 'm':
opt_operation = OP_MAC;
break;
case 'v':
opt_debug++;
break;
}
}
/* create sc_context_t object */
trace("\n");
memset(&ctx_param, 0, sizeof(ctx_param));
ctx_param.ver = 0;
ctx_param.app_name = app_name;
r = sc_context_create(&ctx, &ctx_param);
if (r) {
fprintf(stderr, "Failed to establish context: %s\n",
fprintf(stderr, "Error: Failed to establish context: %s\n",
sc_strerror(r));
return 1;
return -1;
}
if (opt_debug)
ctx->debug = opt_debug;
if (opt_driver != NULL) {
err = sc_set_card_driver(ctx, opt_driver);
if (err) {
fprintf(stderr, "Driver '%s' not found!\n",
opt_driver);
err = -1;
goto end;
}
}
trace("\n");
err = connect_card(ctx, &card, opt_reader, 0, opt_wait, opt_debug);
if (err)
goto end;
if (connect_card(ctx, &card, opt_reader, 0, opt_wait, opt_debug) != 0)
err = -1;
if(opt_is_pin || opt_is_sopin){
if (err == 0 && opt_pin) {
/* verify */
int tries_left = 0;
err = sc_verify(card, SC_AC_CHV, opt_is_sopin ? 1 : 2 , (u8*)opt_pin, strlen(opt_pin), &tries_left);
if(err)
{
fprintf(stderr, "verify failed %d\n", err);
goto end;
r = sc_verify(card, SC_AC_CHV, SC_RUTOKEN_DEF_ID_GCHV_USER,
(u8*)opt_pin, strlen(opt_pin), &tries_left);
if (r) {
fprintf(stderr, "Error: PIN verification failed: %s",
sc_strerror(r));
if (r == SC_ERROR_PIN_CODE_INCORRECT)
fprintf(stderr, " (tries left %d)\n", tries_left);
else
putc('\n', stderr);
err = 1;
}
fprintf(stderr, "Verify ok\n");
}
switch(operation)
{
if (err == 0) {
err = -1;
switch (opt_operation) {
case OP_GET_INFO:
if ((err = rutoken_info(card))) {
goto end;
}
err = rutoken_info(card);
break;
case OP_DECIPHER:
case OP_ENCIPHER:
if(!opt_key)
{
fprintf(stderr, "Not key\n");
err = -1;
case OP_DECRYPT:
case OP_ENCRYPT:
case OP_MAC:
if (!opt_input) {
fprintf(stderr, "Error: No input file specified\n");
break;
}
if (!opt_is_input)
{
fprintf(stderr, "Not input file\n");
err = -1;
if (opt_operation != OP_MAC && !opt_output) {
fprintf(stderr, "Error: No output file specified\n");
break;
}
if (!opt_is_output)
{
fprintf(stderr, "Not output file\n");
err = -1;
case OP_GEN_KEY:
if (opt_key == 0) {
fprintf(stderr, "Error: You must set key ID\n");
break;
}
err = crypt_file(card, opt_key, opt_input, opt_output, operation, opt_is_IV ? (u8*)opt_IV : NULL);
break;
case OP_FORMAT:
trace("OP_FORMAT\n");
err = format_card(card);
if(err != SC_SUCCESS) fprintf(stderr, "Initialization failed\n");
if (opt_operation == OP_GEN_KEY)
err = generate_gostkey(card, (u8)opt_key, opt_keytype);
else if (opt_operation == OP_MAC)
err = gostmac(card, (u8)opt_key, opt_input);
else
err = gostchiper(card, (u8)opt_key, opt_input,opt_output,
IV, opt_is_iv, opt_operation);
break;
default:
printf("No operation --help\n");
fprintf(stderr, "Error: No operation specified\n");
break;
}
end:
}
if (card) {
/* sc_lock and sc_connect_card in connect_card */
sc_unlock(card);
sc_disconnect_card(card, 0);
}
@ -475,3 +534,4 @@ end:
sc_release_context(ctx);
return err;
}