2001-12-22 20:43:09 +00:00
|
|
|
/*
|
2002-02-26 11:27:49 +00:00
|
|
|
* card-setcos.c: Support for PKI cards by Setec
|
2001-12-22 20:43:09 +00:00
|
|
|
*
|
2006-12-19 21:32:31 +00:00
|
|
|
* Copyright (C) 2001, 2002 Juha Yrjölä <juha.yrjola@iki.fi>
|
2005-02-09 11:37:25 +00:00
|
|
|
* Copyright (C) 2005 Antti Tapaninen <aet@cc.hut.fi>
|
2005-04-04 09:30:54 +00:00
|
|
|
* Copyright (C) 2005 Zetes
|
2001-12-22 20:43:09 +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
|
|
|
|
*/
|
|
|
|
|
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
|
2010-03-04 08:14:36 +00:00
|
|
|
|
2002-03-09 17:54:16 +00:00
|
|
|
#include <stdlib.h>
|
2002-03-08 05:59:57 +00:00
|
|
|
#include <string.h>
|
2001-12-22 20:43:09 +00:00
|
|
|
|
2010-03-04 08:14:36 +00:00
|
|
|
#include "internal.h"
|
|
|
|
#include "asn1.h"
|
|
|
|
#include "cardctl.h"
|
2005-04-09 13:32:22 +00:00
|
|
|
|
2011-07-12 08:49:24 +00:00
|
|
|
#define _FINEID_BROKEN_SELECT_FLAG 1
|
|
|
|
|
2018-08-22 15:01:51 +00:00
|
|
|
static const struct sc_atr_table setcos_atrs[] = {
|
2005-02-09 11:37:25 +00:00
|
|
|
/* some Nokia branded SC */
|
2005-09-04 09:23:28 +00:00
|
|
|
{ "3B:1F:11:00:67:80:42:46:49:53:45:10:52:66:FF:81:90:00", NULL, NULL, SC_CARD_TYPE_SETCOS_GENERIC, 0, NULL },
|
2005-02-06 19:40:40 +00:00
|
|
|
/* RSA SecurID 3100 */
|
2005-09-04 09:23:28 +00:00
|
|
|
{ "3B:9F:94:40:1E:00:67:16:43:46:49:53:45:10:52:66:FF:81:90:00", NULL, NULL, SC_CARD_TYPE_SETCOS_PKI, 0, NULL },
|
2005-02-09 11:37:25 +00:00
|
|
|
|
|
|
|
/* FINEID 1016 (SetCOS 4.3.1B3/PKCS#15, VRK) */
|
2005-09-04 09:23:28 +00:00
|
|
|
{ "3b:9f:94:40:1e:00:67:00:43:46:49:53:45:10:52:66:ff:81:90:00", "ff:ff:ff:ff:ff:ff:ff:00:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff", NULL, SC_CARD_TYPE_SETCOS_FINEID, SC_CARD_FLAG_RNG, NULL },
|
2005-02-09 14:05:55 +00:00
|
|
|
/* FINEID 2032 (EIDApplet/7816-15, VRK test) */
|
2005-09-04 09:23:28 +00:00
|
|
|
{ "3b:6b:00:ff:80:62:00:a2:56:46:69:6e:45:49:44", "ff:ff:00:ff:ff:ff:00:ff:ff:ff:ff:ff:ff:ff:ff", NULL, SC_CARD_TYPE_SETCOS_FINEID_V2, 0, NULL },
|
2005-02-24 11:11:12 +00:00
|
|
|
/* FINEID 2132 (EIDApplet/7816-15, 3rdparty test) */
|
2005-09-04 09:23:28 +00:00
|
|
|
{ "3b:64:00:ff:80:62:00:a2", "ff:ff:00:ff:ff:ff:00:ff", NULL, SC_CARD_TYPE_SETCOS_FINEID_V2, 0, NULL },
|
2005-02-09 11:37:25 +00:00
|
|
|
/* FINEID 2064 (EIDApplet/7816-15, VRK) */
|
2005-09-04 09:23:28 +00:00
|
|
|
{ "3b:7b:00:00:00:80:62:00:51:56:46:69:6e:45:49:44", "ff:ff:00:ff:ff:ff:ff:f0:ff:ff:ff:ff:ff:ff:ff:ff", NULL, SC_CARD_TYPE_SETCOS_FINEID_V2, 0, NULL },
|
2005-02-24 11:11:12 +00:00
|
|
|
/* FINEID 2164 (EIDApplet/7816-15, 3rdparty) */
|
2005-09-04 09:23:28 +00:00
|
|
|
{ "3b:64:00:00:80:62:00:51", "ff:ff:ff:ff:ff:ff:f0:ff", NULL, SC_CARD_TYPE_SETCOS_FINEID_V2, 0, NULL },
|
2005-02-09 11:37:25 +00:00
|
|
|
/* FINEID 2264 (EIDApplet/7816-15, OPK/EMV/AVANT) */
|
2005-09-04 09:23:28 +00:00
|
|
|
{ "3b:6e:00:00:00:62:00:00:57:41:56:41:4e:54:10:81:90:00", NULL, NULL, SC_CARD_TYPE_SETCOS_FINEID_V2, 0, NULL },
|
|
|
|
{ "3b:7b:94:00:00:80:62:11:51:56:46:69:6e:45:49:44", NULL, NULL, SC_CARD_TYPE_SETCOS_FINEID_V2, 0, NULL },
|
2011-06-15 11:10:37 +00:00
|
|
|
/* FINEID cards 1.3.2011 with Samsung chips (round connector) that supports 2048 bit keys. */
|
|
|
|
{ "3b:7b:94:00:00:80:62:12:51:56:46:69:6e:45:49:44", NULL, NULL, SC_CARD_TYPE_SETCOS_FINEID_V2_2048, 0, NULL },
|
2011-07-12 08:49:24 +00:00
|
|
|
/* FINEID card for organisations, chip unknown. */
|
|
|
|
{ "3b:7b:18:00:00:80:62:01:54:56:46:69:6e:45:49:44", NULL, NULL, SC_CARD_TYPE_SETCOS_FINEID_V2, _FINEID_BROKEN_SELECT_FLAG, NULL },
|
2006-03-09 20:35:19 +00:00
|
|
|
/* Swedish NIDEL card */
|
|
|
|
{ "3b:9f:94:80:1f:c3:00:68:10:44:05:01:46:49:53:45:31:c8:07:90:00:18", NULL, NULL, SC_CARD_TYPE_SETCOS_NIDEL, 0, NULL },
|
2005-04-04 09:30:54 +00:00
|
|
|
/* Setcos 4.4.1 */
|
2005-09-04 09:23:28 +00:00
|
|
|
{ "3b:9f:94:80:1f:c3:00:68:11:44:05:01:46:49:53:45:31:c8:00:00:00:00", "ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:00:00:00:00", NULL, SC_CARD_TYPE_SETCOS_44, 0, NULL },
|
|
|
|
{ NULL, NULL, NULL, 0, 0, NULL }
|
2002-03-08 05:59:57 +00:00
|
|
|
};
|
|
|
|
|
2006-12-08 14:56:09 +00:00
|
|
|
#define SETCOS_IS_EID_APPLET(card) ((card)->type == SC_CARD_TYPE_SETCOS_EID_V2_0 || (card)->type == SC_CARD_TYPE_SETCOS_EID_V2_1)
|
|
|
|
|
2005-04-04 09:30:54 +00:00
|
|
|
/* Setcos 4.4 Life Cycle Status Integer */
|
|
|
|
#define SETEC_LCSI_CREATE 0x01
|
|
|
|
#define SETEC_LCSI_INIT 0x03
|
|
|
|
#define SETEC_LCSI_ACTIVATED 0x07
|
|
|
|
#define SETEC_LCSI_DEACTIVATE 0x06
|
|
|
|
#define SETEC_LCSI_TEMINATE 0x0F /* MF only */
|
|
|
|
|
2002-02-26 11:27:49 +00:00
|
|
|
static struct sc_card_operations setcos_ops;
|
2003-02-20 12:51:07 +00:00
|
|
|
static struct sc_card_driver setcos_drv = {
|
2005-02-09 14:47:46 +00:00
|
|
|
"Setec cards",
|
2002-02-26 11:27:49 +00:00
|
|
|
"setcos",
|
2005-09-04 09:23:28 +00:00
|
|
|
&setcos_ops,
|
|
|
|
NULL, 0, NULL
|
2001-12-22 20:43:09 +00:00
|
|
|
};
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
static int match_hist_bytes(sc_card_t *card, const char *str, size_t len)
|
2005-02-09 11:37:25 +00:00
|
|
|
{
|
2010-01-24 15:25:08 +00:00
|
|
|
const char *src = (const char *) card->reader->atr_info.hist_bytes;
|
|
|
|
size_t srclen = card->reader->atr_info.hist_bytes_len;
|
2005-02-09 11:37:25 +00:00
|
|
|
size_t offset = 0;
|
|
|
|
|
|
|
|
if (len == 0)
|
|
|
|
len = strlen(str);
|
|
|
|
if (srclen < len)
|
|
|
|
return 0;
|
|
|
|
while (srclen - offset > len) {
|
|
|
|
if (memcmp(src + offset, str, len) == 0) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
offset++;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
static int setcos_match_card(sc_card_t *card)
|
2001-12-22 20:43:09 +00:00
|
|
|
{
|
2006-12-08 14:56:09 +00:00
|
|
|
sc_apdu_t apdu;
|
|
|
|
u8 buf[6];
|
2002-03-08 05:59:57 +00:00
|
|
|
int i;
|
2001-12-22 20:43:09 +00:00
|
|
|
|
2005-02-06 19:40:40 +00:00
|
|
|
i = _sc_match_atr(card, setcos_atrs, &card->type);
|
|
|
|
if (i < 0) {
|
2005-02-09 11:37:25 +00:00
|
|
|
/* Unknown card, but has the FinEID application for sure */
|
|
|
|
if (match_hist_bytes(card, "FinEID", 0)) {
|
2011-06-15 11:10:37 +00:00
|
|
|
card->type = SC_CARD_TYPE_SETCOS_FINEID_V2_2048;
|
2005-02-06 19:40:40 +00:00
|
|
|
return 1;
|
2005-02-09 11:37:25 +00:00
|
|
|
}
|
|
|
|
if (match_hist_bytes(card, "FISE", 0)) {
|
2005-02-10 10:07:13 +00:00
|
|
|
card->type = SC_CARD_TYPE_SETCOS_GENERIC;
|
2005-02-09 11:37:25 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2006-12-08 14:56:09 +00:00
|
|
|
/* Check if it's a EID2.x applet by reading the version info */
|
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xCA, 0xDF, 0x30);
|
|
|
|
apdu.cla = 0x00;
|
|
|
|
apdu.resp = buf;
|
|
|
|
apdu.resplen = 5;
|
|
|
|
apdu.le = 5;
|
|
|
|
i = sc_transmit_apdu(card, &apdu);
|
|
|
|
if (i == 0 && apdu.sw1 == 0x90 && apdu.sw2 == 0x00 && apdu.resplen == 5) {
|
|
|
|
if (memcmp(buf, "v2.0", 4) == 0)
|
|
|
|
card->type = SC_CARD_TYPE_SETCOS_EID_V2_0;
|
|
|
|
else if (memcmp(buf, "v2.1", 4) == 0)
|
|
|
|
card->type = SC_CARD_TYPE_SETCOS_EID_V2_1;
|
|
|
|
else {
|
|
|
|
buf[sizeof(buf) - 1] = '\0';
|
2018-11-22 08:31:29 +00:00
|
|
|
sc_log(card->ctx, "SetCOS EID applet %s is not supported", (char *) buf);
|
2006-12-08 14:56:09 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2002-03-08 05:59:57 +00:00
|
|
|
return 0;
|
2005-02-06 19:40:40 +00:00
|
|
|
}
|
2005-02-24 11:11:12 +00:00
|
|
|
card->flags = setcos_atrs[i].flags;
|
2001-12-22 20:43:09 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2006-03-09 20:35:19 +00:00
|
|
|
static int select_pkcs15_app(sc_card_t * card)
|
2005-02-09 11:37:25 +00:00
|
|
|
{
|
|
|
|
sc_path_t app;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
/* Regular PKCS#15 AID */
|
2005-02-24 11:11:12 +00:00
|
|
|
sc_format_path("A000000063504B43532D3135", &app);
|
2005-02-09 11:37:25 +00:00
|
|
|
app.type = SC_PATH_TYPE_DF_NAME;
|
2005-02-24 11:11:12 +00:00
|
|
|
r = sc_select_file(card, &app, NULL);
|
2005-02-09 11:37:25 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
static int setcos_init(sc_card_t *card)
|
2001-12-22 20:43:09 +00:00
|
|
|
{
|
2003-05-28 20:52:33 +00:00
|
|
|
card->name = "SetCOS";
|
2005-02-06 19:40:40 +00:00
|
|
|
|
2005-02-09 11:37:25 +00:00
|
|
|
/* Handle unknown or forced cards */
|
|
|
|
if (card->type < 0) {
|
2005-02-11 20:09:34 +00:00
|
|
|
card->type = SC_CARD_TYPE_SETCOS_GENERIC;
|
2005-02-09 11:37:25 +00:00
|
|
|
}
|
2005-02-24 11:11:12 +00:00
|
|
|
|
|
|
|
switch (card->type) {
|
|
|
|
case SC_CARD_TYPE_SETCOS_FINEID:
|
2011-06-15 11:10:37 +00:00
|
|
|
case SC_CARD_TYPE_SETCOS_FINEID_V2_2048:
|
2006-03-09 20:35:19 +00:00
|
|
|
case SC_CARD_TYPE_SETCOS_NIDEL:
|
2005-02-09 11:37:25 +00:00
|
|
|
card->cla = 0x00;
|
2006-03-09 20:35:19 +00:00
|
|
|
select_pkcs15_app(card);
|
2005-02-24 11:11:12 +00:00
|
|
|
if (card->flags & SC_CARD_FLAG_RNG)
|
|
|
|
card->caps |= SC_CARD_CAP_RNG;
|
|
|
|
break;
|
2005-04-04 09:30:54 +00:00
|
|
|
case SC_CARD_TYPE_SETCOS_44:
|
2006-12-08 14:56:09 +00:00
|
|
|
case SC_CARD_TYPE_SETCOS_EID_V2_0:
|
|
|
|
case SC_CARD_TYPE_SETCOS_EID_V2_1:
|
2005-04-04 09:30:54 +00:00
|
|
|
card->cla = 0x00;
|
|
|
|
card->caps |= SC_CARD_CAP_USE_FCI_AC;
|
|
|
|
card->caps |= SC_CARD_CAP_RNG;
|
2011-04-07 15:38:22 +00:00
|
|
|
card->caps |= SC_CARD_CAP_APDU_EXT;
|
2005-04-04 09:30:54 +00:00
|
|
|
break;
|
2005-02-24 11:11:12 +00:00
|
|
|
default:
|
|
|
|
/* XXX: Get SetCOS version */
|
|
|
|
card->cla = 0x80; /* SetCOS 4.3.x */
|
|
|
|
/* State that we have an RNG */
|
|
|
|
card->caps |= SC_CARD_CAP_RNG;
|
|
|
|
break;
|
2005-02-09 11:37:25 +00:00
|
|
|
}
|
2002-03-08 05:59:57 +00:00
|
|
|
|
2005-02-24 11:11:12 +00:00
|
|
|
switch (card->type) {
|
|
|
|
case SC_CARD_TYPE_SETCOS_PKI:
|
2011-06-15 11:10:37 +00:00
|
|
|
case SC_CARD_TYPE_SETCOS_FINEID_V2_2048:
|
2005-02-24 11:11:12 +00:00
|
|
|
{
|
|
|
|
unsigned long flags;
|
2001-12-22 20:43:09 +00:00
|
|
|
|
2005-02-24 11:11:12 +00:00
|
|
|
flags = SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_PAD_PKCS1;
|
|
|
|
flags |= SC_ALGORITHM_RSA_HASH_NONE | SC_ALGORITHM_RSA_HASH_SHA1;
|
2003-01-15 13:20:02 +00:00
|
|
|
|
2005-02-24 11:11:12 +00:00
|
|
|
_sc_card_add_rsa_alg(card, 1024, flags, 0);
|
2011-05-24 19:08:55 +00:00
|
|
|
_sc_card_add_rsa_alg(card, 2048, flags, 0);
|
|
|
|
}
|
|
|
|
break;
|
2005-04-04 09:30:54 +00:00
|
|
|
case SC_CARD_TYPE_SETCOS_44:
|
2006-03-09 20:35:19 +00:00
|
|
|
case SC_CARD_TYPE_SETCOS_NIDEL:
|
2006-12-08 14:56:09 +00:00
|
|
|
case SC_CARD_TYPE_SETCOS_EID_V2_0:
|
|
|
|
case SC_CARD_TYPE_SETCOS_EID_V2_1:
|
2005-04-04 09:30:54 +00:00
|
|
|
{
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
flags = SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_PAD_PKCS1;
|
|
|
|
flags |= SC_ALGORITHM_RSA_HASH_NONE | SC_ALGORITHM_RSA_HASH_SHA1;
|
2005-07-05 15:22:17 +00:00
|
|
|
flags |= SC_ALGORITHM_ONBOARD_KEY_GEN;
|
2005-04-04 09:30:54 +00:00
|
|
|
|
2005-07-05 15:22:17 +00:00
|
|
|
_sc_card_add_rsa_alg(card, 512, flags, 0);
|
|
|
|
_sc_card_add_rsa_alg(card, 768, flags, 0);
|
2005-04-04 09:30:54 +00:00
|
|
|
_sc_card_add_rsa_alg(card, 1024, flags, 0);
|
2016-05-13 07:16:21 +00:00
|
|
|
_sc_card_add_rsa_alg(card, 2048, flags, 0);
|
2005-04-04 09:30:54 +00:00
|
|
|
}
|
|
|
|
break;
|
2005-02-24 11:11:12 +00:00
|
|
|
}
|
2001-12-22 20:43:09 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-01-20 21:20:09 +00:00
|
|
|
static const struct sc_card_operations *iso_ops = NULL;
|
2002-01-10 23:02:48 +00:00
|
|
|
|
2005-04-04 09:30:54 +00:00
|
|
|
static int setcos_construct_fci_44(sc_card_t *card, const sc_file_t *file, u8 *out, size_t *outlen)
|
|
|
|
{
|
|
|
|
u8 *p = out;
|
|
|
|
u8 buf[64];
|
2005-09-12 21:09:12 +00:00
|
|
|
const u8 *pin_key_info;
|
2006-12-08 14:56:09 +00:00
|
|
|
int len;
|
2005-04-04 09:30:54 +00:00
|
|
|
|
|
|
|
/* Command */
|
|
|
|
*p++ = 0x6F;
|
|
|
|
p++;
|
|
|
|
|
2006-12-08 14:56:09 +00:00
|
|
|
/* Size (set to 0 for keys/PINs on a Java card) */
|
|
|
|
if (SETCOS_IS_EID_APPLET(card) &&
|
|
|
|
(file->type == SC_FILE_TYPE_INTERNAL_EF ||
|
|
|
|
(file->type == SC_FILE_TYPE_WORKING_EF && file->ef_structure == 0x22)))
|
|
|
|
buf[0] = buf[1] = 0x00;
|
|
|
|
else {
|
|
|
|
buf[0] = (file->size >> 8) & 0xFF;
|
|
|
|
buf[1] = file->size & 0xFF;
|
|
|
|
}
|
|
|
|
sc_asn1_put_tag(0x81, buf, 2, p, *outlen - (p - out), &p);
|
2005-04-04 09:30:54 +00:00
|
|
|
|
|
|
|
/* Type */
|
|
|
|
if (file->type_attr_len) {
|
|
|
|
memcpy(buf, file->type_attr, file->type_attr_len);
|
2006-12-08 14:56:09 +00:00
|
|
|
sc_asn1_put_tag(0x82, buf, file->type_attr_len, p, *outlen - (p - out), &p);
|
2005-04-04 09:30:54 +00:00
|
|
|
} else {
|
|
|
|
u8 bLen = 1;
|
|
|
|
|
|
|
|
buf[0] = file->shareable ? 0x40 : 0;
|
|
|
|
switch (file->type) {
|
|
|
|
case SC_FILE_TYPE_INTERNAL_EF: /* RSA keyfile */
|
|
|
|
buf[0] = 0x11;
|
|
|
|
break;
|
|
|
|
case SC_FILE_TYPE_WORKING_EF:
|
|
|
|
if (file->ef_structure == 0x22) { /* pin-file */
|
|
|
|
buf[0] = 0x0A; /* EF linear fixed EF for ISF keys */
|
2006-12-08 14:56:09 +00:00
|
|
|
if (SETCOS_IS_EID_APPLET(card))
|
|
|
|
bLen = 1;
|
|
|
|
else {
|
|
|
|
/* Setcos V4.4 */
|
|
|
|
bLen = 5;
|
|
|
|
buf[1] = 0x41; /* fixed */
|
|
|
|
buf[2] = file->record_length >> 8; /* 2 byte record length */
|
|
|
|
buf[3] = file->record_length & 0xFF;
|
|
|
|
buf[4] = file->size / file->record_length; /* record count */
|
|
|
|
}
|
2005-04-04 09:30:54 +00:00
|
|
|
} else {
|
|
|
|
buf[0] |= file->ef_structure & 7; /* set file-type, only for EF, not for DF objects */
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SC_FILE_TYPE_DF:
|
|
|
|
buf[0] = 0x38;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return SC_ERROR_NOT_SUPPORTED;
|
|
|
|
}
|
2006-12-08 14:56:09 +00:00
|
|
|
sc_asn1_put_tag(0x82, buf, bLen, p, *outlen - (p - out), &p);
|
2005-04-04 09:30:54 +00:00
|
|
|
}
|
|
|
|
|
2006-12-08 14:56:09 +00:00
|
|
|
/* File ID */
|
2005-04-04 09:30:54 +00:00
|
|
|
buf[0] = (file->id >> 8) & 0xFF;
|
|
|
|
buf[1] = file->id & 0xFF;
|
2006-12-08 14:56:09 +00:00
|
|
|
sc_asn1_put_tag(0x83, buf, 2, p, *outlen - (p - out), &p);
|
2005-04-04 09:30:54 +00:00
|
|
|
|
2006-12-08 14:56:09 +00:00
|
|
|
/* DF name */
|
|
|
|
if (file->type == SC_FILE_TYPE_DF) {
|
2005-04-04 09:30:54 +00:00
|
|
|
if (file->name[0] != 0)
|
2006-12-08 14:56:09 +00:00
|
|
|
sc_asn1_put_tag(0x84, (u8 *) file->name, file->namelen, p, *outlen - (p - out), &p);
|
|
|
|
else { /* Name required -> take the FID if not specified */
|
2005-04-04 09:30:54 +00:00
|
|
|
buf[0] = (file->id >> 8) & 0xFF;
|
|
|
|
buf[1] = file->id & 0xFF;
|
2006-12-08 14:56:09 +00:00
|
|
|
sc_asn1_put_tag(0x84, buf, 2, p, *outlen - (p - out), &p);
|
2005-04-04 09:30:54 +00:00
|
|
|
}
|
2006-12-08 14:56:09 +00:00
|
|
|
}
|
2005-04-04 09:30:54 +00:00
|
|
|
|
2006-12-08 14:56:09 +00:00
|
|
|
/* Security Attributes */
|
|
|
|
memcpy(buf, file->sec_attr, file->sec_attr_len);
|
|
|
|
sc_asn1_put_tag(0x86, buf, file->sec_attr_len, p, *outlen - (p - out), &p);
|
2005-04-04 09:30:54 +00:00
|
|
|
|
2006-12-08 14:56:09 +00:00
|
|
|
/* Life cycle status */
|
|
|
|
if (file->prop_attr_len) {
|
|
|
|
memcpy(buf, file->prop_attr, file->prop_attr_len);
|
|
|
|
sc_asn1_put_tag(0x8A, buf, file->prop_attr_len, p, *outlen - (p - out), &p);
|
2005-04-04 09:30:54 +00:00
|
|
|
}
|
|
|
|
|
2006-12-08 14:56:09 +00:00
|
|
|
/* PIN definitions */
|
|
|
|
if (file->type == SC_FILE_TYPE_DF) {
|
|
|
|
if (card->type == SC_CARD_TYPE_SETCOS_EID_V2_1) {
|
|
|
|
pin_key_info = (const u8*)"\xC1\x04\x81\x82\x83\x84";
|
|
|
|
len = 6;
|
|
|
|
}
|
|
|
|
else if (card->type == SC_CARD_TYPE_SETCOS_EID_V2_0) {
|
|
|
|
pin_key_info = (const u8*)"\xC1\x04\x81\x82"; /* Max 2 PINs supported */
|
|
|
|
len = 4;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* Pin/key info: define 4 pins, no keys */
|
|
|
|
if(file->path.len == 2)
|
|
|
|
pin_key_info = (const u8*)"\xC1\x04\x81\x82\x83\x84\xC2\x00"; /* root-MF: use local pin-file */
|
|
|
|
else
|
|
|
|
pin_key_info = (const u8 *)"\xC1\x04\x01\x02\x03\x04\xC2\x00"; /* sub-DF: use parent pin-file in root-MF */
|
|
|
|
len = 8;
|
|
|
|
}
|
|
|
|
sc_asn1_put_tag(0xA5, pin_key_info, len, p, *outlen - (p - out), &p);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Length */
|
2005-04-04 09:30:54 +00:00
|
|
|
out[1] = p - out - 2;
|
|
|
|
|
|
|
|
*outlen = p - out;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int setcos_construct_fci(sc_card_t *card, const sc_file_t *file, u8 *out, size_t *outlen)
|
|
|
|
{
|
2006-03-09 20:35:19 +00:00
|
|
|
if (card->type == SC_CARD_TYPE_SETCOS_44 ||
|
2006-12-08 14:56:09 +00:00
|
|
|
card->type == SC_CARD_TYPE_SETCOS_NIDEL ||
|
|
|
|
SETCOS_IS_EID_APPLET(card))
|
2005-04-04 09:30:54 +00:00
|
|
|
return setcos_construct_fci_44(card, file, out, outlen);
|
|
|
|
else
|
|
|
|
return iso_ops->construct_fci(card, file, out, outlen);
|
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
static u8 acl_to_byte(const sc_acl_entry_t *e)
|
2002-02-20 09:56:47 +00:00
|
|
|
{
|
|
|
|
switch (e->method) {
|
|
|
|
case SC_AC_NONE:
|
|
|
|
return 0x00;
|
|
|
|
case SC_AC_CHV:
|
|
|
|
switch (e->key_ref) {
|
|
|
|
case 1:
|
|
|
|
return 0x01;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
return 0x02;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return 0x00;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SC_AC_TERM:
|
|
|
|
return 0x04;
|
|
|
|
case SC_AC_NEVER:
|
|
|
|
return 0x0F;
|
|
|
|
}
|
|
|
|
return 0x00;
|
|
|
|
}
|
|
|
|
|
2005-04-09 13:32:22 +00:00
|
|
|
static unsigned int acl_to_byte_44(const struct sc_acl_entry *e, u8* p_bNumber)
|
2005-04-04 09:30:54 +00:00
|
|
|
{
|
|
|
|
/* Handle special fixed values */
|
|
|
|
if (e == (sc_acl_entry_t *) 1) /* SC_AC_NEVER */
|
|
|
|
return SC_AC_NEVER;
|
|
|
|
else if ((e == (sc_acl_entry_t *) 2) || /* SC_AC_NONE */
|
|
|
|
(e == (sc_acl_entry_t *) 3) || /* SC_AC_UNKNOWN */
|
|
|
|
(e == (sc_acl_entry_t *) 0))
|
|
|
|
return SC_AC_NONE;
|
|
|
|
|
|
|
|
/* Handle standard values */
|
|
|
|
*p_bNumber = e->key_ref;
|
|
|
|
return(e->method);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If pin is present in the pins list, return it's index.
|
|
|
|
* If it's not yet present, add it to the list and return the index. */
|
|
|
|
static int setcos_pin_index_44(int *pins, int len, int pin)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
if (pins[i] == pin)
|
|
|
|
return i;
|
|
|
|
if (pins[i] == -1) {
|
|
|
|
pins[i] = pin;
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert(i != len); /* Too much PINs, shouldn't happen */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-04-14 17:38:34 +00:00
|
|
|
/* The ACs are always for the SETEC_LCSI_ACTIVATED state, even if
|
2005-04-04 09:30:54 +00:00
|
|
|
* we have to create the file in the SC_FILE_STATUS_INITIALISATION state. */
|
|
|
|
static int setcos_create_file_44(sc_card_t *card, sc_file_t *file)
|
|
|
|
{
|
|
|
|
const u8 bFileStatus = file->status == SC_FILE_STATUS_CREATION ?
|
|
|
|
SETEC_LCSI_CREATE : SETEC_LCSI_ACTIVATED;
|
|
|
|
u8 bCommands_always = 0;
|
2006-12-08 14:56:09 +00:00
|
|
|
int pins[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
|
2005-12-08 09:05:56 +00:00
|
|
|
u8 bCommands_pin[sizeof(pins)/sizeof(pins[0])]; /* both 7 entries big */
|
2005-04-04 09:30:54 +00:00
|
|
|
u8 bCommands_key = 0;
|
|
|
|
u8 bNumber = 0;
|
|
|
|
u8 bKeyNumber = 0;
|
2005-04-09 13:32:22 +00:00
|
|
|
unsigned int bMethod = 0;
|
2005-04-04 09:30:54 +00:00
|
|
|
|
|
|
|
/* -1 means RFU */
|
|
|
|
const int df_idx[8] = { /* byte 1 = OpenSC type of AC Bit0, byte 2 = OpenSC type of AC Bit1 ...*/
|
|
|
|
SC_AC_OP_DELETE, SC_AC_OP_CREATE, SC_AC_OP_CREATE,
|
|
|
|
SC_AC_OP_INVALIDATE, SC_AC_OP_REHABILITATE,
|
|
|
|
SC_AC_OP_LOCK, SC_AC_OP_DELETE, -1};
|
|
|
|
const int ef_idx[8] = { /* note: SC_AC_OP_SELECT to be ignored, actually RFU */
|
|
|
|
SC_AC_OP_READ, SC_AC_OP_UPDATE, SC_AC_OP_WRITE,
|
|
|
|
SC_AC_OP_INVALIDATE, SC_AC_OP_REHABILITATE,
|
|
|
|
-1, SC_AC_OP_ERASE, -1};
|
|
|
|
const int efi_idx[8] = { /* internal EF used for RSA keys */
|
|
|
|
SC_AC_OP_READ, SC_AC_OP_ERASE, SC_AC_OP_UPDATE,
|
|
|
|
SC_AC_OP_INVALIDATE, SC_AC_OP_REHABILITATE,
|
|
|
|
-1, SC_AC_OP_ERASE, -1};
|
|
|
|
|
|
|
|
/* Set file creation status */
|
|
|
|
sc_file_set_prop_attr(file, &bFileStatus, 1);
|
|
|
|
|
|
|
|
/* Build ACI from local structure = get AC for each operation group */
|
|
|
|
if (file->sec_attr_len == 0) {
|
|
|
|
const int* p_idx;
|
|
|
|
int i;
|
|
|
|
int len = 0;
|
2015-01-28 06:00:02 +00:00
|
|
|
u8 bBuf[64];
|
2005-04-04 09:30:54 +00:00
|
|
|
|
|
|
|
/* Get specific operation groups for specified file-type */
|
|
|
|
switch (file->type){
|
|
|
|
case SC_FILE_TYPE_DF: /* DF */
|
|
|
|
p_idx = df_idx;
|
|
|
|
break;
|
|
|
|
case SC_FILE_TYPE_INTERNAL_EF: /* EF for RSA keys */
|
|
|
|
p_idx = efi_idx;
|
|
|
|
break;
|
|
|
|
default: /* SC_FILE_TYPE_WORKING_EF */
|
|
|
|
p_idx = ef_idx;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get enabled commands + required Keys/Pins */
|
|
|
|
memset(bCommands_pin, 0, sizeof(bCommands_pin));
|
|
|
|
for (i = 7; i >= 0; i--) { /* for each AC Setcos operation */
|
|
|
|
bCommands_always <<= 1;
|
|
|
|
bCommands_key <<= 1;
|
|
|
|
|
|
|
|
if (p_idx[i] == -1) /* -1 means that bit is RFU -> set to 0 */
|
|
|
|
continue;
|
|
|
|
|
|
|
|
bMethod = acl_to_byte_44(file->acl[ p_idx[i] ], &bNumber);
|
|
|
|
/* Convert to OpenSc-index, convert to pin/key number */
|
|
|
|
switch(bMethod){
|
|
|
|
case SC_AC_NONE: /* always allowed */
|
|
|
|
bCommands_always |= 1;
|
|
|
|
break;
|
|
|
|
case SC_AC_CHV: /* pin */
|
2006-12-08 14:56:09 +00:00
|
|
|
if ((bNumber & 0x7F) == 0 || (bNumber & 0x7F) > 7) {
|
2018-11-22 08:31:29 +00:00
|
|
|
sc_log(card->ctx, "SetCOS 4.4 PIN refs can only be 1..7\n");
|
2005-04-04 09:30:54 +00:00
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
}
|
2020-01-31 20:56:11 +00:00
|
|
|
bCommands_pin[setcos_pin_index_44(pins, sizeof(pins)/sizeof(pins[0]), (int) bNumber)] |= 1 << i;
|
2005-04-04 09:30:54 +00:00
|
|
|
break;
|
|
|
|
case SC_AC_TERM: /* key */
|
|
|
|
bKeyNumber = bNumber; /* There should be only 1 key */
|
|
|
|
bCommands_key |= 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-14 17:38:34 +00:00
|
|
|
/* Add the commands that are always allowed */
|
2005-04-04 09:30:54 +00:00
|
|
|
if (bCommands_always) {
|
|
|
|
bBuf[len++] = 1;
|
|
|
|
bBuf[len++] = bCommands_always;
|
|
|
|
}
|
|
|
|
/* Add commands that require pins */
|
2005-09-07 08:33:55 +00:00
|
|
|
for (i = 0; i < (int)sizeof(bCommands_pin) && pins[i] != -1; i++) {
|
2005-04-04 09:30:54 +00:00
|
|
|
bBuf[len++] = 2;
|
|
|
|
bBuf[len++] = bCommands_pin[i];
|
2006-12-08 14:56:09 +00:00
|
|
|
if (SETCOS_IS_EID_APPLET(card))
|
|
|
|
bBuf[len++] = pins[i]; /* pin ref */
|
|
|
|
else
|
|
|
|
bBuf[len++] = pins[i] & 0x07; /* pin ref */
|
2005-04-04 09:30:54 +00:00
|
|
|
}
|
2018-04-14 17:38:34 +00:00
|
|
|
/* Add commands that require the key */
|
2005-04-04 09:30:54 +00:00
|
|
|
if (bCommands_key) {
|
|
|
|
bBuf[len++] = 2 | 0x20; /* indicate keyNumber present */
|
|
|
|
bBuf[len++] = bCommands_key;
|
|
|
|
bBuf[len++] = bKeyNumber;
|
|
|
|
}
|
|
|
|
/* RSA signing/decryption requires AC adaptive coding, can't be put
|
|
|
|
in AC simple coding. Only implemented for pins, not for a key. */
|
|
|
|
if ( (file->type == SC_FILE_TYPE_INTERNAL_EF) &&
|
|
|
|
(acl_to_byte_44(file->acl[SC_AC_OP_CRYPTO], &bNumber) == SC_AC_CHV) ) {
|
|
|
|
bBuf[len++] = 0x83;
|
|
|
|
bBuf[len++] = 0x01;
|
|
|
|
bBuf[len++] = 0x2A; /* INS byte for the sign/decrypt APDU */
|
|
|
|
bBuf[len++] = bNumber & 0x07; /* pin ref */
|
|
|
|
}
|
|
|
|
|
|
|
|
sc_file_set_sec_attr(file, bBuf, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
return iso_ops->create_file(card, file);
|
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
static int setcos_create_file(sc_card_t *card, sc_file_t *file)
|
2002-01-10 23:02:48 +00:00
|
|
|
{
|
2006-12-08 14:56:09 +00:00
|
|
|
if (card->type == SC_CARD_TYPE_SETCOS_44 || SETCOS_IS_EID_APPLET(card))
|
2005-04-04 09:30:54 +00:00
|
|
|
return setcos_create_file_44(card, file);
|
|
|
|
|
2002-04-02 21:26:42 +00:00
|
|
|
if (file->prop_attr_len == 0)
|
2002-04-03 12:59:53 +00:00
|
|
|
sc_file_set_prop_attr(file, (const u8 *) "\x03\x00\x00", 3);
|
2002-02-20 09:56:47 +00:00
|
|
|
if (file->sec_attr_len == 0) {
|
|
|
|
int idx[6], i;
|
|
|
|
u8 buf[6];
|
|
|
|
|
|
|
|
if (file->type == SC_FILE_TYPE_DF) {
|
|
|
|
const int df_idx[6] = {
|
|
|
|
SC_AC_OP_SELECT, SC_AC_OP_LOCK, SC_AC_OP_DELETE,
|
|
|
|
SC_AC_OP_CREATE, SC_AC_OP_REHABILITATE,
|
|
|
|
SC_AC_OP_INVALIDATE
|
|
|
|
};
|
|
|
|
for (i = 0; i < 6; i++)
|
|
|
|
idx[i] = df_idx[i];
|
|
|
|
} else {
|
|
|
|
const int ef_idx[6] = {
|
|
|
|
SC_AC_OP_READ, SC_AC_OP_UPDATE, SC_AC_OP_WRITE,
|
|
|
|
SC_AC_OP_ERASE, SC_AC_OP_REHABILITATE,
|
|
|
|
SC_AC_OP_INVALIDATE
|
|
|
|
};
|
|
|
|
for (i = 0; i < 6; i++)
|
|
|
|
idx[i] = ef_idx[i];
|
|
|
|
}
|
2005-10-12 17:52:56 +00:00
|
|
|
for (i = 0; i < 6; i++) {
|
|
|
|
const struct sc_acl_entry *entry;
|
|
|
|
entry = sc_file_get_acl_entry(file, idx[i]);
|
|
|
|
buf[i] = acl_to_byte(entry);
|
|
|
|
}
|
2002-02-20 09:56:47 +00:00
|
|
|
|
2002-03-28 14:13:36 +00:00
|
|
|
sc_file_set_sec_attr(file, buf, 6);
|
2002-02-20 09:56:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return iso_ops->create_file(card, file);
|
2002-01-20 21:20:09 +00:00
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
static int setcos_set_security_env2(sc_card_t *card,
|
|
|
|
const sc_security_env_t *env, int se_num)
|
2002-06-03 15:05:58 +00:00
|
|
|
{
|
2005-03-08 20:59:35 +00:00
|
|
|
sc_apdu_t apdu;
|
2002-06-03 15:05:58 +00:00
|
|
|
u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
|
|
|
|
u8 *p;
|
|
|
|
int r, locked = 0;
|
|
|
|
|
|
|
|
assert(card != NULL && env != NULL);
|
2005-04-04 09:30:54 +00:00
|
|
|
|
2006-03-09 20:35:19 +00:00
|
|
|
if (card->type == SC_CARD_TYPE_SETCOS_44 ||
|
2006-12-08 14:56:09 +00:00
|
|
|
card->type == SC_CARD_TYPE_SETCOS_NIDEL ||
|
|
|
|
SETCOS_IS_EID_APPLET(card)) {
|
2018-02-21 13:07:53 +00:00
|
|
|
if (env->flags & SC_SEC_ENV_KEY_REF_SYMMETRIC) {
|
2018-11-22 08:31:29 +00:00
|
|
|
sc_log(card->ctx, "symmetric keyref not supported.\n");
|
2005-04-04 09:30:54 +00:00
|
|
|
return SC_ERROR_NOT_SUPPORTED;
|
|
|
|
}
|
|
|
|
if (se_num > 0) {
|
2018-11-22 08:31:29 +00:00
|
|
|
sc_log(card->ctx, "restore security environment not supported.\n");
|
2005-04-04 09:30:54 +00:00
|
|
|
return SC_ERROR_NOT_SUPPORTED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-03 15:05:58 +00:00
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0, 0);
|
|
|
|
switch (env->operation) {
|
|
|
|
case SC_SEC_OPERATION_DECIPHER:
|
2005-02-24 11:11:12 +00:00
|
|
|
/* Should be 0x81 */
|
|
|
|
apdu.p1 = 0x41;
|
2002-06-03 15:05:58 +00:00
|
|
|
apdu.p2 = 0xB8;
|
|
|
|
break;
|
|
|
|
case SC_SEC_OPERATION_SIGN:
|
2005-02-24 11:11:12 +00:00
|
|
|
/* Should be 0x41 */
|
2005-04-04 09:30:54 +00:00
|
|
|
apdu.p1 = ((card->type == SC_CARD_TYPE_SETCOS_FINEID_V2) ||
|
2011-06-15 11:10:37 +00:00
|
|
|
(card->type == SC_CARD_TYPE_SETCOS_FINEID_V2_2048) ||
|
2006-03-09 20:35:19 +00:00
|
|
|
(card->type == SC_CARD_TYPE_SETCOS_44) ||
|
2006-12-08 14:56:09 +00:00
|
|
|
(card->type == SC_CARD_TYPE_SETCOS_NIDEL) ||
|
|
|
|
SETCOS_IS_EID_APPLET(card)) ? 0x41 : 0x81;
|
2002-06-03 15:05:58 +00:00
|
|
|
apdu.p2 = 0xB6;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
}
|
|
|
|
apdu.le = 0;
|
|
|
|
p = sbuf;
|
|
|
|
if (env->flags & SC_SEC_ENV_ALG_REF_PRESENT) {
|
|
|
|
*p++ = 0x80; /* algorithm reference */
|
|
|
|
*p++ = 0x01;
|
|
|
|
*p++ = env->algorithm_ref & 0xFF;
|
|
|
|
}
|
|
|
|
if (env->flags & SC_SEC_ENV_FILE_REF_PRESENT) {
|
|
|
|
*p++ = 0x81;
|
|
|
|
*p++ = env->file_ref.len;
|
|
|
|
memcpy(p, env->file_ref.value, env->file_ref.len);
|
|
|
|
p += env->file_ref.len;
|
|
|
|
}
|
2014-08-03 10:15:58 +00:00
|
|
|
if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT &&
|
|
|
|
!(card->type == SC_CARD_TYPE_SETCOS_NIDEL ||
|
|
|
|
card->type == SC_CARD_TYPE_SETCOS_FINEID_V2_2048)) {
|
2018-02-21 13:07:53 +00:00
|
|
|
if (env->flags & SC_SEC_ENV_KEY_REF_SYMMETRIC)
|
2002-06-03 15:05:58 +00:00
|
|
|
*p++ = 0x83;
|
|
|
|
else
|
|
|
|
*p++ = 0x84;
|
|
|
|
*p++ = env->key_ref_len;
|
|
|
|
memcpy(p, env->key_ref, env->key_ref_len);
|
|
|
|
p += env->key_ref_len;
|
|
|
|
}
|
|
|
|
r = p - sbuf;
|
|
|
|
apdu.lc = r;
|
|
|
|
apdu.datalen = r;
|
|
|
|
apdu.data = sbuf;
|
|
|
|
apdu.resplen = 0;
|
|
|
|
if (se_num > 0) {
|
|
|
|
r = sc_lock(card);
|
2018-11-23 20:54:14 +00:00
|
|
|
LOG_TEST_RET(card->ctx, r, "sc_lock() failed");
|
2002-06-03 15:05:58 +00:00
|
|
|
locked = 1;
|
|
|
|
}
|
|
|
|
if (apdu.datalen != 0) {
|
|
|
|
r = sc_transmit_apdu(card, &apdu);
|
|
|
|
if (r) {
|
2018-11-22 08:31:29 +00:00
|
|
|
sc_log(card->ctx,
|
2010-03-15 12:17:13 +00:00
|
|
|
"%s: APDU transmit failed", sc_strerror(r));
|
2002-06-03 15:05:58 +00:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
|
|
|
if (r) {
|
2018-11-22 08:31:29 +00:00
|
|
|
sc_log(card->ctx,
|
2010-03-15 12:17:13 +00:00
|
|
|
"%s: Card returned error", sc_strerror(r));
|
2002-06-03 15:05:58 +00:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (se_num <= 0)
|
|
|
|
return 0;
|
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0xF2, se_num);
|
|
|
|
r = sc_transmit_apdu(card, &apdu);
|
|
|
|
sc_unlock(card);
|
2018-11-23 20:54:14 +00:00
|
|
|
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
|
2002-06-03 15:05:58 +00:00
|
|
|
return sc_check_sw(card, apdu.sw1, apdu.sw2);
|
|
|
|
err:
|
|
|
|
if (locked)
|
|
|
|
sc_unlock(card);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
static int setcos_set_security_env(sc_card_t *card,
|
|
|
|
const sc_security_env_t *env, int se_num)
|
2002-01-20 21:20:09 +00:00
|
|
|
{
|
|
|
|
if (env->flags & SC_SEC_ENV_ALG_PRESENT) {
|
2005-03-08 20:59:35 +00:00
|
|
|
sc_security_env_t tmp;
|
2002-01-20 21:20:09 +00:00
|
|
|
|
|
|
|
tmp = *env;
|
2002-03-08 05:59:57 +00:00
|
|
|
tmp.flags &= ~SC_SEC_ENV_ALG_PRESENT;
|
2002-01-20 21:20:09 +00:00
|
|
|
tmp.flags |= SC_SEC_ENV_ALG_REF_PRESENT;
|
|
|
|
if (tmp.algorithm != SC_ALGORITHM_RSA) {
|
2018-11-22 08:31:29 +00:00
|
|
|
sc_log(card->ctx, "Only RSA algorithm supported.\n");
|
2002-01-20 21:20:09 +00:00
|
|
|
return SC_ERROR_NOT_SUPPORTED;
|
|
|
|
}
|
2005-02-24 11:11:12 +00:00
|
|
|
switch (card->type) {
|
|
|
|
case SC_CARD_TYPE_SETCOS_PKI:
|
|
|
|
case SC_CARD_TYPE_SETCOS_FINEID:
|
2011-06-15 11:10:37 +00:00
|
|
|
case SC_CARD_TYPE_SETCOS_FINEID_V2_2048:
|
2006-03-09 20:35:19 +00:00
|
|
|
case SC_CARD_TYPE_SETCOS_NIDEL:
|
2005-04-04 09:30:54 +00:00
|
|
|
case SC_CARD_TYPE_SETCOS_44:
|
2006-12-08 14:56:09 +00:00
|
|
|
case SC_CARD_TYPE_SETCOS_EID_V2_0:
|
|
|
|
case SC_CARD_TYPE_SETCOS_EID_V2_1:
|
2005-02-24 11:11:12 +00:00
|
|
|
break;
|
|
|
|
default:
|
2018-11-22 08:31:29 +00:00
|
|
|
sc_log(card->ctx, "Card does not support RSA.\n");
|
2002-03-08 05:59:57 +00:00
|
|
|
return SC_ERROR_NOT_SUPPORTED;
|
2005-02-24 11:11:12 +00:00
|
|
|
break;
|
2002-03-08 05:59:57 +00:00
|
|
|
}
|
|
|
|
tmp.algorithm_ref = 0x00;
|
|
|
|
/* potential FIXME: return an error, if an unsupported
|
|
|
|
* pad or hash was requested, although this shouldn't happen.
|
|
|
|
*/
|
|
|
|
if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1)
|
2002-01-20 21:20:09 +00:00
|
|
|
tmp.algorithm_ref = 0x02;
|
|
|
|
if (tmp.algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA1)
|
2002-03-08 05:59:57 +00:00
|
|
|
tmp.algorithm_ref |= 0x10;
|
2002-06-03 15:05:58 +00:00
|
|
|
return setcos_set_security_env2(card, &tmp, se_num);
|
2002-01-20 21:20:09 +00:00
|
|
|
}
|
2005-02-11 20:09:34 +00:00
|
|
|
return setcos_set_security_env2(card, env, se_num);
|
2002-01-10 23:02:48 +00:00
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
static void add_acl_entry(sc_file_t *file, int op, u8 byte)
|
2002-02-11 15:55:34 +00:00
|
|
|
{
|
2002-02-20 09:56:47 +00:00
|
|
|
unsigned int method, key_ref = SC_AC_KEY_REF_NONE;
|
|
|
|
|
2002-02-11 15:55:34 +00:00
|
|
|
switch (byte >> 4) {
|
|
|
|
case 0:
|
2002-02-20 09:56:47 +00:00
|
|
|
method = SC_AC_NONE;
|
|
|
|
break;
|
2002-02-11 15:55:34 +00:00
|
|
|
case 1:
|
2002-02-20 09:56:47 +00:00
|
|
|
method = SC_AC_CHV;
|
|
|
|
key_ref = 1;
|
|
|
|
break;
|
2002-02-11 15:55:34 +00:00
|
|
|
case 2:
|
2002-02-20 09:56:47 +00:00
|
|
|
method = SC_AC_CHV;
|
|
|
|
key_ref = 2;
|
|
|
|
break;
|
2002-02-11 15:55:34 +00:00
|
|
|
case 4:
|
2002-02-20 09:56:47 +00:00
|
|
|
method = SC_AC_TERM;
|
|
|
|
break;
|
2002-02-11 15:55:34 +00:00
|
|
|
case 15:
|
2002-02-20 09:56:47 +00:00
|
|
|
method = SC_AC_NEVER;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
method = SC_AC_UNKNOWN;
|
|
|
|
break;
|
2002-02-11 15:55:34 +00:00
|
|
|
}
|
2002-02-20 09:56:47 +00:00
|
|
|
sc_file_add_acl_entry(file, op, method, key_ref);
|
2002-02-11 15:55:34 +00:00
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
static void parse_sec_attr(sc_file_t *file, const u8 * buf, size_t len)
|
2002-02-11 15:55:34 +00:00
|
|
|
{
|
|
|
|
int i;
|
2002-02-20 09:56:47 +00:00
|
|
|
int idx[6];
|
|
|
|
|
2002-02-11 15:55:34 +00:00
|
|
|
if (len < 6)
|
|
|
|
return;
|
2002-02-20 09:56:47 +00:00
|
|
|
if (file->type == SC_FILE_TYPE_DF) {
|
|
|
|
const int df_idx[6] = {
|
|
|
|
SC_AC_OP_SELECT, SC_AC_OP_LOCK, SC_AC_OP_DELETE,
|
|
|
|
SC_AC_OP_CREATE, SC_AC_OP_REHABILITATE,
|
|
|
|
SC_AC_OP_INVALIDATE
|
|
|
|
};
|
|
|
|
for (i = 0; i < 6; i++)
|
|
|
|
idx[i] = df_idx[i];
|
|
|
|
} else {
|
|
|
|
const int ef_idx[6] = {
|
|
|
|
SC_AC_OP_READ, SC_AC_OP_UPDATE, SC_AC_OP_WRITE,
|
|
|
|
SC_AC_OP_ERASE, SC_AC_OP_REHABILITATE,
|
|
|
|
SC_AC_OP_INVALIDATE
|
|
|
|
};
|
|
|
|
for (i = 0; i < 6; i++)
|
|
|
|
idx[i] = ef_idx[i];
|
|
|
|
}
|
2002-02-11 15:55:34 +00:00
|
|
|
for (i = 0; i < 6; i++)
|
2002-02-20 09:56:47 +00:00
|
|
|
add_acl_entry(file, idx[i], buf[i]);
|
2002-02-11 15:55:34 +00:00
|
|
|
}
|
|
|
|
|
2005-04-04 09:30:54 +00:00
|
|
|
static void parse_sec_attr_44(sc_file_t *file, const u8 *buf, size_t len)
|
|
|
|
{
|
|
|
|
/* OpenSc Operation values for each command operation-type */
|
|
|
|
const int df_idx[8] = { /* byte 1 = OpenSC type of AC Bit0, byte 2 = OpenSC type of AC Bit1 ...*/
|
|
|
|
SC_AC_OP_DELETE, SC_AC_OP_CREATE, SC_AC_OP_CREATE,
|
|
|
|
SC_AC_OP_INVALIDATE, SC_AC_OP_REHABILITATE,
|
|
|
|
SC_AC_OP_LOCK, SC_AC_OP_DELETE, -1};
|
|
|
|
const int ef_idx[8] = {
|
|
|
|
SC_AC_OP_READ, SC_AC_OP_UPDATE, SC_AC_OP_WRITE,
|
|
|
|
SC_AC_OP_INVALIDATE, SC_AC_OP_REHABILITATE,
|
|
|
|
-1, SC_AC_OP_ERASE, -1};
|
|
|
|
const int efi_idx[8] = { /* internal EF used for RSA keys */
|
|
|
|
SC_AC_OP_READ, SC_AC_OP_ERASE, SC_AC_OP_UPDATE,
|
|
|
|
SC_AC_OP_INVALIDATE, SC_AC_OP_REHABILITATE,
|
|
|
|
-1, SC_AC_OP_ERASE, -1};
|
|
|
|
|
|
|
|
u8 bValue;
|
|
|
|
int i;
|
2005-04-16 10:37:14 +00:00
|
|
|
int iKeyRef = 0;
|
2005-04-04 09:30:54 +00:00
|
|
|
int iMethod;
|
|
|
|
int iPinCount;
|
|
|
|
int iOffset = 0;
|
|
|
|
int iOperation;
|
|
|
|
const int* p_idx;
|
|
|
|
|
2018-04-14 17:38:34 +00:00
|
|
|
/* Check all sub-AC definitions within the total AC */
|
2019-11-08 08:31:37 +00:00
|
|
|
while (len > 1 && (size_t)iOffset < len) { /* minimum length = 2 */
|
2018-05-26 22:38:37 +00:00
|
|
|
size_t iACLen = buf[iOffset] & 0x0F;
|
2019-11-08 08:31:37 +00:00
|
|
|
if (iACLen >= len)
|
2018-05-25 12:54:47 +00:00
|
|
|
break;
|
2005-04-04 09:30:54 +00:00
|
|
|
|
|
|
|
iMethod = SC_AC_NONE; /* default no authentication required */
|
|
|
|
|
|
|
|
if (buf[iOffset] & 0X80) { /* AC in adaptive coding */
|
|
|
|
/* Evaluates only the command-byte, not the optional P1/P2/Option bytes */
|
2018-05-26 22:38:37 +00:00
|
|
|
size_t iParmLen = 1; /* command-byte is always present */
|
|
|
|
size_t iKeyLen = 0; /* Encryption key is optional */
|
2005-04-04 09:30:54 +00:00
|
|
|
|
|
|
|
if (buf[iOffset] & 0x20) iKeyLen++;
|
|
|
|
if (buf[iOffset+1] & 0x40) iParmLen++;
|
|
|
|
if (buf[iOffset+1] & 0x20) iParmLen++;
|
|
|
|
if (buf[iOffset+1] & 0x10) iParmLen++;
|
|
|
|
if (buf[iOffset+1] & 0x08) iParmLen++;
|
|
|
|
|
|
|
|
/* Get KeyNumber if available */
|
|
|
|
if(iKeyLen) {
|
2018-05-25 12:54:47 +00:00
|
|
|
int iSC;
|
2018-05-26 22:38:37 +00:00
|
|
|
if (len < 1+(size_t)iACLen)
|
2018-05-25 12:54:47 +00:00
|
|
|
break;
|
|
|
|
iSC = buf[iOffset+iACLen];
|
2005-04-04 09:30:54 +00:00
|
|
|
|
|
|
|
switch( (iSC>>5) & 0x03 ){
|
|
|
|
case 0:
|
|
|
|
iMethod = SC_AC_TERM; /* key authentication */
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
iMethod = SC_AC_AUT; /* key authentication */
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
case 3:
|
|
|
|
iMethod = SC_AC_PRO; /* secure messaging */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
iKeyRef = iSC & 0x1F; /* get key number */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get PinNumber if available */
|
|
|
|
if (iACLen > (1+iParmLen+iKeyLen)) { /* check via total length if pin is present */
|
2018-05-26 22:38:37 +00:00
|
|
|
if (len < 1+1+1+(size_t)iParmLen)
|
2018-05-25 12:54:47 +00:00
|
|
|
break;
|
2005-04-04 09:30:54 +00:00
|
|
|
iKeyRef = buf[iOffset+1+1+iParmLen]; /* PTL + AM-header + parameter-bytes */
|
|
|
|
iMethod = SC_AC_CHV;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Convert SETCOS command to OpenSC command group */
|
2018-05-25 12:54:47 +00:00
|
|
|
if (len < 1+2)
|
|
|
|
break;
|
2005-04-04 09:30:54 +00:00
|
|
|
switch(buf[iOffset+2]){
|
|
|
|
case 0x2A: /* crypto operation */
|
|
|
|
iOperation = SC_AC_OP_CRYPTO;
|
|
|
|
break;
|
|
|
|
case 0x46: /* key-generation operation */
|
|
|
|
iOperation = SC_AC_OP_UPDATE;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
iOperation = SC_AC_OP_SELECT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
sc_file_add_acl_entry(file, iOperation, iMethod, iKeyRef);
|
|
|
|
}
|
|
|
|
else { /* AC in simple coding */
|
|
|
|
/* Initial AC is treated as an operational AC */
|
|
|
|
|
|
|
|
/* Get specific Cmd groups for specified file-type */
|
|
|
|
switch (file->type) {
|
|
|
|
case SC_FILE_TYPE_DF: /* DF */
|
|
|
|
p_idx = df_idx;
|
|
|
|
break;
|
|
|
|
case SC_FILE_TYPE_INTERNAL_EF: /* EF for RSA keys */
|
|
|
|
p_idx = efi_idx;
|
|
|
|
break;
|
|
|
|
default: /* EF */
|
|
|
|
p_idx = ef_idx;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Encryption key present ? */
|
2019-11-03 03:45:28 +00:00
|
|
|
iPinCount = iACLen > 0 ? iACLen - 1 : 0;
|
2005-04-04 09:30:54 +00:00
|
|
|
|
|
|
|
if (buf[iOffset] & 0x20) {
|
2018-05-25 12:54:47 +00:00
|
|
|
int iSC;
|
2018-05-26 22:38:37 +00:00
|
|
|
if (len < 1 + (size_t)iACLen)
|
2018-05-25 12:54:47 +00:00
|
|
|
break;
|
|
|
|
iSC = buf[iOffset + iACLen];
|
2005-04-04 09:30:54 +00:00
|
|
|
|
|
|
|
switch( (iSC>>5) & 0x03 ) {
|
|
|
|
case 0:
|
|
|
|
iMethod = SC_AC_TERM; /* key authentication */
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
iMethod = SC_AC_AUT; /* key authentication */
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
case 3:
|
|
|
|
iMethod = SC_AC_PRO; /* secure messaging */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
iKeyRef = iSC & 0x1F; /* get key number */
|
|
|
|
|
|
|
|
iPinCount--; /* one byte used for keyReference */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Pin present ? */
|
|
|
|
if ( iPinCount > 0 ) {
|
2018-05-25 12:54:47 +00:00
|
|
|
if (len < 1 + 2)
|
|
|
|
break;
|
2005-08-26 19:33:52 +00:00
|
|
|
iKeyRef = buf[iOffset + 2]; /* pin ref */
|
2005-04-04 09:30:54 +00:00
|
|
|
iMethod = SC_AC_CHV;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add AC for each command-operationType into OpenSc structure */
|
|
|
|
bValue = buf[iOffset + 1];
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
|
|
if((bValue & 1) && (p_idx[i] >= 0))
|
|
|
|
sc_file_add_acl_entry(file, p_idx[i], iMethod, iKeyRef);
|
|
|
|
bValue >>= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Current field treated, get next AC sub-field */
|
|
|
|
iOffset += iACLen +1; /* AC + PTL-byte */
|
|
|
|
len -= iACLen +1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
static int setcos_select_file(sc_card_t *card,
|
|
|
|
const sc_path_t *in_path, sc_file_t **file)
|
2002-02-11 15:55:34 +00:00
|
|
|
{
|
|
|
|
int r;
|
2005-02-11 20:09:34 +00:00
|
|
|
|
2002-02-11 15:55:34 +00:00
|
|
|
r = iso_ops->select_file(card, in_path, file);
|
2011-07-12 08:49:24 +00:00
|
|
|
/* Certain FINeID cards for organisations return 6A88 instead of 6A82 for missing files */
|
|
|
|
if (card->flags & _FINEID_BROKEN_SELECT_FLAG && r == SC_ERROR_DATA_OBJECT_NOT_FOUND)
|
|
|
|
return SC_ERROR_FILE_NOT_FOUND;
|
2002-02-11 15:55:34 +00:00
|
|
|
if (r)
|
|
|
|
return r;
|
2005-04-04 09:30:54 +00:00
|
|
|
if (file != NULL) {
|
2006-03-09 20:35:19 +00:00
|
|
|
if (card->type == SC_CARD_TYPE_SETCOS_44 ||
|
2006-12-08 14:56:09 +00:00
|
|
|
card->type == SC_CARD_TYPE_SETCOS_NIDEL ||
|
|
|
|
SETCOS_IS_EID_APPLET(card))
|
2005-04-04 09:30:54 +00:00
|
|
|
parse_sec_attr_44(*file, (*file)->sec_attr, (*file)->sec_attr_len);
|
|
|
|
else
|
|
|
|
parse_sec_attr(*file, (*file)->sec_attr, (*file)->sec_attr_len);
|
|
|
|
}
|
2002-02-11 15:55:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
static int setcos_list_files(sc_card_t *card, u8 * buf, size_t buflen)
|
2002-02-26 11:23:25 +00:00
|
|
|
{
|
2005-03-08 20:59:35 +00:00
|
|
|
sc_apdu_t apdu;
|
2002-02-26 11:23:25 +00:00
|
|
|
int r;
|
|
|
|
|
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xAA, 0, 0);
|
2006-03-09 20:35:19 +00:00
|
|
|
if (card->type == SC_CARD_TYPE_SETCOS_44 ||
|
2006-12-08 14:56:09 +00:00
|
|
|
card->type == SC_CARD_TYPE_SETCOS_NIDEL ||
|
|
|
|
SETCOS_IS_EID_APPLET(card))
|
2005-04-04 09:30:54 +00:00
|
|
|
apdu.cla = 0x80;
|
2002-02-26 11:23:25 +00:00
|
|
|
apdu.resp = buf;
|
|
|
|
apdu.resplen = buflen;
|
|
|
|
apdu.le = buflen > 256 ? 256 : buflen;
|
|
|
|
r = sc_transmit_apdu(card, &apdu);
|
2018-11-23 20:54:14 +00:00
|
|
|
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
|
2005-04-04 09:30:54 +00:00
|
|
|
if (card->type == SC_CARD_TYPE_SETCOS_44 && apdu.sw1 == 0x6A && apdu.sw2 == 0x82)
|
|
|
|
return 0; /* no files found */
|
2002-02-26 11:23:25 +00:00
|
|
|
if (apdu.resplen == 0)
|
|
|
|
return sc_check_sw(card, apdu.sw1, apdu.sw2);
|
|
|
|
return apdu.resplen;
|
|
|
|
}
|
|
|
|
|
2005-04-04 09:30:54 +00:00
|
|
|
static int setcos_process_fci(sc_card_t *card, sc_file_t *file,
|
|
|
|
const u8 *buf, size_t buflen)
|
|
|
|
{
|
|
|
|
int r = iso_ops->process_fci(card, file, buf, buflen);
|
|
|
|
|
|
|
|
/* SetCOS 4.4: RSA key file is an internal EF but it's
|
|
|
|
* file descriptor doesn't seem to follow ISO7816. */
|
2006-12-08 14:56:09 +00:00
|
|
|
if (r >= 0 && (card->type == SC_CARD_TYPE_SETCOS_44 ||
|
|
|
|
SETCOS_IS_EID_APPLET(card))) {
|
2005-04-04 09:30:54 +00:00
|
|
|
const u8 *tag;
|
|
|
|
size_t taglen = 1;
|
|
|
|
tag = (u8 *) sc_asn1_find_tag(card->ctx, buf, buflen, 0x82, &taglen);
|
|
|
|
if (tag != NULL && taglen == 1 && *tag == 0x11)
|
|
|
|
file->type = SC_FILE_TYPE_INTERNAL_EF;
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Write internal data, e.g. add default pin-records to pin-file */
|
2005-04-09 13:32:22 +00:00
|
|
|
static int setcos_putdata(struct sc_card *card, struct sc_cardctl_setcos_data_obj* data_obj)
|
2005-04-04 09:30:54 +00:00
|
|
|
{
|
|
|
|
int r;
|
|
|
|
struct sc_apdu apdu;
|
|
|
|
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
|
2005-04-04 09:30:54 +00:00
|
|
|
|
|
|
|
memset(&apdu, 0, sizeof(apdu));
|
|
|
|
apdu.cse = SC_APDU_CASE_3_SHORT;
|
|
|
|
apdu.cla = 0x00;
|
|
|
|
apdu.ins = 0xDA;
|
|
|
|
apdu.p1 = data_obj->P1;
|
|
|
|
apdu.p2 = data_obj->P2;
|
|
|
|
apdu.lc = data_obj->DataLen;
|
|
|
|
apdu.datalen = data_obj->DataLen;
|
|
|
|
apdu.data = data_obj->Data;
|
|
|
|
|
|
|
|
r = sc_transmit_apdu(card, &apdu);
|
2018-11-23 20:54:14 +00:00
|
|
|
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
|
2005-04-04 09:30:54 +00:00
|
|
|
|
|
|
|
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2018-11-23 20:54:14 +00:00
|
|
|
LOG_TEST_RET(card->ctx, r, "PUT_DATA returned error");
|
2005-04-04 09:30:54 +00:00
|
|
|
|
2018-11-22 22:10:49 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, r);
|
2005-04-04 09:30:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Read internal data, e.g. get RSA public key */
|
2005-04-09 13:32:22 +00:00
|
|
|
static int setcos_getdata(struct sc_card *card, struct sc_cardctl_setcos_data_obj* data_obj)
|
2005-04-04 09:30:54 +00:00
|
|
|
{
|
|
|
|
int r;
|
|
|
|
struct sc_apdu apdu;
|
|
|
|
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
|
2005-04-04 09:30:54 +00:00
|
|
|
|
|
|
|
memset(&apdu, 0, sizeof(apdu));
|
|
|
|
apdu.cse = SC_APDU_CASE_2_SHORT;
|
|
|
|
apdu.cla = 0x00;
|
|
|
|
apdu.ins = 0xCA; /* GET DATA */
|
|
|
|
apdu.p1 = data_obj->P1;
|
|
|
|
apdu.p2 = data_obj->P2;
|
|
|
|
apdu.lc = 0;
|
|
|
|
apdu.datalen = 0;
|
|
|
|
apdu.data = data_obj->Data;
|
|
|
|
|
|
|
|
apdu.le = 256;
|
|
|
|
apdu.resp = data_obj->Data;
|
|
|
|
apdu.resplen = data_obj->DataLen;
|
|
|
|
|
|
|
|
r = sc_transmit_apdu(card, &apdu);
|
2018-11-23 20:54:14 +00:00
|
|
|
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
|
2005-04-04 09:30:54 +00:00
|
|
|
|
|
|
|
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2018-11-23 20:54:14 +00:00
|
|
|
LOG_TEST_RET(card->ctx, r, "GET_DATA returned error");
|
2005-04-04 09:30:54 +00:00
|
|
|
|
|
|
|
if (apdu.resplen > data_obj->DataLen)
|
|
|
|
r = SC_ERROR_WRONG_LENGTH;
|
|
|
|
else
|
|
|
|
data_obj->DataLen = apdu.resplen;
|
|
|
|
|
2018-11-22 22:10:49 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, r);
|
2005-04-04 09:30:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Generate or store a key */
|
|
|
|
static int setcos_generate_store_key(sc_card_t *card,
|
|
|
|
struct sc_cardctl_setcos_gen_store_key_info *data)
|
|
|
|
{
|
|
|
|
struct sc_apdu apdu;
|
|
|
|
u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
|
2005-04-09 13:32:22 +00:00
|
|
|
int r, len;
|
2005-04-04 09:30:54 +00:00
|
|
|
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
|
2005-04-04 09:30:54 +00:00
|
|
|
|
2018-04-14 17:38:34 +00:00
|
|
|
/* Setup key-generation parameters */
|
2005-04-04 09:30:54 +00:00
|
|
|
len = 0;
|
|
|
|
if (data->op_type == OP_TYPE_GENERATE)
|
2006-03-09 20:35:19 +00:00
|
|
|
sbuf[len++] = 0x92; /* algo ID: RSA CRT */
|
2005-04-04 09:30:54 +00:00
|
|
|
else
|
2006-03-09 20:35:19 +00:00
|
|
|
sbuf[len++] = 0x9A; /* algo ID: EXTERNALLY GENERATED RSA CRT */
|
2005-04-04 09:30:54 +00:00
|
|
|
sbuf[len++] = 0x00;
|
2006-03-09 20:35:19 +00:00
|
|
|
sbuf[len++] = data->mod_len / 256; /* 2 bytes for modulus bitlength */
|
2005-04-04 09:30:54 +00:00
|
|
|
sbuf[len++] = data->mod_len % 256;
|
|
|
|
|
|
|
|
sbuf[len++] = data->pubexp_len / 256; /* 2 bytes for pubexp bitlength */
|
|
|
|
sbuf[len++] = data->pubexp_len % 256;
|
|
|
|
memcpy(sbuf + len, data->pubexp, (data->pubexp_len + 7) / 8);
|
|
|
|
len += (data->pubexp_len + 7) / 8;
|
|
|
|
|
|
|
|
if (data->op_type == OP_TYPE_STORE) {
|
|
|
|
sbuf[len++] = data->primep_len / 256;
|
|
|
|
sbuf[len++] = data->primep_len % 256;
|
|
|
|
memcpy(sbuf + len, data->primep, (data->primep_len + 7) / 8);
|
|
|
|
len += (data->primep_len + 7) / 8;
|
|
|
|
sbuf[len++] = data->primeq_len / 256;
|
|
|
|
sbuf[len++] = data->primeq_len % 256;
|
|
|
|
memcpy(sbuf + len, data->primeq, (data->primeq_len + 7) / 8);
|
|
|
|
len += (data->primeq_len + 7) / 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x46, 0x00, 0x00);
|
|
|
|
apdu.cla = 0x00;
|
|
|
|
apdu.data = sbuf;
|
|
|
|
apdu.datalen = len;
|
|
|
|
apdu.lc = len;
|
|
|
|
|
|
|
|
r = sc_transmit_apdu(card, &apdu);
|
2018-11-23 20:54:14 +00:00
|
|
|
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
|
2005-04-04 09:30:54 +00:00
|
|
|
|
|
|
|
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2018-11-23 20:54:14 +00:00
|
|
|
LOG_TEST_RET(card->ctx, r, "STORE/GENERATE_KEY returned error");
|
2005-04-04 09:30:54 +00:00
|
|
|
|
2018-11-22 22:10:49 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, r);
|
2005-04-04 09:30:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int setcos_activate_file(sc_card_t *card)
|
|
|
|
{
|
|
|
|
int r;
|
|
|
|
u8 sbuf[2];
|
|
|
|
sc_apdu_t apdu;
|
|
|
|
|
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x44, 0x00, 0x00);
|
|
|
|
apdu.data = sbuf;
|
|
|
|
|
|
|
|
r = sc_transmit_apdu(card, &apdu);
|
2018-11-23 20:54:14 +00:00
|
|
|
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
|
2005-04-04 09:30:54 +00:00
|
|
|
|
|
|
|
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2018-11-23 20:54:14 +00:00
|
|
|
LOG_TEST_RET(card->ctx, r, "ACTIVATE_FILE returned error");
|
2005-04-04 09:30:54 +00:00
|
|
|
|
2018-11-22 22:10:49 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, r);
|
2005-04-04 09:30:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int setcos_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr)
|
|
|
|
{
|
2006-12-08 14:56:09 +00:00
|
|
|
if (card->type != SC_CARD_TYPE_SETCOS_44 && !SETCOS_IS_EID_APPLET(card))
|
2005-04-04 09:30:54 +00:00
|
|
|
return SC_ERROR_NOT_SUPPORTED;
|
|
|
|
|
|
|
|
switch(cmd) {
|
|
|
|
case SC_CARDCTL_SETCOS_PUTDATA:
|
|
|
|
return setcos_putdata(card,
|
|
|
|
(struct sc_cardctl_setcos_data_obj*) ptr);
|
|
|
|
break;
|
|
|
|
case SC_CARDCTL_SETCOS_GETDATA:
|
|
|
|
return setcos_getdata(card,
|
|
|
|
(struct sc_cardctl_setcos_data_obj*) ptr);
|
|
|
|
break;
|
|
|
|
case SC_CARDCTL_SETCOS_GENERATE_STORE_KEY:
|
|
|
|
return setcos_generate_store_key(card,
|
|
|
|
(struct sc_cardctl_setcos_gen_store_key_info *) ptr);
|
|
|
|
case SC_CARDCTL_SETCOS_ACTIVATE_FILE:
|
|
|
|
return setcos_activate_file(card);
|
|
|
|
}
|
|
|
|
|
|
|
|
return SC_ERROR_NOT_SUPPORTED;
|
|
|
|
}
|
|
|
|
|
2005-02-24 11:11:12 +00:00
|
|
|
static struct sc_card_driver *sc_get_driver(void)
|
2001-12-22 20:43:09 +00:00
|
|
|
{
|
2003-02-20 12:51:07 +00:00
|
|
|
struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
|
2001-12-22 20:43:09 +00:00
|
|
|
|
2002-02-26 11:27:49 +00:00
|
|
|
setcos_ops = *iso_drv->ops;
|
|
|
|
setcos_ops.match_card = setcos_match_card;
|
|
|
|
setcos_ops.init = setcos_init;
|
2002-01-20 21:20:09 +00:00
|
|
|
if (iso_ops == NULL)
|
2005-02-11 20:09:34 +00:00
|
|
|
iso_ops = iso_drv->ops;
|
2002-02-26 11:27:49 +00:00
|
|
|
setcos_ops.create_file = setcos_create_file;
|
|
|
|
setcos_ops.set_security_env = setcos_set_security_env;
|
|
|
|
setcos_ops.select_file = setcos_select_file;
|
|
|
|
setcos_ops.list_files = setcos_list_files;
|
2005-04-04 09:30:54 +00:00
|
|
|
setcos_ops.process_fci = setcos_process_fci;
|
|
|
|
setcos_ops.construct_fci = setcos_construct_fci;
|
|
|
|
setcos_ops.card_ctl = setcos_card_ctl;
|
2005-02-11 20:09:34 +00:00
|
|
|
|
|
|
|
return &setcos_drv;
|
2001-12-22 20:43:09 +00:00
|
|
|
}
|
|
|
|
|
2005-02-24 11:11:12 +00:00
|
|
|
struct sc_card_driver *sc_get_setcos_driver(void)
|
2001-12-22 20:43:09 +00:00
|
|
|
{
|
|
|
|
return sc_get_driver();
|
|
|
|
}
|