commit changes: cardos-info is now cardos-tool.
and it knows to format, at least some cards/tokens with cardos. git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@3566 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
parent
021dfaccba
commit
5c29dcdb94
|
@ -1,28 +1,28 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<refentry id="cardos-info">
|
||||
<refentry id="cardos-tool">
|
||||
<refmeta>
|
||||
<refentrytitle>cardos-info</refentrytitle>
|
||||
<refentrytitle>cardos-tool</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
<refmiscinfo>opensc</refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>cardos-info</refname>
|
||||
<refpurpose>displays information about Card OS-based security tokens
|
||||
<refname>cardos-tool</refname>
|
||||
<refpurpose>displays information about Card OS-based security tokens or format them
|
||||
</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsect1>
|
||||
<title>Synopsis</title>
|
||||
<para>
|
||||
<command>cardos-info</command> [OPTIONS]
|
||||
<command>cardos-tool</command> [OPTIONS]
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
<para>
|
||||
The <command>cardos-info</command> utility is used to display information about
|
||||
The <command>cardos-tool</command> utility is used to display information about
|
||||
smart cards and similar security tokens based on Siemens Card/OS M4.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
@ -31,9 +31,17 @@ smart cards and similar security tokens based on Siemens Card/OS M4.
|
|||
<title>Options</title>
|
||||
<para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>--info</option>, <option>-i</option></term>
|
||||
<listitem><para>Display information about the card or token.</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--format</option>, <option>-f</option></term>
|
||||
<listitem><para>Format the card or token.</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--reader</option> number, <option>-r</option> number</term>
|
||||
<listitem><para>Display information about the token in reader number <varname>number</varname>.
|
||||
<listitem><para>Specify the reader number <varname>number</varname> to use.
|
||||
The default is reader 0.</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
|
|
|
@ -7,7 +7,7 @@ EXTRA_DIST = Makefile.mak
|
|||
|
||||
noinst_HEADERS = util.h
|
||||
bin_PROGRAMS = opensc-tool opensc-explorer pkcs15-tool pkcs15-crypt \
|
||||
pkcs11-tool cardos-info eidenv rutoken-tool
|
||||
pkcs11-tool cardos-tool eidenv rutoken-tool cardos-info
|
||||
if ENABLE_OPENSSL
|
||||
bin_PROGRAMS += cryptoflex-tool pkcs15-init netkey-tool piv-tool
|
||||
endif
|
||||
|
@ -34,7 +34,8 @@ cryptoflex_tool_LDADD = $(OPTIONAL_OPENSSL_LIBS)
|
|||
pkcs15_init_SOURCES = pkcs15-init.c util.c
|
||||
pkcs15_init_LDADD = $(OPTIONAL_OPENSSL_LIBS) \
|
||||
$(top_builddir)/src/pkcs15init/libpkcs15init.la
|
||||
cardos_info_SOURCES = cardos-info.c util.c
|
||||
cardos_info_SOURCES =
|
||||
cardos_tool_SOURCES = cardos-tool.c util.c
|
||||
eidenv_SOURCES = eidenv.c
|
||||
netkey_tool_SOURCES = netkey-tool.c
|
||||
netkey_tool_LDADD = $(OPTIONAL_OPENSSL_LIBS)
|
||||
|
@ -50,7 +51,7 @@ pkcs11_tool_SOURCES += versioninfo.rc
|
|||
pkcs15_crypt_SOURCES += versioninfo.rc
|
||||
cryptoflex_tool_SOURCES += versioninfo.rc
|
||||
pkcs15_init_SOURCES += versioninfo.rc
|
||||
cardos_info_SOURCES += versioninfo.rc
|
||||
cardos_tool_SOURCES += versioninfo.rc
|
||||
eidenv_SOURCES += versioninfo.rc
|
||||
netkey_tool_SOURCES += versioninfo.rc
|
||||
rutoken_tool_SOURCES += versioninfo.rc
|
||||
|
@ -61,3 +62,14 @@ endif
|
|||
versioninfo.rc:
|
||||
sed 's/@@FILE_DESCRIPTION@@/OpenSC Utility/g' \
|
||||
"$(top_builddir)/win32/versioninfo.rc.in" > versioninfo.rc
|
||||
|
||||
if WIN32
|
||||
cardos-info.bat:
|
||||
echo "@echo off" > cardos-info.bat
|
||||
echo "echo running cardos-tool --info" >> cardos-info.bat
|
||||
echo "cardos-tool --info >> cardos-info.bat
|
||||
else
|
||||
cardos-info:
|
||||
printf '#!/bin/sh\necho "running cardos-tool --info $*"\nexec cardos-tool --info $*\n' > cardos-info
|
||||
chmod +x cardos-info
|
||||
endif
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
/*
|
||||
* cardos-info.c: Info about Card OS based tokens
|
||||
* cardos-tool.c: Tool and Info about Card OS based tokens
|
||||
*
|
||||
* Copyright (C) 2008 Andreas Jellinghaus <aj@dungeon.inka.de>
|
||||
* Copyright (C) 2007 Jean-Pierre Szikora <jean-pierre.szikora@uclouvain.be>
|
||||
* Copyright (C) 2003 Andreas Jellinghaus <aj@dungeon.inka.de>
|
||||
* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
|
||||
*
|
||||
|
@ -31,23 +33,35 @@
|
|||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef ENABLE_OPENSSL
|
||||
#include <openssl/des.h>
|
||||
#endif
|
||||
|
||||
#include <opensc/opensc.h>
|
||||
#include "util.h"
|
||||
|
||||
static const char *app_name = "cardos-info";
|
||||
static const char *app_name = "cardos-tool";
|
||||
|
||||
static int opt_reader = -1, opt_debug = 0, opt_wait = 0;
|
||||
static int verbose = 0;
|
||||
|
||||
static const struct option options[] = {
|
||||
{"info", 0, NULL, 'i'},
|
||||
{"format", 0, NULL, 'f'},
|
||||
{"startkey", 1, NULL, 's'},
|
||||
{"reader", 1, NULL, 'r'},
|
||||
{"card-driver", 1, NULL, 'c'},
|
||||
{"wait", 0, NULL, 'w'},
|
||||
{"verbose", 0, NULL, 'v'},
|
||||
{"debug", 0, NULL, 'd'},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
static const char *option_help[] = {
|
||||
"Print information about this card",
|
||||
"Format this card erasing all content",
|
||||
"Specify startkey for format",
|
||||
"Uses reader number <arg> [0]",
|
||||
"Forces the use of driver <arg> [auto-detect]",
|
||||
"Wait for a card to be inserted",
|
||||
|
@ -148,11 +162,11 @@ static int cardos_info(void)
|
|||
} else if (apdu.resp[0] == 0xc8 && apdu.resp[1] == 0x07) {
|
||||
printf(" (that's CardOS M4.3)\n");
|
||||
} else if (apdu.resp[0] == 0xc8 && apdu.resp[1] == 0x08) {
|
||||
printf(" (that's CardOS M4.3b)\n");
|
||||
printf(" (that's CardOS M4.3B)\n");
|
||||
} else if (apdu.resp[0] == 0xc8 && apdu.resp[1] == 0x09) {
|
||||
printf(" (that's CardOS M4.2b)\n");
|
||||
printf(" (that's CardOS M4.2B)\n");
|
||||
} else if (apdu.resp[0] == 0xc8 && apdu.resp[1] == 0x0B) {
|
||||
printf(" (that's CardOS M4.2c)\n");
|
||||
printf(" (that's CardOS M4.2C)\n");
|
||||
} else {
|
||||
printf(" (unknown Version)\n");
|
||||
}
|
||||
|
@ -185,6 +199,8 @@ static int cardos_info(void)
|
|||
printf("%d (administration)\n", rbuf[0]);
|
||||
} else if (rbuf[0] == 0x10) {
|
||||
printf("%d (operational)\n", rbuf[0]);
|
||||
} else if (rbuf[0] == 0x29) {
|
||||
printf("%d (erase in progress)\n", rbuf[0]);
|
||||
} else {
|
||||
printf("%d (unknown)\n", rbuf[0]);
|
||||
}
|
||||
|
@ -350,15 +366,472 @@ static int cardos_info(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_OPENSSL
|
||||
static int cardos_sm4h(unsigned char *in, size_t inlen, unsigned char
|
||||
*out, size_t outlen, unsigned char *key, size_t keylen) {
|
||||
/* using a buffer with an APDU, build an SM 4h APDU for cardos */
|
||||
|
||||
int plain_lc; /* data size in orig APDU */
|
||||
int mac_input_len, enc_input_len;
|
||||
unsigned char *mac_input, *enc_input;
|
||||
DES_key_schedule ks_a, ks_b;
|
||||
DES_cblock des_in,des_out;
|
||||
int i,j;
|
||||
|
||||
if (keylen != 16) {
|
||||
printf("key has wrong size, need 16 bytes, got %d. aborting.\n",
|
||||
keylen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (inlen < 4)
|
||||
return 0; /* failed, apdu too short */
|
||||
if (inlen == 5)
|
||||
plain_lc = 0;
|
||||
if (inlen > 5)
|
||||
plain_lc = in[4];
|
||||
|
||||
/* 4 + plain_lc plus 0..7 bytes of padding */
|
||||
mac_input_len = 4 + plain_lc;
|
||||
while (mac_input_len % 8) mac_input_len++;
|
||||
|
||||
mac_input = calloc(1,mac_input_len);
|
||||
if (!mac_input) {
|
||||
printf("out of memory, aborting");
|
||||
return 0;
|
||||
}
|
||||
mac_input[0] = in[1]; /* ins */
|
||||
mac_input[1] = in[2]; /* p1 */
|
||||
mac_input[2] = in[3]; /* p2 */
|
||||
mac_input[3] = plain_lc + 8;
|
||||
if (plain_lc) /* copy data from in APDU */
|
||||
memcpy(&mac_input[4],&in[5],plain_lc);
|
||||
/* calloc already did the ansi padding: rest is 00 */
|
||||
|
||||
/* prepare des key using first 8 bytes of key */
|
||||
DES_set_key((const_DES_cblock*) &key[0], &ks_a);
|
||||
/* prepare des key using second 8 bytes of key */
|
||||
DES_set_key((const_DES_cblock*) &key[8], &ks_b);
|
||||
|
||||
/* first block: XOR with IV and encrypt with key A IV is 8 bytes 00 */
|
||||
for (i=0; i < 8; i++) des_in[i] = mac_input[i]^00;
|
||||
DES_ecb_encrypt(des_in, des_out, &ks_a, 1);
|
||||
|
||||
/* all other blocks: XOR with prev. result and encrypt with key A */
|
||||
for (j=1; j < (mac_input_len / 8); j++) {
|
||||
for (i=0; i < 8; i++) des_in[i] = mac_input[i+j*8]^des_out[i];
|
||||
DES_ecb_encrypt(des_in, des_out, &ks_a, 1);
|
||||
}
|
||||
|
||||
/* now decrypt with key B and encrypt with key A again */
|
||||
/* (a noop if key A and B are the same, e.g. 8 bytes ff */
|
||||
for (i=0; i < 8; i++) des_in[i] = des_out[i];
|
||||
DES_ecb_encrypt(des_in, des_out, &ks_b, 0);
|
||||
for (i=0; i < 8; i++) des_in[i] = des_out[i];
|
||||
DES_ecb_encrypt(des_in, des_out, &ks_a, 1);
|
||||
|
||||
/* now we want to enc:
|
||||
* orig APDU data plus mac (8 bytes) plus iso padding (1-8 bytes) */
|
||||
enc_input_len = plain_lc + 8 + 1;
|
||||
while (enc_input_len % 8) enc_input_len++;
|
||||
|
||||
enc_input = calloc(1,enc_input_len);
|
||||
if (!enc_input) {
|
||||
printf("out of memory, aborting");
|
||||
return 0;
|
||||
}
|
||||
if (plain_lc)
|
||||
memcpy(&enc_input[0],&in[5],plain_lc);
|
||||
for (i=0; i < 8; i++) enc_input[i+plain_lc] = des_out[i];
|
||||
enc_input[plain_lc+8] = 0x80; /* iso padding */
|
||||
/* calloc already cleard the remaining bytes to 00 */
|
||||
|
||||
if (outlen < 5 + enc_input_len) {
|
||||
printf("output buffer too small, aborting.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
out[0] = in[0]; /* cla */
|
||||
out[1] = in[1]; /* ins */
|
||||
out[2] = in[2]; /* p1 */
|
||||
out[3] = in[3]; /* p2 */
|
||||
out[4] = enc_input_len; /* lc */
|
||||
|
||||
/* encrypt first block */
|
||||
|
||||
/* xor data and IV (8 bytes 00) to get input data */
|
||||
for (i=0; i < 8; i++) des_in[i] = enc_input[i] ^ 00;
|
||||
|
||||
/* encrypt with des2 (tripple des, but using keys A-B-A) */
|
||||
DES_ecb2_encrypt(des_in, des_out, &ks_a, &ks_b, 1);
|
||||
|
||||
/* copy encrypted bytes into output */
|
||||
for (i=0; i < 8; i++) out[5+i] = des_out[i];
|
||||
|
||||
/* encrypt other blocks (usualy one) */
|
||||
for (j=1; j < (enc_input_len / 8); j++) {
|
||||
/* xor data and prev. result to get input data */
|
||||
for (i=0; i < 8; i++) des_in[i] = enc_input[i+j*8] ^ des_out[i];
|
||||
|
||||
/* encrypt with des2 (tripple des, but using keys A-B-A) */
|
||||
DES_ecb2_encrypt(des_in, des_out, &ks_a, &ks_b, 1);
|
||||
|
||||
/* copy encrypted bytes into output */
|
||||
for (i=0; i < 8; i++) out[5+8*j+i] = des_out[i];
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int cardos_format()
|
||||
{
|
||||
unsigned const char startkey[] = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
sc_apdu_t apdu;
|
||||
u8 rbuf[256];
|
||||
int r;
|
||||
|
||||
/* first run GET DATA for lifecycle 00 CA 01 83
|
||||
* returns 34 MANUFACTURING 20 ADMINISTRATION 10 OPERATIONAL
|
||||
* 26 INITIALITATION, 23 PERSINALIZATION 3f DEATH
|
||||
* 29 ERASE IN PROGRESS
|
||||
* */
|
||||
|
||||
memset(&apdu, 0, sizeof(apdu));
|
||||
apdu.cla = 0x00;
|
||||
apdu.ins = 0xca;
|
||||
apdu.p1 = 0x01;
|
||||
apdu.p2 = 0x83;
|
||||
apdu.resp = rbuf;
|
||||
apdu.resplen = sizeof(rbuf);
|
||||
apdu.lc = 0;
|
||||
apdu.le = 256;
|
||||
apdu.cse = SC_APDU_CASE_2_SHORT;
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
if (r) {
|
||||
fprintf(stderr, "APDU transmit failed: %s\n",
|
||||
sc_strerror(r));
|
||||
return 1;
|
||||
}
|
||||
if (apdu.sw1 != 0x90 || apdu.sw2 != 00 || opt_debug) {
|
||||
fprintf(stderr, "Received (SW1=0x%02X, SW2=0x%02X)%s\n",
|
||||
apdu.sw1, apdu.sw2, apdu.resplen ? ":" : "");
|
||||
if (apdu.resplen)
|
||||
util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
|
||||
return 1;
|
||||
}
|
||||
if (apdu.resp[0] == 0x34) {
|
||||
printf("card in manufacturing state\n");
|
||||
printf("cannot continue without secret change startkey command\n");
|
||||
printf("aborting\n");
|
||||
return 1;
|
||||
|
||||
/* we can leave manufacturing mode with PHASE CYCLE,
|
||||
* but before we do that, we need to change the secret
|
||||
* siemens start key to the default 0xff start key.
|
||||
* we know the APDU for that, but it is secreat and
|
||||
* siemens so far didn't allow us to publish it.
|
||||
*/
|
||||
}
|
||||
|
||||
if (apdu.resp[0] != 0x10 && apdu.resp[0] != 0x20) {
|
||||
printf("card is in unknown state 0x%02x, aborting\n",
|
||||
(int) apdu.resp[0]);
|
||||
return 1;
|
||||
|
||||
/* we should handle ERASE IN PROGRESS (29) too */
|
||||
}
|
||||
|
||||
if (apdu.resp[0] == 0x20) {
|
||||
printf("card in administrative state, ok\n");
|
||||
goto admin_state;
|
||||
}
|
||||
printf("card in operational state, need to switch to admin state\n");
|
||||
|
||||
/* PHASE CONTORL 80 10 00 00 */
|
||||
|
||||
memset(&apdu, 0, sizeof(apdu));
|
||||
apdu.cla = 0x80;
|
||||
apdu.ins = 0x10;
|
||||
apdu.p1 = 0x00;
|
||||
apdu.p2 = 0x00;
|
||||
apdu.resp = 00;
|
||||
apdu.lc = 0;
|
||||
apdu.le = 00;
|
||||
apdu.cse = SC_APDU_CASE_1;
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
if (r) {
|
||||
fprintf(stderr, "APDU transmit failed: %s\n",
|
||||
sc_strerror(r));
|
||||
return 1;
|
||||
}
|
||||
if (apdu.sw1 != 0x90 || apdu.sw2 != 00 || opt_debug) {
|
||||
fprintf(stderr, "Received (SW1=0x%02X, SW2=0x%02X)%s\n",
|
||||
apdu.sw1, apdu.sw2, apdu.resplen ? ":" : "");
|
||||
if (apdu.resplen)
|
||||
util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* use GET DATA for lifecacle one more */
|
||||
|
||||
memset(&apdu, 0, sizeof(apdu));
|
||||
apdu.cla = 0x00;
|
||||
apdu.ins = 0xca;
|
||||
apdu.p1 = 0x01;
|
||||
apdu.p2 = 0x83;
|
||||
apdu.resp = rbuf;
|
||||
apdu.resplen = sizeof(rbuf);
|
||||
apdu.lc = 0;
|
||||
apdu.le = 256;
|
||||
apdu.cse = SC_APDU_CASE_2_SHORT;
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
if (r) {
|
||||
fprintf(stderr, "APDU transmit failed: %s\n",
|
||||
sc_strerror(r));
|
||||
return 1;
|
||||
}
|
||||
if (apdu.sw1 != 0x90 || apdu.sw2 != 00 || opt_debug) {
|
||||
fprintf(stderr, "Received (SW1=0x%02X, SW2=0x%02X)%s\n",
|
||||
apdu.sw1, apdu.sw2, apdu.resplen ? ":" : "");
|
||||
if (apdu.resplen)
|
||||
util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
|
||||
return 1;
|
||||
}
|
||||
if (apdu.resp[0] != 0x20) {
|
||||
printf("card not in administrative state, failed\n");
|
||||
printf("aborting");
|
||||
return 1;
|
||||
}
|
||||
|
||||
admin_state:
|
||||
/* use GET DATA for packages - 00 ca 01 88
|
||||
* returns e1 LEN MM 04 ID ID ID ID 8f 01 SS
|
||||
* MM = Manufacturing ID (01 .. 3f = Siemens
|
||||
* ID ID ID ID = Id of the package
|
||||
* SS = License state (01 enabled, 00 disabled
|
||||
*/
|
||||
|
||||
memset(&apdu, 0, sizeof(apdu));
|
||||
apdu.cla = 0x00;
|
||||
apdu.ins = 0xca;
|
||||
apdu.p1 = 0x01;
|
||||
apdu.p2 = 0x88;
|
||||
apdu.resp = rbuf;
|
||||
apdu.resplen = sizeof(rbuf);
|
||||
apdu.lc = 0;
|
||||
apdu.le = 256;
|
||||
apdu.cse = SC_APDU_CASE_2_SHORT;
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
if (r) {
|
||||
fprintf(stderr, "APDU transmit failed: %s\n",
|
||||
sc_strerror(r));
|
||||
return 1;
|
||||
}
|
||||
if (apdu.sw1 != 0x90 || apdu.sw2 != 00 || opt_debug) {
|
||||
fprintf(stderr, "Received (SW1=0x%02X, SW2=0x%02X)%s\n",
|
||||
apdu.sw1, apdu.sw2, apdu.resplen ? ":" : "");
|
||||
if (apdu.resplen)
|
||||
util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
|
||||
return 1;
|
||||
}
|
||||
if (apdu.resplen != 0x00) {
|
||||
printf("card has packages installed.\n");
|
||||
printf("you would loose those, and we can't re-install them.\n");
|
||||
printf("to protect you card: aborting\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* use GET DATA for version - 00 ca 01 82
|
||||
* returns e.g. c8 09 for 4.2B
|
||||
*/
|
||||
|
||||
memset(&apdu, 0, sizeof(apdu));
|
||||
apdu.cla = 0x00;
|
||||
apdu.ins = 0xca;
|
||||
apdu.p1 = 0x01;
|
||||
apdu.p2 = 0x82;
|
||||
apdu.resp = rbuf;
|
||||
apdu.resplen = sizeof(rbuf);
|
||||
apdu.lc = 0;
|
||||
apdu.le = 256;
|
||||
apdu.cse = SC_APDU_CASE_2_SHORT;
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
if (r) {
|
||||
fprintf(stderr, "APDU transmit failed: %s\n",
|
||||
sc_strerror(r));
|
||||
return 1;
|
||||
}
|
||||
if (apdu.sw1 != 0x90 || apdu.sw2 != 00 || opt_debug) {
|
||||
fprintf(stderr, "Received (SW1=0x%02X, SW2=0x%02X)%s\n",
|
||||
apdu.sw1, apdu.sw2, apdu.resplen ? ":" : "");
|
||||
if (apdu.resplen)
|
||||
util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
|
||||
return 1;
|
||||
}
|
||||
if (apdu.resplen != 0x02) {
|
||||
printf("did not receive version info, aborting\n");
|
||||
return 1;
|
||||
}
|
||||
if (rbuf[0] != 0xc8 || rbuf[1] != 0x09) {
|
||||
printf("currently only CardOS M4.2B is supported, aborting\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* GET DATA for startkey index - 00 ca 01 96
|
||||
* returns 6 bytes PackageLoadKey.Version, PackageLoadKey.Retry
|
||||
* Startkey.Version, Startkey.Retry, 2 internal data byes */
|
||||
|
||||
memset(&apdu, 0, sizeof(apdu));
|
||||
apdu.cla = 0x00;
|
||||
apdu.ins = 0xca;
|
||||
apdu.p1 = 0x01;
|
||||
apdu.p2 = 0x96;
|
||||
apdu.resp = rbuf;
|
||||
apdu.resplen = sizeof(rbuf);
|
||||
apdu.lc = 0;
|
||||
apdu.le = 256;
|
||||
apdu.cse = SC_APDU_CASE_2_SHORT;
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
if (r) {
|
||||
fprintf(stderr, "APDU transmit failed: %s\n",
|
||||
sc_strerror(r));
|
||||
return 1;
|
||||
}
|
||||
if (apdu.sw1 != 0x90 || apdu.sw2 != 00 || opt_debug) {
|
||||
fprintf(stderr, "Received (SW1=0x%02X, SW2=0x%02X)%s\n",
|
||||
apdu.sw1, apdu.sw2, apdu.resplen ? ":" : "");
|
||||
if (apdu.resplen)
|
||||
util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
|
||||
return 1;
|
||||
}
|
||||
if (apdu.resplen < 0x04) {
|
||||
printf("expected 4-6 bytes form GET DATA for startkey data, but got only %ld\n", apdu.resplen);
|
||||
printf("aborting\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (apdu.resp[3] =! 0xff) {
|
||||
printf("startkey version is 0x%02x, currently we support only 0xff\n", (int) apdu.resp[3]);
|
||||
printf("aborting\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (apdu.resp[2] < 5) {
|
||||
printf("startkey has only %d tries left. to be safe: aborting\n", apdu.resp[4]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_OPENSSL
|
||||
/* now we need to erase the card. Our command is:
|
||||
* ERASE FILES 84 06 00 00
|
||||
* but it needs to be send using SM 4h mode (signed and enc.)
|
||||
*/
|
||||
{
|
||||
unsigned const char erase_apdu[] = { 0x84, 0x06, 0x00, 0x00 };
|
||||
|
||||
if (! cardos_sm4h(erase_apdu, sizeof(erase_apdu),
|
||||
rbuf, sizeof(rbuf), startkey, sizeof(startkey)))
|
||||
return 1;
|
||||
|
||||
memset(&apdu, 0, sizeof(apdu));
|
||||
apdu.cse = SC_APDU_CASE_3_SHORT;
|
||||
apdu.cla = rbuf[0];
|
||||
apdu.ins = rbuf[1];
|
||||
apdu.p1 = rbuf[2];
|
||||
apdu.p2 = rbuf[3];
|
||||
apdu.lc = rbuf[4];
|
||||
apdu.data = &rbuf[5];
|
||||
apdu.datalen = rbuf[4];
|
||||
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
if (r) {
|
||||
fprintf(stderr, "APDU transmit failed: %s\n",
|
||||
sc_strerror(r));
|
||||
return 1;
|
||||
}
|
||||
if (apdu.sw1 != 0x90 || apdu.sw2 != 00 || opt_debug) {
|
||||
fprintf(stderr, "Received (SW1=0x%02X, SW2=0x%02X)%s\n",
|
||||
apdu.sw1, apdu.sw2, apdu.resplen ? ":" : "");
|
||||
if (apdu.resplen)
|
||||
util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/* next we need to format the card. Our command is:
|
||||
* FORMAT 84 40 00 01
|
||||
* with P2 = 01 (go to admin mode after format)
|
||||
* and with data: T L V with tag 62 and value: more TLV
|
||||
* 81 02 00 80 Main Folder size 0x0080
|
||||
* 85 01 01 no death bit, no deactivation bit,
|
||||
* but checksums bit
|
||||
* 86 0a 00 ... 10 bytes AC with all set to allow (00)
|
||||
* not included: CB tag with secure mode definition
|
||||
* (defaults are fine for us)
|
||||
*
|
||||
* this APDU needs to be send using SM 4h mode (signed and enc.)
|
||||
*/
|
||||
{
|
||||
unsigned const char format_apdu[] = {
|
||||
0x84, 0x40, 0x00, 0x01, 0x15,
|
||||
0x62, 0x13,
|
||||
0x81, 0x02, 0x00, 0x80,
|
||||
0x85, 0x01, 0x01,
|
||||
0x86, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
if (! cardos_sm4h(format_apdu, sizeof(format_apdu),
|
||||
rbuf, sizeof(rbuf), startkey, sizeof(startkey)))
|
||||
return 1;
|
||||
|
||||
memset(&apdu, 0, sizeof(apdu));
|
||||
apdu.cse = SC_APDU_CASE_3_SHORT;
|
||||
apdu.cla = rbuf[0];
|
||||
apdu.ins = rbuf[1];
|
||||
apdu.p1 = rbuf[2];
|
||||
apdu.p2 = rbuf[3];
|
||||
apdu.lc = rbuf[4];
|
||||
apdu.data = &rbuf[5];
|
||||
apdu.datalen = rbuf[4];
|
||||
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
if (r) {
|
||||
fprintf(stderr, "APDU transmit failed: %s\n",
|
||||
sc_strerror(r));
|
||||
return 1;
|
||||
}
|
||||
if (apdu.sw1 != 0x90 || apdu.sw2 != 00 || opt_debug) {
|
||||
fprintf(stderr, "Received (SW1=0x%02X, SW2=0x%02X)%s\n",
|
||||
apdu.sw1, apdu.sw2, apdu.resplen ? ":" : "");
|
||||
if (apdu.resplen)
|
||||
util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
# else
|
||||
printf("this code needs to be compiled with openssl support enabled.\n");
|
||||
printf("aborting\n");
|
||||
return 1;
|
||||
#endif /* ENABLE_OPENSSL */
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *const argv[])
|
||||
{
|
||||
int err = 0, r, c, long_optind = 0;
|
||||
int do_info = 0;
|
||||
int do_format = 0;
|
||||
int action_count = 0;
|
||||
const char *opt_driver = NULL;
|
||||
const char *opt_startkey = NULL;
|
||||
sc_context_param_t ctx_param;
|
||||
|
||||
while (1) {
|
||||
c = getopt_long(argc, argv, "r:vc:w", options,
|
||||
c = getopt_long(argc, argv, "ifs:r:vdc:w", options,
|
||||
&long_optind);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
@ -366,6 +839,17 @@ int main(int argc, char *const argv[])
|
|||
case 'h':
|
||||
case '?':
|
||||
util_print_usage_and_die(app_name, options, option_help);
|
||||
case 'i':
|
||||
do_info = 1;
|
||||
action_count++;
|
||||
break;
|
||||
case 'f':
|
||||
do_format = 1;
|
||||
action_count++;
|
||||
break;
|
||||
case 's':
|
||||
opt_startkey = optarg;
|
||||
break;
|
||||
case 'r':
|
||||
opt_reader = atoi(optarg);
|
||||
break;
|
||||
|
@ -410,8 +894,17 @@ int main(int argc, char *const argv[])
|
|||
if (err)
|
||||
goto end;
|
||||
|
||||
if ((err = cardos_info())) {
|
||||
goto end;
|
||||
if (do_info) {
|
||||
if ((err = cardos_info())) {
|
||||
goto end;
|
||||
}
|
||||
action_count--;
|
||||
}
|
||||
if (do_format) {
|
||||
if ((err = cardos_format(opt_startkey))) {
|
||||
goto end;
|
||||
}
|
||||
action_count--;
|
||||
}
|
||||
end:
|
||||
if (card) {
|
||||
|
|
Loading…
Reference in New Issue