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"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<refentry id="cardos-info">
|
<refentry id="cardos-tool">
|
||||||
<refmeta>
|
<refmeta>
|
||||||
<refentrytitle>cardos-info</refentrytitle>
|
<refentrytitle>cardos-tool</refentrytitle>
|
||||||
<manvolnum>1</manvolnum>
|
<manvolnum>1</manvolnum>
|
||||||
<refmiscinfo>opensc</refmiscinfo>
|
<refmiscinfo>opensc</refmiscinfo>
|
||||||
</refmeta>
|
</refmeta>
|
||||||
|
|
||||||
<refnamediv>
|
<refnamediv>
|
||||||
<refname>cardos-info</refname>
|
<refname>cardos-tool</refname>
|
||||||
<refpurpose>displays information about Card OS-based security tokens
|
<refpurpose>displays information about Card OS-based security tokens or format them
|
||||||
</refpurpose>
|
</refpurpose>
|
||||||
</refnamediv>
|
</refnamediv>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
<title>Synopsis</title>
|
<title>Synopsis</title>
|
||||||
<para>
|
<para>
|
||||||
<command>cardos-info</command> [OPTIONS]
|
<command>cardos-tool</command> [OPTIONS]
|
||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
<title>Description</title>
|
<title>Description</title>
|
||||||
<para>
|
<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.
|
smart cards and similar security tokens based on Siemens Card/OS M4.
|
||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
@ -31,9 +31,17 @@ smart cards and similar security tokens based on Siemens Card/OS M4.
|
||||||
<title>Options</title>
|
<title>Options</title>
|
||||||
<para>
|
<para>
|
||||||
<variablelist>
|
<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>
|
<varlistentry>
|
||||||
<term><option>--reader</option> number, <option>-r</option> number</term>
|
<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>
|
The default is reader 0.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
|
|
|
@ -7,7 +7,7 @@ EXTRA_DIST = Makefile.mak
|
||||||
|
|
||||||
noinst_HEADERS = util.h
|
noinst_HEADERS = util.h
|
||||||
bin_PROGRAMS = opensc-tool opensc-explorer pkcs15-tool pkcs15-crypt \
|
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
|
if ENABLE_OPENSSL
|
||||||
bin_PROGRAMS += cryptoflex-tool pkcs15-init netkey-tool piv-tool
|
bin_PROGRAMS += cryptoflex-tool pkcs15-init netkey-tool piv-tool
|
||||||
endif
|
endif
|
||||||
|
@ -34,7 +34,8 @@ cryptoflex_tool_LDADD = $(OPTIONAL_OPENSSL_LIBS)
|
||||||
pkcs15_init_SOURCES = pkcs15-init.c util.c
|
pkcs15_init_SOURCES = pkcs15-init.c util.c
|
||||||
pkcs15_init_LDADD = $(OPTIONAL_OPENSSL_LIBS) \
|
pkcs15_init_LDADD = $(OPTIONAL_OPENSSL_LIBS) \
|
||||||
$(top_builddir)/src/pkcs15init/libpkcs15init.la
|
$(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
|
eidenv_SOURCES = eidenv.c
|
||||||
netkey_tool_SOURCES = netkey-tool.c
|
netkey_tool_SOURCES = netkey-tool.c
|
||||||
netkey_tool_LDADD = $(OPTIONAL_OPENSSL_LIBS)
|
netkey_tool_LDADD = $(OPTIONAL_OPENSSL_LIBS)
|
||||||
|
@ -50,7 +51,7 @@ pkcs11_tool_SOURCES += versioninfo.rc
|
||||||
pkcs15_crypt_SOURCES += versioninfo.rc
|
pkcs15_crypt_SOURCES += versioninfo.rc
|
||||||
cryptoflex_tool_SOURCES += versioninfo.rc
|
cryptoflex_tool_SOURCES += versioninfo.rc
|
||||||
pkcs15_init_SOURCES += versioninfo.rc
|
pkcs15_init_SOURCES += versioninfo.rc
|
||||||
cardos_info_SOURCES += versioninfo.rc
|
cardos_tool_SOURCES += versioninfo.rc
|
||||||
eidenv_SOURCES += versioninfo.rc
|
eidenv_SOURCES += versioninfo.rc
|
||||||
netkey_tool_SOURCES += versioninfo.rc
|
netkey_tool_SOURCES += versioninfo.rc
|
||||||
rutoken_tool_SOURCES += versioninfo.rc
|
rutoken_tool_SOURCES += versioninfo.rc
|
||||||
|
@ -61,3 +62,14 @@ endif
|
||||||
versioninfo.rc:
|
versioninfo.rc:
|
||||||
sed 's/@@FILE_DESCRIPTION@@/OpenSC Utility/g' \
|
sed 's/@@FILE_DESCRIPTION@@/OpenSC Utility/g' \
|
||||||
"$(top_builddir)/win32/versioninfo.rc.in" > versioninfo.rc
|
"$(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) 2003 Andreas Jellinghaus <aj@dungeon.inka.de>
|
||||||
* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
|
* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
|
||||||
*
|
*
|
||||||
|
@ -31,23 +33,35 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#ifdef ENABLE_OPENSSL
|
||||||
|
#include <openssl/des.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <opensc/opensc.h>
|
#include <opensc/opensc.h>
|
||||||
#include "util.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 opt_reader = -1, opt_debug = 0, opt_wait = 0;
|
||||||
static int verbose = 0;
|
static int verbose = 0;
|
||||||
|
|
||||||
static const struct option options[] = {
|
static const struct option options[] = {
|
||||||
|
{"info", 0, NULL, 'i'},
|
||||||
|
{"format", 0, NULL, 'f'},
|
||||||
|
{"startkey", 1, NULL, 's'},
|
||||||
{"reader", 1, NULL, 'r'},
|
{"reader", 1, NULL, 'r'},
|
||||||
{"card-driver", 1, NULL, 'c'},
|
{"card-driver", 1, NULL, 'c'},
|
||||||
{"wait", 0, NULL, 'w'},
|
{"wait", 0, NULL, 'w'},
|
||||||
{"verbose", 0, NULL, 'v'},
|
{"verbose", 0, NULL, 'v'},
|
||||||
|
{"debug", 0, NULL, 'd'},
|
||||||
{NULL, 0, NULL, 0}
|
{NULL, 0, NULL, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *option_help[] = {
|
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]",
|
"Uses reader number <arg> [0]",
|
||||||
"Forces the use of driver <arg> [auto-detect]",
|
"Forces the use of driver <arg> [auto-detect]",
|
||||||
"Wait for a card to be inserted",
|
"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) {
|
} else if (apdu.resp[0] == 0xc8 && apdu.resp[1] == 0x07) {
|
||||||
printf(" (that's CardOS M4.3)\n");
|
printf(" (that's CardOS M4.3)\n");
|
||||||
} else if (apdu.resp[0] == 0xc8 && apdu.resp[1] == 0x08) {
|
} 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) {
|
} 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) {
|
} 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 {
|
} else {
|
||||||
printf(" (unknown Version)\n");
|
printf(" (unknown Version)\n");
|
||||||
}
|
}
|
||||||
|
@ -185,6 +199,8 @@ static int cardos_info(void)
|
||||||
printf("%d (administration)\n", rbuf[0]);
|
printf("%d (administration)\n", rbuf[0]);
|
||||||
} else if (rbuf[0] == 0x10) {
|
} else if (rbuf[0] == 0x10) {
|
||||||
printf("%d (operational)\n", rbuf[0]);
|
printf("%d (operational)\n", rbuf[0]);
|
||||||
|
} else if (rbuf[0] == 0x29) {
|
||||||
|
printf("%d (erase in progress)\n", rbuf[0]);
|
||||||
} else {
|
} else {
|
||||||
printf("%d (unknown)\n", rbuf[0]);
|
printf("%d (unknown)\n", rbuf[0]);
|
||||||
}
|
}
|
||||||
|
@ -350,15 +366,472 @@ static int cardos_info(void)
|
||||||
return 0;
|
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 main(int argc, char *const argv[])
|
||||||
{
|
{
|
||||||
int err = 0, r, c, long_optind = 0;
|
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_driver = NULL;
|
||||||
|
const char *opt_startkey = NULL;
|
||||||
sc_context_param_t ctx_param;
|
sc_context_param_t ctx_param;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
c = getopt_long(argc, argv, "r:vc:w", options,
|
c = getopt_long(argc, argv, "ifs:r:vdc:w", options,
|
||||||
&long_optind);
|
&long_optind);
|
||||||
if (c == -1)
|
if (c == -1)
|
||||||
break;
|
break;
|
||||||
|
@ -366,6 +839,17 @@ int main(int argc, char *const argv[])
|
||||||
case 'h':
|
case 'h':
|
||||||
case '?':
|
case '?':
|
||||||
util_print_usage_and_die(app_name, options, option_help);
|
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':
|
case 'r':
|
||||||
opt_reader = atoi(optarg);
|
opt_reader = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
|
@ -410,8 +894,17 @@ int main(int argc, char *const argv[])
|
||||||
if (err)
|
if (err)
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
if ((err = cardos_info())) {
|
if (do_info) {
|
||||||
goto end;
|
if ((err = cardos_info())) {
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
action_count--;
|
||||||
|
}
|
||||||
|
if (do_format) {
|
||||||
|
if ((err = cardos_format(opt_startkey))) {
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
action_count--;
|
||||||
}
|
}
|
||||||
end:
|
end:
|
||||||
if (card) {
|
if (card) {
|
||||||
|
|
Loading…
Reference in New Issue