Merge branch 'master' into gnuk

This commit is contained in:
Nguyễn Hồng Quân 2015-09-13 22:09:59 +08:00
commit 76b6b483c7
28 changed files with 472 additions and 185 deletions

View File

@ -88,4 +88,12 @@ pkgbuild --nopayload --identifier org.opensc-project.mac.uninstall --scripts Mac
# Create .dmg
rm -f OpenSC-@PACKAGE_VERSION@.dmg
TIMESTAMP=$(date +%Y.%m.%d)
hdiutil create -srcfolder Uninstall_OpenSC.pkg -srcfolder OpenSC-@PACKAGE_VERSION@.pkg -volname "OpenSC @PACKAGE_VERSION@ for Mac OS X 10.9+ (${TIMESTAMP})" OpenSC-@PACKAGE_VERSION@.dmg
i=0
while ! hdiutil create -srcfolder Uninstall_OpenSC.pkg -srcfolder OpenSC-@PACKAGE_VERSION@.pkg -volname "OpenSC @PACKAGE_VERSION@ for Mac OS X 10.9+ (${TIMESTAMP})" OpenSC-@PACKAGE_VERSION@.dmg
do
i=$[$i+1]
if [ $i -gt 2 ]
then
exit 1
fi
done

View File

@ -12,3 +12,5 @@ Jenkins CI:
Travis CI:
[![Build Status](https://api.travis-ci.org/OpenSC/OpenSC.png)](https://travis-ci.org/OpenSC/OpenSC)
AppVeyor CI:
[![Build status](https://ci.appveyor.com/api/projects/status/94wjbxyfb0u3cvg9?svg=true)](https://ci.appveyor.com/project/LudovicRousseau/opensc)

71
appveyor.yml Normal file
View File

@ -0,0 +1,71 @@
platform:
- x86
- x64
environment:
matrix:
- VSVER: 14
- VSVER: 12
- VSVER: 10
matrix:
allow_failures:
# not included in AppVeyor right now
- platform: x64
VSVER: 10
# does not currently work
- VSVER: 14
- VSVER: 12
- VSVER: 10
install:
- date /T & time /T
- set PATH=C:\cygwin\bin;%PATH%
- ps: >-
If(!(Test-Path -Path "C:\cccl-1.0" )) {
git clone -q --depth=1 git://github.com/swig/cccl.git "C:\cccl-1.0"
}
- bash -c "cp C:/cccl-1.0/cccl /usr/bin"
- ps: >-
If ($env:Platform -Match "x86") {
$env:JAVA_HOME="C:/Program Files (x86)/Java/jdk1.8.0"
$env:VCVARS_PLATFORM="x86"
$env:ENV_PLATFORM="x86"
$env:OPENSSL="https://slproweb.com/download/Win32OpenSSL-1_0_2d.exe"
$env:NMAKE_FLAGS=""
} Else {
$env:JAVA_HOME="C:/Program Files/Java/jdk1.8.0"
$env:VCVARS_PLATFORM="amd64"
$env:ENV_PLATFORM="x64"
$env:OPENSSL="https://slproweb.com/download/Win64OpenSSL-1_0_2d.exe"
$env:NMAKE_FLAGS="BUILD_ON=WIN64 BUILD_FOR=WIN64"
}
- ps: $env:VSCOMNTOOLS=(Get-Content ("env:VS" + "$env:VSVER" + "0COMNTOOLS"))
- echo "Using Visual Studio %VSVER%.0 at %VSCOMNTOOLS%"
- call "%VSCOMNTOOLS%\..\..\VC\vcvarsall.bat" %VCVARS_PLATFORM%
- call "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /%ENV_PLATFORM% /Release
- appveyor DownloadFile %OPENSSL% -FileName C:\WinOpenSSL.exe
- C:\WinOpenSSL.exe /SILENT /VERYSILENT /SP- /SUPPRESSMSGBOXES /NORESTART /DIR="C:\OpenSSL"
- appveyor DownloadFile "http://prdownloads.sourceforge.net/libpng/zlib128-dll.zip"
- 7z x zlib128-dll.zip -oC:\zlib-1.2.8-dll
- bash -c "which cl.exe"
- bash -c "cl.exe /? 2>&1 | head -n 2"
- bash -c "which csc.exe"
- bash -c "csc.exe /? | head -n 2"
- bash -c "which cccl"
- bash -c "cccl --version"
- uname -a
build_script:
- set CCCL_OPTIONS=--cccl-muffle /W3 /D_CRT_SECURE_NO_DEPRECATE /Dsnprintf=_snprintf
- set CC=cccl
- set CXX=cccl
- set LD=cccl
- bash -c "exec 0</dev/null && find C:/zlib-1.2.8-dll"
- bash -c "exec 0</dev/null && find C:/OpenSSL"
- bash -c "exec 0</dev/null && ./bootstrap"
- bash -c "exec 0</dev/null && ./configure OPENSSL_LIBS='-LC:/OpenSSL/lib -llibeay32' OPENSSL_CFLAGS='-IC:/OpenSSL/include' ZLIB_CFLAGS='-IC:/zlib-1.2.8-dll/include' ZLIB_LIBS='-LC:/zlib-1.2.8-dll/lib -lzdll' LDFLAGS='-LC:/OpenSSL/bin -LC:/zlib-1.2.5-dll' --with-cygwin-native"
- bash -c "exec 0</dev/null && cp win32/winconfig.h config.h && make"
# nmake doesn't work out of the box, all Makefile.mak have way too many hard coded paths
#- bash -c "exec 0</dev/null && ./bootstrap >> /tmp/oscout 2>&1 && ./configure >> /tmp/oscout 2>&1"
#- nmake /f Makefile.mak %NMAKE_FLAGS%

View File

@ -154,6 +154,18 @@
If this option is not given, keys will be printed to standard output.</para></listitem>
</varlistentry>
<varlistentry>
<term>
<option>--raw</option>
</term>
<listitem><para>Changes how <option>--read-data-object</option> prints the content
to standard output. By default, when <option>--raw</option> is not given, it will
print the content in hex notation. If <option>--raw</option> is set, it will print
the binary data directly. This does not affect the output that is written to the
file specified by the <option>--output</option> option. Data written to a file will
always be in raw binary.</para></listitem>
</varlistentry>
<varlistentry>
<term>
<option>--read-certificate</option> <replaceable>cert</replaceable>,
@ -168,7 +180,12 @@
<option>-R</option> <replaceable>data</replaceable>
</term>
<listitem><para>Reads data object with OID, applicationName or label.
</para></listitem>
The content is printed to standard output in hex notation, unless
the <option>--raw</option> option is given.
If an output file is given with the <option>--output</option> option,
the content is additionally written to the file.
Output to the file is always written in raw binary mode, the
<option>--raw</option> only affects standard output behavior.</para></listitem>
</varlistentry>
<varlistentry>

View File

@ -431,6 +431,12 @@ app default {
# Default: false
# use_file_caching = true;
#
# set a path for caching
# so you do not use the env variables and for pam_pkcs11
# (with certificate check) where $HOME is not set
# Default: path in user home
# file_cache_dir = /var/lib/opensc/cache
#
# Use PIN caching?
# Default: true
# use_pin_caching = false;

View File

@ -24,7 +24,7 @@
#include "libscdl.h"
#ifdef WIN32
#ifdef _WIN32
#include <windows.h>
void *sc_dlopen(const char *filename)
{

View File

@ -581,7 +581,7 @@ int sc_transmit_apdu(sc_card_t *card, sc_apdu_t *apdu)
* bytes using command chaining */
size_t len = apdu->datalen;
const u8 *buf = apdu->data;
size_t max_send_size = card->max_send_size;
size_t max_send_size = sc_get_max_send_size(card);
while (len != 0) {
size_t plen;

View File

@ -871,7 +871,7 @@ static int dnie_compose_and_send_apdu(sc_card_t *card, const u8 *path, size_t pa
apdu.lc = pathlen;
apdu.data = path;
apdu.datalen = pathlen;
apdu.le = card->max_recv_size;
apdu.le = sc_get_max_recv_size(card);
if (p1 == 3)
apdu.cse= SC_APDU_CASE_1;

View File

@ -32,13 +32,13 @@
#include "iso7816.h"
static struct sc_atr_table masktech_atrs[] = {
{"3B:89:80:01:4D:54:43:4F:53:70:02:02:05:3B", NULL, NULL,
{"3B:89:80:01:4D:54:43:4F:53:70:02:00:04:31",
"FF:FF:FF:FF:FF:FF:FF:FF:FF:FC:FF:FC:F4:F5" , NULL,
SC_CARD_TYPE_MASKTECH_GENERIC, 0, NULL},
{"3B:88:80:01:00:00:00:00:77:81:81:00:7E", NULL, NULL,
{"3B:88:80:01:00:00:00:00:77:81:80:00:6E", "FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:EE:FF:EE", NULL,
SC_CARD_TYPE_MASKTECH_GENERIC, 0, NULL},
{"3B:9D:13:81:31:60:37:80:31:C0:69:4D:54:43:4F:53:73:02:02:05:41", NULL, NULL,
SC_CARD_TYPE_MASKTECH_GENERIC, 0, NULL},
{"3B:9D:13:81:31:60:37:80:31:C0:69:4D:54:43:4F:53:73:02:01:02:45", NULL, NULL,
{"3B:9D:13:81:31:60:35:80:31:C0:69:4D:54:43:4F:53:73:02:00:00:40",
"FF:FF:FF:FF:FF:FF:FD:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FC:F0:F0", NULL,
SC_CARD_TYPE_MASKTECH_GENERIC, 0, NULL},
{NULL, NULL, NULL, 0, 0, NULL}
};

View File

@ -170,7 +170,7 @@ static int myeid_init(struct sc_card *card)
#endif
/* State that we have an RNG */
card->caps |= SC_CARD_CAP_RNG;
card->caps |= SC_CARD_CAP_RNG | SC_CARD_CAP_ISO7816_PIN_INFO;
card->max_recv_size = 255;
card->max_send_size = 255;
@ -524,42 +524,6 @@ static int myeid_delete_file(struct sc_card *card, const struct sc_path *path)
LOG_FUNC_RETURN(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2));
}
static int myeid_pin_info(sc_card_t *card, struct sc_pin_cmd_data *data,
int *tries_left)
{
sc_apdu_t apdu;
int r;
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x20, 0x00, data->pin_reference);
r = sc_transmit_apdu(card, &apdu);
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
if (r == SC_ERROR_PIN_CODE_INCORRECT) {
data->pin1.tries_left = apdu.sw2 & 0xF;
r = SC_SUCCESS;
} else if (r == SC_ERROR_AUTH_METHOD_BLOCKED) {
data->pin1.tries_left = 0;
r = SC_SUCCESS;
}
LOG_TEST_RET(card->ctx, r, "Check SW error");
if (r == SC_SUCCESS)
{
data->pin1.pad_length = data->pin2.pad_length = 8;
data->pin1.pad_char = data->pin2.pad_char = 0xFF;
}
if (tries_left != NULL) {
*tries_left = data->pin1.tries_left;
}
LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
}
static int myeid_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data,
int *tries_left)
{
@ -567,11 +531,6 @@ static int myeid_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data,
LOG_FUNC_CALLED(card->ctx);
if (data->cmd == SC_PIN_CMD_GET_INFO)
{
return myeid_pin_info(card, data, tries_left);
}
sc_log(card->ctx, "ref (%d), pin1 len(%d), pin2 len (%d)\n",
data->pin_reference, data->pin1.len, data->pin2.len);

View File

@ -2895,7 +2895,7 @@ static int piv_init(sc_card_t *card)
_sc_card_add_ec_alg(card, 256, flags, ext_flags, NULL);
_sc_card_add_ec_alg(card, 384, flags, ext_flags, NULL);
card->caps |= SC_CARD_CAP_RNG;
card->caps |= SC_CARD_CAP_RNG | SC_CARD_CAP_ISO7816_PIN_INFO;
/*
* 800-73-3 cards may have a history object and/or a discovery object
@ -2912,6 +2912,27 @@ static int piv_init(sc_card_t *card)
}
static int piv_check_sw(struct sc_card *card, unsigned int sw1, unsigned int sw2)
{
struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
const u8 *yubikey_neo_atr =
(const u8*)"\x3B\xFC\x13\x00\x00\x81\x31\xFE\x15\x59\x75\x62\x69\x6B\x65\x79\x4E\x45\x4F\x72\x33\xE1";
if (card->atr.len != 22 || memcmp(card->atr.value, yubikey_neo_atr, 22) != 0)
return iso_drv->ops->check_sw(card, sw1, sw2);
/* Handle here the Yubikey NEO, which returns 0x0X rather than 0xCX to
* indicate the number of remaining PIN retries. Perhaps they misread the
* spec and thought 0xCX meant "clear" or "don't care", not a literal 0xC! */
if (sw1 == 0x63U && (sw2 & ~0x0fU) == 0x00U && sw2 != 0) {
sc_log(card->ctx, "Verification failed (remaining tries: %d)", (sw2 & 0x0f));
return SC_ERROR_PIN_CODE_INCORRECT;
}
return iso_drv->ops->check_sw(card, sw1, sw2);
}
static int piv_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data,
int *tries_left)
{
@ -2952,6 +2973,7 @@ static struct sc_card_driver * sc_get_driver(void)
piv_ops.restore_security_env = piv_restore_security_env;
piv_ops.compute_signature = piv_compute_signature;
piv_ops.decipher = piv_decipher;
piv_ops.check_sw = piv_check_sw;
piv_ops.card_ctl = piv_card_ctl;
piv_ops.pin_cmd = piv_pin_cmd;

View File

@ -137,37 +137,6 @@ static int sc_hsm_match_card(struct sc_card *card)
static int sc_hsm_pin_info(sc_card_t *card, struct sc_pin_cmd_data *data,
int *tries_left)
{
sc_apdu_t apdu;
int r;
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x20, 0x00, data->pin_reference);
r = sc_transmit_apdu(card, &apdu);
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
if (r == SC_ERROR_PIN_CODE_INCORRECT) {
data->pin1.tries_left = apdu.sw2 & 0xF;
r = SC_SUCCESS;
} else if (r == SC_ERROR_AUTH_METHOD_BLOCKED) {
data->pin1.tries_left = 0;
r = SC_SUCCESS;
}
LOG_TEST_RET(card->ctx, r, "Check SW error");
if (tries_left != NULL) {
*tries_left = data->pin1.tries_left;
}
LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
}
/*
* Encode 16 hexadecimals of SO-PIN into binary form
* Caller must check length of sopin and provide an 8 byte buffer
@ -206,9 +175,6 @@ static int sc_hsm_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data,
sc_hsm_private_data_t *priv = (sc_hsm_private_data_t *) card->drv_data;
int r;
if (data->cmd == SC_PIN_CMD_GET_INFO) {
return sc_hsm_pin_info(card, data, tries_left);
}
if ((data->cmd == SC_PIN_CMD_VERIFY) && (data->pin_reference == 0x88)) {
if (data->pin1.len != 16)
return SC_ERROR_INVALID_PIN_LENGTH;
@ -249,7 +215,7 @@ static int sc_hsm_read_binary(sc_card_t *card,
cmdbuff[2] = (idx >> 8) & 0xFF;
cmdbuff[3] = idx & 0xFF;
assert(count <= card->max_recv_size);
assert(count <= sc_get_max_recv_size(card));
sc_format_apdu(card, &apdu, SC_APDU_CASE_4, 0xB1, 0x00, 0x00);
apdu.data = cmdbuff;
apdu.datalen = 4;
@ -867,7 +833,7 @@ static int sc_hsm_init_token(sc_card_t *card, sc_cardctl_pkcs11_init_token_t *pa
memset(&ip, 0, sizeof(ip));
ip.dkek_shares = -1;
ip.options[0] = 0x00;
ip.options[0] = 0x01;
ip.options[1] = 0x01;
r = sc_hsm_encode_sopin(params->so_pin, ip.init_code);
LOG_TEST_RET(ctx, r, "SO PIN wrong format");
@ -1058,7 +1024,7 @@ static int sc_hsm_init(struct sc_card *card)
_sc_card_add_ec_alg(card, 256, flags, ext_flags, NULL);
_sc_card_add_ec_alg(card, 320, flags, ext_flags, NULL);
card->caps |= SC_CARD_CAP_RNG|SC_CARD_CAP_APDU_EXT;
card->caps |= SC_CARD_CAP_RNG|SC_CARD_CAP_APDU_EXT|SC_CARD_CAP_ISO7816_PIN_INFO;
card->max_send_size = 1431; // 1439 buffer size - 8 byte TLV because of odd ins in UPDATE BINARY
card->max_recv_size = 0; // Card supports sending with extended length APDU and without limit

View File

@ -50,6 +50,9 @@
#define ID_USER_PIN 0x81 /* User PIN identifier */
#define ID_SO_PIN 0x88 /* Security officer PIN identifier */
#define INIT_RRC_ENABLED 0x01 /* Bit 1 of initialization options */
#define INIT_TRANSPORT_PIN 0x02 /* Bit 2 of initialization options */
/* Information the driver maintains between calls */
typedef struct sc_hsm_private_data {
const sc_security_env_t *env;

View File

@ -135,6 +135,54 @@ static void sc_card_free(sc_card_t *card)
free(card);
}
size_t sc_get_max_recv_size(const sc_card_t *card)
{
size_t max_recv_size;
assert(card != NULL && card->reader != NULL);
max_recv_size = card->max_recv_size;
/* initialize max_recv_size to a meaningfull value */
if (card->caps & SC_CARD_CAP_APDU_EXT) {
if (!max_recv_size)
max_recv_size = 65536;
} else {
if (!max_recv_size)
max_recv_size = 256;
}
/* Override card limitations with reader limitations. */
if (card->reader->max_recv_size != 0
&& (card->reader->max_recv_size < card->max_recv_size))
max_recv_size = card->reader->max_recv_size;
return max_recv_size;
}
size_t sc_get_max_send_size(const sc_card_t *card)
{
size_t max_send_size;
assert(card != NULL && card->reader != NULL);
max_send_size = card->max_send_size;
/* initialize max_send_size to a meaningfull value */
if (card->caps & SC_CARD_CAP_APDU_EXT) {
if (!max_send_size)
max_send_size = 65535;
} else {
if (!max_send_size)
max_send_size = 255;
}
/* Override card limitations with reader limitations. */
if (card->reader->max_send_size != 0
&& (card->reader->max_send_size < card->max_send_size))
max_send_size = card->reader->max_send_size;
return max_send_size;
}
int sc_connect_card(sc_reader_t *reader, sc_card_t **card_out)
{
sc_card_t *card;
@ -252,25 +300,8 @@ int sc_connect_card(sc_reader_t *reader, sc_card_t **card_out)
card->name = card->driver->name;
/* initialize max_send_size/max_recv_size to a meaningfull value */
if (card->caps & SC_CARD_CAP_APDU_EXT) {
if (!card->max_send_size)
card->max_send_size = 65535;
if (!card->max_recv_size)
card->max_recv_size = 65536;
} else {
if (!card->max_send_size)
card->max_send_size = 255;
if (!card->max_recv_size)
card->max_recv_size = 256;
}
/* Override card limitations with reader limitations. */
if (reader->max_recv_size != 0
&& (reader->max_recv_size < card->max_recv_size))
card->max_recv_size = reader->max_recv_size;
if (reader->max_send_size != 0
&& (reader->max_send_size < card->max_send_size))
card->max_send_size = reader->max_send_size;
card->max_recv_size = sc_get_max_recv_size(card);
card->max_send_size = sc_get_max_send_size(card);
sc_log(ctx, "card info name:'%s', type:%i, flags:0x%X, max_send/recv_size:%i/%i",
card->name, card->type, card->flags, card->max_send_size, card->max_recv_size);
@ -489,7 +520,7 @@ int sc_delete_file(sc_card_t *card, const sc_path_t *path)
int sc_read_binary(sc_card_t *card, unsigned int idx,
unsigned char *buf, size_t count, unsigned long flags)
{
size_t max_le = card->max_recv_size;
size_t max_le = sc_get_max_recv_size(card);
int r;
assert(card != NULL && card->ops != NULL && buf != NULL);
@ -539,7 +570,7 @@ int sc_read_binary(sc_card_t *card, unsigned int idx,
int sc_write_binary(sc_card_t *card, unsigned int idx,
const u8 *buf, size_t count, unsigned long flags)
{
size_t max_lc = card->max_send_size;
size_t max_lc = sc_get_max_send_size(card);
int r;
assert(card != NULL && card->ops != NULL && buf != NULL);
@ -582,7 +613,7 @@ int sc_write_binary(sc_card_t *card, unsigned int idx,
int sc_update_binary(sc_card_t *card, unsigned int idx,
const u8 *buf, size_t count, unsigned long flags)
{
size_t max_lc = card->max_send_size;
size_t max_lc = sc_get_max_send_size(card);
int r;
assert(card != NULL && card->ops != NULL && buf != NULL);

View File

@ -880,9 +880,18 @@ int sc_get_cache_dir(sc_context_t *ctx, char *buf, size_t bufsize)
{
char *homedir;
const char *cache_dir;
scconf_block *conf_block = NULL;
#ifdef _WIN32
char temp_path[PATH_MAX];
#endif
conf_block = sc_get_conf_block(ctx, "framework", "pkcs15", 1);
cache_dir = scconf_get_str(conf_block, "file_cache_dir", NULL);
if (cache_dir != NULL) {
if (bufsize <= strlen(cache_dir))
return SC_ERROR_BUFFER_TOO_SMALL;
strcpy(buf, cache_dir);
return SC_SUCCESS;
}
#ifndef _WIN32
cache_dir = ".eid/cache";

View File

@ -21,7 +21,7 @@ typedef unsigned __int8 uint8_t;
#include <wintypes.h>
#endif
// allow unicode built where SCARD_READERSTATE is defined as SCARD_READERSTATEW and SCardGetStatusChange renamed to SCardGetStatusChangeW
#ifdef WIN32
#ifdef _WIN32
#ifdef UNICODE
#define SCARD_READERSTATE SCARD_READERSTATEA
#undef SCardGetStatusChange
@ -201,6 +201,8 @@ typedef LONG (PCSC_API *SCardGetAttrib_t)(SCARDHANDLE hCard, DWORD dwAttrId,\
#define PCSCv2_PART10_PROPERTY_sFirmwareID 8
#define PCSCv2_PART10_PROPERTY_bPPDUSupport 9
#define PCSCv2_PART10_PROPERTY_dwMaxAPDUDataSize 10
#define PCSCv2_PART10_PROPERTY_wIdVendor 11
#define PCSCv2_PART10_PROPERTY_wIdProduct 12
/* structures used (but not defined) in PCSC Part 10:
* "IFDs with Secure Pin Entry Capabilities" */

View File

@ -35,15 +35,15 @@ static void fixup_transceive_length(const struct sc_card *card,
{
assert(card != NULL && apdu != NULL);
if (apdu->lc > card->max_send_size) {
if (apdu->lc > sc_get_max_send_size(card)) {
/* The lower layers will automatically do chaining */
apdu->flags |= SC_APDU_FLAGS_CHAINING;
}
if (apdu->le > card->max_recv_size) {
if (apdu->le > sc_get_max_recv_size(card)) {
/* The lower layers will automatically do a GET RESPONSE, if possible.
* All other workarounds must be carried out by the upper layers. */
apdu->le = card->max_recv_size;
apdu->le = sc_get_max_recv_size(card);
}
}
@ -526,7 +526,7 @@ iso7816_select_file(struct sc_card *card, const struct sc_path *in_path, struct
apdu.p2 = 0; /* first record, return FCI */
apdu.resp = buf;
apdu.resplen = sizeof(buf);
apdu.le = card->max_recv_size < 256 ? card->max_recv_size : 256;
apdu.le = sc_get_max_recv_size(card) < 256 ? sc_get_max_recv_size(card) : 256;
}
else {
apdu.p2 = 0x0C; /* first record, return nothing */
@ -719,8 +719,8 @@ iso7816_get_response(struct sc_card *card, size_t *count, u8 *buf)
size_t rlen;
/* request at most max_recv_size bytes */
if (*count > card->max_recv_size)
rlen = card->max_recv_size;
if (*count > sc_get_max_recv_size(card))
rlen = sc_get_max_recv_size(card);
else
rlen = *count;
@ -969,6 +969,7 @@ iso7816_build_pin_apdu(struct sc_card *card, struct sc_apdu *apdu,
struct sc_pin_cmd_data *data, u8 *buf, size_t buf_len)
{
int r, len = 0, pad = 0, use_pin_pad = 0, ins, p1 = 0;
int cse = SC_APDU_CASE_3_SHORT;
switch (data->pin_type) {
case SC_AC_CHV:
@ -1034,11 +1035,16 @@ iso7816_build_pin_apdu(struct sc_card *card, struct sc_apdu *apdu,
p1 |= 0x01;
}
break;
case SC_PIN_CMD_GET_INFO:
ins = 0x20;
/* No data to send or to receive */
cse = SC_APDU_CASE_1;
break;
default:
return SC_ERROR_NOT_SUPPORTED;
}
sc_format_apdu(card, apdu, SC_APDU_CASE_3_SHORT, ins, p1, data->pin_reference);
sc_format_apdu(card, apdu, cse, ins, p1, data->pin_reference);
apdu->lc = len;
apdu->datalen = len;
apdu->data = buf;
@ -1058,6 +1064,16 @@ iso7816_pin_cmd(struct sc_card *card, struct sc_pin_cmd_data *data, int *tries_l
if (tries_left)
*tries_left = -1;
/* Many cards do support PIN status queries, but some cards don't and
* mistakenly count the command as a failed PIN attempt, so for now we
* whitelist cards with this flag. In future this may be reduced to a
* blacklist, subject to testing more cards. */
if (data->cmd == SC_PIN_CMD_GET_INFO &&
!(card->caps & SC_CARD_CAP_ISO7816_PIN_INFO)) {
sc_log(card->ctx, "Card does not support PIN status queries");
return SC_ERROR_NOT_SUPPORTED;
}
/* See if we've been called from another card driver, which is
* passing an APDU to us (this allows to write card drivers
* whose PIN functions behave "mostly like ISO" except in some
@ -1071,7 +1087,7 @@ iso7816_pin_cmd(struct sc_card *card, struct sc_pin_cmd_data *data, int *tries_l
}
apdu = data->apdu;
if (!(data->flags & SC_PIN_CMD_USE_PINPAD)) {
if (!(data->flags & SC_PIN_CMD_USE_PINPAD) || data->cmd == SC_PIN_CMD_GET_INFO) {
/* Transmit the APDU to the card */
r = sc_transmit_apdu(card, apdu);
@ -1101,12 +1117,23 @@ iso7816_pin_cmd(struct sc_card *card, struct sc_pin_cmd_data *data, int *tries_l
data->apdu = NULL;
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
if (apdu->sw1 == 0x63) {
if ((apdu->sw2 & 0xF0) == 0xC0 && tries_left != NULL)
*tries_left = apdu->sw2 & 0x0F;
return SC_ERROR_PIN_CODE_INCORRECT;
r = sc_check_sw(card, apdu->sw1, apdu->sw2);
if (data->cmd == SC_PIN_CMD_GET_INFO) {
if (r == SC_ERROR_PIN_CODE_INCORRECT) {
data->pin1.tries_left = apdu->sw2 & 0xF;
r = SC_SUCCESS;
} else if (r == SC_ERROR_AUTH_METHOD_BLOCKED) {
data->pin1.tries_left = 0;
r = SC_SUCCESS;
}
if (tries_left != NULL) {
*tries_left = data->pin1.tries_left;
}
}
return sc_check_sw(card, apdu->sw1, apdu->sw2);
return r;
}

View File

@ -439,6 +439,9 @@ struct sc_reader_operations {
/* Card has on-board random number source. */
#define SC_CARD_CAP_RNG 0x00000004
/* Card supports ISO7816 PIN status queries using an empty VERIFY */
#define SC_CARD_CAP_ISO7816_PIN_INFO 0x00000008
/* Use the card's ACs in sc_pkcs15init_authenticate(),
* instead of relying on the ACL info in the profile files. */
#define SC_CARD_CAP_USE_FCI_AC 0x00000010
@ -910,6 +913,30 @@ int sc_lock(struct sc_card *card);
*/
int sc_unlock(struct sc_card *card);
/**
* @brief Calculate the maximum size of R-APDU payload (Ne).
*
* Takes card limitations into account such as extended length support as well
* as the reader's limitation for data transfer.
*
* @param card Initialized card object with its reader
*
* @return maximum Ne
*/
size_t sc_get_max_recv_size(const sc_card_t *card);
/**
* @brief Calculate the maximum size of C-APDU payload (Nc).
*
* Takes card limitations into account such as extended length support as well
* as the reader's limitation for data transfer.
*
* @param card
*
* @return maximum Nc
*/
size_t sc_get_max_send_size(const sc_card_t *card);
/********************************************************************/
/* ISO 7816-4 related functions */

View File

@ -424,8 +424,9 @@ fix_starcos_pkcs15_card(struct sc_pkcs15_card *p15card)
if (strcmp(p15card->card->driver->short_name,"cardos") == 0) {
/* D-Trust cards (D-TRUST, D-SIGN) */
if (strstr(p15card->tokeninfo->label,"D-TRUST") != NULL
|| strstr(p15card->tokeninfo->label,"D-SIGN") != NULL) {
if (p15card->tokeninfo->label
&& (strstr(p15card->tokeninfo->label,"D-TRUST") != NULL
|| strstr(p15card->tokeninfo->label,"D-SIGN") != NULL)) {
/* D-TRUST Card 2.0 2cc (standard cards, which always add
* SHA1 prefix itself */

View File

@ -880,6 +880,46 @@ err:
return max_data;
}
static int part10_get_vendor_product(struct sc_reader *reader,
SCARDHANDLE card_handle, int *id_vendor, int *id_product)
{
u8 rbuf[256];
DWORD rcount = sizeof rbuf;
struct pcsc_private_data *priv;
/* 0 means no limitations */
int this_vendor = -1, this_product = -1;
if (!reader)
return SC_ERROR_INVALID_ARGUMENTS;
priv = GET_PRIV_DATA(reader);
if (!priv)
return SC_ERROR_INVALID_ARGUMENTS;
if (priv->get_tlv_properties && priv->gpriv) {
if (SCARD_S_SUCCESS != priv->gpriv->SCardControl(card_handle,
priv->get_tlv_properties, NULL, 0, rbuf, sizeof(rbuf),
&rcount)) {
sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL,
"PC/SC v2 part 10: Get TLV properties failed!");
return SC_ERROR_TRANSMIT_FAILED;
}
this_vendor = part10_find_property_by_tag(rbuf, rcount,
PCSCv2_PART10_PROPERTY_wIdVendor);
this_product = part10_find_property_by_tag(rbuf, rcount,
PCSCv2_PART10_PROPERTY_wIdProduct);
}
sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL, "id_vendor=%04x id_product=%04x", this_vendor, this_product);
if (id_vendor)
*id_vendor = this_vendor;
if (id_product)
*id_product = this_product;
return SC_SUCCESS;
}
static void detect_reader_features(sc_reader_t *reader, SCARDHANDLE card_handle) {
sc_context_t *ctx = reader->ctx;
struct pcsc_global_private_data *gpriv = (struct pcsc_global_private_data *) ctx->reader_drv_data;
@ -889,7 +929,6 @@ static void detect_reader_features(sc_reader_t *reader, SCARDHANDLE card_handle)
PCSC_TLV_STRUCTURE *pcsc_tlv;
LONG rv;
const char *log_disabled = "but it's disabled in configuration file";
const char *broken_readers[] = {"HP USB Smart Card Keyboard"};
SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_NORMAL);
@ -957,14 +996,6 @@ static void detect_reader_features(sc_reader_t *reader, SCARDHANDLE card_handle)
}
}
/* Ignore advertised pinpad capability on readers known to be broken. Trac #340 */
for (i = 0; i < sizeof(broken_readers)/sizeof(broken_readers[0]); i++) {
if (strstr(reader->name, broken_readers[i]) && (reader->capabilities & SC_READER_CAP_PIN_PAD)) {
sc_log(ctx, "%s has a broken pinpad, ignoring", reader->name);
reader->capabilities &= ~SC_READER_CAP_PIN_PAD;
}
}
/* Detect display */
if (priv->pin_properties_ioctl) {
rcount = sizeof(rbuf);
@ -1004,10 +1035,15 @@ static void detect_reader_features(sc_reader_t *reader, SCARDHANDLE card_handle)
}
}
/* Set reader max_send_size and max_recv_size based on detected max_data */
if (priv->get_tlv_properties) {
reader->max_send_size = part10_detect_max_data(reader, card_handle);
/* Set reader max_send_size and max_recv_size based on
* detected max_data */
reader->max_send_size = part10_detect_max_data(reader,
card_handle);
reader->max_recv_size = reader->max_send_size;
/* debug the product and vendor ID of the reader */
part10_get_vendor_product(reader, card_handle, NULL, NULL);
}
}

View File

@ -12,7 +12,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/src
OPENSC_PKCS11_INC = sc-pkcs11.h pkcs11.h pkcs11-opensc.h
OPENSC_PKCS11_SRC = pkcs11-global.c pkcs11-session.c pkcs11-object.c misc.c slot.c \
mechanism.c openssl.c framework-pkcs15.c \
framework-pkcs15init.c debug.c opensc-pkcs11.exports \
framework-pkcs15init.c debug.c pkcs11.exports \
pkcs11-display.c pkcs11-display.h
OPENSC_PKCS11_LIBS = \
$(top_builddir)/src/libopensc/libopensc.la \
@ -23,23 +23,23 @@ OPENSC_PKCS11_LIBS = \
opensc_pkcs11_la_SOURCES = $(OPENSC_PKCS11_SRC) $(OPENSC_PKCS11_INC)
opensc_pkcs11_la_LIBADD = $(OPENSC_PKCS11_LIBS)
opensc_pkcs11_la_LDFLAGS = $(AM_LDFLAGS) \
-export-symbols "$(srcdir)/opensc-pkcs11.exports" \
-export-symbols "$(srcdir)/pkcs11.exports" \
-module -shared -avoid-version -no-undefined
onepin_opensc_pkcs11_la_SOURCES = $(OPENSC_PKCS11_SRC) $(OPENSC_PKCS11_INC)
onepin_opensc_pkcs11_la_CFLAGS = -DMODULE_APP_NAME=\"onepin-opensc-pkcs11\"
onepin_opensc_pkcs11_la_LIBADD = $(OPENSC_PKCS11_LIBS)
onepin_opensc_pkcs11_la_LDFLAGS = $(AM_LDFLAGS) \
-export-symbols "$(srcdir)/opensc-pkcs11.exports" \
-export-symbols "$(srcdir)/pkcs11.exports" \
-module -shared -avoid-version -no-undefined
pkcs11_spy_la_SOURCES = pkcs11-spy.c pkcs11-display.c pkcs11-display.h pkcs11-spy.exports
pkcs11_spy_la_SOURCES = pkcs11-spy.c pkcs11-display.c pkcs11-display.h pkcs11.exports
pkcs11_spy_la_LIBADD = \
$(top_builddir)/src/common/libpkcs11.la \
$(top_builddir)/src/common/libscdl.la \
$(OPTIONAL_OPENSSL_LIBS)
pkcs11_spy_la_LDFLAGS = $(AM_LDFLAGS) \
-export-symbols "$(srcdir)/pkcs11-spy.exports" \
-export-symbols "$(srcdir)/pkcs11.exports" \
-module -shared -avoid-version -no-undefined
if WIN32

View File

@ -16,14 +16,14 @@ all: versioninfo-pkcs11.res $(TARGET1) $(TARGET2) $(TARGET3) versioninfo-pkcs11-
$(TARGET1): $(OBJECTS) ..\libopensc\opensc_a.lib ..\pkcs15init\pkcs15init.lib
echo LIBRARY $* > $*.def
echo EXPORTS >> $*.def
type opensc-pkcs11.exports >> $*.def
type pkcs11.exports >> $*.def
link $(LINKFLAGS) /dll /def:$*.def /implib:$*.lib /out:$(TARGET1) $(OBJECTS) ..\libopensc\opensc_a.lib ..\pkcs15init\pkcs15init.lib $(OPENSSL_LIB) gdi32.lib
if EXIST $(TARGET1).manifest mt -manifest $(TARGET1).manifest -outputresource:$(TARGET1);2
$(TARGET2): $(OBJECTS) ..\libopensc\opensc_a.lib ..\pkcs15init\pkcs15init.lib
echo LIBRARY $* > $*.def
echo EXPORTS >> $*.def
type opensc-pkcs11.exports >> $*.def
type pkcs11.exports >> $*.def
del pkcs11-global.obj
cl $(CODE_OPTIMIZATION) $(COPTS) /DMODULE_APP_NAME=\"onepin-opensc-pkcs11\" /c pkcs11-global.c
link $(LINKFLAGS) /dll /def:$*.def /implib:$*.lib /out:$(TARGET2) $(OBJECTS) ..\libopensc\opensc_a.lib ..\pkcs15init\pkcs15init.lib $(OPENSSL_LIB) gdi32.lib
@ -32,6 +32,6 @@ $(TARGET2): $(OBJECTS) ..\libopensc\opensc_a.lib ..\pkcs15init\pkcs15init.lib
$(TARGET3): $(OBJECTS3) ..\libopensc\opensc.lib
echo LIBRARY $* > $*.def
echo EXPORTS >> $*.def
type $*.exports >> $*.def
type pkcs11.exports >> $*.def
link $(LINKFLAGS) /dll /def:$*.def /implib:$*.lib /out:$(TARGET3) $(OBJECTS3) ..\libopensc\opensc.lib ..\common\libpkcs11.lib ..\common\libscdl.lib $(OPENSSL_LIB) gdi32.lib advapi32.lib
if EXIST $(TARGET3).manifest mt -manifest $(TARGET3).manifest -outputresource:$(TARGET3);2

View File

@ -1 +0,0 @@
C_GetFunctionList

View File

@ -1 +0,0 @@
C_GetFunctionList

View File

@ -0,0 +1,3 @@
C_GetFunctionList
C_Initialize
C_Finalize

View File

@ -50,6 +50,7 @@ static char * opt_auth_id = NULL;
static char * opt_reader = NULL;
static char * opt_cert = NULL;
static char * opt_data = NULL;
static int opt_raw = 0;
static char * opt_pubkey = NULL;
static char * opt_outfile = NULL;
static char * opt_bind_to_aid = NULL;
@ -82,6 +83,7 @@ enum {
OPT_LIST_APPLICATIONS,
OPT_LIST_SKEYS,
OPT_NO_PROMPT,
OPT_RAW,
};
#define NELEMENTS(x) (sizeof(x)/sizeof((x)[0]))
@ -94,6 +96,7 @@ static const struct option options[] = {
{ "read-certificate", required_argument, NULL, 'r' },
{ "list-certificates", no_argument, NULL, 'c' },
{ "read-data-object", required_argument, NULL, 'R' },
{ "raw", no_argument, NULL, OPT_RAW },
{ "list-data-objects", no_argument, NULL, 'C' },
{ "list-pins", no_argument, NULL, OPT_LIST_PINS },
{ "list-secret-keys", no_argument, NULL, OPT_LIST_SKEYS },
@ -130,6 +133,7 @@ static const char *option_help[] = {
"Reads certificate with ID <arg>",
"Lists certificates",
"Reads data object with OID, applicationName or label <arg>",
"Outputs raw 8 bit data to stdout. File output will not be affected by this, it always uses raw mode.",
"Lists data objects",
"Lists PIN codes",
"Lists secret keys",
@ -346,18 +350,28 @@ print_data_object(const char *kind, const u8*data, size_t data_len)
}
for (i=0; i < data_len; i++)
fprintf(outf, "%c", data[i]);
printf("Dumping (%lu bytes) to file <%s>: <",
(unsigned long) data_len, opt_outfile);
for (i=0; i < data_len; i++)
printf(" %02X", data[i]);
printf(" >\n");
if (opt_raw) {
for (i=0; i < data_len; i++)
printf("%c", data[i]);
} else {
printf("Dumping (%lu bytes) to file <%s>: <",
(unsigned long) data_len, opt_outfile);
for (i=0; i < data_len; i++)
printf(" %02X", data[i]);
printf(" >\n");
}
fclose(outf);
} else {
printf("%s (%lu bytes): <",
kind, (unsigned long) data_len);
for (i=0; i < data_len; i++)
printf(" %02X", data[i]);
printf(" >\n");
if (opt_raw) {
for (i=0; i < data_len; i++)
printf("%c", data[i]);
} else {
printf("%s (%lu bytes): <",
kind, (unsigned long) data_len);
for (i=0; i < data_len; i++)
printf(" %02X", data[i]);
printf(" >\n");
}
}
return 0;
}
@ -1564,11 +1578,47 @@ static int read_and_cache_file(const sc_path_t *path)
printf("out of memory!");
return -1;
}
r = sc_read_binary(card, 0, buf, size, 0);
if (r < 0) {
fprintf(stderr, "sc_read_binary() failed: %s\n", sc_strerror(r));
free(buf);
return -1;
if (tfile->ef_structure == SC_FILE_EF_LINEAR_VARIABLE_TLV) {
int i;
size_t l, record_len;
unsigned char *head = buf;
for (i=1; ; i++) {
l = size - (head - buf);
if (l > 256) { l = 256; }
r = sc_read_record(p15card->card, i, head, l, SC_RECORD_BY_REC_NR);
if (r == SC_ERROR_RECORD_NOT_FOUND) {
r = 0;
break;
}
if (r < 0) {
free(buf);
return -1;
}
if (r < 2)
break;
record_len = head[1];
if (record_len != 0xff) {
memmove(head,head+2,r-2);
head += (r-2);
}
else {
if (r < 4)
break;
memmove(head,head+4,r-4);
head += (r-4);
}
}
r = head - buf;
} else {
r = sc_read_binary(card, 0, buf, size, 0);
if (r < 0) {
fprintf(stderr, "sc_read_binary() failed: %s\n", sc_strerror(r));
free(buf);
return -1;
}
}
r = sc_pkcs15_cache_file(p15card, path, buf, r);
if (r) {
@ -1895,6 +1945,9 @@ int main(int argc, char * const argv[])
do_read_data_object = 1;
action_count++;
break;
case OPT_RAW:
opt_raw = 1;
break;
case 'C':
do_list_data_objects = 1;
action_count++;

View File

@ -461,27 +461,75 @@ static void print_info(sc_card_t *card, sc_file_t *file)
struct sc_pin_cmd_data data;
sc_cardctl_sc_hsm_dkek_t dkekinfo;
u8 major, minor;
u8 major, minor, opt;
major = file->prop_attr[file->prop_attr_len - 2];
minor = file->prop_attr[file->prop_attr_len - 1];
printf("Version : %d.%d\n", (int)major, (int)minor);
/* Try to update PIN info from card */
memset(&data, 0, sizeof(data));
data.cmd = SC_PIN_CMD_GET_INFO;
data.pin_type = SC_AC_CHV;
data.pin_reference = ID_USER_PIN;
if (file->prop_attr_len > 2) { /* Version >= 2.0 */
opt = file->prop_attr[file->prop_attr_len - 4];
if (opt != 0) {
printf("Config options :\n");
if (opt & INIT_RRC_ENABLED) {
printf(" User PIN reset with SO-PIN enabled\n");
}
if (opt & INIT_TRANSPORT_PIN) {
printf(" Transport-PIN mode enabled\n");
}
}
r = sc_pin_cmd(card, &data, &tries_left);
/* Try to update SO-PIN info from card */
memset(&data, 0, sizeof(data));
data.cmd = SC_PIN_CMD_GET_INFO;
data.pin_type = SC_AC_CHV;
data.pin_reference = ID_SO_PIN;
if (r == SC_ERROR_REF_DATA_NOT_USABLE) {
printf("SmartCard-HSM has never been initialized. Please use --initialize to set SO-PIN and user PIN.\n");
} else {
if (tries_left == 0) {
printf("User PIN locked\n");
r = sc_pin_cmd(card, &data, &tries_left);
if (r == SC_ERROR_DATA_OBJECT_NOT_FOUND) {
printf("SmartCard-HSM has never been initialized. Please use --initialize to set SO-PIN and user PIN.\n");
} else {
printf("User PIN tries left : %d\n", tries_left);
if (tries_left == 0) {
printf("SO-PIN locked\n");
} else {
printf("SO-PIN tries left : %d\n", tries_left);
}
/* Try to update PIN info from card */
memset(&data, 0, sizeof(data));
data.cmd = SC_PIN_CMD_GET_INFO;
data.pin_type = SC_AC_CHV;
data.pin_reference = ID_USER_PIN;
r = sc_pin_cmd(card, &data, &tries_left);
if (r == SC_ERROR_CARD_CMD_FAILED) {
printf("Public key authentication active.\n");
} else if (r == SC_ERROR_REF_DATA_NOT_USABLE) {
printf("Transport-PIN active. Please change to user selected PIN first.\n");
} else {
if (tries_left == 0) {
printf("User PIN locked\n");
} else {
printf("User PIN tries left : %d\n", tries_left);
}
}
}
} else { /* Version < 2.0 */
/* Try to update PIN info from card */
memset(&data, 0, sizeof(data));
data.cmd = SC_PIN_CMD_GET_INFO;
data.pin_type = SC_AC_CHV;
data.pin_reference = ID_USER_PIN;
r = sc_pin_cmd(card, &data, &tries_left);
if (r == SC_ERROR_REF_DATA_NOT_USABLE) {
printf("SmartCard-HSM has never been initialized. Please use --initialize to set SO-PIN and user PIN.\n");
} else {
if (tries_left == 0) {
printf("User PIN locked\n");
} else {
printf("User PIN tries left : %d\n", tries_left);
}
}
}

View File

@ -78,14 +78,12 @@ MD_REGISTRATION minidriver_registration[] = {
21, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}},
/* from card-masktech.c */
/* note: the card name MUST be unique */
{TEXT("MaskTech smart card (a)"), {0x3b,0x89,0x80,0x01,0x4d,0x54,0x43,0x4f,0x53,0x70,0x02,0x02,0x05,0x3b},
14, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}},
{TEXT("MaskTech smart card (b)"), {0x3B,0x9D,0x13,0x81,0x31,0x60,0x37,0x80,0x31,0xC0,0x69,0x4D,0x54,0x43,0x4F,0x53,0x73,0x02,0x02,0x05,0x41},
21, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}},
{TEXT("MaskTech smart card (c)"), {0x3B,0x88,0x80,0x01,0x00,0x00,0x00,0x00,0x77,0x81,0x81,0x00,0x7E},
13, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}},
{TEXT("MaskTech smart card (d)"), {0x3B,0x9D,0x13,0x81,0x31,0x60,0x37,0x80,0x31,0xC0,0x69,0x4D,0x54,0x43,0x4F,0x53,0x73,0x02,0x01,0x02,0x45},
21, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}},
{TEXT("MaskTech smart card (a)"), {0x3b,0x89,0x80,0x01,0x4d,0x54,0x43,0x4f,0x53,0x70,0x02,0x00,0x04,0x31},
14, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xff,0xfc,0xf4,0xf5}},
{TEXT("MaskTech smart card (b)"), {0x3B,0x9D,0x13,0x81,0x31,0x60,0x35,0x80,0x31,0xC0,0x69,0x4D,0x54,0x43,0x4F,0x53,0x73,0x02,0x00,0x00,0x40},
21, {0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xf0,0xf0}},
{TEXT("MaskTech smart card (c)"), {0x3B,0x88,0x80,0x01,0x00,0x00,0x00,0x00,0x77,0x81,0x80,0x00,0x6E},
13, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xee,0xff,0xee}},
};