2008-01-04 08:57:12 +00:00
|
|
|
/*
|
2010-09-09 17:28:44 +00:00
|
|
|
* Rutoken S specific operation for PKCS15 initialization
|
2008-01-04 08:57:12 +00:00
|
|
|
*
|
|
|
|
* Copyright (C) 2007 Pavel Mironchik <rutoken@rutoken.ru>
|
|
|
|
* Copyright (C) 2007 Eugene Hermann <rutoken@rutoken.ru>
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*/
|
2008-04-18 14:08:23 +00:00
|
|
|
|
2010-03-04 08:14:36 +00:00
|
|
|
#include "config.h"
|
|
|
|
|
2008-01-04 08:57:12 +00:00
|
|
|
#include <sys/types.h>
|
2010-09-09 17:28:44 +00:00
|
|
|
#include <stddef.h>
|
2008-01-04 08:57:12 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2010-03-04 08:14:36 +00:00
|
|
|
|
|
|
|
#include "libopensc/opensc.h"
|
|
|
|
#include "libopensc/cardctl.h"
|
|
|
|
#include "libopensc/log.h"
|
|
|
|
#include "libopensc/pkcs15.h"
|
2008-01-04 08:57:12 +00:00
|
|
|
#include "pkcs15-init.h"
|
|
|
|
#include "profile.h"
|
|
|
|
|
2009-11-23 16:38:02 +00:00
|
|
|
static const sc_SecAttrV2_t pr_sec_attr = {
|
|
|
|
0x43, 1, 1, 0, 0, 0, 0, 1,
|
|
|
|
2, 0, 0, 0,
|
|
|
|
2, 0, 0, 0,
|
|
|
|
0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0,
|
|
|
|
2, 0, 0, 0,
|
|
|
|
0, 0, 0, 0 /* reserve */
|
|
|
|
};
|
|
|
|
static const sc_SecAttrV2_t wn_sec_attr = {
|
|
|
|
0x43, 1, 1, 0, 0, 0, 0, -1,
|
|
|
|
2, 0, 0, 0,
|
|
|
|
2
|
|
|
|
};
|
|
|
|
static const sc_SecAttrV2_t p2_sec_attr = {
|
|
|
|
0x43, 1, 1, 0, 0, 0, 0, -1,
|
|
|
|
1, 0, 0, 0,
|
|
|
|
2
|
|
|
|
};
|
|
|
|
static const sc_SecAttrV2_t p1_sec_attr = {
|
2010-02-04 10:39:30 +00:00
|
|
|
0x43, -1, 1, 0, 0, 0, 0, -1,
|
|
|
|
0, 0, 0, 0,
|
2009-11-23 16:38:02 +00:00
|
|
|
1
|
|
|
|
};
|
2008-01-04 08:57:12 +00:00
|
|
|
|
|
|
|
static const struct
|
|
|
|
{
|
2009-01-28 12:10:13 +00:00
|
|
|
u8 id, options, flags, try, pass[8];
|
|
|
|
sc_SecAttrV2_t const* p_sattr;
|
|
|
|
} do_pins[] =
|
2008-01-04 08:57:12 +00:00
|
|
|
{
|
2009-01-28 12:10:13 +00:00
|
|
|
{ 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
|
|
|
|
}
|
2008-01-04 08:57:12 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create a DF
|
|
|
|
*/
|
|
|
|
static int
|
2010-02-21 16:21:57 +00:00
|
|
|
rutoken_create_dir(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
|
|
|
|
sc_file_t *df)
|
2008-01-04 08:57:12 +00:00
|
|
|
{
|
2010-02-24 08:57:37 +00:00
|
|
|
if (!profile || !p15card || !p15card->card || !p15card->card->ctx || !df)
|
2009-01-28 12:10:13 +00:00
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(p15card->card->ctx, SC_LOG_DEBUG_VERBOSE);
|
2010-02-21 16:21:57 +00:00
|
|
|
return sc_pkcs15init_create_file(profile, p15card, df);
|
2009-01-28 12:10:13 +00:00
|
|
|
}
|
2008-01-04 08:57:12 +00:00
|
|
|
|
2009-01-28 12:10:13 +00:00
|
|
|
/*
|
|
|
|
* Select a PIN reference
|
|
|
|
*/
|
|
|
|
static int
|
2010-02-21 16:21:57 +00:00
|
|
|
rutoken_select_pin_reference(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
|
2009-01-28 12:10:13 +00:00
|
|
|
sc_pkcs15_pin_info_t *pin_info)
|
|
|
|
{
|
2010-02-03 12:10:41 +00:00
|
|
|
int pin_ref;
|
|
|
|
unsigned int so_pin_flag;
|
|
|
|
|
2010-02-24 08:22:24 +00:00
|
|
|
if (!profile || !p15card || !p15card->card || !p15card->card->ctx || !pin_info)
|
2008-01-04 08:57:12 +00:00
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(p15card->card->ctx, SC_LOG_DEBUG_VERBOSE);
|
2008-01-04 08:57:12 +00:00
|
|
|
|
2010-02-03 12:10:41 +00:00
|
|
|
pin_ref = pin_info->reference;
|
|
|
|
so_pin_flag = pin_info->flags & SC_PKCS15_PIN_FLAG_SO_PIN;
|
2008-01-04 08:57:12 +00:00
|
|
|
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, "PIN reference %i%s\n",
|
2010-02-03 12:10:41 +00:00
|
|
|
pin_ref, so_pin_flag ? " SO PIN flag" : "");
|
|
|
|
|
|
|
|
if ((pin_ref == SC_RUTOKEN_DEF_ID_GCHV_ADMIN && so_pin_flag)
|
|
|
|
|| (pin_ref == SC_RUTOKEN_DEF_ID_GCHV_USER && !so_pin_flag)
|
|
|
|
)
|
|
|
|
return SC_SUCCESS;
|
2009-01-28 12:10:13 +00:00
|
|
|
else
|
2010-02-03 12:10:41 +00:00
|
|
|
return SC_ERROR_NOT_SUPPORTED;
|
2008-01-04 08:57:12 +00:00
|
|
|
}
|
|
|
|
|
2009-01-28 12:10:13 +00:00
|
|
|
/*
|
|
|
|
* Create a PIN object within the given DF
|
|
|
|
*/
|
|
|
|
static int
|
2010-02-21 16:21:57 +00:00
|
|
|
rutoken_create_pin(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
|
2009-01-28 12:10:13 +00:00
|
|
|
sc_file_t *df, sc_pkcs15_object_t *pin_obj,
|
|
|
|
const unsigned char *pin, size_t pin_len,
|
|
|
|
const unsigned char *puk, size_t puk_len)
|
2008-01-04 08:57:12 +00:00
|
|
|
{
|
2010-02-24 08:22:24 +00:00
|
|
|
sc_context_t *ctx;
|
2009-01-28 12:10:13 +00:00
|
|
|
sc_pkcs15_pin_info_t *pin_info;
|
|
|
|
size_t i;
|
2008-01-04 08:57:12 +00:00
|
|
|
|
2010-02-24 08:22:24 +00:00
|
|
|
(void)puk; /* no warning */
|
2010-02-24 08:57:37 +00:00
|
|
|
if (!profile || !p15card || !p15card->card || !p15card->card->ctx
|
2010-02-24 08:22:24 +00:00
|
|
|
|| !df || !pin_obj || !pin_obj->data || !pin || !pin_len)
|
2009-01-28 12:10:13 +00:00
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
2008-01-04 08:57:12 +00:00
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
ctx = p15card->card->ctx;
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
|
2009-01-28 12:10:13 +00:00
|
|
|
|
|
|
|
if (puk_len != 0)
|
|
|
|
{
|
2010-09-09 17:28:44 +00:00
|
|
|
sc_debug(ctx, SC_LOG_DEBUG_NORMAL,
|
|
|
|
"Do not enter User unblocking PIN (PUK): %s\n",
|
2009-01-28 12:10:13 +00:00
|
|
|
sc_strerror(SC_ERROR_NOT_SUPPORTED));
|
|
|
|
return SC_ERROR_NOT_SUPPORTED;
|
|
|
|
}
|
|
|
|
pin_info = (sc_pkcs15_pin_info_t *)pin_obj->data;
|
|
|
|
for (i = 0; i < sizeof(do_pins)/sizeof(do_pins[0]); ++i)
|
|
|
|
if (pin_info->reference == do_pins[i].id)
|
|
|
|
{
|
|
|
|
if (pin_len == sizeof(do_pins[i].pass)
|
|
|
|
&& memcmp(do_pins[i].pass, pin, pin_len) == 0
|
|
|
|
)
|
|
|
|
return SC_SUCCESS;
|
|
|
|
else
|
|
|
|
{
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Incorrect PIN\n");
|
2009-01-28 12:10:13 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2010-09-09 17:28:44 +00:00
|
|
|
sc_debug(ctx, SC_LOG_DEBUG_NORMAL,
|
|
|
|
"PIN reference %i not found in standard (Rutoken) PINs\n",
|
2009-01-28 12:10:13 +00:00
|
|
|
pin_info->reference);
|
|
|
|
return SC_ERROR_NOT_SUPPORTED;
|
2008-01-04 08:57:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialization routine
|
|
|
|
*/
|
|
|
|
|
|
|
|
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
|
|
|
|
{
|
2009-11-23 11:41:23 +00:00
|
|
|
r = sc_file_set_sec_attr(df, wn_sec_attr, sizeof(wn_sec_attr));
|
2008-01-04 08:57:12 +00:00
|
|
|
if (r != SC_SUCCESS) break;
|
|
|
|
|
|
|
|
/* Create MF 3F00 */
|
|
|
|
df->id = 0x3F00;
|
|
|
|
sc_format_path("3F00", &df->path);
|
2009-01-28 12:10:13 +00:00
|
|
|
r = sc_create_file(card, df);
|
2008-01-04 08:57:12 +00:00
|
|
|
if (r != SC_SUCCESS) break;
|
|
|
|
|
|
|
|
/* Create 3F00/0000 */
|
|
|
|
df->id = 0x0000;
|
|
|
|
sc_append_file_id(&df->path, df->id);
|
2009-01-28 12:10:13 +00:00
|
|
|
r = sc_create_file(card, df);
|
2008-01-04 08:57:12 +00:00
|
|
|
if (r != SC_SUCCESS) break;
|
|
|
|
|
|
|
|
/* Create 3F00/0000/0000 */
|
|
|
|
df->id = 0x0000;
|
|
|
|
sc_append_file_id(&df->path, df->id);
|
2009-01-28 12:10:13 +00:00
|
|
|
r = sc_create_file(card, df);
|
2008-01-04 08:57:12 +00:00
|
|
|
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);
|
2009-01-28 12:10:13 +00:00
|
|
|
r = sc_create_file(card, df);
|
2008-01-04 08:57:12 +00:00
|
|
|
if (r != SC_SUCCESS) break;
|
|
|
|
|
|
|
|
sc_format_path("3F0000000000", &df->path);
|
2009-01-28 12:10:13 +00:00
|
|
|
r = sc_select_file(card, &df->path, NULL);
|
2008-01-04 08:57:12 +00:00
|
|
|
if (r != SC_SUCCESS) break;
|
|
|
|
|
|
|
|
/* Create 3F00/0000/0000/0002 */
|
|
|
|
df->id = 0x0002;
|
|
|
|
sc_append_file_id(&df->path, df->id);
|
2009-01-28 12:10:13 +00:00
|
|
|
r = sc_create_file(card, df);
|
2008-01-04 08:57:12 +00:00
|
|
|
if (r != SC_SUCCESS) break;
|
|
|
|
|
|
|
|
sc_format_path("3F000000", &df->path);
|
2009-01-28 12:10:13 +00:00
|
|
|
r = sc_select_file(card, &df->path, NULL);
|
2008-01-04 08:57:12 +00:00
|
|
|
if (r != SC_SUCCESS) break;
|
|
|
|
|
|
|
|
/* Create 3F00/0000/0001 */
|
|
|
|
df->id = 0x0001;
|
|
|
|
sc_append_file_id(&df->path, df->id);
|
2009-01-28 12:10:13 +00:00
|
|
|
r = sc_create_file(card, df);
|
2008-01-04 08:57:12 +00:00
|
|
|
if (r != SC_SUCCESS) break;
|
|
|
|
|
|
|
|
/* RESET ACCESS RIGHTS */
|
|
|
|
r = sc_logout(card);
|
|
|
|
} while(0);
|
|
|
|
sc_file_free(df);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Erase everything that's on the card
|
|
|
|
*/
|
|
|
|
static int
|
2010-02-21 16:21:57 +00:00
|
|
|
rutoken_erase(struct sc_profile *profile, sc_pkcs15_card_t *p15card)
|
2008-01-04 08:57:12 +00:00
|
|
|
{
|
2010-02-24 08:22:24 +00:00
|
|
|
sc_card_t *card;
|
2008-01-04 08:57:12 +00:00
|
|
|
int ret, ret_end;
|
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
if (!profile || !p15card || !p15card->card || !p15card->card->ctx)
|
2008-01-04 08:57:12 +00:00
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
|
2010-02-24 08:22:24 +00:00
|
|
|
card = p15card->card;
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
|
2008-01-04 08:57:12 +00:00
|
|
|
|
|
|
|
/* ret = sc_card_ctl(card, SC_CARDCTL_ERASE_CARD, NULL); */
|
2010-02-24 08:22:24 +00:00
|
|
|
ret = sc_card_ctl(card, SC_CARDCTL_RUTOKEN_FORMAT_INIT, NULL);
|
2009-01-28 12:10:13 +00:00
|
|
|
if (ret == SC_SUCCESS)
|
2008-01-04 08:57:12 +00:00
|
|
|
{
|
2010-02-24 08:22:24 +00:00
|
|
|
ret = create_typical_fs(card);
|
2008-01-04 08:57:12 +00:00
|
|
|
if (ret != SC_SUCCESS)
|
2010-09-09 17:28:44 +00:00
|
|
|
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
|
|
|
|
"Failed to create typical fs: %s\n",
|
2008-01-04 08:57:12 +00:00
|
|
|
sc_strerror(ret));
|
2010-02-24 08:22:24 +00:00
|
|
|
ret_end = sc_card_ctl(card, SC_CARDCTL_RUTOKEN_FORMAT_END, NULL);
|
2008-01-04 08:57:12 +00:00
|
|
|
if (ret_end != SC_SUCCESS)
|
|
|
|
ret = ret_end;
|
|
|
|
}
|
2009-01-28 12:10:13 +00:00
|
|
|
if (ret != SC_SUCCESS)
|
2010-09-09 17:28:44 +00:00
|
|
|
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
|
|
|
|
"Failed to erase: %s\n", sc_strerror(ret));
|
2009-07-22 12:24:33 +00:00
|
|
|
else
|
2010-02-24 08:22:24 +00:00
|
|
|
sc_free_apps(card);
|
2008-01-04 08:57:12 +00:00
|
|
|
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 */
|
2009-01-28 12:10:13 +00:00
|
|
|
rutoken_select_pin_reference, /* select_pin_reference */
|
|
|
|
rutoken_create_pin, /* create_pin */
|
2010-09-09 17:28:44 +00:00
|
|
|
NULL, /* select_key_reference */
|
|
|
|
NULL, /* create_key */
|
|
|
|
NULL, /* store_key */
|
2008-01-04 08:57:12 +00:00
|
|
|
NULL, /* generate_key */
|
2009-01-28 12:10:13 +00:00
|
|
|
NULL, /* encode_private_key */
|
2008-01-04 08:57:12 +00:00
|
|
|
NULL, /* encode_public_key */
|
|
|
|
NULL, /* finalize_card */
|
2010-03-28 11:37:13 +00:00
|
|
|
NULL, /* delete_object */
|
2010-09-09 17:28:44 +00:00
|
|
|
NULL, NULL, NULL, NULL, NULL /* pkcs15init emulation */
|
2008-01-04 08:57:12 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct sc_pkcs15init_operations* sc_pkcs15init_get_rutoken_ops(void)
|
|
|
|
{
|
|
|
|
return &sc_pkcs15init_rutoken_operations;
|
|
|
|
}
|
|
|
|
|