add two missing files for ruToken support
Thanks to Ian Young for the bug report git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@3312 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
parent
a9ff90382e
commit
156f368f9d
|
@ -0,0 +1,364 @@
|
|||
/*
|
||||
* ruToken specific operation for PKCS #15 private key functions
|
||||
*
|
||||
* Copyright (C) 2007 Pavel Mironchik <rutoken@rutoken.ru>
|
||||
* Copyright (C) 2007 Eugene Hermann <rutoken@rutoken.ru>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <opensc/opensc.h>
|
||||
#include <opensc/pkcs15.h>
|
||||
|
||||
/* BLOB definition */
|
||||
|
||||
typedef struct _RSAPUBKEY {
|
||||
u_int32_t magic;
|
||||
u_int32_t bitlen;
|
||||
u_int32_t 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;
|
||||
|
||||
|
||||
static void ArrayReverse(u8 *buf, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
u8 tmp;
|
||||
|
||||
for (i=0; i < size/2; ++i)
|
||||
{
|
||||
tmp = buf[i];
|
||||
buf[i] = buf[size-1-i];
|
||||
buf[size-1-i] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
static int free_private_blob(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;
|
||||
}
|
||||
|
||||
static int bin_to_private_blob(PRIVATEKEYBLOB *pr_blob, const u8* buf, size_t buf_len)
|
||||
{
|
||||
const u8 *tmp;
|
||||
size_t len = 2 + sizeof(pr_blob->blobheader) + sizeof(pr_blob->rsapubkey);
|
||||
|
||||
if (buf_len < len)
|
||||
return -1;
|
||||
|
||||
tmp = buf + 2;
|
||||
memcpy(&pr_blob->blobheader, tmp, sizeof(pr_blob->blobheader));
|
||||
tmp += sizeof(pr_blob->blobheader);
|
||||
|
||||
memcpy(&pr_blob->rsapubkey, tmp, sizeof(pr_blob->rsapubkey));
|
||||
tmp += sizeof(pr_blob->rsapubkey);
|
||||
|
||||
u_int32_t bitlen = pr_blob->rsapubkey.bitlen;
|
||||
|
||||
len += bitlen/8 * 2 + bitlen/16 * 5;
|
||||
if (buf_len < len)
|
||||
return -1;
|
||||
|
||||
pr_blob->modulus = malloc(bitlen/8);
|
||||
pr_blob->prime1 = malloc(bitlen/16);
|
||||
pr_blob->prime2 = malloc(bitlen/16);
|
||||
pr_blob->exponent1 = malloc(bitlen/16);
|
||||
pr_blob->exponent2 = malloc(bitlen/16);
|
||||
pr_blob->coefficient = malloc(bitlen/16);
|
||||
pr_blob->privateExponent = malloc(bitlen/8);
|
||||
if (!pr_blob->modulus || !pr_blob->prime1 || !pr_blob->prime2
|
||||
|| !pr_blob->exponent1 || !pr_blob->exponent2
|
||||
|| !pr_blob->coefficient || !pr_blob->privateExponent
|
||||
)
|
||||
{
|
||||
free_private_blob(pr_blob);
|
||||
return -1;
|
||||
}
|
||||
memcpy(pr_blob->modulus, tmp, bitlen/8);
|
||||
tmp += bitlen/8;
|
||||
memcpy(pr_blob->prime1, tmp, bitlen/16);
|
||||
tmp += bitlen/16;
|
||||
memcpy(pr_blob->prime2, tmp, bitlen/16);
|
||||
tmp += bitlen/16;
|
||||
memcpy(pr_blob->exponent1, tmp, bitlen/16);
|
||||
tmp += bitlen/16;
|
||||
memcpy(pr_blob->exponent2, tmp, bitlen/16);
|
||||
tmp += bitlen/16;
|
||||
memcpy(pr_blob->coefficient, tmp, bitlen/16);
|
||||
tmp += bitlen/16;
|
||||
memcpy(pr_blob->privateExponent, tmp, bitlen/8);
|
||||
tmp += bitlen/8;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int create_private_blob(PRIVATEKEYBLOB *pr_blob, const struct sc_pkcs15_prkey_rsa *key)
|
||||
{
|
||||
size_t n;
|
||||
const u_int32_t bitlen = key->modulus.len*8;
|
||||
|
||||
if ( key->modulus.len != bitlen/8
|
||||
|| key->p.len != bitlen/16
|
||||
|| key->q.len != bitlen/16
|
||||
|| key->dmp1.len != bitlen/16
|
||||
|| key->dmq1.len != bitlen/16
|
||||
|| key->iqmp.len != bitlen/16
|
||||
|| key->d.len != bitlen/8
|
||||
)
|
||||
return -1;
|
||||
|
||||
/* blobheader */
|
||||
/* u8 bType; */
|
||||
pr_blob->blobheader.bType = 0x07;
|
||||
/* u8 bVersion; */
|
||||
pr_blob->blobheader.bVersion = 0x02;
|
||||
/* u16 reserved; */
|
||||
pr_blob->blobheader.reserved = 0;
|
||||
/* u32 aiKeyAlg; */
|
||||
pr_blob->blobheader.aiKeyAlg = 0x0000a400;
|
||||
|
||||
pr_blob->rsapubkey.magic = 0x32415352; /* "RSA2" */
|
||||
pr_blob->rsapubkey.bitlen = bitlen;
|
||||
|
||||
pr_blob->rsapubkey.pubexp = 0;
|
||||
for (n=0; n < key->exponent.len && n < sizeof(pr_blob->rsapubkey.pubexp); ++n)
|
||||
pr_blob->rsapubkey.pubexp +=
|
||||
(u_int32_t)key->exponent.data[key->exponent.len - n - 1] << 8*n;
|
||||
|
||||
pr_blob->modulus = malloc(bitlen/8);
|
||||
pr_blob->prime1 = malloc(bitlen/16);
|
||||
pr_blob->prime2 = malloc(bitlen/16);
|
||||
pr_blob->exponent1 = malloc(bitlen/16);
|
||||
pr_blob->exponent2 = malloc(bitlen/16);
|
||||
pr_blob->coefficient = malloc(bitlen/16);
|
||||
pr_blob->privateExponent = malloc(bitlen/8);
|
||||
if (!pr_blob->modulus || !pr_blob->prime1 || !pr_blob->prime2
|
||||
|| !pr_blob->exponent1 || !pr_blob->exponent2
|
||||
|| !pr_blob->coefficient || !pr_blob->privateExponent
|
||||
)
|
||||
{
|
||||
free_private_blob(pr_blob);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(pr_blob->modulus, key->modulus.data, key->modulus.len);
|
||||
ArrayReverse(pr_blob->modulus, key->modulus.len);
|
||||
memcpy(pr_blob->prime1, key->p.data, key->p.len);
|
||||
ArrayReverse(pr_blob->prime1, key->p.len);
|
||||
memcpy(pr_blob->prime2, key->q.data, key->q.len);
|
||||
ArrayReverse(pr_blob->prime2, key->q.len);
|
||||
memcpy(pr_blob->exponent1, key->dmp1.data, key->dmp1.len);
|
||||
ArrayReverse(pr_blob->exponent1, key->dmp1.len);
|
||||
memcpy(pr_blob->exponent2, key->dmq1.data, key->dmq1.len);
|
||||
ArrayReverse(pr_blob->exponent2, key->dmq1.len);
|
||||
memcpy(pr_blob->coefficient, key->iqmp.data, key->iqmp.len);
|
||||
ArrayReverse(pr_blob->coefficient, key->iqmp.len);
|
||||
memcpy(pr_blob->privateExponent, key->d.data, key->d.len);
|
||||
ArrayReverse(pr_blob->privateExponent, key->d.len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_sc_pksc15_prkey_rsa(const PRIVATEKEYBLOB *pr_blob, struct sc_pkcs15_prkey_rsa *key)
|
||||
{
|
||||
static const u8 Exp[3] = { 0x01, 0x00, 0x01 }; /* big endian */
|
||||
|
||||
const u_int32_t bitlen = pr_blob->rsapubkey.bitlen;
|
||||
|
||||
key->modulus.data = malloc(bitlen/8);
|
||||
key->modulus.len = bitlen/8;
|
||||
key->p.data = malloc(bitlen/16);
|
||||
key->p.len = bitlen/16;
|
||||
key->q.data = malloc(bitlen/16);
|
||||
key->q.len = bitlen/16;
|
||||
key->dmp1.data = malloc(bitlen/16);
|
||||
key->dmp1.len = bitlen/16;
|
||||
key->dmq1.data = malloc(bitlen/16);
|
||||
key->dmq1.len = bitlen/16; /* ?! bitlen/16 - 1; */
|
||||
key->iqmp.data = malloc(bitlen/16);
|
||||
key->iqmp.len = bitlen/16;
|
||||
key->d.data = malloc(bitlen/8);
|
||||
key->d.len = bitlen/8;
|
||||
key->exponent.data = malloc(sizeof(Exp));
|
||||
key->exponent.len = sizeof(Exp);
|
||||
if(!key->modulus.data || !key->p.data || !key->q.data || !key->dmp1.data
|
||||
|| !key->dmq1.data || !key->iqmp.data || !key->d.data
|
||||
|| !key->exponent.data
|
||||
)
|
||||
{
|
||||
free(key->modulus.data);
|
||||
free(key->p.data);
|
||||
free(key->q.data);
|
||||
free(key->dmp1.data);
|
||||
free(key->dmq1.data);
|
||||
free(key->iqmp.data);
|
||||
free(key->d.data);
|
||||
free(key->exponent.data);
|
||||
memset(key, 0, sizeof(*key));
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(key->exponent.data, &Exp, sizeof(Exp));
|
||||
memcpy(key->modulus.data, pr_blob->modulus, key->modulus.len);
|
||||
ArrayReverse(key->modulus.data, key->modulus.len);
|
||||
memcpy(key->p.data, pr_blob->prime1, key->p.len);
|
||||
ArrayReverse(key->p.data, key->p.len);
|
||||
memcpy(key->q.data, pr_blob->prime2, key->q.len);
|
||||
ArrayReverse(key->q.data, key->q.len);
|
||||
memcpy(key->dmp1.data, pr_blob->exponent1, key->dmp1.len);
|
||||
ArrayReverse(key->dmp1.data, key->dmp1.len);
|
||||
memcpy(key->dmq1.data, pr_blob->exponent2, key->dmq1.len);
|
||||
ArrayReverse(key->dmq1.data, key->dmq1.len);
|
||||
memcpy(key->iqmp.data, pr_blob->coefficient, key->iqmp.len);
|
||||
ArrayReverse(key->iqmp.data, key->iqmp.len);
|
||||
memcpy(key->d.data, pr_blob->privateExponent, key->d.len);
|
||||
ArrayReverse(key->d.data, key->d.len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int private_blob_to_bin(const PRIVATEKEYBLOB *pr_blob, u8 *buf, size_t *buf_len)
|
||||
{
|
||||
size_t len = 2 + sizeof(pr_blob->blobheader) + sizeof(pr_blob->rsapubkey);
|
||||
|
||||
if(*buf_len < len)
|
||||
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);
|
||||
|
||||
len += pr_blob->rsapubkey.bitlen/8 * 2 + pr_blob->rsapubkey.bitlen/16 * 5;
|
||||
if (*buf_len < len)
|
||||
return -1;
|
||||
|
||||
memcpy(tmp, pr_blob->modulus, pr_blob->rsapubkey.bitlen/8);
|
||||
tmp += pr_blob->rsapubkey.bitlen/8;
|
||||
|
||||
memcpy(tmp, pr_blob->prime1, pr_blob->rsapubkey.bitlen/16);
|
||||
tmp += pr_blob->rsapubkey.bitlen/16;
|
||||
|
||||
memcpy(tmp, pr_blob->prime2, pr_blob->rsapubkey.bitlen/16);
|
||||
tmp += pr_blob->rsapubkey.bitlen/16;
|
||||
|
||||
memcpy(tmp, pr_blob->exponent1, pr_blob->rsapubkey.bitlen/16);
|
||||
tmp += pr_blob->rsapubkey.bitlen/16;
|
||||
|
||||
memcpy(tmp, pr_blob->exponent2, pr_blob->rsapubkey.bitlen/16);
|
||||
tmp += pr_blob->rsapubkey.bitlen/16;
|
||||
|
||||
memcpy(tmp, pr_blob->coefficient, pr_blob->rsapubkey.bitlen/16);
|
||||
tmp += pr_blob->rsapubkey.bitlen/16;
|
||||
|
||||
memcpy(tmp, pr_blob->privateExponent, pr_blob->rsapubkey.bitlen/8);
|
||||
tmp += pr_blob->rsapubkey.bitlen/8;
|
||||
|
||||
*buf_len = len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clean_prkey_private_blob(const PRIVATEKEYBLOB* pr_blob)
|
||||
{
|
||||
const u_int32_t bitlen = pr_blob->rsapubkey.bitlen;
|
||||
|
||||
memset(pr_blob->modulus, 0, bitlen/8);
|
||||
memset(pr_blob->prime1, 0, bitlen/16);
|
||||
memset(pr_blob->prime2, 0, bitlen/16);
|
||||
memset(pr_blob->exponent1, 0, bitlen/16);
|
||||
memset(pr_blob->exponent2, 0, bitlen/16);
|
||||
memset(pr_blob->coefficient, 0, bitlen/16);
|
||||
memset(pr_blob->privateExponent, 0, bitlen/8);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_prkey_from_bin(const u8 *data, size_t len, struct sc_pkcs15_prkey **key)
|
||||
{
|
||||
int ret = -1;
|
||||
PRIVATEKEYBLOB pr_blob;
|
||||
|
||||
if (data && key)
|
||||
{
|
||||
*key = malloc(sizeof(struct sc_pkcs15_prkey));
|
||||
if (*key)
|
||||
{
|
||||
memset(*key, 0, sizeof(**key));
|
||||
ret = bin_to_private_blob(&pr_blob, data, len);
|
||||
if (ret == 0)
|
||||
{
|
||||
ret = get_sc_pksc15_prkey_rsa(&pr_blob, &(*key)->u.rsa);
|
||||
if (ret == 0)
|
||||
(*key)->algorithm = SC_ALGORITHM_RSA;
|
||||
clean_prkey_private_blob(&pr_blob);
|
||||
free_private_blob(&pr_blob);
|
||||
memset(&pr_blob, 0, sizeof(pr_blob));
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int get_bin_from_prkey(const struct sc_pkcs15_prkey_rsa *rsa, u8 *key, size_t *keysize)
|
||||
{
|
||||
int r = -1;
|
||||
PRIVATEKEYBLOB prkeyblob;
|
||||
|
||||
if (rsa && key && keysize)
|
||||
{
|
||||
r = create_private_blob(&prkeyblob, rsa);
|
||||
if (r == 0)
|
||||
{
|
||||
r = private_blob_to_bin(&prkeyblob, key, keysize);
|
||||
clean_prkey_private_blob(&prkeyblob);
|
||||
free_private_blob(&prkeyblob);
|
||||
memset(&prkeyblob, 0, sizeof(prkeyblob));
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
|
@ -0,0 +1,698 @@
|
|||
/*
|
||||
* ruToken specific operation for PKCS15 initialization
|
||||
*
|
||||
* Copyright (C) 2007 Pavel Mironchik <rutoken@rutoken.ru>
|
||||
* Copyright (C) 2007 Eugene Hermann <rutoken@rutoken.ru>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <opensc/opensc.h>
|
||||
#include <opensc/cardctl.h>
|
||||
#include <opensc/log.h>
|
||||
#include <opensc/pkcs15.h>
|
||||
#include "pkcs15-init.h"
|
||||
#include "profile.h"
|
||||
|
||||
#define MAX_ID 255
|
||||
|
||||
static const sc_SecAttrV2_t pr_sec_attr = {0x43, 1, 1, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 2};
|
||||
static const sc_SecAttrV2_t pb_sec_attr = {0x42, 0, 1, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 2};
|
||||
static const sc_SecAttrV2_t wn_sec_attr = {0x43, 1, 1, 0, 0, 0, 0,-1, 2, 2, 0, 0, 0, 0, 0};
|
||||
static const sc_SecAttrV2_t df_sec_attr = {0x43, 1, 1, 0, 0, 0, 0, 1, 2, 2, 0, 0, 0, 0, 2};
|
||||
static const sc_SecAttrV2_t ef_sec_attr = {0x42, 0, 1, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 2};
|
||||
static const sc_SecAttrV2_t p2_sec_attr = {0x43, 1, 1, 0, 0, 0, 0,-1, 1, 2, 0, 0, 0, 0, 0};
|
||||
static const sc_SecAttrV2_t p1_sec_attr = {0x43, 1, 1, 0, 0, 0, 0,-1, 1, 1, 0, 0, 0, 0, 0};
|
||||
|
||||
enum DF_IDs
|
||||
{
|
||||
PrKDFid = 0x1001,
|
||||
PuKDFid = 0x1002,
|
||||
CDFid = 0x1003,
|
||||
DODFid = 0x1004,
|
||||
AODFid = 0xFFFF
|
||||
};
|
||||
|
||||
#define PrKDF_name "PKCS15-PrKDF"
|
||||
#define PuKDF_name "PKCS15-PuKDF"
|
||||
#define CDF_name "PKCS15-CDF"
|
||||
#define DODF_name "PKCS15-DODF"
|
||||
#define AODF_name "PKCS15-AODF"
|
||||
#define ODF_name "PKCS15-ODF"
|
||||
|
||||
static const struct
|
||||
{
|
||||
char const* name;
|
||||
unsigned int dir;
|
||||
unsigned int type;
|
||||
} arr_def_df[] =
|
||||
{
|
||||
{ PrKDF_name, PrKDFid, SC_PKCS15_PRKDF },
|
||||
{ PuKDF_name, PuKDFid, SC_PKCS15_PUKDF },
|
||||
{ CDF_name, CDFid, SC_PKCS15_CDF },
|
||||
{ DODF_name, DODFid, SC_PKCS15_DODF },
|
||||
{ AODF_name, AODFid, SC_PKCS15_AODF }
|
||||
};
|
||||
|
||||
int get_bin_from_prkey(const struct sc_pkcs15_prkey_rsa *rsa, u8 *key, size_t *keysize);
|
||||
|
||||
/*
|
||||
* Create/override new EF.
|
||||
*/
|
||||
static int rutoken_create_file(sc_card_t *card, sc_path_t *path, sc_file_t *ef)
|
||||
{
|
||||
int ret = SC_SUCCESS;
|
||||
sc_path_t path_dir;
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
|
||||
if (path)
|
||||
{
|
||||
sc_ctx_suppress_errors_on(card->ctx);
|
||||
ret = card->ops->select_file(card, path, NULL);
|
||||
sc_ctx_suppress_errors_off(card->ctx);
|
||||
if (ret == SC_SUCCESS)
|
||||
{
|
||||
sc_path_t del_path;
|
||||
del_path.len = 2;
|
||||
del_path.type = SC_PATH_TYPE_FILE_ID;
|
||||
del_path.value[0] = (u8)(ef->id / 256);
|
||||
del_path.value[1] = (u8)(ef->id % 256);
|
||||
if (card->ops->select_file(card, &del_path, NULL) == SC_SUCCESS)
|
||||
ret = card->ops->delete_file(card, &del_path);
|
||||
}
|
||||
path_dir = *path;
|
||||
path_dir.len -= 2;
|
||||
ret = card->ops->select_file(card, &path_dir, NULL);
|
||||
}
|
||||
if (ret == SC_SUCCESS)
|
||||
{
|
||||
ret = card->ops->create_file(card, ef);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a DF
|
||||
*/
|
||||
static int
|
||||
rutoken_create_dir(sc_profile_t *profile, sc_card_t *card, sc_file_t *df)
|
||||
{
|
||||
int ret;
|
||||
sc_file_t *file = NULL;
|
||||
|
||||
if (!card || !card->ctx || !df)
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int get_dfpath(sc_profile_t *profile, unsigned int df_type,
|
||||
sc_path_t *out_path)
|
||||
{
|
||||
static const int DFid[SC_PKCS15_DF_TYPE_COUNT] =
|
||||
{ PrKDFid, PuKDFid, 0, 0, CDFid, 0, 0, DODFid };
|
||||
/* assert(0 == SC_PKCS15_PRKDF);
|
||||
* assert(1 == SC_PKCS15_PUKDF);
|
||||
* assert(4 == SC_PKCS15_CDF);
|
||||
* assert(7 == SC_PKCS15_DODF);
|
||||
*/
|
||||
|
||||
if (df_type >= SC_PKCS15_DF_TYPE_COUNT || !profile
|
||||
|| !profile->df || !profile->df[df_type]
|
||||
)
|
||||
return -1;
|
||||
|
||||
*out_path = profile->df[df_type]->path;
|
||||
out_path->len -= 2;
|
||||
sc_append_file_id(out_path, DFid[df_type]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
if (!profile || !card || !card->ctx || !key_info)
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
|
||||
if (get_dfpath(profile, SC_PKCS15_PRKDF, &key_info->path) < 0)
|
||||
{
|
||||
sc_debug(card->ctx, "Call error get_dfpath\n");
|
||||
return SC_ERROR_INTERNAL;
|
||||
}
|
||||
sc_append_file_id(&key_info->path, 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)
|
||||
{
|
||||
if (!profile || !card || !card->ctx || !obj)
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
return SC_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create private key files
|
||||
*/
|
||||
static int rutoken_create_prkeyfile(sc_card_t *card,
|
||||
sc_pkcs15_prkey_info_t *key_info, size_t prsize)
|
||||
{
|
||||
sc_path_t path;
|
||||
sc_file_t *file;
|
||||
int ret;
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
|
||||
file = sc_file_new();
|
||||
if (file)
|
||||
{
|
||||
/* create key file */
|
||||
path = key_info->path;
|
||||
file->type = SC_FILE_TYPE_WORKING_EF;
|
||||
file->id = key_info->key_reference;
|
||||
file->size = prsize;
|
||||
sc_file_set_sec_attr(file, (u8*)&pr_sec_attr, SEC_ATTR_SIZE);
|
||||
ret = rutoken_create_file(card, &path, file);
|
||||
if (file)
|
||||
sc_file_free(file);
|
||||
}
|
||||
else
|
||||
ret = SC_ERROR_OUT_OF_MEMORY;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Store a private key object.
|
||||
*/
|
||||
static int
|
||||
rutoken_store_key(sc_profile_t *profile, sc_card_t *card,
|
||||
sc_pkcs15_object_t *obj,
|
||||
sc_pkcs15_prkey_t *key)
|
||||
{
|
||||
sc_pkcs15_prkey_info_t *key_info;
|
||||
const int nKeyBufSize = 2048;
|
||||
u8 *prkeybuf = NULL;
|
||||
size_t prsize;
|
||||
int ret;
|
||||
|
||||
if (!profile || !profile->ops || !card || !card->ctx
|
||||
|| !obj || !obj->data || !key
|
||||
|| !profile->ops->encode_private_key
|
||||
)
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
|
||||
if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA)
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
|
||||
key_info = (sc_pkcs15_prkey_info_t *) obj->data;
|
||||
prkeybuf = calloc(nKeyBufSize, 1);
|
||||
if(!prkeybuf)
|
||||
return SC_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
/*
|
||||
* encode private key
|
||||
* create key file
|
||||
* write a key
|
||||
*/
|
||||
prsize = nKeyBufSize;
|
||||
ret = profile->ops->encode_private_key(profile, card, &key->u.rsa, prkeybuf, &prsize, 0);
|
||||
if (ret == 0)
|
||||
{
|
||||
ret = rutoken_create_prkeyfile(card, key_info, prsize);
|
||||
if (ret == 0)
|
||||
{
|
||||
ret = sc_update_binary(card, 0, prkeybuf, prsize, 0);
|
||||
if (ret < 0 || (size_t)ret != prsize)
|
||||
sc_debug(card->ctx, "ret=%i (%u)\n", ret, prsize);
|
||||
}
|
||||
memset(prkeybuf, 0, prsize);
|
||||
}
|
||||
free(prkeybuf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Encode private key
|
||||
*/
|
||||
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)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!card || !card->ctx || !rsa || !key || !keysize)
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
r = get_bin_from_prkey(rsa, key, keysize);
|
||||
sc_debug(card->ctx, "get_bin_from_prkey returned %i\n", r);
|
||||
return r;
|
||||
}
|
||||
|
||||
static 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;
|
||||
}
|
||||
|
||||
static int rutoken_find_id(sc_card_t *card, const sc_path_t *path)
|
||||
{
|
||||
int ret = SC_SUCCESS;
|
||||
sc_file_t *file = NULL;
|
||||
u8 *files = malloc(2048);
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a file based on a PKCS15_TYPE_xxx
|
||||
*/
|
||||
static int
|
||||
rutoken_new_file(struct sc_profile *profile, struct sc_card *card,
|
||||
unsigned int type, unsigned int idx, struct sc_file **file)
|
||||
{
|
||||
int ret = SC_SUCCESS, id, ret_s;
|
||||
sc_path_t path;
|
||||
u8 const *sec_attr;
|
||||
|
||||
if (!profile || !file || *file != NULL
|
||||
|| !card || !card->ctx || !card->ops
|
||||
|| !card->ops->delete_file || !card->ops->select_file
|
||||
|| !card->ops->list_files /* for call rutoken_find_id */
|
||||
)
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
|
||||
switch (type & SC_PKCS15_TYPE_CLASS_MASK)
|
||||
{
|
||||
case SC_PKCS15_TYPE_CERT:
|
||||
ret = get_dfpath(profile, SC_PKCS15_CDF, &path);
|
||||
sec_attr = pb_sec_attr;
|
||||
break;
|
||||
case SC_PKCS15_TYPE_PUBKEY:
|
||||
ret = get_dfpath(profile, SC_PKCS15_PUKDF, &path);
|
||||
sec_attr = pb_sec_attr;
|
||||
break;
|
||||
case SC_PKCS15_TYPE_DATA_OBJECT:
|
||||
ret = get_dfpath(profile, SC_PKCS15_DODF, &path);
|
||||
sec_attr = pr_sec_attr;
|
||||
break;
|
||||
case SC_PKCS15_TYPE_PRKEY_RSA:
|
||||
default:
|
||||
ret = SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
/* find first unlished file id */
|
||||
if (ret == SC_SUCCESS)
|
||||
{
|
||||
id = rutoken_find_id(card, &path);
|
||||
if (id < 0)
|
||||
{
|
||||
sc_debug(card->ctx, "Error find id (%i)\n", id);
|
||||
ret = SC_ERROR_TOO_MANY_OBJECTS;
|
||||
}
|
||||
}
|
||||
if(ret == SC_SUCCESS)
|
||||
{
|
||||
sc_debug(card->ctx, "new id %i\n", id);
|
||||
*file = sc_file_new();
|
||||
if (!*file)
|
||||
ret = SC_ERROR_OUT_OF_MEMORY;
|
||||
{
|
||||
(*file)->size = 0;
|
||||
(*file)->id = id;
|
||||
sc_append_file_id(&path, (*file)->id);
|
||||
(*file)->path = path;
|
||||
sc_file_set_sec_attr(*file, sec_attr, SEC_ATTR_SIZE);
|
||||
(*file)->type = SC_FILE_TYPE_WORKING_EF;
|
||||
/* If target file exist than remove it */
|
||||
sc_ctx_suppress_errors_on(card->ctx);
|
||||
ret_s = card->ops->select_file(card, &(*file)->path, NULL);
|
||||
sc_ctx_suppress_errors_off(card->ctx);
|
||||
if (ret_s == 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialization routine
|
||||
*/
|
||||
|
||||
static const struct
|
||||
{
|
||||
u8 id, options, flags, try, pass[8];
|
||||
sc_SecAttrV2_t const* p_sattr;
|
||||
} do_pins[] =
|
||||
{
|
||||
{ SC_RUTOKEN_DEF_ID_GCHV_USER, SC_RUTOKEN_OPTIONS_GACCESS_USER,
|
||||
SC_RUTOKEN_FLAGS_COMPACT_DO, 0xFF,
|
||||
{ '1', '2', '3', '4', '5', '6', '7', '8' }, &p2_sec_attr
|
||||
},
|
||||
{ SC_RUTOKEN_DEF_ID_GCHV_ADMIN, SC_RUTOKEN_OPTIONS_GACCESS_ADMIN,
|
||||
SC_RUTOKEN_FLAGS_COMPACT_DO, 0xFF,
|
||||
{ '8', '7', '6', '5', '4', '3', '2', '1' }, &p1_sec_attr
|
||||
}
|
||||
};
|
||||
|
||||
static int create_pins(sc_card_t *card)
|
||||
{
|
||||
sc_DO_V2_t param_do;
|
||||
size_t i;
|
||||
int r = SC_SUCCESS;
|
||||
|
||||
for (i = 0; i < sizeof(do_pins)/sizeof(do_pins[0]); ++i)
|
||||
{
|
||||
memset(¶m_do, 0, sizeof(param_do));
|
||||
param_do.HDR.OTID.byObjectType = SC_RUTOKEN_TYPE_CHV;
|
||||
param_do.HDR.OTID.byObjectID = do_pins[i].id;
|
||||
param_do.HDR.OP.byObjectOptions = do_pins[i].options;
|
||||
param_do.HDR.OP.byObjectFlags = do_pins[i].flags;
|
||||
param_do.HDR.OP.byObjectTry = do_pins[i].try;
|
||||
param_do.HDR.wDOBodyLen = sizeof(do_pins[i].pass);
|
||||
/* assert(do_pins[i].p_sattr != NULL); */
|
||||
/* assert(sizeof(*param_do.HDR.SA_V2)) */
|
||||
/* assert(sizeof(param_do.HDR.SA_V2) == sizeof(*do_pins[i].p_sattr)); */
|
||||
memcpy(param_do.HDR.SA_V2, *do_pins[i].p_sattr,
|
||||
sizeof(*do_pins[i].p_sattr));
|
||||
/* assert(do_pins[i].pass); */
|
||||
/* assert(sizeof(*param_do.abyDOBody)) */
|
||||
/* assert(sizeof(param_do.abyDOBody) >= sizeof(do_pins[i].pass)); */
|
||||
memcpy(param_do.abyDOBody, do_pins[i].pass, sizeof(do_pins[i].pass));
|
||||
|
||||
r = sc_card_ctl(card, SC_CARDCTL_RUTOKEN_CREATE_DO, ¶m_do);
|
||||
if (r != SC_SUCCESS) break;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static int create_typical_fs(sc_card_t *card)
|
||||
{
|
||||
sc_file_t *df;
|
||||
int r;
|
||||
|
||||
df = sc_file_new();
|
||||
if (!df)
|
||||
return SC_ERROR_OUT_OF_MEMORY;
|
||||
df->type = SC_FILE_TYPE_DF;
|
||||
do
|
||||
{
|
||||
r = sc_file_set_sec_attr(df, wn_sec_attr, SEC_ATTR_SIZE);
|
||||
if (r != SC_SUCCESS) break;
|
||||
|
||||
/* Create MF 3F00 */
|
||||
df->id = 0x3F00;
|
||||
sc_format_path("3F00", &df->path);
|
||||
r = card->ops->create_file(card, df);
|
||||
if (r != SC_SUCCESS) break;
|
||||
|
||||
/* Create 3F00/0000 */
|
||||
df->id = 0x0000;
|
||||
sc_append_file_id(&df->path, df->id);
|
||||
r = card->ops->create_file(card, df);
|
||||
if (r != SC_SUCCESS) break;
|
||||
|
||||
/* Create 3F00/0000/0000 */
|
||||
df->id = 0x0000;
|
||||
sc_append_file_id(&df->path, df->id);
|
||||
r = card->ops->create_file(card, df);
|
||||
if (r != SC_SUCCESS) break;
|
||||
|
||||
/* Create USER PIN and SO PIN*/
|
||||
r = create_pins(card);
|
||||
if (r != SC_SUCCESS) break;
|
||||
|
||||
/* VERIFY USER PIN */
|
||||
r = sc_verify(card, SC_AC_CHV, do_pins[0].id,
|
||||
do_pins[0].pass, sizeof(do_pins[0].pass), NULL);
|
||||
if (r != SC_SUCCESS) break;
|
||||
|
||||
/* Create 3F00/0000/0000/0001 */
|
||||
df->id = 0x0001;
|
||||
sc_append_file_id(&df->path, df->id);
|
||||
r = card->ops->create_file(card, df);
|
||||
if (r != SC_SUCCESS) break;
|
||||
|
||||
sc_format_path("3F0000000000", &df->path);
|
||||
r = card->ops->select_file(card, &df->path, NULL);
|
||||
if (r != SC_SUCCESS) break;
|
||||
|
||||
/* Create 3F00/0000/0000/0002 */
|
||||
df->id = 0x0002;
|
||||
sc_append_file_id(&df->path, df->id);
|
||||
r = card->ops->create_file(card, df);
|
||||
if (r != SC_SUCCESS) break;
|
||||
|
||||
sc_format_path("3F000000", &df->path);
|
||||
r = card->ops->select_file(card, &df->path, NULL);
|
||||
if (r != SC_SUCCESS) break;
|
||||
|
||||
/* Create 3F00/0000/0001 */
|
||||
df->id = 0x0001;
|
||||
sc_append_file_id(&df->path, df->id);
|
||||
r = card->ops->create_file(card, df);
|
||||
if (r != SC_SUCCESS) break;
|
||||
|
||||
/* RESET ACCESS RIGHTS */
|
||||
r = sc_logout(card);
|
||||
} while(0);
|
||||
sc_file_free(df);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Card-specific initialization of PKCS15 profile information
|
||||
*/
|
||||
static int rutoken_init(sc_profile_t *profile, sc_card_t *card)
|
||||
{
|
||||
struct file_info *ef_list;
|
||||
sc_file_t *df, *ef;
|
||||
size_t i;
|
||||
int r, ret = SC_SUCCESS;
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
|
||||
df = sc_file_new();
|
||||
if (!df)
|
||||
{
|
||||
sc_debug(card->ctx, "Failed to create file\n");
|
||||
return SC_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
df->type = SC_FILE_TYPE_DF;
|
||||
r = sc_file_set_sec_attr(df, df_sec_attr, SEC_ATTR_SIZE);
|
||||
if (r != SC_SUCCESS)
|
||||
sc_debug(card->ctx, "Failed to set secure attr: %s\n", sc_strerror(r));
|
||||
|
||||
for (ef_list = profile->ef_list; ef_list; ef_list = ef_list->next)
|
||||
{
|
||||
if (!ef_list->file || ef_list->file->path.len <= 2)
|
||||
continue;
|
||||
df->path = ef_list->file->path;
|
||||
df->path.len -= 2;
|
||||
ret = card->ops->select_file(card, &df->path, NULL);
|
||||
if (ret != SC_SUCCESS)
|
||||
{
|
||||
sc_debug(card->ctx,"Failed select file: %s\n", sc_strerror(ret));
|
||||
break;
|
||||
}
|
||||
|
||||
sc_file_dup(&ef, ef_list->file);
|
||||
if (!ef)
|
||||
{
|
||||
sc_debug(card->ctx, "Failed to dup file\n");
|
||||
ret = SC_ERROR_OUT_OF_MEMORY;
|
||||
break;
|
||||
}
|
||||
r = sc_file_set_sec_attr(ef,
|
||||
ef->type == SC_FILE_TYPE_DF ?
|
||||
df_sec_attr : ef_sec_attr, SEC_ATTR_SIZE);
|
||||
if (r != SC_SUCCESS)
|
||||
sc_debug(card->ctx, "Failed to set secure attr: %s\n",
|
||||
sc_strerror(r));
|
||||
|
||||
ret = card->ops->create_file(card, ef);
|
||||
sc_file_free(ef);
|
||||
if (ret != SC_SUCCESS)
|
||||
{
|
||||
sc_error(card->ctx, "Failed to create file "
|
||||
"in compliance with profile: %s\n",
|
||||
sc_strerror(ret));
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof(arr_def_df)/sizeof(arr_def_df[0]); ++i)
|
||||
if (arr_def_df[i].dir != AODFid
|
||||
&& strcasecmp(ef_list->ident, arr_def_df[i].name) == 0
|
||||
)
|
||||
{
|
||||
df->id = arr_def_df[i].dir;
|
||||
r = sc_append_file_id(&df->path, df->id);
|
||||
if (r == SC_SUCCESS)
|
||||
r = card->ops->create_file(card, df);
|
||||
if (r != SC_SUCCESS)
|
||||
sc_error(card->ctx, "Failed to create df, %s\n",
|
||||
sc_strerror(r));
|
||||
break;
|
||||
}
|
||||
}
|
||||
sc_file_free(df);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Erase everything that's on the card
|
||||
* And create PKCS15 profile
|
||||
*/
|
||||
static int
|
||||
rutoken_erase(struct sc_profile *profile, sc_card_t *card)
|
||||
{
|
||||
int ret, ret_end;
|
||||
|
||||
if (!profile || !card || !card->ctx || !card->ops
|
||||
|| !card->ops->select_file || !card->ops->create_file
|
||||
)
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
|
||||
/* ret = sc_card_ctl(card, SC_CARDCTL_ERASE_CARD, NULL); */
|
||||
ret = sc_card_ctl(card, SC_CARDCTL_RUTOKEN_FORMAT_INIT, NULL);
|
||||
if (ret != SC_SUCCESS)
|
||||
sc_error(card->ctx, "Failed to erase: %s\n", sc_strerror(ret));
|
||||
else
|
||||
{
|
||||
ret = create_typical_fs(card);
|
||||
if (ret != SC_SUCCESS)
|
||||
sc_error(card->ctx, "Failed to create typical fs: %s\n",
|
||||
sc_strerror(ret));
|
||||
ret_end = sc_card_ctl(card, SC_CARDCTL_RUTOKEN_FORMAT_END, NULL);
|
||||
if (ret_end != SC_SUCCESS)
|
||||
ret = ret_end;
|
||||
if (ret == SC_SUCCESS)
|
||||
{
|
||||
/* VERIFY __default__ USER PIN */
|
||||
/* assert(sizeof(do_pins)/sizeof(do_pins[0]) >= 1); */
|
||||
/* assert(do_pins[0].id == SC_RUTOKEN_DEF_ID_GCHV_USER); */
|
||||
ret = sc_verify(card, SC_AC_CHV, do_pins[0].id,
|
||||
do_pins[0].pass, sizeof(do_pins[0].pass), NULL);
|
||||
if (ret != SC_SUCCESS)
|
||||
sc_debug(card->ctx, "VERIFY default USER PIN: %s\n",
|
||||
sc_strerror(ret));
|
||||
else
|
||||
{
|
||||
ret = rutoken_init(profile, card);
|
||||
|
||||
/* RESET ACCESS RIGHTS */
|
||||
if (sc_logout(card) != SC_SUCCESS)
|
||||
sc_debug(card->ctx,
|
||||
"Failed RESET ACCESS RIGHTS\n");
|
||||
}
|
||||
}
|
||||
if (ret != SC_SUCCESS)
|
||||
sc_error(card->ctx, "Failed to init PKCS15: %s\n",
|
||||
sc_strerror(ret));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct sc_pkcs15init_operations sc_pkcs15init_rutoken_operations = {
|
||||
rutoken_erase, /* erase_card */
|
||||
NULL, /* init_card */
|
||||
rutoken_create_dir, /* create_dir */
|
||||
NULL, /* create_domain */
|
||||
NULL, /* select_pin_reference */
|
||||
NULL, /* create_pin */
|
||||
rutoken_select_key_reference, /* select_key_reference */
|
||||
rutoken_create_key, /* create_key */
|
||||
rutoken_store_key, /* store_key */
|
||||
NULL, /* generate_key */
|
||||
rutoken_encode_private_key, /* encode_private_key */
|
||||
NULL, /* encode_public_key */
|
||||
NULL, /* finalize_card */
|
||||
/* Old-style API */
|
||||
NULL, /* init_app */
|
||||
NULL, /* new_pin */
|
||||
NULL, /* new_key */
|
||||
rutoken_new_file, /* new_file */
|
||||
NULL, /* old_generate_key */
|
||||
NULL /* delete_object */
|
||||
};
|
||||
|
||||
struct sc_pkcs15init_operations* sc_pkcs15init_get_rutoken_ops(void)
|
||||
{
|
||||
return &sc_pkcs15init_rutoken_operations;
|
||||
}
|
||||
|
Loading…
Reference in New Issue