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:
parent
513a3dde0a
commit
bf9d6beaac
|
@ -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
|
@ -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 {
|
||||
|
@ -545,7 +546,7 @@ typedef struct sc_DO_INFO_V2 {
|
|||
} sc_DO_INFO_t;
|
||||
|
||||
struct sc_rutoken_decipherinfo {
|
||||
u8 *inbuf;
|
||||
const u8 *inbuf;
|
||||
size_t inlen;
|
||||
u8 *outbuf;
|
||||
size_t outlen;
|
||||
|
|
|
@ -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"
|
||||
|
||||
static const struct {
|
||||
int type, id, auth_id, min_length;
|
||||
unsigned char reference;
|
||||
const char *path;
|
||||
const char *label;
|
||||
int flags;
|
||||
} pinlist[]=
|
||||
{
|
||||
#define PrKDF_path "3F00FF000001"
|
||||
#define PuKDF_path "3F00FF000002"
|
||||
#define CDF_path "3F00FF000003"
|
||||
#define DODF_path "3F00FF000004"
|
||||
#define AODF_path "3F00FF00A0DF"
|
||||
|
||||
{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}
|
||||
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 }
|
||||
};
|
||||
|
||||
int sc_pkcs15emu_rutoken_init_ex(sc_pkcs15_card_t *p15card, sc_pkcs15emu_opt_t *opts);
|
||||
static const struct {
|
||||
int reference;
|
||||
const char *label;
|
||||
unsigned int flags;
|
||||
} pinlist[]=
|
||||
{
|
||||
{ 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
|
||||
}
|
||||
};
|
||||
|
||||
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();
|
||||
r = set_card_info(p15card);
|
||||
if (r != SC_SUCCESS)
|
||||
{
|
||||
sc_error(ctx, "Unable to set card info: %s\n", sc_strerror(r));
|
||||
r = SC_SUCCESS;
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof(arr_profile_df)/sizeof(arr_profile_df[0]); ++i)
|
||||
{
|
||||
df = NULL;
|
||||
sc_format_path(arr_profile_df[i].path, &path);
|
||||
if (card->ops->select_file(card, &path, &df) == SC_ERROR_FILE_NOT_FOUND)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
df->path = path;
|
||||
sc_pkcs15_add_df(p15card, SC_PKCS15_PRKDF, &path, df);
|
||||
}
|
||||
sc_format_path(PUK_DF, &path);
|
||||
sc_append_file_id(&path, df->id);
|
||||
if(card->ops->select_file(card, &path, NULL) == SC_SUCCESS)
|
||||
{
|
||||
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->path = path;
|
||||
sc_pkcs15_add_df(p15card, SC_PKCS15_CDF, &path, 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,
|
||||
|
|
|
@ -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)
|
||||
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:
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
# Default settings.
|
||||
# This option block will always be processed.
|
||||
option default_32k {
|
||||
macros {
|
||||
odf-size = 0;
|
||||
aodf-size = 0;
|
||||
dodf-size = 2048;
|
||||
cdf-size = 2048;
|
||||
prkdf-size = 2048;
|
||||
pukdf-size = 2048;
|
||||
}
|
||||
}
|
||||
|
||||
# This option is for cards with very little memory.
|
||||
# It sets the size of various PKCS15 directory files
|
||||
# to 128 or 256, respectively.
|
||||
#option small {
|
||||
option default {
|
||||
macros {
|
||||
so-pin-flags = initialized, needs-padding, soPin;
|
||||
isf_acl = WRITE=$SOPIN;
|
||||
df_acl = *=$SOPIN;
|
||||
odf-size = 0;
|
||||
aodf-size = 0;
|
||||
dodf-size = 512;
|
||||
cdf-size = 512;
|
||||
prkdf-size = 512;
|
||||
pukdf-size = 512;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# 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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
fprintf(stderr, "Error: Get info failed: %s\n", sc_strerror(r));
|
||||
return -1;
|
||||
}
|
||||
sc_bin_to_hex(rbuf, 8, szInfo, sizeof(szInfo), 0);
|
||||
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]);
|
||||
|
||||
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);
|
||||
r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial);
|
||||
if (r) {
|
||||
fprintf(stderr, "get serial failed: %s\n",
|
||||
sc_strerror(r));
|
||||
return 1;
|
||||
fprintf(stderr, "Error: 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);
|
||||
printf("Serial number: ");
|
||||
hex_dump(stdout, serial.value, serial.len, NULL);
|
||||
putchar('\n');
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Cryptografic routine */
|
||||
/* Cipher/Decipher a buffer on token (used GOST key chosen by ID) */
|
||||
|
||||
/* Size of file */
|
||||
|
||||
off_t get_file_size(int fd)
|
||||
static int rutoken_cipher(sc_card_t *card, u8 keyid,
|
||||
const u8 *in, size_t inlen,
|
||||
u8 *out, size_t outlen, int oper)
|
||||
{
|
||||
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);
|
||||
return -1;
|
||||
}
|
||||
r = write(file, buff, len);
|
||||
if( r < 0) {
|
||||
printf("Write error!!!\n");
|
||||
return r;
|
||||
};
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Decrypt a buffer */
|
||||
|
||||
int rutoken_decipher(sc_card_t *card, u8 keyid, 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;
|
||||
/* cipher */
|
||||
r = sc_card_ctl(card, cmd, &inf);
|
||||
if (r) {
|
||||
fprintf(stderr, "Error: Cipher failed: %s\n", sc_strerror(r));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Decrypt a file */
|
||||
/* Compute MAC a buffer on token (used GOST key chosen by ID) */
|
||||
|
||||
int crypt_file(sc_card_t *card, u8 keyid, const char *szInFile, const char *szOutFile, int oper, u8* IV)
|
||||
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;
|
||||
int size = -1;
|
||||
u8 *pBuf = NULL, *pOut = NULL;
|
||||
int r;
|
||||
sc_security_env_t env;
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
return ret;
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
/* 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 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 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;
|
||||
}
|
||||
|
||||
int main(int argc, char *const argv[])
|
||||
/* 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 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 r;
|
||||
u8 iv[IV_SIZE];
|
||||
|
||||
int operation = 0;
|
||||
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(¶mkey, 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, ¶mkey);
|
||||
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);
|
||||
|
||||
if (connect_card(ctx, &card, opt_reader, 0, opt_wait, opt_debug) != 0)
|
||||
err = -1;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
trace("\n");
|
||||
err = connect_card(ctx, &card, opt_reader, 0, opt_wait, opt_debug);
|
||||
if (err)
|
||||
goto end;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue