2004-06-16 20:59:59 +00:00
|
|
|
/*
|
2014-01-19 13:11:16 +00:00
|
|
|
* card-oberthur.c: Support for Oberthur smart cards
|
|
|
|
* CosmopolIC v5;
|
2004-06-16 20:59:59 +00:00
|
|
|
*
|
2007-01-03 11:44:24 +00:00
|
|
|
* Copyright (C) 2001, 2002 Juha Yrjölä <juha.yrjola@iki.fi>
|
2014-01-19 13:11:16 +00:00
|
|
|
* Copyright (C) 2009 Viktor Tarasov <viktor.tarasov@opentrust.com>,
|
2009-11-05 18:27:56 +00:00
|
|
|
* OpenTrust <www.opentrust.com>
|
2004-06-16 20:59:59 +00:00
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*
|
|
|
|
* best view with tabstop=4
|
|
|
|
*/
|
|
|
|
|
2015-04-22 21:55:33 +00:00
|
|
|
#if HAVE_CONFIG_H
|
2010-03-04 08:14:36 +00:00
|
|
|
#include "config.h"
|
2015-04-22 21:55:33 +00:00
|
|
|
#endif
|
2007-01-02 10:06:02 +00:00
|
|
|
|
2010-03-04 08:14:36 +00:00
|
|
|
#ifdef ENABLE_OPENSSL /* empty file without openssl */
|
2004-06-16 20:59:59 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <ctype.h>
|
2007-01-02 10:06:02 +00:00
|
|
|
#include <openssl/sha.h>
|
2007-01-08 17:04:39 +00:00
|
|
|
#include <openssl/evp.h>
|
2007-01-02 10:06:02 +00:00
|
|
|
#include <openssl/rsa.h>
|
2004-07-19 15:42:19 +00:00
|
|
|
#include <openssl/opensslv.h>
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2010-03-04 08:14:36 +00:00
|
|
|
#include "internal.h"
|
|
|
|
#include "cardctl.h"
|
|
|
|
#include "pkcs15.h"
|
2018-04-17 09:00:37 +00:00
|
|
|
#include "gp.h"
|
2010-03-04 08:14:36 +00:00
|
|
|
|
2009-11-13 09:45:21 +00:00
|
|
|
#define OBERTHUR_PIN_LOCAL 0x80
|
2010-01-27 18:07:14 +00:00
|
|
|
#define OBERTHUR_PIN_REFERENCE_USER 0x81
|
|
|
|
#define OBERTHUR_PIN_REFERENCE_ONETIME 0x82
|
2009-11-13 09:45:21 +00:00
|
|
|
#define OBERTHUR_PIN_REFERENCE_SO 0x04
|
2010-01-27 18:07:14 +00:00
|
|
|
#define OBERTHUR_PIN_REFERENCE_PUK 0x84
|
2009-11-13 09:45:21 +00:00
|
|
|
|
2018-08-22 15:01:51 +00:00
|
|
|
static const struct sc_atr_table oberthur_atrs[] = {
|
2014-01-19 13:11:16 +00:00
|
|
|
{ "3B:7D:18:00:00:00:31:80:71:8E:64:77:E3:01:00:82:90:00", NULL,
|
2007-01-02 10:06:02 +00:00
|
|
|
"Oberthur 64k v4/2.1.1", SC_CARD_TYPE_OBERTHUR_64K, 0, NULL },
|
2014-01-19 13:11:16 +00:00
|
|
|
{ "3B:7D:18:00:00:00:31:80:71:8E:64:77:E3:02:00:82:90:00", NULL,
|
2007-01-02 10:06:02 +00:00
|
|
|
"Oberthur 64k v4/2.1.1", SC_CARD_TYPE_OBERTHUR_64K, 0, NULL },
|
2014-01-19 13:11:16 +00:00
|
|
|
{ "3B:7D:11:00:00:00:31:80:71:8E:64:77:E3:01:00:82:90:00", NULL,
|
2007-01-02 10:06:02 +00:00
|
|
|
"Oberthur 64k v5", SC_CARD_TYPE_OBERTHUR_64K, 0, NULL },
|
2014-01-19 13:11:16 +00:00
|
|
|
{ "3B:7D:11:00:00:00:31:80:71:8E:64:77:E3:02:00:82:90:00", NULL,
|
2007-01-02 10:06:02 +00:00
|
|
|
"Oberthur 64k v5/2.2.0", SC_CARD_TYPE_OBERTHUR_64K, 0, NULL },
|
2014-01-19 13:11:16 +00:00
|
|
|
{ "3B:7B:18:00:00:00:31:C0:64:77:E3:03:00:82:90:00", NULL,
|
2007-01-02 10:06:02 +00:00
|
|
|
"Oberthur 64k CosmopolIC v5.2/2.2", SC_CARD_TYPE_OBERTHUR_64K, 0, NULL },
|
2010-01-13 16:39:37 +00:00
|
|
|
{ "3B:FB:11:00:00:81:31:FE:45:00:31:C0:64:77:E9:10:00:00:90:00:6A", NULL,
|
|
|
|
"OCS ID-One Cosmo Card", SC_CARD_TYPE_OBERTHUR_64K, 0, NULL },
|
2005-09-07 08:33:55 +00:00
|
|
|
{ NULL, NULL, NULL, 0, 0, NULL }
|
2004-06-16 20:59:59 +00:00
|
|
|
};
|
|
|
|
|
2005-02-10 10:07:13 +00:00
|
|
|
struct auth_senv {
|
|
|
|
unsigned int algorithm;
|
|
|
|
int key_file_id;
|
|
|
|
size_t key_size;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct auth_private_data {
|
2007-01-02 10:06:02 +00:00
|
|
|
unsigned char aid[SC_MAX_AID_SIZE];
|
|
|
|
int aid_len;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2005-02-10 10:07:13 +00:00
|
|
|
struct sc_pin_cmd_pin pin_info;
|
2009-11-13 09:45:21 +00:00
|
|
|
struct auth_senv senv;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
long int sn;
|
2005-02-10 10:07:13 +00:00
|
|
|
};
|
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
struct auth_update_component_info {
|
|
|
|
enum SC_CARDCTL_OBERTHUR_KEY_TYPE type;
|
|
|
|
unsigned int component;
|
|
|
|
unsigned char *data;
|
|
|
|
unsigned int len;
|
|
|
|
};
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
static const unsigned char *aidAuthentIC_V5 =
|
2009-11-13 09:45:21 +00:00
|
|
|
(const unsigned char *)"\xA0\x00\x00\x00\x77\x01\x03\x03\x00\x00\x00\xF1\x00\x00\x00\x02";
|
2014-01-19 13:11:16 +00:00
|
|
|
static const int lenAidAuthentIC_V5 = 16;
|
|
|
|
static const char *nameAidAuthentIC_V5 = "AuthentIC v5";
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2009-11-23 13:40:05 +00:00
|
|
|
#define OBERTHUR_AUTH_TYPE_PIN 1
|
|
|
|
#define OBERTHUR_AUTH_TYPE_PUK 2
|
|
|
|
|
|
|
|
#define OBERTHUR_AUTH_MAX_LENGTH_PIN 64
|
|
|
|
#define OBERTHUR_AUTH_MAX_LENGTH_PUK 16
|
2005-02-10 10:07:13 +00:00
|
|
|
|
|
|
|
#define SC_OBERTHUR_MAX_ATTR_SIZE 8
|
|
|
|
|
|
|
|
#define PUBKEY_512_ASN1_SIZE 0x4A
|
|
|
|
#define PUBKEY_1024_ASN1_SIZE 0x8C
|
|
|
|
#define PUBKEY_2048_ASN1_SIZE 0x10E
|
2004-06-16 20:59:59 +00:00
|
|
|
|
|
|
|
static unsigned char rsa_der[PUBKEY_2048_ASN1_SIZE];
|
|
|
|
static int rsa_der_len = 0;
|
|
|
|
|
2009-11-13 09:45:21 +00:00
|
|
|
static struct sc_file *auth_current_ef = NULL, *auth_current_df = NULL;
|
2004-06-16 20:59:59 +00:00
|
|
|
static struct sc_card_operations auth_ops;
|
|
|
|
static struct sc_card_operations *iso_ops;
|
|
|
|
static struct sc_card_driver auth_drv = {
|
|
|
|
"Oberthur AuthentIC.v2/CosmopolIC.v4",
|
|
|
|
"oberthur",
|
2005-09-07 08:33:55 +00:00
|
|
|
&auth_ops,
|
|
|
|
NULL, 0, NULL
|
2004-06-16 20:59:59 +00:00
|
|
|
};
|
|
|
|
|
2009-11-13 09:45:21 +00:00
|
|
|
static int auth_get_pin_reference (struct sc_card *card,
|
2004-06-16 20:59:59 +00:00
|
|
|
int type, int reference, int cmd, int *out_ref);
|
2014-01-19 13:11:16 +00:00
|
|
|
static int auth_read_component(struct sc_card *card,
|
|
|
|
enum SC_CARDCTL_OBERTHUR_KEY_TYPE type, int num,
|
2004-06-16 20:59:59 +00:00
|
|
|
unsigned char *out, size_t outlen);
|
2014-01-19 13:11:16 +00:00
|
|
|
static int auth_pin_is_verified(struct sc_card *card, int pin_reference,
|
2009-11-13 09:45:21 +00:00
|
|
|
int *tries_left);
|
2009-12-03 11:11:04 +00:00
|
|
|
static int auth_pin_verify(struct sc_card *card, unsigned int type,
|
|
|
|
struct sc_pin_cmd_data *data, int *tries_left);
|
2014-01-19 13:11:16 +00:00
|
|
|
static int auth_pin_reset(struct sc_card *card, unsigned int type,
|
2009-11-13 09:45:21 +00:00
|
|
|
struct sc_pin_cmd_data *data, int *tries_left);
|
|
|
|
static int auth_create_reference_data (struct sc_card *card,
|
2004-06-16 20:59:59 +00:00
|
|
|
struct sc_cardctl_oberthur_createpin_info *args);
|
2009-11-13 09:45:21 +00:00
|
|
|
static int auth_get_serialnr(struct sc_card *card, struct sc_serial_number *serial);
|
|
|
|
static int auth_select_file(struct sc_card *card, const struct sc_path *in_path,
|
|
|
|
struct sc_file **file_out);
|
2009-11-23 13:40:05 +00:00
|
|
|
static int acl_to_ac_byte(struct sc_card *card, const struct sc_acl_entry *e);
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
static int
|
2009-11-13 09:45:21 +00:00
|
|
|
auth_finish(struct sc_card *card)
|
2004-06-16 20:59:59 +00:00
|
|
|
{
|
|
|
|
free(card->drv_data);
|
2007-01-02 10:06:02 +00:00
|
|
|
return SC_SUCCESS;
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
static int
|
2009-11-13 09:45:21 +00:00
|
|
|
auth_select_aid(struct sc_card *card)
|
2004-06-16 20:59:59 +00:00
|
|
|
{
|
2009-11-13 09:45:21 +00:00
|
|
|
struct sc_apdu apdu;
|
2004-06-16 20:59:59 +00:00
|
|
|
unsigned char apdu_resp[SC_MAX_APDU_BUFFER_SIZE];
|
2004-12-15 18:01:47 +00:00
|
|
|
struct auth_private_data *data = (struct auth_private_data *) card->drv_data;
|
2004-06-16 20:59:59 +00:00
|
|
|
int rv, ii;
|
2009-11-13 09:45:21 +00:00
|
|
|
struct sc_path tmp_path;
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2004-12-15 10:56:45 +00:00
|
|
|
/* Select Card Manager (to deselect previously selected application) */
|
2018-04-17 09:00:37 +00:00
|
|
|
rv = gp_select_card_manager(card);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "APDU transmit failed");
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-12-15 10:56:45 +00:00
|
|
|
/* Get smart card serial number */
|
2004-06-16 20:59:59 +00:00
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xCA, 0x9F, 0x7F);
|
|
|
|
apdu.cla = 0x80;
|
|
|
|
apdu.le = 0x2D;
|
|
|
|
apdu.resplen = 0x30;
|
|
|
|
apdu.resp = apdu_resp;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
rv = sc_transmit_apdu(card, &apdu);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "APDU transmit failed");
|
2007-01-02 10:06:02 +00:00
|
|
|
card->serialnr.len = 4;
|
|
|
|
memcpy(card->serialnr.value, apdu.resp+15, 4);
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
for (ii=0, data->sn = 0; ii < 4; ii++)
|
2015-09-17 18:48:08 +00:00
|
|
|
data->sn += (long int)(*(apdu.resp + 15 + ii)) << (3-ii)*8;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "serial number %li/0x%lX", data->sn, data->sn);
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2011-01-18 09:48:26 +00:00
|
|
|
memset(&tmp_path, 0, sizeof(struct sc_path));
|
2007-01-02 10:06:02 +00:00
|
|
|
tmp_path.type = SC_PATH_TYPE_DF_NAME;
|
|
|
|
memcpy(tmp_path.value, aidAuthentIC_V5, lenAidAuthentIC_V5);
|
|
|
|
tmp_path.len = lenAidAuthentIC_V5;
|
|
|
|
|
|
|
|
rv = iso_ops->select_file(card, &tmp_path, NULL);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "select parent failed");
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
sc_format_path("3F00", &tmp_path);
|
|
|
|
rv = iso_ops->select_file(card, &tmp_path, &auth_current_df);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "select parent failed");
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
sc_format_path("3F00", &card->cache.current_path);
|
|
|
|
sc_file_dup(&auth_current_ef, auth_current_df);
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
memcpy(data->aid, aidAuthentIC_V5, lenAidAuthentIC_V5);
|
|
|
|
data->aid_len = lenAidAuthentIC_V5;
|
|
|
|
card->name = nameAidAuthentIC_V5;
|
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, rv);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
|
2009-11-13 09:45:21 +00:00
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
static int
|
2009-11-13 09:45:21 +00:00
|
|
|
auth_match_card(struct sc_card *card)
|
2004-06-16 20:59:59 +00:00
|
|
|
{
|
2007-01-02 10:06:02 +00:00
|
|
|
if (_sc_match_atr(card, oberthur_atrs, &card->type) < 0)
|
2005-02-04 20:29:35 +00:00
|
|
|
return 0;
|
2007-01-02 10:06:02 +00:00
|
|
|
else
|
|
|
|
return 1;
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
|
2009-11-13 09:45:21 +00:00
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
static int
|
2009-11-13 09:45:21 +00:00
|
|
|
auth_init(struct sc_card *card)
|
2004-06-16 20:59:59 +00:00
|
|
|
{
|
|
|
|
struct auth_private_data *data;
|
2009-11-13 09:45:21 +00:00
|
|
|
struct sc_path path;
|
|
|
|
unsigned long flags;
|
|
|
|
int rv = 0;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
Do not cast the return value of malloc(3) and calloc(3)
From http://en.wikipedia.org/wiki/Malloc#Casting_and_type_safety
" Casting and type safety
malloc returns a void pointer (void *), which indicates that it is a
pointer to a region of unknown data type. One may "cast" (see type
conversion) this pointer to a specific type, as in
int *ptr = (int*)malloc(10 * sizeof (int));
When using C, this is considered bad practice; it is redundant under the
C standard. Moreover, putting in a cast may mask failure to include the
header stdlib.h, in which the prototype for malloc is found. In the
absence of a prototype for malloc, the C compiler will assume that
malloc returns an int, and will issue a warning in a context such as the
above, provided the error is not masked by a cast. On certain
architectures and data models (such as LP64 on 64 bit systems, where
long and pointers are 64 bit and int is 32 bit), this error can actually
result in undefined behavior, as the implicitly declared malloc returns
a 32 bit value whereas the actually defined function returns a 64 bit
value. Depending on calling conventions and memory layout, this may
result in stack smashing.
The returned pointer need not be explicitly cast to a more specific
pointer type, since ANSI C defines an implicit conversion between the
void pointer type and other pointers to objects. An explicit cast of
malloc's return value is sometimes performed because malloc originally
returned a char *, but this cast is unnecessary in standard C
code.[4][5] Omitting the cast, however, creates an incompatibility with
C++, which does require it.
The lack of a specific pointer type returned from malloc is type-unsafe
behaviour: malloc allocates based on byte count but not on type. This
distinguishes it from the C++ new operator that returns a pointer whose
type relies on the operand. (see C Type Safety). "
See also
http://www.opensc-project.org/pipermail/opensc-devel/2010-August/014586.html
git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@4636 c6295689-39f2-0310-b995-f0e70906c6a9
2010-08-18 15:08:51 +00:00
|
|
|
data = calloc(1, sizeof(struct auth_private_data));
|
2004-06-16 20:59:59 +00:00
|
|
|
if (!data)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
|
2004-06-16 20:59:59 +00:00
|
|
|
|
|
|
|
card->cla = 0x00;
|
|
|
|
card->drv_data = data;
|
|
|
|
|
|
|
|
card->caps |= SC_CARD_CAP_RNG;
|
2007-01-02 10:06:02 +00:00
|
|
|
card->caps |= SC_CARD_CAP_USE_FCI_AC;
|
2004-06-16 20:59:59 +00:00
|
|
|
|
|
|
|
if (auth_select_aid(card)) {
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "Failed to initialize %s", card->name);
|
2019-01-24 13:24:07 +00:00
|
|
|
rv = SC_ERROR_INVALID_CARD;
|
|
|
|
LOG_TEST_GOTO_ERR(card->ctx, SC_ERROR_INVALID_CARD, "Failed to initialize");
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
sc_format_path("3F00", &path);
|
2016-04-28 08:52:25 +00:00
|
|
|
rv = auth_select_file(card, &path, NULL);
|
2007-01-02 10:06:02 +00:00
|
|
|
|
2019-01-24 13:24:07 +00:00
|
|
|
err:
|
|
|
|
if (rv == SC_SUCCESS) {
|
|
|
|
flags = SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_PAD_ISO9796;
|
|
|
|
flags |= SC_ALGORITHM_RSA_HASH_NONE;
|
|
|
|
flags |= SC_ALGORITHM_ONBOARD_KEY_GEN;
|
|
|
|
|
|
|
|
_sc_card_add_rsa_alg(card, 512, flags, 0);
|
|
|
|
_sc_card_add_rsa_alg(card, 1024, flags, 0);
|
|
|
|
_sc_card_add_rsa_alg(card, 2048, flags, 0);
|
|
|
|
} else {
|
|
|
|
free(card->drv_data);
|
|
|
|
card->drv_data = NULL;
|
|
|
|
}
|
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, rv);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
static void
|
|
|
|
add_acl_entry(struct sc_card *card, struct sc_file *file, unsigned int op,
|
2009-11-13 09:45:21 +00:00
|
|
|
unsigned char acl_byte)
|
2004-06-16 20:59:59 +00:00
|
|
|
{
|
2007-01-02 10:06:02 +00:00
|
|
|
if ((acl_byte & 0xE0) == 0x60) {
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "called; op 0x%X; SC_AC_PRO; ref 0x%X", op, acl_byte);
|
2007-01-02 10:06:02 +00:00
|
|
|
sc_file_add_acl_entry(file, op, SC_AC_PRO, acl_byte);
|
|
|
|
return;
|
|
|
|
}
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
switch (acl_byte) {
|
|
|
|
case 0x00:
|
|
|
|
sc_file_add_acl_entry(file, op, SC_AC_NONE, SC_AC_KEY_REF_NONE);
|
|
|
|
break;
|
2010-01-27 18:07:14 +00:00
|
|
|
/* User and OneTime PINs are locals */
|
2007-01-02 10:06:02 +00:00
|
|
|
case 0x21:
|
|
|
|
case 0x22:
|
2010-01-27 18:07:14 +00:00
|
|
|
sc_file_add_acl_entry(file, op, SC_AC_CHV, (acl_byte & 0x0F) | OBERTHUR_PIN_LOCAL);
|
|
|
|
break;
|
|
|
|
/* Local SOPIN is only for the unblocking. */
|
2007-01-02 10:06:02 +00:00
|
|
|
case 0x24:
|
|
|
|
case 0x25:
|
2010-01-27 18:07:14 +00:00
|
|
|
if (op == SC_AC_OP_PIN_RESET)
|
|
|
|
sc_file_add_acl_entry(file, op, SC_AC_CHV, 0x84);
|
|
|
|
else
|
|
|
|
sc_file_add_acl_entry(file, op, SC_AC_CHV, 0x04);
|
2007-01-02 10:06:02 +00:00
|
|
|
break;
|
|
|
|
case 0xFF:
|
|
|
|
sc_file_add_acl_entry(file, op, SC_AC_NEVER, SC_AC_KEY_REF_NONE);
|
2004-06-16 20:59:59 +00:00
|
|
|
break;
|
|
|
|
default:
|
2007-01-02 10:06:02 +00:00
|
|
|
sc_file_add_acl_entry(file, op, SC_AC_UNKNOWN, SC_AC_KEY_REF_NONE);
|
2004-06-16 20:59:59 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2007-01-02 10:06:02 +00:00
|
|
|
auth_process_fci(struct sc_card *card, struct sc_file *file,
|
|
|
|
const unsigned char *buf, size_t buflen)
|
2004-06-16 20:59:59 +00:00
|
|
|
{
|
2019-01-25 12:54:38 +00:00
|
|
|
unsigned char type;
|
|
|
|
const unsigned char *attr;
|
|
|
|
size_t attr_len = 0;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
2019-01-25 12:54:38 +00:00
|
|
|
attr = sc_asn1_find_tag(card->ctx, buf, buflen, 0x82, &attr_len);
|
|
|
|
if (!attr || attr_len < 1)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);
|
2004-06-16 20:59:59 +00:00
|
|
|
type = attr[0];
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2019-01-25 12:54:38 +00:00
|
|
|
attr = sc_asn1_find_tag(card->ctx, buf, buflen, 0x83, &attr_len);
|
|
|
|
if (!attr || attr_len < 2)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);
|
2004-06-16 20:59:59 +00:00
|
|
|
file->id = attr[0]*0x100 + attr[1];
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2019-01-25 12:54:38 +00:00
|
|
|
attr = sc_asn1_find_tag(card->ctx, buf, buflen, type==0x01 ? 0x80 : 0x85, &attr_len);
|
2004-06-16 20:59:59 +00:00
|
|
|
switch (type) {
|
|
|
|
case 0x01:
|
2019-01-25 12:54:38 +00:00
|
|
|
if (!attr || attr_len < 2)
|
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);
|
2004-06-16 20:59:59 +00:00
|
|
|
file->type = SC_FILE_TYPE_WORKING_EF;
|
|
|
|
file->ef_structure = SC_FILE_EF_TRANSPARENT;
|
|
|
|
file->size = attr[0]*0x100 + attr[1];
|
|
|
|
break;
|
|
|
|
case 0x04:
|
2019-01-25 12:54:38 +00:00
|
|
|
if (!attr || attr_len < 1)
|
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);
|
2004-06-16 20:59:59 +00:00
|
|
|
file->type = SC_FILE_TYPE_WORKING_EF;
|
|
|
|
file->ef_structure = SC_FILE_EF_LINEAR_VARIABLE;
|
|
|
|
file->size = attr[0];
|
2019-01-25 12:54:38 +00:00
|
|
|
attr = sc_asn1_find_tag(card->ctx, buf, buflen, 0x82, &attr_len);
|
|
|
|
if (!attr || attr_len < 5)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);
|
2004-06-16 20:59:59 +00:00
|
|
|
file->record_length = attr[2]*0x100+attr[3];
|
|
|
|
file->record_count = attr[4];
|
|
|
|
break;
|
|
|
|
case 0x11:
|
2019-01-25 12:54:38 +00:00
|
|
|
if (!attr || attr_len < 2)
|
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);
|
2004-06-16 20:59:59 +00:00
|
|
|
file->type = SC_FILE_TYPE_INTERNAL_EF;
|
|
|
|
file->ef_structure = SC_CARDCTL_OBERTHUR_KEY_DES;
|
|
|
|
file->size = attr[0]*0x100 + attr[1];
|
|
|
|
file->size /= 8;
|
|
|
|
break;
|
|
|
|
case 0x12:
|
2019-01-25 12:54:38 +00:00
|
|
|
if (!attr || attr_len < 2)
|
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);
|
2004-06-16 20:59:59 +00:00
|
|
|
file->type = SC_FILE_TYPE_INTERNAL_EF;
|
|
|
|
file->ef_structure = SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
file->size = attr[0]*0x100 + attr[1];
|
|
|
|
if (file->size==512)
|
|
|
|
file->size = PUBKEY_512_ASN1_SIZE;
|
|
|
|
else if (file->size==1024)
|
|
|
|
file->size = PUBKEY_1024_ASN1_SIZE;
|
|
|
|
else if (file->size==2048)
|
|
|
|
file->size = PUBKEY_2048_ASN1_SIZE;
|
|
|
|
else {
|
2017-03-14 19:02:30 +00:00
|
|
|
sc_log(card->ctx,
|
|
|
|
"Not supported public key size: %"SC_FORMAT_LEN_SIZE_T"u",
|
|
|
|
file->size);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 0x14:
|
2019-01-25 12:54:38 +00:00
|
|
|
if (!attr || attr_len < 2)
|
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);
|
2004-06-16 20:59:59 +00:00
|
|
|
file->type = SC_FILE_TYPE_INTERNAL_EF;
|
|
|
|
file->ef_structure = SC_CARDCTL_OBERTHUR_KEY_RSA_CRT;
|
|
|
|
file->size = attr[0]*0x100 + attr[1];
|
|
|
|
break;
|
|
|
|
case 0x38:
|
2019-01-25 12:54:38 +00:00
|
|
|
if (!attr || attr_len < 1)
|
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);
|
2004-06-16 20:59:59 +00:00
|
|
|
file->type = SC_FILE_TYPE_DF;
|
|
|
|
file->size = attr[0];
|
2015-01-28 03:45:08 +00:00
|
|
|
if (SC_SUCCESS != sc_file_set_type_attr(file,attr,attr_len))
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);
|
2004-06-16 20:59:59 +00:00
|
|
|
break;
|
|
|
|
default:
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2019-01-25 12:54:38 +00:00
|
|
|
attr = sc_asn1_find_tag(card->ctx, buf, buflen, 0x86, &attr_len);
|
|
|
|
if (!attr || attr_len < 8)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);
|
2004-06-16 20:59:59 +00:00
|
|
|
|
|
|
|
if (file->type == SC_FILE_TYPE_DF) {
|
|
|
|
add_acl_entry(card, file, SC_AC_OP_CREATE, attr[0]);
|
|
|
|
add_acl_entry(card, file, SC_AC_OP_CRYPTO, attr[1]);
|
|
|
|
add_acl_entry(card, file, SC_AC_OP_LIST_FILES, attr[2]);
|
|
|
|
add_acl_entry(card, file, SC_AC_OP_DELETE, attr[3]);
|
2009-11-13 09:45:21 +00:00
|
|
|
add_acl_entry(card, file, SC_AC_OP_PIN_DEFINE, attr[4]);
|
|
|
|
add_acl_entry(card, file, SC_AC_OP_PIN_CHANGE, attr[5]);
|
|
|
|
add_acl_entry(card, file, SC_AC_OP_PIN_RESET, attr[6]);
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "SC_FILE_TYPE_DF:CRYPTO %X", attr[1]);
|
2014-01-19 13:11:16 +00:00
|
|
|
}
|
2004-06-16 20:59:59 +00:00
|
|
|
else if (file->type == SC_FILE_TYPE_INTERNAL_EF) { /* EF */
|
|
|
|
switch (file->ef_structure) {
|
|
|
|
case SC_CARDCTL_OBERTHUR_KEY_DES:
|
|
|
|
add_acl_entry(card, file, SC_AC_OP_UPDATE, attr[0]);
|
2010-01-25 16:10:54 +00:00
|
|
|
add_acl_entry(card, file, SC_AC_OP_PSO_DECRYPT, attr[1]);
|
|
|
|
add_acl_entry(card, file, SC_AC_OP_PSO_ENCRYPT, attr[2]);
|
|
|
|
add_acl_entry(card, file, SC_AC_OP_PSO_COMPUTE_CHECKSUM, attr[3]);
|
|
|
|
add_acl_entry(card, file, SC_AC_OP_PSO_VERIFY_CHECKSUM, attr[4]);
|
|
|
|
add_acl_entry(card, file, SC_AC_OP_INTERNAL_AUTHENTICATE, attr[5]);
|
|
|
|
add_acl_entry(card, file, SC_AC_OP_EXTERNAL_AUTHENTICATE, attr[6]);
|
2004-06-16 20:59:59 +00:00
|
|
|
break;
|
|
|
|
case SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC:
|
|
|
|
add_acl_entry(card, file, SC_AC_OP_UPDATE, attr[0]);
|
2010-01-25 16:10:54 +00:00
|
|
|
add_acl_entry(card, file, SC_AC_OP_PSO_ENCRYPT, attr[2]);
|
|
|
|
add_acl_entry(card, file, SC_AC_OP_PSO_VERIFY_SIGNATURE, attr[4]);
|
|
|
|
add_acl_entry(card, file, SC_AC_OP_EXTERNAL_AUTHENTICATE, attr[6]);
|
2004-06-16 20:59:59 +00:00
|
|
|
break;
|
|
|
|
case SC_CARDCTL_OBERTHUR_KEY_RSA_CRT:
|
|
|
|
add_acl_entry(card, file, SC_AC_OP_UPDATE, attr[0]);
|
2010-01-25 16:10:54 +00:00
|
|
|
add_acl_entry(card, file, SC_AC_OP_PSO_DECRYPT, attr[1]);
|
|
|
|
add_acl_entry(card, file, SC_AC_OP_PSO_COMPUTE_SIGNATURE, attr[3]);
|
|
|
|
add_acl_entry(card, file, SC_AC_OP_INTERNAL_AUTHENTICATE, attr[5]);
|
2004-06-16 20:59:59 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
switch (file->ef_structure) {
|
|
|
|
case SC_FILE_EF_TRANSPARENT:
|
|
|
|
add_acl_entry(card, file, SC_AC_OP_WRITE, attr[0]);
|
|
|
|
add_acl_entry(card, file, SC_AC_OP_UPDATE, attr[1]);
|
|
|
|
add_acl_entry(card, file, SC_AC_OP_READ, attr[2]);
|
|
|
|
add_acl_entry(card, file, SC_AC_OP_ERASE, attr[3]);
|
|
|
|
break;
|
|
|
|
case SC_FILE_EF_LINEAR_VARIABLE:
|
|
|
|
add_acl_entry(card, file, SC_AC_OP_WRITE, attr[0]);
|
|
|
|
add_acl_entry(card, file, SC_AC_OP_UPDATE, attr[1]);
|
|
|
|
add_acl_entry(card, file, SC_AC_OP_READ, attr[2]);
|
|
|
|
add_acl_entry(card, file, SC_AC_OP_ERASE, attr[3]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
file->status = SC_FILE_STATUS_ACTIVATED;
|
|
|
|
file->magic = SC_FILE_MAGIC;
|
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
static int
|
2009-11-13 09:45:21 +00:00
|
|
|
auth_select_file(struct sc_card *card, const struct sc_path *in_path,
|
|
|
|
struct sc_file **file_out)
|
2004-06-16 20:59:59 +00:00
|
|
|
{
|
2009-11-13 09:45:21 +00:00
|
|
|
struct sc_path path;
|
|
|
|
struct sc_file *tmp_file = NULL;
|
2007-05-13 09:32:13 +00:00
|
|
|
size_t offs, ii;
|
2009-11-13 09:45:21 +00:00
|
|
|
int rv;
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
2007-01-02 10:06:02 +00:00
|
|
|
assert(card != NULL && in_path != NULL);
|
|
|
|
|
2009-11-13 09:45:21 +00:00
|
|
|
memcpy(&path, in_path, sizeof(struct sc_path));
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2018-05-25 12:54:47 +00:00
|
|
|
if (!auth_current_df)
|
|
|
|
return SC_ERROR_OBJECT_NOT_FOUND;
|
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "in_path; type=%d, path=%s, out %p",
|
2007-01-02 10:06:02 +00:00
|
|
|
in_path->type, sc_print_path(in_path), file_out);
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "current path; type=%d, path=%s",
|
2007-01-02 10:06:02 +00:00
|
|
|
auth_current_df->path.type, sc_print_path(&auth_current_df->path));
|
|
|
|
if (auth_current_ef)
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "current file; type=%d, path=%s",
|
2007-01-02 10:06:02 +00:00
|
|
|
auth_current_ef->path.type, sc_print_path(&auth_current_ef->path));
|
|
|
|
|
|
|
|
if (path.type == SC_PATH_TYPE_PARENT || path.type == SC_PATH_TYPE_FILE_ID) {
|
2017-01-05 19:21:44 +00:00
|
|
|
sc_file_free(auth_current_ef);
|
2007-01-02 10:06:02 +00:00
|
|
|
auth_current_ef = NULL;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
rv = iso_ops->select_file(card, &path, &tmp_file);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "select file failed");
|
2015-10-14 21:10:48 +00:00
|
|
|
if (!tmp_file)
|
|
|
|
return SC_ERROR_OBJECT_NOT_FOUND;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
if (path.type == SC_PATH_TYPE_PARENT) {
|
2009-11-13 09:45:21 +00:00
|
|
|
memcpy(&tmp_file->path, &auth_current_df->path, sizeof(struct sc_path));
|
2007-01-02 10:06:02 +00:00
|
|
|
if (tmp_file->path.len > 2)
|
|
|
|
tmp_file->path.len -= 2;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
sc_file_free(auth_current_df);
|
|
|
|
sc_file_dup(&auth_current_df, tmp_file);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (tmp_file->type == SC_FILE_TYPE_DF) {
|
|
|
|
sc_concatenate_path(&tmp_file->path, &auth_current_df->path, &path);
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
sc_file_free(auth_current_df);
|
|
|
|
sc_file_dup(&auth_current_df, tmp_file);
|
|
|
|
}
|
|
|
|
else {
|
2017-01-05 19:21:44 +00:00
|
|
|
sc_file_free(auth_current_ef);
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
sc_file_dup(&auth_current_ef, tmp_file);
|
|
|
|
sc_concatenate_path(&auth_current_ef->path, &auth_current_df->path, &path);
|
|
|
|
}
|
|
|
|
}
|
2014-01-19 13:11:16 +00:00
|
|
|
if (file_out)
|
2007-01-02 10:06:02 +00:00
|
|
|
sc_file_dup(file_out, tmp_file);
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
sc_file_free(tmp_file);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
2007-01-02 10:06:02 +00:00
|
|
|
else if (path.type == SC_PATH_TYPE_DF_NAME) {
|
|
|
|
rv = iso_ops->select_file(card, &path, NULL);
|
|
|
|
if (rv) {
|
2017-01-05 19:21:44 +00:00
|
|
|
sc_file_free(auth_current_ef);
|
2007-01-02 10:06:02 +00:00
|
|
|
auth_current_ef = NULL;
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "select file failed");
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
2007-01-02 10:06:02 +00:00
|
|
|
else {
|
2014-01-19 13:11:16 +00:00
|
|
|
for (offs = 0; offs < path.len && offs < auth_current_df->path.len; offs += 2)
|
2007-01-02 10:06:02 +00:00
|
|
|
if (path.value[offs] != auth_current_df->path.value[offs] ||
|
|
|
|
path.value[offs + 1] != auth_current_df->path.value[offs + 1])
|
|
|
|
break;
|
2006-01-11 23:41:17 +00:00
|
|
|
|
2017-03-14 19:02:30 +00:00
|
|
|
sc_log(card->ctx, "offs %"SC_FORMAT_LEN_SIZE_T"u", offs);
|
2007-01-02 10:06:02 +00:00
|
|
|
if (offs && offs < auth_current_df->path.len) {
|
2007-05-13 09:32:13 +00:00
|
|
|
size_t deep = auth_current_df->path.len - offs;
|
2006-01-11 23:41:17 +00:00
|
|
|
|
2017-03-14 19:02:30 +00:00
|
|
|
sc_log(card->ctx, "deep %"SC_FORMAT_LEN_SIZE_T"u",
|
|
|
|
deep);
|
2007-01-02 10:06:02 +00:00
|
|
|
for (ii=0; ii<deep; ii+=2) {
|
2009-11-13 09:45:21 +00:00
|
|
|
struct sc_path tmp_path;
|
2006-01-11 23:41:17 +00:00
|
|
|
|
2009-11-13 09:45:21 +00:00
|
|
|
memcpy(&tmp_path, &auth_current_df->path, sizeof(struct sc_path));
|
2007-01-02 10:06:02 +00:00
|
|
|
tmp_path.type = SC_PATH_TYPE_PARENT;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
rv = auth_select_file (card, &tmp_path, file_out);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "select file failed");
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
2007-01-02 10:06:02 +00:00
|
|
|
}
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
if (path.len - offs > 0) {
|
2009-11-13 09:45:21 +00:00
|
|
|
struct sc_path tmp_path;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
|
|
|
memset(&tmp_path, 0, sizeof(struct sc_path));
|
2007-01-02 10:06:02 +00:00
|
|
|
tmp_path.type = SC_PATH_TYPE_FILE_ID;
|
|
|
|
tmp_path.len = 2;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
for (ii=0; ii < path.len - offs; ii+=2) {
|
|
|
|
memcpy(tmp_path.value, path.value + offs + ii, 2);
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
rv = auth_select_file(card, &tmp_path, file_out);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "select file failed");
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
}
|
2007-01-02 10:06:02 +00:00
|
|
|
else if (path.len - offs == 0 && file_out) {
|
2014-01-19 13:11:16 +00:00
|
|
|
if (sc_compare_path(&path, &auth_current_df->path))
|
2007-01-02 10:06:02 +00:00
|
|
|
sc_file_dup(file_out, auth_current_df);
|
|
|
|
else if (auth_current_ef)
|
|
|
|
sc_file_dup(file_out, auth_current_ef);
|
|
|
|
else
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, SC_ERROR_INTERNAL, "No current EF");
|
2007-01-02 10:06:02 +00:00
|
|
|
}
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
2007-01-02 10:06:02 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, 0);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
static int
|
2009-11-13 09:45:21 +00:00
|
|
|
auth_list_files(struct sc_card *card, unsigned char *buf, size_t buflen)
|
2004-06-16 20:59:59 +00:00
|
|
|
{
|
2009-11-13 09:45:21 +00:00
|
|
|
struct sc_apdu apdu;
|
|
|
|
unsigned char rbuf[SC_MAX_APDU_BUFFER_SIZE];
|
2004-06-16 20:59:59 +00:00
|
|
|
int rv;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
2004-06-16 20:59:59 +00:00
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x34, 0, 0);
|
|
|
|
apdu.cla = 0x80;
|
|
|
|
apdu.le = 0x40;
|
|
|
|
apdu.resplen = sizeof(rbuf);
|
|
|
|
apdu.resp = rbuf;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
rv = sc_transmit_apdu(card, &apdu);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "APDU transmit failed");
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
rv = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "Card returned error");
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2005-08-09 07:53:59 +00:00
|
|
|
if (apdu.resplen == 0x100 && rbuf[0]==0 && rbuf[1]==0)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, 0);
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
buflen = buflen < apdu.resplen ? buflen : apdu.resplen;
|
|
|
|
memcpy(buf, rbuf, buflen);
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, buflen);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
static int
|
2009-11-13 09:45:21 +00:00
|
|
|
auth_delete_file(struct sc_card *card, const struct sc_path *path)
|
2004-06-16 20:59:59 +00:00
|
|
|
{
|
2009-11-13 09:45:21 +00:00
|
|
|
struct sc_apdu apdu;
|
|
|
|
unsigned char sbuf[2];
|
2004-06-16 20:59:59 +00:00
|
|
|
int rv;
|
2010-03-15 12:17:13 +00:00
|
|
|
char pbuf[SC_MAX_PATH_STRING_SIZE];
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
2006-01-11 23:41:17 +00:00
|
|
|
|
2010-03-15 12:17:13 +00:00
|
|
|
rv = sc_path_print(pbuf, sizeof(pbuf), path);
|
|
|
|
if (rv != SC_SUCCESS)
|
|
|
|
pbuf[0] = '\0';
|
2006-01-11 23:41:17 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "path; type=%d, path=%s", path->type, pbuf);
|
2006-01-11 23:41:17 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
if (path->len < 2) {
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "Invalid path length");
|
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
if (path->len > 2) {
|
2009-11-13 09:45:21 +00:00
|
|
|
struct sc_path parent = *path;
|
2004-06-16 20:59:59 +00:00
|
|
|
|
|
|
|
parent.len -= 2;
|
|
|
|
parent.type = SC_PATH_TYPE_PATH;
|
|
|
|
rv = auth_select_file(card, &parent, NULL);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "select parent failed ");
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sbuf[0] = path->value[path->len - 2];
|
|
|
|
sbuf[1] = path->value[path->len - 1];
|
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
if (memcmp(sbuf,"\x00\x00",2)==0 || (memcmp(sbuf,"\xFF\xFF",2)==0) ||
|
2007-01-02 10:06:02 +00:00
|
|
|
memcmp(sbuf,"\x3F\xFF",2)==0)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INCORRECT_PARAMETERS);
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE4, 0x02, 0x00);
|
|
|
|
apdu.lc = 2;
|
|
|
|
apdu.datalen = 2;
|
|
|
|
apdu.data = sbuf;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
rv = sc_transmit_apdu(card, &apdu);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "APDU transmit failed");
|
2004-06-16 20:59:59 +00:00
|
|
|
if (apdu.sw1==0x6A && apdu.sw2==0x82) {
|
2009-11-13 09:45:21 +00:00
|
|
|
/* Clean up tDF contents.*/
|
|
|
|
struct sc_path tmp_path;
|
2004-06-16 20:59:59 +00:00
|
|
|
int ii, len;
|
2009-11-13 09:45:21 +00:00
|
|
|
unsigned char lbuf[SC_MAX_APDU_BUFFER_SIZE];
|
2014-01-19 13:11:16 +00:00
|
|
|
|
|
|
|
memset(&tmp_path, 0, sizeof(struct sc_path));
|
2007-01-02 10:06:02 +00:00
|
|
|
tmp_path.type = SC_PATH_TYPE_FILE_ID;
|
|
|
|
memcpy(tmp_path.value, sbuf, 2);
|
|
|
|
tmp_path.len = 2;
|
|
|
|
rv = auth_select_file(card, &tmp_path, NULL);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "select DF failed");
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
len = auth_list_files(card, lbuf, sizeof(lbuf));
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, len, "list DF failed");
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
for (ii=0; ii<len/2; ii++) {
|
2009-11-13 09:45:21 +00:00
|
|
|
struct sc_path tmp_path_x;
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
memset(&tmp_path_x, 0, sizeof(struct sc_path));
|
2007-01-02 10:06:02 +00:00
|
|
|
tmp_path_x.type = SC_PATH_TYPE_FILE_ID;
|
|
|
|
tmp_path_x.value[0] = *(lbuf + ii*2);
|
|
|
|
tmp_path_x.value[1] = *(lbuf + ii*2 + 1);
|
|
|
|
tmp_path_x.len = 2;
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
rv = auth_delete_file(card, &tmp_path_x);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "delete failed");
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
2007-01-02 10:06:02 +00:00
|
|
|
|
|
|
|
tmp_path.type = SC_PATH_TYPE_PARENT;
|
|
|
|
rv = auth_select_file(card, &tmp_path, NULL);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "select parent failed");
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
apdu.p1 = 1;
|
|
|
|
rv = sc_transmit_apdu(card, &apdu);
|
|
|
|
}
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "APDU transmit failed");
|
2004-06-16 20:59:59 +00:00
|
|
|
rv = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2007-01-02 10:06:02 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, rv);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
static int
|
2009-11-13 09:45:21 +00:00
|
|
|
acl_to_ac_byte(struct sc_card *card, const struct sc_acl_entry *e)
|
2004-06-16 20:59:59 +00:00
|
|
|
{
|
2010-02-02 14:31:37 +00:00
|
|
|
unsigned key_ref;
|
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
if (e == NULL)
|
2010-01-25 16:10:54 +00:00
|
|
|
return SC_ERROR_OBJECT_NOT_FOUND;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2010-02-02 14:31:37 +00:00
|
|
|
key_ref = e->key_ref & ~OBERTHUR_PIN_LOCAL;
|
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
switch (e->method) {
|
|
|
|
case SC_AC_NONE:
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, 0);
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
case SC_AC_CHV:
|
2010-02-02 14:31:37 +00:00
|
|
|
if (key_ref > 0 && key_ref < 6)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, (0x20 | key_ref));
|
2007-01-02 10:06:02 +00:00
|
|
|
else
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INCORRECT_PARAMETERS);
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
case SC_AC_PRO:
|
2010-02-02 14:31:37 +00:00
|
|
|
if (((key_ref & 0xE0) != 0x60) || ((key_ref & 0x18) == 0))
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INCORRECT_PARAMETERS);
|
2007-01-02 10:06:02 +00:00
|
|
|
else
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, key_ref);
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
case SC_AC_NEVER:
|
|
|
|
return 0xff;
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INCORRECT_PARAMETERS);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
static int
|
2009-11-13 09:45:21 +00:00
|
|
|
encode_file_structure_V5(struct sc_card *card, const struct sc_file *file,
|
|
|
|
unsigned char *buf, size_t *buflen)
|
2004-06-16 20:59:59 +00:00
|
|
|
{
|
2004-12-21 22:38:37 +00:00
|
|
|
size_t ii;
|
2009-11-13 09:45:21 +00:00
|
|
|
int rv=0, size;
|
|
|
|
unsigned char *p = buf;
|
2004-06-16 20:59:59 +00:00
|
|
|
unsigned char ops[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
2017-03-14 19:02:30 +00:00
|
|
|
sc_log(card->ctx,
|
|
|
|
"id %04X; size %"SC_FORMAT_LEN_SIZE_T"u; type 0x%X/0x%X",
|
|
|
|
file->id, file->size, file->type, file->ef_structure);
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
if (*buflen < 0x18)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INCORRECT_PARAMETERS);
|
2004-06-16 20:59:59 +00:00
|
|
|
|
|
|
|
p[0] = 0x62, p[1] = 0x16;
|
|
|
|
p[2] = 0x82, p[3] = 0x02;
|
|
|
|
|
|
|
|
rv = 0;
|
|
|
|
if (file->type == SC_FILE_TYPE_DF) {
|
|
|
|
p[4] = 0x38;
|
|
|
|
p[5] = 0x00;
|
|
|
|
}
|
|
|
|
else if (file->type == SC_FILE_TYPE_WORKING_EF) {
|
|
|
|
switch (file->ef_structure) {
|
|
|
|
case SC_FILE_EF_TRANSPARENT:
|
|
|
|
p[4] = 0x01;
|
|
|
|
p[5] = 0x01;
|
|
|
|
break;
|
|
|
|
case SC_FILE_EF_LINEAR_VARIABLE:
|
|
|
|
p[4] = 0x04;
|
|
|
|
p[5] = 0x01;
|
|
|
|
break;
|
|
|
|
default:
|
2007-01-02 10:06:02 +00:00
|
|
|
rv = SC_ERROR_INVALID_ARGUMENTS;
|
2004-06-16 20:59:59 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (file->type == SC_FILE_TYPE_INTERNAL_EF) {
|
|
|
|
switch (file->ef_structure) {
|
|
|
|
case SC_CARDCTL_OBERTHUR_KEY_DES:
|
|
|
|
p[4] = 0x11;
|
|
|
|
p[5] = 0x00;
|
|
|
|
break;
|
|
|
|
case SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC:
|
|
|
|
p[4] = 0x12;
|
|
|
|
p[5] = 0x00;
|
|
|
|
break;
|
|
|
|
case SC_CARDCTL_OBERTHUR_KEY_RSA_CRT:
|
|
|
|
p[4] = 0x14;
|
|
|
|
p[5] = 0x00;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
rv = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2007-01-02 10:06:02 +00:00
|
|
|
rv = SC_ERROR_INVALID_ARGUMENTS;
|
2004-06-16 20:59:59 +00:00
|
|
|
|
|
|
|
if (rv) {
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "Invalid EF structure 0x%X/0x%X", file->type, file->ef_structure);
|
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INCORRECT_PARAMETERS);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
p[6] = 0x83;
|
|
|
|
p[7] = 0x02;
|
|
|
|
p[8] = file->id >> 8;
|
|
|
|
p[9] = file->id & 0xFF;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
p[10] = 0x85;
|
|
|
|
p[11] = 0x02;
|
|
|
|
|
|
|
|
size = file->size;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
if (file->type == SC_FILE_TYPE_DF) {
|
|
|
|
size &= 0xFF;
|
|
|
|
}
|
2014-01-19 13:11:16 +00:00
|
|
|
else if (file->type == SC_FILE_TYPE_INTERNAL_EF &&
|
2004-06-16 20:59:59 +00:00
|
|
|
file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC) {
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "ef %s","SC_FILE_EF_RSA_PUBLIC");
|
2004-06-16 20:59:59 +00:00
|
|
|
if (file->size == PUBKEY_512_ASN1_SIZE || file->size == 512)
|
|
|
|
size = 512;
|
|
|
|
else if (file->size == PUBKEY_1024_ASN1_SIZE || file->size == 1024)
|
|
|
|
size = 1024;
|
|
|
|
else if (file->size == PUBKEY_2048_ASN1_SIZE || file->size == 2048)
|
|
|
|
size = 2048;
|
|
|
|
else {
|
2017-03-14 19:02:30 +00:00
|
|
|
sc_log(card->ctx,
|
|
|
|
"incorrect RSA size %"SC_FORMAT_LEN_SIZE_T"X",
|
|
|
|
file->size);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INCORRECT_PARAMETERS);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (file->type == SC_FILE_TYPE_INTERNAL_EF &&
|
|
|
|
file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_DES) {
|
|
|
|
if (file->size == 8 || file->size == 64)
|
|
|
|
size = 64;
|
|
|
|
else if (file->size == 16 || file->size == 128)
|
|
|
|
size = 128;
|
|
|
|
else if (file->size == 24 || file->size == 192)
|
|
|
|
size = 192;
|
|
|
|
else {
|
2017-03-14 19:02:30 +00:00
|
|
|
sc_log(card->ctx,
|
|
|
|
"incorrect DES size %"SC_FORMAT_LEN_SIZE_T"u",
|
|
|
|
file->size);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INCORRECT_PARAMETERS);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
p[12] = (size >> 8) & 0xFF;
|
|
|
|
p[13] = size & 0xFF;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
p[14] = 0x86;
|
|
|
|
p[15] = 0x08;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
if (file->type == SC_FILE_TYPE_DF) {
|
|
|
|
ops[0] = SC_AC_OP_CREATE;
|
|
|
|
ops[1] = SC_AC_OP_CRYPTO;
|
|
|
|
ops[2] = SC_AC_OP_LIST_FILES;
|
|
|
|
ops[3] = SC_AC_OP_DELETE;
|
2009-11-13 09:45:21 +00:00
|
|
|
ops[4] = SC_AC_OP_PIN_DEFINE;
|
|
|
|
ops[5] = SC_AC_OP_PIN_CHANGE;
|
|
|
|
ops[6] = SC_AC_OP_PIN_RESET;
|
2014-01-19 13:11:16 +00:00
|
|
|
}
|
2004-06-16 20:59:59 +00:00
|
|
|
else if (file->type == SC_FILE_TYPE_WORKING_EF) {
|
|
|
|
if (file->ef_structure == SC_FILE_EF_TRANSPARENT) {
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "SC_FILE_EF_TRANSPARENT");
|
2004-06-16 20:59:59 +00:00
|
|
|
ops[0] = SC_AC_OP_WRITE;
|
|
|
|
ops[1] = SC_AC_OP_UPDATE;
|
|
|
|
ops[2] = SC_AC_OP_READ;
|
|
|
|
ops[3] = SC_AC_OP_ERASE;
|
|
|
|
}
|
|
|
|
else if (file->ef_structure == SC_FILE_EF_LINEAR_VARIABLE) {
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "SC_FILE_EF_LINEAR_VARIABLE");
|
2004-06-16 20:59:59 +00:00
|
|
|
ops[0] = SC_AC_OP_WRITE;
|
|
|
|
ops[1] = SC_AC_OP_UPDATE;
|
|
|
|
ops[2] = SC_AC_OP_READ;
|
|
|
|
ops[3] = SC_AC_OP_ERASE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (file->type == SC_FILE_TYPE_INTERNAL_EF) {
|
|
|
|
if (file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_DES) {
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "EF_DES");
|
2004-06-16 20:59:59 +00:00
|
|
|
ops[0] = SC_AC_OP_UPDATE;
|
2010-01-25 16:10:54 +00:00
|
|
|
ops[1] = SC_AC_OP_PSO_DECRYPT;
|
2014-01-19 13:11:16 +00:00
|
|
|
ops[2] = SC_AC_OP_PSO_ENCRYPT;
|
2010-01-25 16:10:54 +00:00
|
|
|
ops[3] = SC_AC_OP_PSO_COMPUTE_CHECKSUM;
|
|
|
|
ops[4] = SC_AC_OP_PSO_VERIFY_CHECKSUM;
|
|
|
|
ops[5] = SC_AC_OP_INTERNAL_AUTHENTICATE;
|
|
|
|
ops[6] = SC_AC_OP_EXTERNAL_AUTHENTICATE;
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
else if (file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC) {
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "EF_RSA_PUBLIC");
|
2004-06-16 20:59:59 +00:00
|
|
|
ops[0] = SC_AC_OP_UPDATE;
|
2014-01-19 13:11:16 +00:00
|
|
|
ops[2] = SC_AC_OP_PSO_ENCRYPT;
|
2010-01-25 16:10:54 +00:00
|
|
|
ops[4] = SC_AC_OP_PSO_VERIFY_SIGNATURE;
|
|
|
|
ops[6] = SC_AC_OP_EXTERNAL_AUTHENTICATE;
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
else if (file->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_CRT) {
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "EF_RSA_PRIVATE");
|
2004-06-16 20:59:59 +00:00
|
|
|
ops[0] = SC_AC_OP_UPDATE;
|
2010-01-25 16:10:54 +00:00
|
|
|
ops[1] = SC_AC_OP_PSO_DECRYPT;
|
|
|
|
ops[3] = SC_AC_OP_PSO_COMPUTE_SIGNATURE;
|
|
|
|
ops[5] = SC_AC_OP_INTERNAL_AUTHENTICATE;
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
}
|
2010-01-25 16:10:54 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
for (ii = 0; ii < sizeof(ops); ii++) {
|
2009-11-13 09:45:21 +00:00
|
|
|
const struct sc_acl_entry *entry;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
p[16+ii] = 0xFF;
|
|
|
|
if (ops[ii]==0xFF)
|
|
|
|
continue;
|
|
|
|
entry = sc_file_get_acl_entry(file, ops[ii]);
|
|
|
|
rv = acl_to_ac_byte(card,entry);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "Invalid ACL");
|
2004-06-16 20:59:59 +00:00
|
|
|
p[16+ii] = rv;
|
|
|
|
}
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
*buflen = 0x18;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
static int
|
2009-11-13 09:45:21 +00:00
|
|
|
auth_create_file(struct sc_card *card, struct sc_file *file)
|
2004-06-16 20:59:59 +00:00
|
|
|
{
|
2009-11-13 09:45:21 +00:00
|
|
|
struct sc_apdu apdu;
|
|
|
|
struct sc_path path;
|
2004-06-16 20:59:59 +00:00
|
|
|
int rv, rec_nr;
|
2009-11-13 09:45:21 +00:00
|
|
|
unsigned char sbuf[0x18];
|
|
|
|
size_t sendlen = sizeof(sbuf);
|
2006-01-11 23:41:17 +00:00
|
|
|
char pbuf[SC_MAX_PATH_STRING_SIZE];
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
2006-01-11 23:41:17 +00:00
|
|
|
|
2010-03-15 12:17:13 +00:00
|
|
|
rv = sc_path_print(pbuf, sizeof(pbuf), &file->path);
|
|
|
|
if (rv != SC_SUCCESS)
|
|
|
|
pbuf[0] = '\0';
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, " create path=%s", pbuf);
|
2010-03-15 12:17:13 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx,
|
2017-03-14 19:02:30 +00:00
|
|
|
"id %04X; size %"SC_FORMAT_LEN_SIZE_T"u; type 0x%X; ef 0x%X",
|
|
|
|
file->id, file->size, file->type, file->ef_structure);
|
2006-01-11 23:41:17 +00:00
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
if (file->id==0x0000 || file->id==0xFFFF || file->id==0x3FFF)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2010-03-15 12:17:13 +00:00
|
|
|
rv = sc_path_print(pbuf, sizeof(pbuf), &card->cache.current_path);
|
|
|
|
if (rv != SC_SUCCESS)
|
|
|
|
pbuf[0] = '\0';
|
2004-06-16 20:59:59 +00:00
|
|
|
|
|
|
|
if (file->path.len) {
|
|
|
|
memcpy(&path, &file->path, sizeof(path));
|
2014-01-19 13:11:16 +00:00
|
|
|
if (path.len>2)
|
2004-06-16 20:59:59 +00:00
|
|
|
path.len -= 2;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
if (auth_select_file(card, &path, NULL)) {
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "Cannot select parent DF.");
|
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
}
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
rv = encode_file_structure_V5(card, file, sbuf, &sendlen);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "File structure encoding failed");
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
if (file->type != SC_FILE_TYPE_DF && file->ef_structure != SC_FILE_EF_TRANSPARENT)
|
|
|
|
rec_nr = file->record_count;
|
|
|
|
else
|
|
|
|
rec_nr = 0;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE0, 0x00, rec_nr);
|
|
|
|
apdu.data = sbuf;
|
|
|
|
apdu.datalen = sendlen;
|
|
|
|
apdu.lc = sendlen;
|
|
|
|
|
|
|
|
rv = sc_transmit_apdu(card, &apdu);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "APDU transmit failed");
|
2004-06-16 20:59:59 +00:00
|
|
|
rv = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "Card returned error");
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
/* select created DF. */
|
|
|
|
if (file->type == SC_FILE_TYPE_DF) {
|
2009-11-13 09:45:21 +00:00
|
|
|
struct sc_path tmp_path;
|
|
|
|
struct sc_file *df_file = NULL;
|
2007-01-02 10:06:02 +00:00
|
|
|
|
2016-04-27 18:09:29 +00:00
|
|
|
memset(&tmp_path, 0, sizeof(struct sc_path));
|
2007-01-02 10:06:02 +00:00
|
|
|
tmp_path.type = SC_PATH_TYPE_FILE_ID;
|
|
|
|
tmp_path.value[0] = file->id >> 8;
|
|
|
|
tmp_path.value[1] = file->id & 0xFF;
|
|
|
|
tmp_path.len = 2;
|
|
|
|
rv = auth_select_file(card, &tmp_path, &df_file);
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "rv %i", rv);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
|
2017-01-05 19:21:44 +00:00
|
|
|
sc_file_free(auth_current_ef);
|
2007-01-02 10:06:02 +00:00
|
|
|
sc_file_dup(&auth_current_ef, file);
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, rv);
|
2007-01-02 10:06:02 +00:00
|
|
|
}
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2009-11-13 09:45:21 +00:00
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
static int
|
|
|
|
auth_set_security_env(struct sc_card *card,
|
|
|
|
const struct sc_security_env *env, int se_num)
|
2004-06-16 20:59:59 +00:00
|
|
|
{
|
2009-11-13 09:45:21 +00:00
|
|
|
struct auth_senv *auth_senv = &((struct auth_private_data *) card->drv_data)->senv;
|
|
|
|
struct sc_apdu apdu;
|
2004-06-16 20:59:59 +00:00
|
|
|
long unsigned pads = env->algorithm_flags & SC_ALGORITHM_RSA_PADS;
|
2009-11-13 09:45:21 +00:00
|
|
|
long unsigned supported_pads = SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_PAD_ISO9796;
|
|
|
|
int rv;
|
2014-01-19 13:11:16 +00:00
|
|
|
unsigned char rsa_sbuf[3] = {
|
2007-01-02 10:06:02 +00:00
|
|
|
0x80, 0x01, 0xFF
|
|
|
|
};
|
2009-11-13 09:45:21 +00:00
|
|
|
unsigned char des_sbuf[13] = {
|
2014-01-19 13:11:16 +00:00
|
|
|
0x80, 0x01, 0x01,
|
2007-01-02 10:06:02 +00:00
|
|
|
0x87, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
|
|
|
};
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
2017-03-14 19:02:30 +00:00
|
|
|
sc_log(card->ctx,
|
|
|
|
"op %i; path %s; key_ref 0x%X; algos 0x%X; flags 0x%lX",
|
|
|
|
env->operation, sc_print_path(&env->file_ref), env->key_ref[0],
|
|
|
|
env->algorithm_flags, env->flags);
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2009-11-13 09:45:21 +00:00
|
|
|
memset(auth_senv, 0, sizeof(struct auth_senv));
|
2014-01-19 13:11:16 +00:00
|
|
|
|
|
|
|
if (!(env->flags & SC_SEC_ENV_FILE_REF_PRESENT))
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, SC_ERROR_INTERNAL, "Key file is not selected.");
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
switch (env->algorithm) {
|
|
|
|
case SC_ALGORITHM_DES:
|
|
|
|
case SC_ALGORITHM_3DES:
|
2017-03-14 19:02:30 +00:00
|
|
|
sc_log(card->ctx,
|
|
|
|
"algo SC_ALGORITHM_xDES: ref %X, flags %lX",
|
|
|
|
env->algorithm_ref, env->flags);
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
if (env->operation == SC_SEC_OPERATION_DECIPHER) {
|
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0xB8);
|
2007-01-02 10:06:02 +00:00
|
|
|
apdu.lc = 3;
|
2004-06-16 20:59:59 +00:00
|
|
|
apdu.data = des_sbuf;
|
2007-01-02 10:06:02 +00:00
|
|
|
apdu.datalen = 3;
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
else {
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "Invalid crypto operation: %X", env->operation);
|
|
|
|
LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, "Invalid crypto operation");
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
break;
|
|
|
|
case SC_ALGORITHM_RSA:
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "algo SC_ALGORITHM_RSA");
|
2004-06-16 20:59:59 +00:00
|
|
|
if (env->algorithm_flags & SC_ALGORITHM_RSA_HASHES) {
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, "No support for hashes.");
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
if (pads & (~supported_pads)) {
|
2017-03-14 19:02:30 +00:00
|
|
|
sc_log(card->ctx, "No support for PAD %lX", pads);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, "No padding support.");
|
2006-05-01 10:26:17 +00:00
|
|
|
}
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
if (env->operation == SC_SEC_OPERATION_SIGN) {
|
2007-01-02 10:06:02 +00:00
|
|
|
rsa_sbuf[2] = 0x11;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0xB6);
|
|
|
|
apdu.lc = sizeof(rsa_sbuf);
|
|
|
|
apdu.datalen = sizeof(rsa_sbuf);
|
|
|
|
apdu.data = rsa_sbuf;
|
|
|
|
}
|
|
|
|
else if (env->operation == SC_SEC_OPERATION_DECIPHER) {
|
2007-01-02 10:06:02 +00:00
|
|
|
rsa_sbuf[2] = 0x11;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0xB8);
|
|
|
|
apdu.lc = sizeof(rsa_sbuf);
|
|
|
|
apdu.datalen = sizeof(rsa_sbuf);
|
|
|
|
apdu.data = rsa_sbuf;
|
|
|
|
}
|
|
|
|
else {
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "Invalid crypto operation: %X", env->operation);
|
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
break;
|
|
|
|
default:
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, "Invalid crypto algorithm supplied");
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
rv = sc_transmit_apdu(card, &apdu);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "APDU transmit failed");
|
2004-06-16 20:59:59 +00:00
|
|
|
rv = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "Card returned error");
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
auth_senv->algorithm = env->algorithm;
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, rv);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
static int
|
2009-11-13 09:45:21 +00:00
|
|
|
auth_restore_security_env(struct sc_card *card, int se_num)
|
2004-06-16 20:59:59 +00:00
|
|
|
{
|
2007-01-02 10:06:02 +00:00
|
|
|
return SC_SUCCESS;
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
static int
|
2009-11-13 09:45:21 +00:00
|
|
|
auth_compute_signature(struct sc_card *card, const unsigned char *in, size_t ilen,
|
|
|
|
unsigned char * out, size_t olen)
|
2004-06-16 20:59:59 +00:00
|
|
|
{
|
2009-11-13 09:45:21 +00:00
|
|
|
struct sc_apdu apdu;
|
2007-01-02 10:06:02 +00:00
|
|
|
unsigned char resp[SC_MAX_APDU_BUFFER_SIZE];
|
2004-06-16 20:59:59 +00:00
|
|
|
int rv;
|
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
if (!card || !in || !out) {
|
2015-01-22 19:29:33 +00:00
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
2007-01-02 10:06:02 +00:00
|
|
|
else if (ilen > 96) {
|
2017-03-14 19:02:30 +00:00
|
|
|
sc_log(card->ctx,
|
|
|
|
"Illegal input length %"SC_FORMAT_LEN_SIZE_T"u",
|
|
|
|
ilen);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, "Illegal input length");
|
2007-01-02 10:06:02 +00:00
|
|
|
}
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
2017-03-14 19:02:30 +00:00
|
|
|
sc_log(card->ctx,
|
|
|
|
"inlen %"SC_FORMAT_LEN_SIZE_T"u, outlen %"SC_FORMAT_LEN_SIZE_T"u",
|
|
|
|
ilen, olen);
|
2015-01-22 19:29:33 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x9E, 0x9A);
|
|
|
|
apdu.datalen = ilen;
|
|
|
|
apdu.data = in;
|
|
|
|
apdu.lc = ilen;
|
2007-03-07 12:39:52 +00:00
|
|
|
apdu.le = olen > 256 ? 256 : olen;
|
2007-01-02 10:06:02 +00:00
|
|
|
apdu.resp = resp;
|
|
|
|
apdu.resplen = olen;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
rv = sc_transmit_apdu(card, &apdu);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "APDU transmit failed");
|
2004-06-16 20:59:59 +00:00
|
|
|
rv = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "Compute signature failed");
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
if (apdu.resplen > olen) {
|
2017-03-14 19:02:30 +00:00
|
|
|
sc_log(card->ctx,
|
|
|
|
"Compute signature failed: invalid response length %"SC_FORMAT_LEN_SIZE_T"u",
|
|
|
|
apdu.resplen);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_CARD_CMD_FAILED);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-07-03 13:44:45 +00:00
|
|
|
memcpy(out, apdu.resp, apdu.resplen);
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, apdu.resplen);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
static int
|
2009-11-13 09:45:21 +00:00
|
|
|
auth_decipher(struct sc_card *card, const unsigned char *in, size_t inlen,
|
|
|
|
unsigned char *out, size_t outlen)
|
2004-06-16 20:59:59 +00:00
|
|
|
{
|
2009-11-13 09:45:21 +00:00
|
|
|
struct sc_apdu apdu;
|
|
|
|
unsigned char resp[SC_MAX_APDU_BUFFER_SIZE];
|
2007-01-02 10:06:02 +00:00
|
|
|
int rv, _inlen = inlen;
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
2017-03-14 19:02:30 +00:00
|
|
|
sc_log(card->ctx,
|
|
|
|
"crgram_len %"SC_FORMAT_LEN_SIZE_T"u; outlen %"SC_FORMAT_LEN_SIZE_T"u",
|
|
|
|
inlen, outlen);
|
2014-01-19 13:11:16 +00:00
|
|
|
if (!out || !outlen || inlen > SC_MAX_APDU_BUFFER_SIZE)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x80, 0x86);
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "algorithm SC_ALGORITHM_RSA");
|
2007-01-02 10:06:02 +00:00
|
|
|
if (inlen % 64) {
|
|
|
|
rv = SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
goto done;
|
|
|
|
}
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
_inlen = inlen;
|
|
|
|
if (_inlen == 256) {
|
|
|
|
apdu.cla |= 0x10;
|
|
|
|
apdu.data = in;
|
|
|
|
apdu.datalen = 8;
|
|
|
|
apdu.resp = resp;
|
|
|
|
apdu.resplen = SC_MAX_APDU_BUFFER_SIZE;
|
|
|
|
apdu.lc = 8;
|
|
|
|
apdu.le = 256;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
rv = sc_transmit_apdu(card, &apdu);
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "rv %i", rv);
|
|
|
|
LOG_TEST_RET(card->ctx, rv, "APDU transmit failed");
|
2007-01-02 10:06:02 +00:00
|
|
|
rv = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "Card returned error");
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
_inlen -= 8;
|
|
|
|
in += 8;
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
apdu.cla &= ~0x10;
|
|
|
|
}
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
apdu.data = in;
|
|
|
|
apdu.datalen = _inlen;
|
|
|
|
apdu.resp = resp;
|
2004-06-16 20:59:59 +00:00
|
|
|
apdu.resplen = SC_MAX_APDU_BUFFER_SIZE;
|
2007-01-02 10:06:02 +00:00
|
|
|
apdu.lc = _inlen;
|
|
|
|
apdu.le = _inlen;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
rv = sc_transmit_apdu(card, &apdu);
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "rv %i", rv);
|
|
|
|
LOG_TEST_RET(card->ctx, rv, "APDU transmit failed");
|
2004-06-16 20:59:59 +00:00
|
|
|
rv = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "rv %i", rv);
|
|
|
|
LOG_TEST_RET(card->ctx, rv, "Card returned error");
|
2007-01-02 10:06:02 +00:00
|
|
|
|
|
|
|
if (outlen > apdu.resplen)
|
|
|
|
outlen = apdu.resplen;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
memcpy(out, apdu.resp, outlen);
|
|
|
|
rv = outlen;
|
2004-06-16 20:59:59 +00:00
|
|
|
|
|
|
|
done:
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, rv);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
/* Return the default AAK for this type of card */
|
2014-01-19 13:11:16 +00:00
|
|
|
static int
|
2009-11-13 09:45:21 +00:00
|
|
|
auth_get_default_key(struct sc_card *card, struct sc_cardctl_default_key *data)
|
2004-06-16 20:59:59 +00:00
|
|
|
{
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NO_DEFAULT_KEY);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
static int
|
2009-11-13 09:45:21 +00:00
|
|
|
auth_encode_exponent(unsigned long exponent, unsigned char *buff, size_t buff_len)
|
2004-06-16 20:59:59 +00:00
|
|
|
{
|
2004-12-21 22:38:37 +00:00
|
|
|
int shift;
|
|
|
|
size_t ii;
|
2004-06-16 20:59:59 +00:00
|
|
|
|
|
|
|
for (shift=0; exponent >> (shift+8); shift += 8)
|
|
|
|
;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
|
|
|
for (ii = 0; ii<buff_len && shift>=0 ; ii++, shift-=8)
|
2004-06-16 20:59:59 +00:00
|
|
|
*(buff + ii) = (exponent >> shift) & 0xFF;
|
|
|
|
|
|
|
|
if (ii==buff_len)
|
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return ii;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Generate key on-card */
|
2014-01-19 13:11:16 +00:00
|
|
|
static int
|
|
|
|
auth_generate_key(struct sc_card *card, int use_sm,
|
2007-01-02 10:06:02 +00:00
|
|
|
struct sc_cardctl_oberthur_genkey_info *data)
|
2004-06-16 20:59:59 +00:00
|
|
|
{
|
2009-11-13 09:45:21 +00:00
|
|
|
struct sc_apdu apdu;
|
|
|
|
unsigned char sbuf[SC_MAX_APDU_BUFFER_SIZE];
|
|
|
|
struct sc_path tmp_path;
|
2004-06-16 20:59:59 +00:00
|
|
|
int rv = 0;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
2014-01-19 13:11:16 +00:00
|
|
|
if (data->key_bits < 512 || data->key_bits > 2048 ||
|
2004-06-16 20:59:59 +00:00
|
|
|
(data->key_bits%0x20)!=0) {
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, "Illegal key length");
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
sbuf[0] = (data->id_pub >> 8) & 0xFF;
|
|
|
|
sbuf[1] = data->id_pub & 0xFF;
|
|
|
|
sbuf[2] = (data->id_prv >> 8) & 0xFF;
|
|
|
|
sbuf[3] = data->id_prv & 0xFF;
|
|
|
|
if (data->exponent != 0x10001) {
|
|
|
|
rv = auth_encode_exponent(data->exponent, &sbuf[5],SC_MAX_APDU_BUFFER_SIZE-6);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "Cannot encode exponent");
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
sbuf[4] = rv;
|
|
|
|
rv++;
|
|
|
|
}
|
2007-01-02 10:06:02 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x46, 0x00, 0x00);
|
Do not cast the return value of malloc(3) and calloc(3)
From http://en.wikipedia.org/wiki/Malloc#Casting_and_type_safety
" Casting and type safety
malloc returns a void pointer (void *), which indicates that it is a
pointer to a region of unknown data type. One may "cast" (see type
conversion) this pointer to a specific type, as in
int *ptr = (int*)malloc(10 * sizeof (int));
When using C, this is considered bad practice; it is redundant under the
C standard. Moreover, putting in a cast may mask failure to include the
header stdlib.h, in which the prototype for malloc is found. In the
absence of a prototype for malloc, the C compiler will assume that
malloc returns an int, and will issue a warning in a context such as the
above, provided the error is not masked by a cast. On certain
architectures and data models (such as LP64 on 64 bit systems, where
long and pointers are 64 bit and int is 32 bit), this error can actually
result in undefined behavior, as the implicitly declared malloc returns
a 32 bit value whereas the actually defined function returns a 64 bit
value. Depending on calling conventions and memory layout, this may
result in stack smashing.
The returned pointer need not be explicitly cast to a more specific
pointer type, since ANSI C defines an implicit conversion between the
void pointer type and other pointers to objects. An explicit cast of
malloc's return value is sometimes performed because malloc originally
returned a char *, but this cast is unnecessary in standard C
code.[4][5] Omitting the cast, however, creates an incompatibility with
C++, which does require it.
The lack of a specific pointer type returned from malloc is type-unsafe
behaviour: malloc allocates based on byte count but not on type. This
distinguishes it from the C++ new operator that returns a pointer whose
type relies on the operand. (see C Type Safety). "
See also
http://www.opensc-project.org/pipermail/opensc-devel/2010-August/014586.html
git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@4636 c6295689-39f2-0310-b995-f0e70906c6a9
2010-08-18 15:08:51 +00:00
|
|
|
apdu.resp = calloc(1, data->key_bits/8+8);
|
2009-11-13 09:45:21 +00:00
|
|
|
if (!apdu.resp)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
|
2009-11-13 09:45:21 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
apdu.resplen = data->key_bits/8+8;
|
|
|
|
apdu.lc = rv + 4;
|
|
|
|
apdu.le = data->key_bits/8;
|
|
|
|
apdu.data = sbuf;
|
2007-01-02 10:06:02 +00:00
|
|
|
apdu.datalen = rv + 4;
|
|
|
|
|
2009-11-05 18:27:56 +00:00
|
|
|
rv = sc_transmit_apdu(card, &apdu);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "APDU transmit failed");
|
2009-11-05 18:27:56 +00:00
|
|
|
rv = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "Card returned error");
|
2014-01-19 13:11:16 +00:00
|
|
|
|
|
|
|
memset(&tmp_path, 0, sizeof(struct sc_path));
|
2007-01-02 10:06:02 +00:00
|
|
|
tmp_path.type = SC_PATH_TYPE_FILE_ID;
|
|
|
|
tmp_path.len = 2;
|
|
|
|
memcpy(tmp_path.value, sbuf, 2);
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
rv = auth_select_file(card, &tmp_path, NULL);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "cannot select public key");
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
rv = auth_read_component(card, SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC,
|
|
|
|
1, apdu.resp, data->key_bits/8);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "auth_read_component() returned error");
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
apdu.resplen = rv;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
if (data->pubkey) {
|
2014-01-19 13:11:16 +00:00
|
|
|
if (data->pubkey_len < apdu.resplen)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
|
2007-01-02 10:06:02 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
memcpy(data->pubkey,apdu.resp,apdu.resplen);
|
|
|
|
}
|
|
|
|
|
|
|
|
data->pubkey_len = apdu.resplen;
|
|
|
|
free(apdu.resp);
|
2007-01-02 10:06:02 +00:00
|
|
|
|
2017-03-14 19:02:30 +00:00
|
|
|
sc_log(card->ctx, "resulted public key len %"SC_FORMAT_LEN_SIZE_T"u",
|
|
|
|
apdu.resplen);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2009-11-13 09:45:21 +00:00
|
|
|
auth_update_component(struct sc_card *card, struct auth_update_component_info *args)
|
2004-06-16 20:59:59 +00:00
|
|
|
{
|
2009-11-13 09:45:21 +00:00
|
|
|
struct sc_apdu apdu;
|
|
|
|
unsigned char sbuf[SC_MAX_APDU_BUFFER_SIZE + 0x10];
|
|
|
|
unsigned char ins, p1, p2;
|
2004-06-16 20:59:59 +00:00
|
|
|
int rv, len;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
2004-06-16 20:59:59 +00:00
|
|
|
if (args->len > sizeof(sbuf) || args->len > 0x100)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "nn %i; len %i", args->component, args->len);
|
2004-06-16 20:59:59 +00:00
|
|
|
ins = 0xD8;
|
|
|
|
p1 = args->component;
|
|
|
|
p2 = 0x04;
|
|
|
|
len = 0;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
sbuf[len++] = args->type;
|
|
|
|
sbuf[len++] = args->len;
|
|
|
|
memcpy(sbuf + len, args->data, args->len);
|
|
|
|
len += args->len;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
if (args->type == SC_CARDCTL_OBERTHUR_KEY_DES) {
|
2007-01-08 17:04:39 +00:00
|
|
|
int outl;
|
|
|
|
const unsigned char in[8] = {0,0,0,0,0,0,0,0};
|
2007-01-02 10:06:02 +00:00
|
|
|
unsigned char out[8];
|
2016-01-06 14:40:59 +00:00
|
|
|
EVP_CIPHER_CTX * ctx = NULL;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
if (args->len!=8 && args->len!=24)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2016-01-06 14:40:59 +00:00
|
|
|
ctx = EVP_CIPHER_CTX_new();
|
|
|
|
if (ctx == NULL)
|
2018-11-22 22:10:49 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
|
2016-01-06 14:40:59 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
p2 = 0;
|
2014-01-19 13:11:16 +00:00
|
|
|
if (args->len == 24)
|
2016-01-06 14:40:59 +00:00
|
|
|
EVP_EncryptInit_ex(ctx, EVP_des_ede(), NULL, args->data, NULL);
|
2007-01-08 17:04:39 +00:00
|
|
|
else
|
2016-01-06 14:40:59 +00:00
|
|
|
EVP_EncryptInit_ex(ctx, EVP_des_ecb(), NULL, args->data, NULL);
|
|
|
|
rv = EVP_EncryptUpdate(ctx, out, &outl, in, 8);
|
|
|
|
EVP_CIPHER_CTX_free(ctx);
|
|
|
|
if (rv == 0) {
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "OpenSSL encryption error.");
|
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
2007-01-02 10:06:02 +00:00
|
|
|
|
|
|
|
sbuf[len++] = 0x03;
|
|
|
|
memcpy(sbuf + len, out, 3);
|
|
|
|
len += 3;
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
else {
|
2007-01-02 10:06:02 +00:00
|
|
|
sbuf[len++] = 0;
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, ins, p1, p2);
|
|
|
|
apdu.cla |= 0x80;
|
|
|
|
apdu.data = sbuf;
|
|
|
|
apdu.datalen = len;
|
|
|
|
apdu.lc = len;
|
|
|
|
if (args->len == 0x100) {
|
2007-01-02 10:06:02 +00:00
|
|
|
sbuf[0] = args->type;
|
|
|
|
sbuf[1] = 0x20;
|
|
|
|
memcpy(sbuf + 2, args->data, 0x20);
|
|
|
|
sbuf[0x22] = 0;
|
|
|
|
apdu.cla |= 0x10;
|
|
|
|
apdu.data = sbuf;
|
|
|
|
apdu.datalen = 0x23;
|
|
|
|
apdu.lc = 0x23;
|
|
|
|
rv = sc_transmit_apdu(card, &apdu);
|
|
|
|
apdu.cla &= ~0x10;
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "APDU transmit failed");
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
sbuf[0] = args->type;
|
|
|
|
sbuf[1] = 0xE0;
|
|
|
|
memcpy(sbuf + 2, args->data + 0x20, 0xE0);
|
|
|
|
sbuf[0xE2] = 0;
|
|
|
|
apdu.data = sbuf;
|
|
|
|
apdu.datalen = 0xE3;
|
|
|
|
apdu.lc = 0xE3;
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
rv = sc_transmit_apdu(card, &apdu);
|
2005-09-17 10:44:45 +00:00
|
|
|
sc_mem_clear(sbuf, sizeof(sbuf));
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "APDU transmit failed");
|
2004-06-16 20:59:59 +00:00
|
|
|
|
|
|
|
rv = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, rv);
|
2007-01-02 10:06:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2009-11-13 09:45:21 +00:00
|
|
|
auth_update_key(struct sc_card *card, struct sc_cardctl_oberthur_updatekey_info *info)
|
2007-01-02 10:06:02 +00:00
|
|
|
{
|
|
|
|
int rv, ii;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
if (info->data_len != sizeof(void *) || !info->data)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
|
2007-01-02 10:06:02 +00:00
|
|
|
|
|
|
|
if (info->type == SC_CARDCTL_OBERTHUR_KEY_RSA_CRT) {
|
|
|
|
struct sc_pkcs15_prkey_rsa *rsa = (struct sc_pkcs15_prkey_rsa *)info->data;
|
2009-11-13 09:45:21 +00:00
|
|
|
struct sc_pkcs15_bignum bn[5];
|
2007-01-02 10:06:02 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "Import RSA CRT");
|
2007-01-02 10:06:02 +00:00
|
|
|
bn[0] = rsa->p;
|
|
|
|
bn[1] = rsa->q;
|
|
|
|
bn[2] = rsa->iqmp;
|
|
|
|
bn[3] = rsa->dmp1;
|
|
|
|
bn[4] = rsa->dmq1;
|
|
|
|
for (ii=0;ii<5;ii++) {
|
|
|
|
struct auth_update_component_info args;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
memset(&args, 0, sizeof(args));
|
|
|
|
args.type = SC_CARDCTL_OBERTHUR_KEY_RSA_CRT;
|
|
|
|
args.component = ii+1;
|
|
|
|
args.data = bn[ii].data;
|
|
|
|
args.len = bn[ii].len;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
rv = auth_update_component(card, &args);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "Update RSA component failed");
|
2007-01-02 10:06:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (info->type == SC_CARDCTL_OBERTHUR_KEY_DES) {
|
2014-01-19 13:11:16 +00:00
|
|
|
rv = SC_ERROR_NOT_SUPPORTED;
|
2007-01-02 10:06:02 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
rv = SC_ERROR_INVALID_DATA;
|
|
|
|
}
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, rv);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
static int
|
2009-11-13 09:45:21 +00:00
|
|
|
auth_card_ctl(struct sc_card *card, unsigned long cmd, void *ptr)
|
2004-06-16 20:59:59 +00:00
|
|
|
{
|
|
|
|
switch (cmd) {
|
|
|
|
case SC_CARDCTL_GET_DEFAULT_KEY:
|
|
|
|
return auth_get_default_key(card,
|
|
|
|
(struct sc_cardctl_default_key *) ptr);
|
|
|
|
case SC_CARDCTL_OBERTHUR_GENERATE_KEY:
|
2007-01-02 10:06:02 +00:00
|
|
|
return auth_generate_key(card, 0,
|
2004-06-16 20:59:59 +00:00
|
|
|
(struct sc_cardctl_oberthur_genkey_info *) ptr);
|
|
|
|
case SC_CARDCTL_OBERTHUR_UPDATE_KEY:
|
2014-01-19 13:11:16 +00:00
|
|
|
return auth_update_key(card,
|
2004-06-16 20:59:59 +00:00
|
|
|
(struct sc_cardctl_oberthur_updatekey_info *) ptr);
|
|
|
|
case SC_CARDCTL_OBERTHUR_CREATE_PIN:
|
|
|
|
return auth_create_reference_data(card,
|
2014-01-19 13:11:16 +00:00
|
|
|
(struct sc_cardctl_oberthur_createpin_info *) ptr);
|
2016-04-28 08:52:25 +00:00
|
|
|
case SC_CARDCTL_GET_SERIALNR:
|
|
|
|
return auth_get_serialnr(card, (struct sc_serial_number *)ptr);
|
2007-07-04 14:25:39 +00:00
|
|
|
case SC_CARDCTL_LIFECYCLE_GET:
|
|
|
|
case SC_CARDCTL_LIFECYCLE_SET:
|
|
|
|
return SC_ERROR_NOT_SUPPORTED;
|
2004-06-16 20:59:59 +00:00
|
|
|
default:
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2014-01-19 13:11:16 +00:00
|
|
|
auth_read_component(struct sc_card *card, enum SC_CARDCTL_OBERTHUR_KEY_TYPE type,
|
2004-06-16 20:59:59 +00:00
|
|
|
int num, unsigned char *out, size_t outlen)
|
|
|
|
{
|
2009-11-13 09:45:21 +00:00
|
|
|
struct sc_apdu apdu;
|
2004-06-16 20:59:59 +00:00
|
|
|
int rv;
|
2016-04-28 08:52:25 +00:00
|
|
|
unsigned char resp[256];
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
2017-03-14 19:02:30 +00:00
|
|
|
sc_log(card->ctx, "num %i, outlen %"SC_FORMAT_LEN_SIZE_T"u, type %i",
|
|
|
|
num, outlen, type);
|
2007-01-02 10:06:02 +00:00
|
|
|
|
|
|
|
if (!outlen || type!=SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INCORRECT_PARAMETERS);
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xB4, num, 0x00);
|
|
|
|
apdu.cla |= 0x80;
|
|
|
|
apdu.le = outlen;
|
|
|
|
apdu.resp = resp;
|
|
|
|
apdu.resplen = sizeof(resp);
|
|
|
|
rv = sc_transmit_apdu(card, &apdu);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "APDU transmit failed");
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
rv = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "Card returned error");
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
if (outlen < apdu.resplen)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_WRONG_LENGTH);
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
memcpy(out, apdu.resp, apdu.resplen);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, apdu.resplen);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
static int
|
2009-11-13 09:45:21 +00:00
|
|
|
auth_get_pin_reference (struct sc_card *card, int type, int reference, int cmd, int *out_ref)
|
2004-06-16 20:59:59 +00:00
|
|
|
{
|
2011-02-05 21:50:48 +00:00
|
|
|
if (!out_ref)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
switch (type) {
|
|
|
|
case SC_AC_CHV:
|
|
|
|
if (reference != 1 && reference != 2 && reference != 4)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_PIN_REFERENCE);
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
*out_ref = reference;
|
2009-11-13 09:45:21 +00:00
|
|
|
if (reference == 1 || reference == 4)
|
2007-07-03 15:33:28 +00:00
|
|
|
if (cmd == SC_PIN_CMD_VERIFY)
|
|
|
|
*out_ref |= 0x80;
|
2004-06-16 20:59:59 +00:00
|
|
|
break;
|
2007-01-02 10:06:02 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
default:
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
static void
|
|
|
|
auth_init_pin_info(struct sc_card *card, struct sc_pin_cmd_pin *pin,
|
2004-06-16 20:59:59 +00:00
|
|
|
unsigned int type)
|
|
|
|
{
|
2009-11-13 09:45:21 +00:00
|
|
|
pin->offset = 0;
|
2004-06-16 20:59:59 +00:00
|
|
|
pin->pad_char = 0xFF;
|
|
|
|
pin->encoding = SC_PIN_ENCODING_ASCII;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2009-11-23 13:40:05 +00:00
|
|
|
if (type == OBERTHUR_AUTH_TYPE_PIN) {
|
|
|
|
pin->max_length = OBERTHUR_AUTH_MAX_LENGTH_PIN;
|
|
|
|
pin->pad_length = OBERTHUR_AUTH_MAX_LENGTH_PIN;
|
2007-01-02 10:06:02 +00:00
|
|
|
}
|
|
|
|
else {
|
2009-11-23 13:40:05 +00:00
|
|
|
pin->max_length = OBERTHUR_AUTH_MAX_LENGTH_PUK;
|
|
|
|
pin->pad_length = OBERTHUR_AUTH_MAX_LENGTH_PUK;
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-11-23 13:40:05 +00:00
|
|
|
static int
|
2014-01-19 13:11:16 +00:00
|
|
|
auth_pin_verify_pinpad(struct sc_card *card, int pin_reference, int *tries_left)
|
2009-11-23 13:40:05 +00:00
|
|
|
{
|
|
|
|
struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
|
2014-01-19 13:11:16 +00:00
|
|
|
struct sc_pin_cmd_data pin_cmd;
|
2009-11-23 13:40:05 +00:00
|
|
|
struct sc_apdu apdu;
|
2014-01-19 13:11:16 +00:00
|
|
|
unsigned char ffs1[0x100];
|
2009-11-23 13:40:05 +00:00
|
|
|
int rv;
|
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
2009-11-23 13:40:05 +00:00
|
|
|
|
2011-03-23 15:51:29 +00:00
|
|
|
memset(ffs1, 0xFF, sizeof(ffs1));
|
2009-11-23 13:40:05 +00:00
|
|
|
memset(&pin_cmd, 0, sizeof(pin_cmd));
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2009-12-03 11:11:04 +00:00
|
|
|
rv = auth_pin_is_verified(card, pin_reference, tries_left);
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "auth_pin_is_verified returned rv %i", rv);
|
2009-11-23 13:40:05 +00:00
|
|
|
|
|
|
|
/* Return SUCCESS without verifying if
|
|
|
|
* PIN has been already verified and PIN pad has to be used. */
|
|
|
|
if (!rv)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, rv);
|
2009-11-23 13:40:05 +00:00
|
|
|
|
|
|
|
pin_cmd.flags |= SC_PIN_CMD_NEED_PADDING;
|
|
|
|
|
|
|
|
/* For Oberthur card, PIN command data length has to be 0x40.
|
2018-04-14 17:38:34 +00:00
|
|
|
* In PCSC10 v2.06 the upper limit of pin.max_length is 8.
|
2014-01-19 13:11:16 +00:00
|
|
|
*
|
2009-11-23 13:40:05 +00:00
|
|
|
* The standard sc_build_pin() throws an error when 'pin.len > pin.max_length' .
|
|
|
|
* So, let's build our own APDU.
|
|
|
|
*/
|
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x20, 0x00, pin_reference);
|
|
|
|
apdu.lc = OBERTHUR_AUTH_MAX_LENGTH_PIN;
|
|
|
|
apdu.datalen = OBERTHUR_AUTH_MAX_LENGTH_PIN;
|
2011-03-23 15:51:29 +00:00
|
|
|
apdu.data = ffs1;
|
2009-11-23 13:40:05 +00:00
|
|
|
|
|
|
|
pin_cmd.apdu = &apdu;
|
|
|
|
pin_cmd.pin_type = SC_AC_CHV;
|
|
|
|
pin_cmd.cmd = SC_PIN_CMD_VERIFY;
|
|
|
|
pin_cmd.flags |= SC_PIN_CMD_USE_PINPAD;
|
|
|
|
pin_cmd.pin_reference = pin_reference;
|
|
|
|
if (pin_cmd.pin1.min_length < 4)
|
|
|
|
pin_cmd.pin1.min_length = 4;
|
|
|
|
pin_cmd.pin1.max_length = 8;
|
|
|
|
pin_cmd.pin1.encoding = SC_PIN_ENCODING_ASCII;
|
|
|
|
pin_cmd.pin1.offset = 5;
|
2011-03-23 15:51:29 +00:00
|
|
|
pin_cmd.pin1.data = ffs1;
|
2009-11-23 13:40:05 +00:00
|
|
|
pin_cmd.pin1.len = OBERTHUR_AUTH_MAX_LENGTH_PIN;
|
2010-12-30 13:04:55 +00:00
|
|
|
pin_cmd.pin1.pad_length = OBERTHUR_AUTH_MAX_LENGTH_PIN;
|
2009-11-23 13:40:05 +00:00
|
|
|
|
|
|
|
rv = iso_drv->ops->pin_cmd(card, &pin_cmd, tries_left);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "PIN CMD 'VERIFY' with pinpad failed");
|
2009-11-23 13:40:05 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, rv);
|
2009-11-23 13:40:05 +00:00
|
|
|
}
|
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
static int
|
2014-01-19 13:11:16 +00:00
|
|
|
auth_pin_verify(struct sc_card *card, unsigned int type,
|
|
|
|
struct sc_pin_cmd_data *data, int *tries_left)
|
2004-06-16 20:59:59 +00:00
|
|
|
{
|
2009-11-13 09:45:21 +00:00
|
|
|
struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
|
|
|
|
int rv;
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2009-11-13 09:45:21 +00:00
|
|
|
if (type != SC_AC_CHV)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, "PIN type other then SC_AC_CHV is not supported");
|
2009-11-13 09:45:21 +00:00
|
|
|
|
|
|
|
data->flags |= SC_PIN_CMD_NEED_PADDING;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2009-11-23 13:40:05 +00:00
|
|
|
auth_init_pin_info(card, &data->pin1, OBERTHUR_AUTH_TYPE_PIN);
|
2007-01-02 10:06:02 +00:00
|
|
|
|
2009-11-13 09:45:21 +00:00
|
|
|
/* User PIN is always local. */
|
2014-01-19 13:11:16 +00:00
|
|
|
if (data->pin_reference == OBERTHUR_PIN_REFERENCE_USER
|
2009-12-03 11:11:04 +00:00
|
|
|
|| data->pin_reference == OBERTHUR_PIN_REFERENCE_ONETIME)
|
2009-11-13 09:45:21 +00:00
|
|
|
data->pin_reference |= OBERTHUR_PIN_LOCAL;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2009-12-03 11:11:04 +00:00
|
|
|
rv = auth_pin_is_verified(card, data->pin_reference, tries_left);
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "auth_pin_is_verified returned rv %i", rv);
|
2007-01-02 10:06:02 +00:00
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
/* Return if only PIN status has been asked. */
|
2009-11-13 09:45:21 +00:00
|
|
|
if (data->pin1.data && !data->pin1.len)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, rv);
|
2009-11-13 09:45:21 +00:00
|
|
|
|
|
|
|
/* Return SUCCESS without verifying if
|
|
|
|
* PIN has been already verified and PIN pad has to be used. */
|
|
|
|
if (!rv && !data->pin1.data && !data->pin1.len)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, rv);
|
2009-11-13 09:45:21 +00:00
|
|
|
|
2009-11-23 13:40:05 +00:00
|
|
|
if (!data->pin1.data && !data->pin1.len)
|
2009-12-03 11:11:04 +00:00
|
|
|
rv = auth_pin_verify_pinpad(card, data->pin_reference, tries_left);
|
2009-11-23 13:40:05 +00:00
|
|
|
else
|
|
|
|
rv = iso_drv->ops->pin_cmd(card, data, tries_left);
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, rv);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-11-13 09:45:21 +00:00
|
|
|
static int
|
2009-12-03 11:11:04 +00:00
|
|
|
auth_pin_is_verified(struct sc_card *card, int pin_reference, int *tries_left)
|
2004-06-16 20:59:59 +00:00
|
|
|
{
|
2009-11-13 09:45:21 +00:00
|
|
|
struct sc_apdu apdu;
|
|
|
|
int rv;
|
|
|
|
|
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x20, 0, pin_reference);
|
2004-06-16 20:59:59 +00:00
|
|
|
|
|
|
|
rv = sc_transmit_apdu(card, &apdu);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "APDU transmit failed");
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2009-11-13 09:45:21 +00:00
|
|
|
if (tries_left && apdu.sw1 == 0x63 && (apdu.sw2 & 0xF0) == 0xC0)
|
2004-06-16 20:59:59 +00:00
|
|
|
*tries_left = apdu.sw2 & 0x0F;
|
|
|
|
|
2009-11-13 09:45:21 +00:00
|
|
|
/* Replace 'no tries left' with 'auth method blocked' */
|
|
|
|
if (apdu.sw1 == 0x63 && apdu.sw2 == 0xC0) {
|
|
|
|
apdu.sw1 = 0x69;
|
|
|
|
apdu.sw2 = 0x83;
|
|
|
|
}
|
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
rv = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2009-11-13 09:45:21 +00:00
|
|
|
|
|
|
|
return rv;
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-12-03 11:11:04 +00:00
|
|
|
static int
|
2014-01-19 13:11:16 +00:00
|
|
|
auth_pin_change_pinpad(struct sc_card *card, struct sc_pin_cmd_data *data,
|
|
|
|
int *tries_left)
|
2004-06-16 20:59:59 +00:00
|
|
|
{
|
2009-11-13 09:45:21 +00:00
|
|
|
struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
|
2014-01-19 13:11:16 +00:00
|
|
|
struct sc_pin_cmd_data pin_cmd;
|
2009-11-13 09:45:21 +00:00
|
|
|
struct sc_apdu apdu;
|
2014-01-19 13:11:16 +00:00
|
|
|
unsigned char ffs1[0x100];
|
|
|
|
unsigned char ffs2[0x100];
|
2010-01-27 18:07:14 +00:00
|
|
|
int rv, pin_reference;
|
2009-11-13 09:45:21 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
2007-01-02 10:06:02 +00:00
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
pin_reference = data->pin_reference & ~OBERTHUR_PIN_LOCAL;
|
2010-01-27 18:07:14 +00:00
|
|
|
|
2009-12-03 11:11:04 +00:00
|
|
|
memset(ffs1, 0xFF, sizeof(ffs1));
|
|
|
|
memset(ffs2, 0xFF, sizeof(ffs2));
|
|
|
|
memset(&pin_cmd, 0, sizeof(pin_cmd));
|
|
|
|
|
|
|
|
if (data->pin1.len > OBERTHUR_AUTH_MAX_LENGTH_PIN)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, "'PIN CHANGE' failed");
|
2009-12-03 11:11:04 +00:00
|
|
|
|
|
|
|
if (data->pin1.data && data->pin1.len)
|
|
|
|
memcpy(ffs1, data->pin1.data, data->pin1.len);
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2009-12-03 11:11:04 +00:00
|
|
|
pin_cmd.flags |= SC_PIN_CMD_NEED_PADDING;
|
|
|
|
|
2010-01-27 18:07:14 +00:00
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x24, 0x00, pin_reference);
|
2009-12-03 11:11:04 +00:00
|
|
|
apdu.lc = OBERTHUR_AUTH_MAX_LENGTH_PIN * 2;
|
|
|
|
apdu.datalen = OBERTHUR_AUTH_MAX_LENGTH_PIN * 2;
|
|
|
|
apdu.data = ffs1;
|
|
|
|
|
|
|
|
pin_cmd.apdu = &apdu;
|
|
|
|
pin_cmd.pin_type = SC_AC_CHV;
|
|
|
|
pin_cmd.cmd = SC_PIN_CMD_CHANGE;
|
|
|
|
pin_cmd.flags |= SC_PIN_CMD_USE_PINPAD;
|
2010-01-27 18:07:14 +00:00
|
|
|
pin_cmd.pin_reference = pin_reference;
|
2009-12-03 11:11:04 +00:00
|
|
|
if (pin_cmd.pin1.min_length < 4)
|
|
|
|
pin_cmd.pin1.min_length = 4;
|
|
|
|
pin_cmd.pin1.max_length = 8;
|
|
|
|
pin_cmd.pin1.encoding = SC_PIN_ENCODING_ASCII;
|
|
|
|
pin_cmd.pin1.offset = 5 + OBERTHUR_AUTH_MAX_LENGTH_PIN;
|
|
|
|
pin_cmd.pin1.data = ffs1;
|
|
|
|
pin_cmd.pin1.len = OBERTHUR_AUTH_MAX_LENGTH_PIN;
|
|
|
|
pin_cmd.pin1.pad_length = 0;
|
|
|
|
|
|
|
|
memcpy(&pin_cmd.pin2, &pin_cmd.pin1, sizeof(pin_cmd.pin2));
|
|
|
|
pin_cmd.pin1.offset = 5;
|
|
|
|
pin_cmd.pin2.data = ffs2;
|
|
|
|
|
|
|
|
rv = iso_drv->ops->pin_cmd(card, &pin_cmd, tries_left);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "PIN CMD 'VERIFY' with pinpad failed");
|
2009-12-03 11:11:04 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, rv);
|
2009-12-03 11:11:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2014-01-19 13:11:16 +00:00
|
|
|
auth_pin_change(struct sc_card *card, unsigned int type,
|
|
|
|
struct sc_pin_cmd_data *data, int *tries_left)
|
2009-12-03 11:11:04 +00:00
|
|
|
{
|
|
|
|
struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
|
2014-02-25 08:07:09 +00:00
|
|
|
int rv = SC_ERROR_INTERNAL;
|
2009-12-03 11:11:04 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
2009-12-03 11:11:04 +00:00
|
|
|
|
|
|
|
if (data->pin1.len && data->pin2.len) {
|
|
|
|
/* Direct unblock style */
|
2009-11-13 09:45:21 +00:00
|
|
|
data->flags |= SC_PIN_CMD_NEED_PADDING;
|
2009-12-03 12:51:12 +00:00
|
|
|
data->flags &= ~SC_PIN_CMD_USE_PINPAD;
|
2009-11-13 09:45:21 +00:00
|
|
|
data->apdu = NULL;
|
|
|
|
|
2010-01-27 18:07:14 +00:00
|
|
|
data->pin_reference &= ~OBERTHUR_PIN_LOCAL;
|
|
|
|
|
2009-11-23 13:40:05 +00:00
|
|
|
auth_init_pin_info(card, &data->pin1, OBERTHUR_AUTH_TYPE_PIN);
|
|
|
|
auth_init_pin_info(card, &data->pin2, OBERTHUR_AUTH_TYPE_PIN);
|
2009-11-13 09:45:21 +00:00
|
|
|
|
|
|
|
rv = iso_drv->ops->pin_cmd(card, data, tries_left);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "CMD 'PIN CHANGE' failed");
|
2009-12-03 11:11:04 +00:00
|
|
|
}
|
|
|
|
else if (!data->pin1.len && !data->pin2.len) {
|
|
|
|
/* Oberthur unblock style with PIN pad. */
|
|
|
|
rv = auth_pin_change_pinpad(card, data, tries_left);
|
2018-04-14 17:38:34 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "'PIN CHANGE' failed: SOPIN verify with pinpad failed");
|
2009-12-03 11:11:04 +00:00
|
|
|
}
|
|
|
|
else {
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, "'PIN CHANGE' failed");
|
2009-12-03 11:11:04 +00:00
|
|
|
}
|
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, rv);
|
2009-12-03 11:11:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2014-01-19 13:11:16 +00:00
|
|
|
auth_pin_reset_oberthur_style(struct sc_card *card, unsigned int type,
|
|
|
|
struct sc_pin_cmd_data *data, int *tries_left)
|
2009-12-03 11:11:04 +00:00
|
|
|
{
|
|
|
|
struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
|
|
|
|
struct sc_pin_cmd_data pin_cmd;
|
|
|
|
struct sc_path tmp_path;
|
|
|
|
struct sc_file *tmp_file = NULL;
|
|
|
|
struct sc_apdu apdu;
|
|
|
|
unsigned char puk[OBERTHUR_AUTH_MAX_LENGTH_PUK];
|
2014-01-19 13:11:16 +00:00
|
|
|
unsigned char ffs1[0x100];
|
2010-01-27 18:07:14 +00:00
|
|
|
int rv, rvv, local_pin_reference;
|
2009-12-03 11:11:04 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
2009-12-03 11:11:04 +00:00
|
|
|
|
2010-01-27 18:07:14 +00:00
|
|
|
local_pin_reference = data->pin_reference & ~OBERTHUR_PIN_LOCAL;
|
|
|
|
|
2009-12-03 11:11:04 +00:00
|
|
|
if (data->pin_reference != OBERTHUR_PIN_REFERENCE_USER)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, "Oberthur style 'PIN RESET' failed: invalid PIN reference");
|
2009-12-03 11:11:04 +00:00
|
|
|
|
|
|
|
memset(&pin_cmd, 0, sizeof(pin_cmd));
|
2014-01-19 13:11:16 +00:00
|
|
|
memset(&tmp_path, 0, sizeof(struct sc_path));
|
2011-01-18 09:48:26 +00:00
|
|
|
|
2009-12-03 11:11:04 +00:00
|
|
|
pin_cmd.pin_type = SC_AC_CHV;
|
2015-10-14 21:10:48 +00:00
|
|
|
pin_cmd.cmd = SC_PIN_CMD_VERIFY;
|
2010-01-27 18:07:14 +00:00
|
|
|
pin_cmd.pin_reference = OBERTHUR_PIN_REFERENCE_PUK;
|
2009-12-03 11:11:04 +00:00
|
|
|
memcpy(&pin_cmd.pin1, &data->pin1, sizeof(pin_cmd.pin1));
|
|
|
|
|
|
|
|
rv = auth_pin_verify(card, SC_AC_CHV, &pin_cmd, tries_left);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "Oberthur style 'PIN RESET' failed: SOPIN verify error");
|
2009-12-03 11:11:04 +00:00
|
|
|
|
2015-10-14 21:10:48 +00:00
|
|
|
sc_format_path("2000", &tmp_path);
|
2009-12-03 11:11:04 +00:00
|
|
|
tmp_path.type = SC_PATH_TYPE_FILE_ID;
|
2015-10-14 21:10:48 +00:00
|
|
|
rv = iso_ops->select_file(card, &tmp_path, &tmp_file);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "select PUK file");
|
2009-12-03 11:11:04 +00:00
|
|
|
|
2015-10-14 21:10:48 +00:00
|
|
|
if (!tmp_file || tmp_file->size < OBERTHUR_AUTH_MAX_LENGTH_PUK)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, SC_ERROR_FILE_TOO_SMALL, "Oberthur style 'PIN RESET' failed");
|
2009-12-03 11:11:04 +00:00
|
|
|
|
|
|
|
rv = iso_ops->read_binary(card, 0, puk, OBERTHUR_AUTH_MAX_LENGTH_PUK, 0);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "read PUK file error");
|
2009-12-03 11:11:04 +00:00
|
|
|
if (rv != OBERTHUR_AUTH_MAX_LENGTH_PUK)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, "Oberthur style 'PIN RESET' failed");
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2011-03-23 15:51:29 +00:00
|
|
|
memset(ffs1, 0xFF, sizeof(ffs1));
|
|
|
|
memcpy(ffs1, puk, rv);
|
2009-12-03 11:11:04 +00:00
|
|
|
|
|
|
|
memset(&pin_cmd, 0, sizeof(pin_cmd));
|
|
|
|
pin_cmd.pin_type = SC_AC_CHV;
|
|
|
|
pin_cmd.cmd = SC_PIN_CMD_UNBLOCK;
|
2010-01-27 18:07:14 +00:00
|
|
|
pin_cmd.pin_reference = local_pin_reference;
|
2009-12-03 11:11:04 +00:00
|
|
|
auth_init_pin_info(card, &pin_cmd.pin1, OBERTHUR_AUTH_TYPE_PUK);
|
2011-03-23 15:51:29 +00:00
|
|
|
pin_cmd.pin1.data = ffs1;
|
2009-12-03 11:11:04 +00:00
|
|
|
pin_cmd.pin1.len = OBERTHUR_AUTH_MAX_LENGTH_PUK;
|
|
|
|
|
|
|
|
if (data->pin2.data) {
|
|
|
|
memcpy(&pin_cmd.pin2, &data->pin2, sizeof(pin_cmd.pin2));
|
|
|
|
rv = auth_pin_reset(card, SC_AC_CHV, &pin_cmd, tries_left);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, rv);
|
2009-12-03 11:11:04 +00:00
|
|
|
}
|
|
|
|
|
2015-10-14 21:10:48 +00:00
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x2C, 0x00, local_pin_reference);
|
2009-12-03 11:11:04 +00:00
|
|
|
apdu.lc = OBERTHUR_AUTH_MAX_LENGTH_PIN + OBERTHUR_AUTH_MAX_LENGTH_PUK;
|
|
|
|
apdu.datalen = OBERTHUR_AUTH_MAX_LENGTH_PIN + OBERTHUR_AUTH_MAX_LENGTH_PUK;
|
2011-03-23 15:51:29 +00:00
|
|
|
apdu.data = ffs1;
|
2009-12-03 11:11:04 +00:00
|
|
|
|
|
|
|
pin_cmd.apdu = &apdu;
|
|
|
|
pin_cmd.flags |= SC_PIN_CMD_USE_PINPAD | SC_PIN_CMD_IMPLICIT_CHANGE;
|
|
|
|
|
|
|
|
pin_cmd.pin1.min_length = 4;
|
|
|
|
pin_cmd.pin1.max_length = 8;
|
2015-10-14 21:10:48 +00:00
|
|
|
pin_cmd.pin1.encoding = SC_PIN_ENCODING_ASCII;
|
|
|
|
pin_cmd.pin1.offset = 5;
|
2009-12-03 11:11:04 +00:00
|
|
|
|
2011-03-23 15:51:29 +00:00
|
|
|
pin_cmd.pin2.data = &ffs1[OBERTHUR_AUTH_MAX_LENGTH_PUK];
|
2009-12-03 11:11:04 +00:00
|
|
|
pin_cmd.pin2.len = OBERTHUR_AUTH_MAX_LENGTH_PIN;
|
|
|
|
pin_cmd.pin2.offset = 5 + OBERTHUR_AUTH_MAX_LENGTH_PUK;
|
|
|
|
pin_cmd.pin2.min_length = 4;
|
|
|
|
pin_cmd.pin2.max_length = 8;
|
2015-10-14 21:10:48 +00:00
|
|
|
pin_cmd.pin2.encoding = SC_PIN_ENCODING_ASCII;
|
2009-12-03 11:11:04 +00:00
|
|
|
|
2015-10-14 21:10:48 +00:00
|
|
|
rvv = iso_drv->ops->pin_cmd(card, &pin_cmd, tries_left);
|
2009-12-03 11:11:04 +00:00
|
|
|
if (rvv)
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx,
|
2015-10-14 21:10:48 +00:00
|
|
|
"%s: PIN CMD 'VERIFY' with pinpad failed",
|
|
|
|
sc_strerror(rvv));
|
2009-12-03 11:11:04 +00:00
|
|
|
|
|
|
|
if (auth_current_ef)
|
2015-10-14 21:10:48 +00:00
|
|
|
rv = iso_ops->select_file(card, &auth_current_ef->path, &auth_current_ef);
|
2009-12-03 11:11:04 +00:00
|
|
|
|
|
|
|
if (rv > 0)
|
|
|
|
rv = 0;
|
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, rv ? rv: rvv);
|
2009-12-03 11:11:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2014-01-19 13:11:16 +00:00
|
|
|
auth_pin_reset(struct sc_card *card, unsigned int type,
|
|
|
|
struct sc_pin_cmd_data *data, int *tries_left)
|
2009-12-03 11:11:04 +00:00
|
|
|
{
|
|
|
|
int rv;
|
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
2009-12-03 11:11:04 +00:00
|
|
|
|
2010-01-27 18:07:14 +00:00
|
|
|
/* Oberthur unblock style: PUK value is a SOPIN */
|
|
|
|
rv = auth_pin_reset_oberthur_style(card, SC_AC_CHV, data, tries_left);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "Oberthur style 'PIN RESET' failed");
|
2009-12-03 11:11:04 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, rv);
|
2009-12-03 11:11:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
static int
|
2009-12-03 11:11:04 +00:00
|
|
|
auth_pin_cmd(struct sc_card *card, struct sc_pin_cmd_data *data, int *tries_left)
|
|
|
|
{
|
2014-02-25 08:07:09 +00:00
|
|
|
int rv = SC_ERROR_INTERNAL;
|
2009-12-03 11:11:04 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
2009-12-03 11:11:04 +00:00
|
|
|
if (data->pin_type != SC_AC_CHV)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, "auth_pin_cmd() unsupported PIN type");
|
2009-12-03 11:11:04 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "PIN CMD:%i; reference:%i; pin1:%p/%i, pin2:%p/%i", data->cmd,
|
2014-01-19 13:11:16 +00:00
|
|
|
data->pin_reference, data->pin1.data, data->pin1.len,
|
2009-12-03 11:11:04 +00:00
|
|
|
data->pin2.data, data->pin2.len);
|
|
|
|
switch (data->cmd) {
|
|
|
|
case SC_PIN_CMD_VERIFY:
|
|
|
|
rv = auth_pin_verify(card, SC_AC_CHV, data, tries_left);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "CMD 'PIN VERIFY' failed");
|
2009-12-03 11:11:04 +00:00
|
|
|
break;
|
|
|
|
case SC_PIN_CMD_CHANGE:
|
|
|
|
rv = auth_pin_change(card, SC_AC_CHV, data, tries_left);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "CMD 'PIN VERIFY' failed");
|
2009-12-03 11:11:04 +00:00
|
|
|
break;
|
|
|
|
case SC_PIN_CMD_UNBLOCK:
|
|
|
|
rv = auth_pin_reset(card, SC_AC_CHV, data, tries_left);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "CMD 'PIN VERIFY' failed");
|
2009-11-13 09:45:21 +00:00
|
|
|
break;
|
|
|
|
default:
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, "Unsupported PIN operation");
|
2009-11-13 09:45:21 +00:00
|
|
|
}
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, rv);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
static int
|
|
|
|
auth_create_reference_data (struct sc_card *card,
|
2004-06-16 20:59:59 +00:00
|
|
|
struct sc_cardctl_oberthur_createpin_info *args)
|
|
|
|
{
|
2009-11-13 09:45:21 +00:00
|
|
|
struct sc_apdu apdu;
|
2004-06-16 20:59:59 +00:00
|
|
|
struct sc_pin_cmd_pin pin_info, puk_info;
|
2009-11-13 09:45:21 +00:00
|
|
|
int rv, len;
|
|
|
|
unsigned char sbuf[SC_MAX_APDU_BUFFER_SIZE];
|
2007-01-02 10:06:02 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
|
|
|
sc_log(card->ctx, "PIN reference %i", args->ref);
|
2009-11-13 09:45:21 +00:00
|
|
|
|
|
|
|
if (args->type != SC_AC_CHV)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, "Unsupported PIN type");
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
if (args->pin_tries < 1 || !args->pin || !args->pin_len)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, "Invalid PIN options");
|
2009-11-13 09:45:21 +00:00
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
if (args->ref != OBERTHUR_PIN_REFERENCE_USER && args->ref != OBERTHUR_PIN_REFERENCE_PUK)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_PIN_REFERENCE, "Invalid PIN reference");
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2009-11-23 13:40:05 +00:00
|
|
|
auth_init_pin_info(card, &puk_info, OBERTHUR_AUTH_TYPE_PUK);
|
|
|
|
auth_init_pin_info(card, &pin_info, OBERTHUR_AUTH_TYPE_PIN);
|
2004-06-16 20:59:59 +00:00
|
|
|
|
|
|
|
if (args->puk && args->puk_len && (args->puk_len%puk_info.pad_length))
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, "Invalid PUK options");
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
len = 0;
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "len %i", len);
|
2004-06-16 20:59:59 +00:00
|
|
|
sbuf[len++] = args->pin_tries;
|
|
|
|
sbuf[len++] = pin_info.pad_length;
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "len %i", len);
|
2004-06-16 20:59:59 +00:00
|
|
|
memset(sbuf + len, pin_info.pad_char, pin_info.pad_length);
|
|
|
|
memcpy(sbuf + len, args->pin, args->pin_len);
|
|
|
|
len += pin_info.pad_length;
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "len %i", len);
|
2004-06-16 20:59:59 +00:00
|
|
|
|
|
|
|
if (args->puk && args->puk_len) {
|
|
|
|
sbuf[len++] = args->puk_tries;
|
|
|
|
sbuf[len++] = args->puk_len / puk_info.pad_length;
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "len %i", len);
|
2004-06-16 20:59:59 +00:00
|
|
|
memcpy(sbuf + len, args->puk, args->puk_len);
|
|
|
|
len += args->puk_len;
|
|
|
|
}
|
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "len %i", len);
|
2010-01-27 18:07:14 +00:00
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x24, 1, args->ref & ~OBERTHUR_PIN_LOCAL);
|
2004-06-16 20:59:59 +00:00
|
|
|
apdu.data = sbuf;
|
|
|
|
apdu.datalen = len;
|
|
|
|
apdu.lc = len;
|
|
|
|
|
|
|
|
rv = sc_transmit_apdu(card, &apdu);
|
2005-09-17 10:44:45 +00:00
|
|
|
sc_mem_clear(sbuf, sizeof(sbuf));
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "APDU transmit failed");
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
rv = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2007-01-02 10:06:02 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, rv);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
static int
|
2009-11-13 09:45:21 +00:00
|
|
|
auth_logout(struct sc_card *card)
|
2004-06-16 20:59:59 +00:00
|
|
|
{
|
2009-11-13 09:45:21 +00:00
|
|
|
struct sc_apdu apdu;
|
2007-01-02 10:06:02 +00:00
|
|
|
int ii, rv = 0, pin_ref;
|
|
|
|
int reset_flag = 0x20;
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
for (ii=0; ii < 4; ii++) {
|
|
|
|
rv = auth_get_pin_reference (card, SC_AC_CHV, ii+1, SC_PIN_CMD_UNBLOCK, &pin_ref);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "Cannot get PIN reference");
|
2007-01-02 10:06:02 +00:00
|
|
|
|
2009-11-13 09:45:21 +00:00
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x2E, 0x00, 0x00);
|
|
|
|
apdu.cla = 0x80;
|
2007-01-02 10:06:02 +00:00
|
|
|
apdu.p2 = pin_ref | reset_flag;
|
|
|
|
rv = sc_transmit_apdu(card, &apdu);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "APDU transmit failed");
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
}
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, rv);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
|
2009-11-13 09:45:21 +00:00
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
static int
|
2009-11-13 09:45:21 +00:00
|
|
|
write_publickey (struct sc_card *card, unsigned int offset,
|
|
|
|
const unsigned char *buf, size_t count)
|
2004-06-16 20:59:59 +00:00
|
|
|
{
|
2009-11-13 09:45:21 +00:00
|
|
|
struct auth_update_component_info args;
|
2004-06-16 20:59:59 +00:00
|
|
|
struct sc_pkcs15_pubkey_rsa key;
|
2009-11-13 09:45:21 +00:00
|
|
|
int ii, rv;
|
2004-12-21 22:38:37 +00:00
|
|
|
size_t len = 0, der_size = 0;
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2017-11-13 14:11:58 +00:00
|
|
|
sc_log_hex(card->ctx, "write_publickey", buf, count);
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2015-02-04 08:24:50 +00:00
|
|
|
if (1+offset > sizeof(rsa_der))
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, "Invalid offset value");
|
2004-06-16 20:59:59 +00:00
|
|
|
|
|
|
|
len = offset+count > sizeof(rsa_der) ? sizeof(rsa_der) - offset : count;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
memcpy(rsa_der + offset, buf, len);
|
|
|
|
rsa_der_len = offset + len;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
if (rsa_der[0]==0x30) {
|
2014-01-19 13:11:16 +00:00
|
|
|
if (rsa_der[1] & 0x80)
|
2004-06-16 20:59:59 +00:00
|
|
|
for (ii=0; ii < (rsa_der[1]&0x0F); ii++)
|
|
|
|
der_size = der_size*0x100 + rsa_der[2+ii];
|
|
|
|
else
|
|
|
|
der_size = rsa_der[1];
|
|
|
|
}
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2017-03-14 19:02:30 +00:00
|
|
|
sc_log(card->ctx, "der_size %"SC_FORMAT_LEN_SIZE_T"u", der_size);
|
2004-06-16 20:59:59 +00:00
|
|
|
if (offset + len < der_size + 2)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, len);
|
2004-06-16 20:59:59 +00:00
|
|
|
|
|
|
|
rv = sc_pkcs15_decode_pubkey_rsa(card->ctx, &key, rsa_der, rsa_der_len);
|
|
|
|
rsa_der_len = 0;
|
|
|
|
memset(rsa_der, 0, sizeof(rsa_der));
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "cannot decode public key");
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
memset(&args, 0, sizeof(args));
|
|
|
|
args.type = SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC;
|
|
|
|
args.component = 1;
|
|
|
|
args.data = key.modulus.data;
|
|
|
|
args.len = key.modulus.len;
|
|
|
|
rv = auth_update_component(card, &args);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "Update component failed");
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
memset(&args, 0, sizeof(args));
|
|
|
|
args.type = SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC;
|
|
|
|
args.component = 2;
|
|
|
|
args.data = key.exponent.data;
|
|
|
|
args.len = key.exponent.len;
|
|
|
|
rv = auth_update_component(card, &args);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "Update component failed");
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, len);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
|
|
|
|
static int
|
2009-11-13 09:45:21 +00:00
|
|
|
auth_update_binary(struct sc_card *card, unsigned int offset,
|
|
|
|
const unsigned char *buf, size_t count, unsigned long flags)
|
2004-06-16 20:59:59 +00:00
|
|
|
{
|
|
|
|
int rv = 0;
|
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
2017-03-14 19:02:30 +00:00
|
|
|
sc_log(card->ctx, "offset %i; count %"SC_FORMAT_LEN_SIZE_T"u", offset,
|
|
|
|
count);
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "last selected : magic %X; ef %X",
|
2007-01-02 10:06:02 +00:00
|
|
|
auth_current_ef->magic, auth_current_ef->ef_structure);
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
if (offset & ~0x7FFF)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, "Invalid file offset");
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
if (auth_current_ef->magic==SC_FILE_MAGIC &&
|
|
|
|
auth_current_ef->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC) {
|
2004-06-16 20:59:59 +00:00
|
|
|
rv = write_publickey(card, offset, buf, count);
|
|
|
|
}
|
2014-01-19 13:11:16 +00:00
|
|
|
else if (auth_current_ef->magic==SC_FILE_MAGIC &&
|
2007-01-02 10:06:02 +00:00
|
|
|
auth_current_ef->ef_structure == SC_CARDCTL_OBERTHUR_KEY_DES) {
|
|
|
|
struct auth_update_component_info args;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
memset(&args, 0, sizeof(args));
|
2004-12-21 22:38:37 +00:00
|
|
|
args.type = SC_CARDCTL_OBERTHUR_KEY_DES;
|
2009-11-13 09:45:21 +00:00
|
|
|
args.data = (unsigned char *)buf;
|
2004-06-16 20:59:59 +00:00
|
|
|
args.len = count;
|
|
|
|
rv = auth_update_component(card, &args);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
rv = iso_ops->update_binary(card, offset, buf, count, 0);
|
|
|
|
}
|
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, rv);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2009-11-13 09:45:21 +00:00
|
|
|
auth_read_binary(struct sc_card *card, unsigned int offset,
|
|
|
|
unsigned char *buf, size_t count, unsigned long flags)
|
2004-06-16 20:59:59 +00:00
|
|
|
{
|
|
|
|
int rv;
|
2017-04-20 19:08:49 +00:00
|
|
|
struct sc_pkcs15_bignum bn[2];
|
|
|
|
unsigned char *out = NULL;
|
|
|
|
bn[0].data = NULL;
|
|
|
|
bn[1].data = NULL;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
2018-05-25 12:54:47 +00:00
|
|
|
|
|
|
|
if (!auth_current_ef)
|
|
|
|
LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, "Invalid auth_current_ef");
|
|
|
|
|
2017-03-14 19:02:30 +00:00
|
|
|
sc_log(card->ctx,
|
|
|
|
"offset %i; size %"SC_FORMAT_LEN_SIZE_T"u; flags 0x%lX",
|
|
|
|
offset, count, flags);
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx,"last selected : magic %X; ef %X",
|
2007-01-02 10:06:02 +00:00
|
|
|
auth_current_ef->magic, auth_current_ef->ef_structure);
|
|
|
|
|
|
|
|
if (offset & ~0x7FFF)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, "Invalid file offset");
|
2007-01-02 10:06:02 +00:00
|
|
|
|
|
|
|
if (auth_current_ef->magic==SC_FILE_MAGIC &&
|
2016-04-28 08:52:25 +00:00
|
|
|
auth_current_ef->ef_structure == SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC) {
|
2004-06-16 20:59:59 +00:00
|
|
|
int jj;
|
2017-04-20 19:08:49 +00:00
|
|
|
unsigned char resp[256];
|
2004-06-16 20:59:59 +00:00
|
|
|
size_t resp_len, out_len;
|
|
|
|
struct sc_pkcs15_pubkey_rsa key;
|
|
|
|
|
|
|
|
resp_len = sizeof(resp);
|
2014-01-19 13:11:16 +00:00
|
|
|
rv = auth_read_component(card, SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC,
|
2007-01-02 10:06:02 +00:00
|
|
|
2, resp, resp_len);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "read component failed");
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
for (jj=0; jj<rv && *(resp+jj)==0; jj++)
|
|
|
|
;
|
|
|
|
|
Do not cast the return value of malloc(3) and calloc(3)
From http://en.wikipedia.org/wiki/Malloc#Casting_and_type_safety
" Casting and type safety
malloc returns a void pointer (void *), which indicates that it is a
pointer to a region of unknown data type. One may "cast" (see type
conversion) this pointer to a specific type, as in
int *ptr = (int*)malloc(10 * sizeof (int));
When using C, this is considered bad practice; it is redundant under the
C standard. Moreover, putting in a cast may mask failure to include the
header stdlib.h, in which the prototype for malloc is found. In the
absence of a prototype for malloc, the C compiler will assume that
malloc returns an int, and will issue a warning in a context such as the
above, provided the error is not masked by a cast. On certain
architectures and data models (such as LP64 on 64 bit systems, where
long and pointers are 64 bit and int is 32 bit), this error can actually
result in undefined behavior, as the implicitly declared malloc returns
a 32 bit value whereas the actually defined function returns a 64 bit
value. Depending on calling conventions and memory layout, this may
result in stack smashing.
The returned pointer need not be explicitly cast to a more specific
pointer type, since ANSI C defines an implicit conversion between the
void pointer type and other pointers to objects. An explicit cast of
malloc's return value is sometimes performed because malloc originally
returned a char *, but this cast is unnecessary in standard C
code.[4][5] Omitting the cast, however, creates an incompatibility with
C++, which does require it.
The lack of a specific pointer type returned from malloc is type-unsafe
behaviour: malloc allocates based on byte count but not on type. This
distinguishes it from the C++ new operator that returns a pointer whose
type relies on the operand. (see C Type Safety). "
See also
http://www.opensc-project.org/pipermail/opensc-devel/2010-August/014586.html
git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@4636 c6295689-39f2-0310-b995-f0e70906c6a9
2010-08-18 15:08:51 +00:00
|
|
|
bn[0].data = calloc(1, rv - jj);
|
2017-04-20 19:08:49 +00:00
|
|
|
if (!bn[0].data) {
|
|
|
|
rv = SC_ERROR_OUT_OF_MEMORY;
|
|
|
|
goto err;
|
|
|
|
}
|
2004-06-16 20:59:59 +00:00
|
|
|
bn[0].len = rv - jj;
|
|
|
|
memcpy(bn[0].data, resp + jj, rv - jj);
|
2014-01-19 13:11:16 +00:00
|
|
|
|
|
|
|
rv = auth_read_component(card, SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC,
|
2007-01-02 10:06:02 +00:00
|
|
|
1, resp, resp_len);
|
2017-04-20 19:08:49 +00:00
|
|
|
LOG_TEST_GOTO_ERR(card->ctx, rv, "Cannot read RSA public key component");
|
2014-01-19 13:11:16 +00:00
|
|
|
|
Do not cast the return value of malloc(3) and calloc(3)
From http://en.wikipedia.org/wiki/Malloc#Casting_and_type_safety
" Casting and type safety
malloc returns a void pointer (void *), which indicates that it is a
pointer to a region of unknown data type. One may "cast" (see type
conversion) this pointer to a specific type, as in
int *ptr = (int*)malloc(10 * sizeof (int));
When using C, this is considered bad practice; it is redundant under the
C standard. Moreover, putting in a cast may mask failure to include the
header stdlib.h, in which the prototype for malloc is found. In the
absence of a prototype for malloc, the C compiler will assume that
malloc returns an int, and will issue a warning in a context such as the
above, provided the error is not masked by a cast. On certain
architectures and data models (such as LP64 on 64 bit systems, where
long and pointers are 64 bit and int is 32 bit), this error can actually
result in undefined behavior, as the implicitly declared malloc returns
a 32 bit value whereas the actually defined function returns a 64 bit
value. Depending on calling conventions and memory layout, this may
result in stack smashing.
The returned pointer need not be explicitly cast to a more specific
pointer type, since ANSI C defines an implicit conversion between the
void pointer type and other pointers to objects. An explicit cast of
malloc's return value is sometimes performed because malloc originally
returned a char *, but this cast is unnecessary in standard C
code.[4][5] Omitting the cast, however, creates an incompatibility with
C++, which does require it.
The lack of a specific pointer type returned from malloc is type-unsafe
behaviour: malloc allocates based on byte count but not on type. This
distinguishes it from the C++ new operator that returns a pointer whose
type relies on the operand. (see C Type Safety). "
See also
http://www.opensc-project.org/pipermail/opensc-devel/2010-August/014586.html
git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@4636 c6295689-39f2-0310-b995-f0e70906c6a9
2010-08-18 15:08:51 +00:00
|
|
|
bn[1].data = calloc(1, rv);
|
2017-04-20 19:08:49 +00:00
|
|
|
if (!bn[1].data) {
|
|
|
|
rv = SC_ERROR_OUT_OF_MEMORY;
|
|
|
|
goto err;
|
|
|
|
}
|
2004-06-16 20:59:59 +00:00
|
|
|
bn[1].len = rv;
|
|
|
|
memcpy(bn[1].data, resp, rv);
|
|
|
|
|
|
|
|
key.exponent = bn[0];
|
|
|
|
key.modulus = bn[1];
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
if (sc_pkcs15_encode_pubkey_rsa(card->ctx, &key, &out, &out_len)) {
|
2017-04-20 19:08:49 +00:00
|
|
|
rv = SC_ERROR_INVALID_ASN1_OBJECT;
|
|
|
|
LOG_TEST_GOTO_ERR(card->ctx, rv, "cannot encode RSA public key");
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
rv = out_len - offset > count ? count : out_len - offset;
|
|
|
|
memcpy(buf, out + offset, rv);
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2017-11-13 14:11:58 +00:00
|
|
|
sc_log_hex(card->ctx, "write_publickey", buf, rv);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
}
|
2017-04-20 19:08:49 +00:00
|
|
|
else {
|
2014-01-19 13:11:16 +00:00
|
|
|
rv = iso_ops->read_binary(card, offset, buf, count, 0);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
|
2017-04-20 19:08:49 +00:00
|
|
|
err:
|
|
|
|
free(bn[0].data);
|
|
|
|
free(bn[1].data);
|
|
|
|
free(out);
|
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, rv);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
static int
|
|
|
|
auth_read_record(struct sc_card *card, unsigned int nr_rec,
|
2009-11-13 09:45:21 +00:00
|
|
|
unsigned char *buf, size_t count, unsigned long flags)
|
2007-01-02 10:06:02 +00:00
|
|
|
{
|
|
|
|
struct sc_apdu apdu;
|
2009-11-13 09:45:21 +00:00
|
|
|
int rv = 0;
|
|
|
|
unsigned char recvbuf[SC_MAX_APDU_BUFFER_SIZE];
|
2007-01-02 10:06:02 +00:00
|
|
|
|
2017-03-14 19:02:30 +00:00
|
|
|
sc_log(card->ctx,
|
|
|
|
"auth_read_record(): nr_rec %i; count %"SC_FORMAT_LEN_SIZE_T"u",
|
|
|
|
nr_rec, count);
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2009-11-13 09:45:21 +00:00
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xB2, nr_rec, 0);
|
|
|
|
apdu.p2 = (flags & SC_RECORD_EF_ID_MASK) << 3;
|
|
|
|
if (flags & SC_RECORD_BY_REC_NR)
|
2007-01-02 10:06:02 +00:00
|
|
|
apdu.p2 |= 0x04;
|
|
|
|
|
|
|
|
apdu.le = count;
|
|
|
|
apdu.resplen = count;
|
|
|
|
apdu.resp = recvbuf;
|
|
|
|
|
|
|
|
rv = sc_transmit_apdu(card, &apdu);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "APDU transmit failed");
|
2007-01-02 10:06:02 +00:00
|
|
|
if (apdu.resplen == 0)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2));
|
2007-01-02 10:06:02 +00:00
|
|
|
memcpy(buf, recvbuf, apdu.resplen);
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
rv = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "Card returned error");
|
2007-01-02 10:06:02 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, apdu.resplen);
|
2007-01-02 10:06:02 +00:00
|
|
|
}
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2007-01-02 10:06:02 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
static int
|
2009-11-13 09:45:21 +00:00
|
|
|
auth_delete_record(struct sc_card *card, unsigned int nr_rec)
|
2004-06-16 20:59:59 +00:00
|
|
|
{
|
2009-11-13 09:45:21 +00:00
|
|
|
struct sc_apdu apdu;
|
2004-06-16 20:59:59 +00:00
|
|
|
int rv = 0;
|
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
|
|
|
sc_log(card->ctx, "auth_delete_record(): nr_rec %i", nr_rec);
|
2007-01-02 10:06:02 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x32, nr_rec, 0x04);
|
|
|
|
apdu.cla = 0x80;
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
rv = sc_transmit_apdu(card, &apdu);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_TEST_RET(card->ctx, rv, "APDU transmit failed");
|
2004-06-16 20:59:59 +00:00
|
|
|
|
|
|
|
rv = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, rv);
|
2004-06-16 20:59:59 +00:00
|
|
|
}
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2009-11-13 09:45:21 +00:00
|
|
|
|
2005-08-22 09:17:44 +00:00
|
|
|
static int
|
2009-11-13 09:45:21 +00:00
|
|
|
auth_get_serialnr(struct sc_card *card, struct sc_serial_number *serial)
|
2005-08-22 09:17:44 +00:00
|
|
|
{
|
2011-02-05 21:50:48 +00:00
|
|
|
if (!serial)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
|
2005-08-22 09:17:44 +00:00
|
|
|
|
|
|
|
if (card->serialnr.len==0)
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2005-08-22 09:17:44 +00:00
|
|
|
memcpy(serial, &card->serialnr, sizeof(*serial));
|
2007-01-02 10:06:02 +00:00
|
|
|
|
2016-04-28 09:01:54 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
|
2007-01-02 10:06:02 +00:00
|
|
|
}
|
|
|
|
|
2009-11-13 09:45:21 +00:00
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
static const struct sc_card_error
|
2010-01-13 16:39:37 +00:00
|
|
|
auth_warnings[] = {
|
2014-01-19 13:11:16 +00:00
|
|
|
{ 0x6282, SC_SUCCESS,
|
2010-01-13 16:39:37 +00:00
|
|
|
"ignore warning 'End of file or record reached before reading Ne bytes'" },
|
|
|
|
{0, 0, NULL},
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
static int
|
2010-01-13 16:39:37 +00:00
|
|
|
auth_check_sw(struct sc_card *card, unsigned int sw1, unsigned int sw2)
|
|
|
|
{
|
|
|
|
int ii;
|
|
|
|
|
|
|
|
for (ii=0; auth_warnings[ii].SWs; ii++) {
|
|
|
|
if (auth_warnings[ii].SWs == ((sw1 << 8) | sw2)) {
|
2016-04-28 09:01:54 +00:00
|
|
|
sc_log(card->ctx, "%s", auth_warnings[ii].errorstr);
|
2010-01-13 16:39:37 +00:00
|
|
|
return auth_warnings[ii].errorno;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return iso_ops->check_sw(card, sw1, sw2);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
static struct sc_card_driver *
|
2004-06-16 20:59:59 +00:00
|
|
|
sc_get_driver(void)
|
|
|
|
{
|
|
|
|
if (iso_ops == NULL)
|
|
|
|
iso_ops = sc_get_iso7816_driver()->ops;
|
|
|
|
|
|
|
|
auth_ops = *iso_ops;
|
|
|
|
auth_ops.match_card = auth_match_card;
|
|
|
|
auth_ops.init = auth_init;
|
|
|
|
auth_ops.finish = auth_finish;
|
|
|
|
auth_ops.select_file = auth_select_file;
|
|
|
|
auth_ops.list_files = auth_list_files;
|
|
|
|
auth_ops.delete_file = auth_delete_file;
|
|
|
|
auth_ops.create_file = auth_create_file;
|
|
|
|
auth_ops.read_binary = auth_read_binary;
|
|
|
|
auth_ops.update_binary = auth_update_binary;
|
2007-01-02 10:06:02 +00:00
|
|
|
auth_ops.read_record = auth_read_record;
|
2004-06-16 20:59:59 +00:00
|
|
|
auth_ops.delete_record = auth_delete_record;
|
|
|
|
auth_ops.card_ctl = auth_card_ctl;
|
|
|
|
auth_ops.set_security_env = auth_set_security_env;
|
|
|
|
auth_ops.restore_security_env = auth_restore_security_env;
|
|
|
|
auth_ops.compute_signature = auth_compute_signature;
|
|
|
|
auth_ops.decipher = auth_decipher;
|
2007-01-02 10:06:02 +00:00
|
|
|
auth_ops.process_fci = auth_process_fci;
|
2009-11-13 09:45:21 +00:00
|
|
|
auth_ops.pin_cmd = auth_pin_cmd;
|
2004-06-16 20:59:59 +00:00
|
|
|
auth_ops.logout = auth_logout;
|
2010-01-13 16:39:37 +00:00
|
|
|
auth_ops.check_sw = auth_check_sw;
|
2004-06-16 20:59:59 +00:00
|
|
|
return &auth_drv;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-19 13:11:16 +00:00
|
|
|
struct sc_card_driver *
|
2004-06-16 20:59:59 +00:00
|
|
|
sc_get_oberthur_driver(void)
|
|
|
|
{
|
|
|
|
return sc_get_driver();
|
|
|
|
}
|
|
|
|
|
2008-03-06 16:06:59 +00:00
|
|
|
#endif /* ENABLE_OPENSSL */
|