Adding support for DNIe.

This commit is contained in:
German Blanco 2013-06-13 17:12:07 +02:00
parent e8eb4cd7ed
commit 63ce563d76
21 changed files with 6874 additions and 7 deletions

3
.gitignore vendored
View File

@ -77,6 +77,7 @@ src/tools/cardos-info
src/tools/cryptoflex-tool
src/tools/netkey-tool
src/tools/pkcs11-tool
src/tools/dnie-tool
win32/OpenSC.iss
win32/OpenSC.wxs
@ -97,4 +98,4 @@ src/tests/base64
src/tests/lottery
src/tests/p15dump
src/tests/pintest
src/tests/prngtest
src/tests/prngtest

View File

@ -168,6 +168,13 @@ AC_ARG_ENABLE(
[enable_doc="no"]
)
AC_ARG_ENABLE(
[dnie-ui],
[AS_HELP_STRING([--enable-dnie-ui],[enable use of external user interface program to request DNIe pin@<:@disabled@:>@])],
,
[enable_dnie_ui="no"]
)
AC_ARG_WITH(
[xsl-stylesheetsdir],
[AS_HELP_STRING([--with-xsl-stylesheetsdir=PATH],[docbook xsl-stylesheets for svn build @<:@detect@:>@])],
@ -326,6 +333,18 @@ if test "${enable_sm}" = "yes"; then
AC_DEFINE_UNQUOTED([DEFAULT_SM_MODULE], ["${DEFAULT_SM_MODULE}"], [Default SM module])
fi
if test "${enable_dnie_ui}" = "yes"; then
AC_DEFINE([ENABLE_DNIE_UI], [1], [Enable the use of external user interface program to request DNIe user pin])
case "${host}" in
*-apple-*)
if test "${enable_dnie_ui}" = "yes"; then
LDFLAGS="${LDFLAGS} -framework Carbon"
fi
;;
esac
fi
AC_ARG_VAR([ZLIB_CFLAGS], [C compiler flags for zlib])
AC_ARG_VAR([ZLIB_LIBS], [linker flags for zlib])
if test -z "${ZLIB_LIBS}"; then
@ -588,6 +607,7 @@ AM_CONDITIONAL([WIN32], [test "${WIN32}" = "yes"])
AM_CONDITIONAL([CYGWIN], [test "${CYGWIN}" = "yes"])
AM_CONDITIONAL([ENABLE_MINIDRIVER], [test "${enable_minidriver}" = "yes"])
AM_CONDITIONAL([ENABLE_SM], [test "${enable_sm}" = "yes"])
AM_CONDITIONAL([ENABLE_DNIE_UI], [test "${enable_dnie_ui}" = "yes"])
if test "${enable_pedantic}" = "yes"; then
enable_strict="yes";
@ -601,6 +621,8 @@ if test "$GCC" = "yes"; then
CFLAGS="-fno-strict-aliasing ${CFLAGS}"
fi
CFLAGS="${CFLAGS} -Werror=declaration-after-statement"
AC_CONFIG_FILES([
Makefile
doc/Makefile
@ -652,6 +674,7 @@ CT-API support: ${enable_ctapi}
minidriver support: ${enable_minidriver}
SM support: ${enable_sm}
SM default module: ${DEFAULT_SM_MODULE}
DNIe UI support: ${enable_dnie_ui}
Debug file: ${DEBUG_FILE}
PC/SC default provider: ${DEFAULT_PCSC_PROVIDER}

98
doc/tools/dnie-tool.xml Executable file
View File

@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8"?>
<refentry id="dnie-tool">
<refmeta>
<refentrytitle>dnie-tool</refentrytitle>
<manvolnum>1</manvolnum>
<refmiscinfo>opensc</refmiscinfo>
</refmeta>
<refnamediv>
<refname>dnie-tool</refname>
<refpurpose>displays information about DNIe based security tokens</refpurpose>
</refnamediv>
<refsect1>
<title>Synopsis</title>
<para>
<command>dnie-tool</command> [OPTIONS]
</para>
</refsect1>
<refsect1>
<title>Description</title>
<para>
The <command>dnie-tool</command> utility is used to display additional information about DNIe, the Spanish National eID card.
</para>
</refsect1>
<refsect1>
<title>Options</title>
<para>
<variablelist>
<varlistentry>
<term><option>--idesp, -i </option></term>
<listitem><para>Show the DNIe IDESP value.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--data, -d </option></term>
<listitem><para>Show DNIe personal information.
Reads and print DNIe number and User Name and SurName</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--all, -a </option></term>
<listitem><para>Displays every available information.
This command is equivalent to -d -i -s
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--serial, -s </option></term>
<listitem><para>Displays DNIe Serial Number
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--version, -V </option></term>
<listitem><para>Show DNIe sw version.
Displays sofware version for in-card DNIe OS</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--pin</option> pin, <option>-p</option> pin</term>
<listitem><para>Specify the user pin <varname>value</varname> to use.
The default is do not enter pin</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--reader</option> number, <option>-r</option> number</term>
<listitem><para>Specify the reader <varname>number</varname> to use.
The default is reader 0.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--driver</option> number, <option>-c</option> driver</term>
<listitem><para>Specify the reader driver <varname>name</varname> to use.
Default is use driver from configuration file, or auto-detect if absent</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--wait, -w</option></term>
<listitem><para>Causes <command>dnie-tool</command> to wait for the token to be inserted into reader.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--verbose, -v</option></term>
<listitem><para>Causes <command>dnie-tool</command> to be more verbose.
Specify this flag several times
to enable debug output in the opensc library.</para></listitem>
</varlistentry>
</variablelist>
</para>
</refsect1>
<refsect1>
<title>See also</title>
<para>opensc(7)</para>
</refsect1>
<refsect1>
<title>Authors</title>
<para><command>dnie-tool</command> was written by
Juan Antonio Martinez <email>jonsito@terra.es</email>.</para>
</refsect1>
</refentry>

View File

@ -11,7 +11,7 @@ noinst_HEADERS = cards.h ctbcs.h internal.h esteid.h muscle.h muscle-filesystem.
cardctl.h asn1.h log.h \
errors.h types.h compression.h itacns.h iso7816.h \
authentic.h iasecc.h iasecc-sdo.h sm.h card-sc-hsm.h \
pace.h
pace.h cwa14890.h user-interface.h cwa-dnie.h
AM_CPPFLAGS = -DOPENSC_CONF_PATH=\"$(sysconfdir)/opensc.conf\" \
-I$(top_srcdir)/src
@ -40,12 +40,14 @@ libopensc_la_SOURCES = \
card-rtecp.c card-westcos.c card-myeid.c card-ias.c \
card-javacard.c card-itacns.c card-authentic.c \
card-iasecc.c iasecc-sdo.c iasecc-sm.c card-sc-hsm.c \
card-dnie.c cwa14890.c cwa-dnie.c user-interface.c \
\
pkcs15-openpgp.c pkcs15-infocamere.c pkcs15-starcert.c \
pkcs15-tcos.c pkcs15-esteid.c pkcs15-postecert.c pkcs15-gemsafeGPK.c \
pkcs15-actalis.c pkcs15-atrust-acos.c pkcs15-tccardos.c pkcs15-piv.c \
pkcs15-esinit.c pkcs15-westcos.c pkcs15-pteid.c pkcs15-oberthur.c \
pkcs15-itacns.c pkcs15-gemsafeV1.c pkcs15-sc-hsm.c \
pkcs15-dnie.c \
compression.c p15card-helper.c sm.c \
libopensc.exports
if WIN32

View File

@ -22,14 +22,15 @@ OBJECTS = \
card-asepcos.obj card-akis.obj card-gemsafeV1.obj card-rutoken.obj \
card-rtecp.obj card-westcos.obj card-myeid.obj card-ias.obj \
card-javacard.obj card-itacns.obj card-authentic.obj \
card-iasecc.obj iasecc-sdo.obj iasecc-sm.obj \
card-sc-hsm.obj \
card-iasecc.obj iasecc-sdo.obj iasecc-sm.obj cwa-dnie.obj cwa14890.obj \
card-sc-hsm.obj card-dnie.obj user-interface.obj \
\
pkcs15-openpgp.obj pkcs15-infocamere.obj pkcs15-starcert.obj \
pkcs15-tcos.obj pkcs15-esteid.obj pkcs15-postecert.obj pkcs15-gemsafeGPK.obj \
pkcs15-actalis.obj pkcs15-atrust-acos.obj pkcs15-tccardos.obj pkcs15-piv.obj \
pkcs15-esinit.obj pkcs15-westcos.obj pkcs15-pteid.obj pkcs15-oberthur.obj \
pkcs15-itacns.obj pkcs15-gemsafeV1.obj pkcs15-sc-hsm.obj \
pkcs15-dnie.obj \
compression.obj p15card-helper.obj sm.obj \
$(TOPDIR)\win32\versioninfo.res

2311
src/libopensc/card-dnie.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -248,7 +248,14 @@ enum {
SC_CARDCTL_SC_HSM_INITIALIZE,
SC_CARDCTL_SC_HSM_IMPORT_DKEK_SHARE,
SC_CARDCTL_SC_HSM_WRAP_KEY,
SC_CARDCTL_SC_HSM_UNWRAP_KEY
SC_CARDCTL_SC_HSM_UNWRAP_KEY,
/*
* DNIe specific calls
*/
SC_CARDCTL_DNIE_BASE = _CTL_PREFIX('D', 'N', 'I'),
SC_CARDCTL_DNIE_GENERATE_KEY,
SC_CARDCTL_DNIE_GET_INFO
};
enum {

View File

@ -191,6 +191,13 @@ enum {
/* SmartCard-HSM */
SC_CARD_TYPE_SC_HSM = 26000,
/* Spanish DNIe card */
SC_CARD_TYPE_DNIE_BASE = 27000,
SC_CARD_TYPE_DNIE_BLANK, /* ATR LC byte: 00 */
SC_CARD_TYPE_DNIE_ADMIN, /* ATR LC byte: 01 */
SC_CARD_TYPE_DNIE_USER, /* ATR LC byte: 03 */
SC_CARD_TYPE_DNIE_TERMINATED /* ATR LC byte: 0F */
};
extern sc_card_driver_t *sc_get_default_driver(void);
@ -227,6 +234,7 @@ extern sc_card_driver_t *sc_get_itacns_driver(void);
extern sc_card_driver_t *sc_get_authentic_driver(void);
extern sc_card_driver_t *sc_get_iasecc_driver(void);
extern sc_card_driver_t *sc_get_epass2003_driver(void);
extern sc_card_driver_t *sc_get_dnie_driver(void);
#ifdef __cplusplus
}

View File

@ -97,6 +97,9 @@ static const struct _sc_driver_entry internal_card_drivers[] = {
{ "westcos", (void *(*)(void)) sc_get_westcos_driver },
{ "myeid", (void *(*)(void)) sc_get_myeid_driver },
{ "sc-hsm", (void *(*)(void)) sc_get_sc_hsm_driver },
#ifdef ENABLE_OPENSSL
{ "dnie", (void *(*)(void)) sc_get_dnie_driver },
#endif
/* Here should be placed drivers that need some APDU transactions to
* recognise its cards. */

885
src/libopensc/cwa-dnie.c Normal file
View File

@ -0,0 +1,885 @@
/**
* cwa-dnie.c: DNIe data provider for CWA SM handling.
*
* Copyright (C) 2010 Juan Antonio Martinez <jonsito@terra.es>
*
* This work is derived from many sources at OpenSC Project site,
* (see references) and the information made public by Spanish
* Direccion General de la Policia y de la Guardia Civil
*
* 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
*/
#define __SM_DNIE_C__
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef ENABLE_OPENSSL /* empty file without openssl */
#include <stdlib.h>
#include <string.h>
#include "opensc.h"
#include "cardctl.h"
#include "internal.h"
#include "cwa14890.h"
#include "cwa-dnie.h"
#include <openssl/x509.h>
#include <openssl/evp.h>
/********************* Keys and certificates as published by DGP ********/
/**
* Modulo de la clave pública de la Root CA del DNIe electronico
*/
static u8 icc_root_ca_modulus[] = {
0xEA, 0xDE, 0xDA, 0x45, 0x53, 0x32, 0x94, 0x50, 0x39, 0xDA, 0xA4, 0x04,
0xC8, 0xEB, 0xC4, 0xD3, 0xB7, 0xF5, 0xDC, 0x86, 0x92, 0x83, 0xCD, 0xEA,
0x2F, 0x10, 0x1E, 0x2A, 0xB5, 0x4F, 0xB0, 0xD0, 0xB0, 0x3D, 0x8F, 0x03,
0x0D, 0xAF, 0x24, 0x58, 0x02, 0x82, 0x88, 0xF5, 0x4C, 0xE5, 0x52, 0xF8,
0xFA, 0x57, 0xAB, 0x2F, 0xB1, 0x03, 0xB1, 0x12, 0x42, 0x7E, 0x11, 0x13,
0x1D, 0x1D, 0x27, 0xE1, 0x0A, 0x5B, 0x50, 0x0E, 0xAA, 0xE5, 0xD9, 0x40,
0x30, 0x1E, 0x30, 0xEB, 0x26, 0xC3, 0xE9, 0x06, 0x6B, 0x25, 0x71, 0x56,
0xED, 0x63, 0x9D, 0x70, 0xCC, 0xC0, 0x90, 0xB8, 0x63, 0xAF, 0xBB, 0x3B,
0xFE, 0xD8, 0xC1, 0x7B, 0xE7, 0x67, 0x30, 0x34, 0xB9, 0x82, 0x3E, 0x97,
0x7E, 0xD6, 0x57, 0x25, 0x29, 0x27, 0xF9, 0x57, 0x5B, 0x9F, 0xFF, 0x66,
0x91, 0xDB, 0x64, 0xF8, 0x0B, 0x5E, 0x92, 0xCD
};
/**
* Exponente de la clave publica de la Root CA del DNI electronico
*/
static u8 icc_root_ca_public_exponent[] = {
0x01, 0x00, 0x01
};
/**
* Terminal (IFD) key modulus for SM channel creation
*/
static u8 ifd_modulus[] = {
0xdb, 0x2c, 0xb4, 0x1e, 0x11, 0x2b, 0xac, 0xfa, 0x2b, 0xd7, 0xc3, 0xd3,
0xd7, 0x96, 0x7e, 0x84, 0xfb, 0x94, 0x34, 0xfc, 0x26, 0x1f, 0x9d, 0x09,
0x0a, 0x89, 0x83, 0x94, 0x7d, 0xaf, 0x84, 0x88, 0xd3, 0xdf, 0x8f, 0xbd,
0xcc, 0x1f, 0x92, 0x49, 0x35, 0x85, 0xe1, 0x34, 0xa1, 0xb4, 0x2d, 0xe5,
0x19, 0xf4, 0x63, 0x24, 0x4d, 0x7e, 0xd3, 0x84, 0xe2, 0x6d, 0x51, 0x6c,
0xc7, 0xa4, 0xff, 0x78, 0x95, 0xb1, 0x99, 0x21, 0x40, 0x04, 0x3a, 0xac,
0xad, 0xfc, 0x12, 0xe8, 0x56, 0xb2, 0x02, 0x34, 0x6a, 0xf8, 0x22, 0x6b,
0x1a, 0x88, 0x21, 0x37, 0xdc, 0x3c, 0x5a, 0x57, 0xf0, 0xd2, 0x81, 0x5c,
0x1f, 0xcd, 0x4b, 0xb4, 0x6f, 0xa9, 0x15, 0x7f, 0xdf, 0xfd, 0x79, 0xec,
0x3a, 0x10, 0xa8, 0x24, 0xcc, 0xc1, 0xeb, 0x3c, 0xe0, 0xb6, 0xb4, 0x39,
0x6a, 0xe2, 0x36, 0x59, 0x00, 0x16, 0xba, 0x69
};
/**
* Terminal (IFD) public exponent for SM channel creation
*/
static u8 ifd_public_exponent[] = {
0x01, 0x00, 0x01
};
/**
* Terminal (IFD) private exponent for SM channel establishment
*/
static u8 ifd_private_exponent[] = {
0x18, 0xb4, 0x4a, 0x3d, 0x15, 0x5c, 0x61, 0xeb, 0xf4, 0xe3, 0x26, 0x1c,
0x8b, 0xb1, 0x57, 0xe3, 0x6f, 0x63, 0xfe, 0x30, 0xe9, 0xaf, 0x28, 0x89,
0x2b, 0x59, 0xe2, 0xad, 0xeb, 0x18, 0xcc, 0x8c, 0x8b, 0xad, 0x28, 0x4b,
0x91, 0x65, 0x81, 0x9c, 0xa4, 0xde, 0xc9, 0x4a, 0xa0, 0x6b, 0x69, 0xbc,
0xe8, 0x17, 0x06, 0xd1, 0xc1, 0xb6, 0x68, 0xeb, 0x12, 0x86, 0x95, 0xe5,
0xf7, 0xfe, 0xde, 0x18, 0xa9, 0x08, 0xa3, 0x01, 0x1a, 0x64, 0x6a, 0x48,
0x1d, 0x3e, 0xa7, 0x1d, 0x8a, 0x38, 0x7d, 0x47, 0x46, 0x09, 0xbd, 0x57,
0xa8, 0x82, 0xb1, 0x82, 0xe0, 0x47, 0xde, 0x80, 0xe0, 0x4b, 0x42, 0x21,
0x41, 0x6b, 0xd3, 0x9d, 0xfa, 0x1f, 0xac, 0x03, 0x00, 0x64, 0x19, 0x62,
0xad, 0xb1, 0x09, 0xe2, 0x8c, 0xaf, 0x50, 0x06, 0x1b, 0x68, 0xc9, 0xca,
0xbd, 0x9b, 0x00, 0x31, 0x3c, 0x0f, 0x46, 0xed
};
/**
* Intermediate CA certificate in CVC format (Card verifiable certificate)
*/
static u8 C_CV_CA_CS_AUT_cert[] = {
0x7f, 0x21, 0x81, 0xce, 0x5f, 0x37, 0x81, 0x80, 0x3c, 0xba, 0xdc, 0x36,
0x84, 0xbe, 0xf3, 0x20, 0x41, 0xad, 0x15, 0x50, 0x89, 0x25, 0x8d, 0xfd,
0x20, 0xc6, 0x91, 0x15, 0xd7, 0x2f, 0x9c, 0x38, 0xaa, 0x99, 0xad, 0x6c,
0x1a, 0xed, 0xfa, 0xb2, 0xbf, 0xac, 0x90, 0x92, 0xfc, 0x70, 0xcc, 0xc0,
0x0c, 0xaf, 0x48, 0x2a, 0x4b, 0xe3, 0x1a, 0xfd, 0xbd, 0x3c, 0xbc, 0x8c,
0x83, 0x82, 0xcf, 0x06, 0xbc, 0x07, 0x19, 0xba, 0xab, 0xb5, 0x6b, 0x6e,
0xc8, 0x07, 0x60, 0xa4, 0xa9, 0x3f, 0xa2, 0xd7, 0xc3, 0x47, 0xf3, 0x44,
0x27, 0xf9, 0xff, 0x5c, 0x8d, 0xe6, 0xd6, 0x5d, 0xac, 0x95, 0xf2, 0xf1,
0x9d, 0xac, 0x00, 0x53, 0xdf, 0x11, 0xa5, 0x07, 0xfb, 0x62, 0x5e, 0xeb,
0x8d, 0xa4, 0xc0, 0x29, 0x9e, 0x4a, 0x21, 0x12, 0xab, 0x70, 0x47, 0x58,
0x8b, 0x8d, 0x6d, 0xa7, 0x59, 0x22, 0x14, 0xf2, 0xdb, 0xa1, 0x40, 0xc7,
0xd1, 0x22, 0x57, 0x9b, 0x5f, 0x38, 0x3d, 0x22, 0x53, 0xc8, 0xb9, 0xcb,
0x5b, 0xc3, 0x54, 0x3a, 0x55, 0x66, 0x0b, 0xda, 0x80, 0x94, 0x6a, 0xfb,
0x05, 0x25, 0xe8, 0xe5, 0x58, 0x6b, 0x4e, 0x63, 0xe8, 0x92, 0x41, 0x49,
0x78, 0x36, 0xd8, 0xd3, 0xab, 0x08, 0x8c, 0xd4, 0x4c, 0x21, 0x4d, 0x6a,
0xc8, 0x56, 0xe2, 0xa0, 0x07, 0xf4, 0x4f, 0x83, 0x74, 0x33, 0x37, 0x37,
0x1a, 0xdd, 0x8e, 0x03, 0x00, 0x01, 0x00, 0x01, 0x42, 0x08, 0x65, 0x73,
0x52, 0x44, 0x49, 0x60, 0x00, 0x06
};
/**
* Terminal (IFD) certificate in CVC format (PK.IFD.AUT)
*/
static u8 C_CV_IFDUser_AUT_cert[] = {
0x7f, 0x21, 0x81, 0xcd, 0x5f, 0x37, 0x81, 0x80, 0x82, 0x5b, 0x69, 0xc6,
0x45, 0x1e, 0x5f, 0x51, 0x70, 0x74, 0x38, 0x5f, 0x2f, 0x17, 0xd6, 0x4d,
0xfe, 0x2e, 0x68, 0x56, 0x75, 0x67, 0x09, 0x4b, 0x57, 0xf3, 0xc5, 0x78,
0xe8, 0x30, 0xe4, 0x25, 0x57, 0x2d, 0xe8, 0x28, 0xfa, 0xf4, 0xde, 0x1b,
0x01, 0xc3, 0x94, 0xe3, 0x45, 0xc2, 0xfb, 0x06, 0x29, 0xa3, 0x93, 0x49,
0x2f, 0x94, 0xf5, 0x70, 0xb0, 0x0b, 0x1d, 0x67, 0x77, 0x29, 0xf7, 0x55,
0xd1, 0x07, 0x02, 0x2b, 0xb0, 0xa1, 0x16, 0xe1, 0xd7, 0xd7, 0x65, 0x9d,
0xb5, 0xc4, 0xac, 0x0d, 0xde, 0xab, 0x07, 0xff, 0x04, 0x5f, 0x37, 0xb5,
0xda, 0xf1, 0x73, 0x2b, 0x54, 0xea, 0xb2, 0x38, 0xa2, 0xce, 0x17, 0xc9,
0x79, 0x41, 0x87, 0x75, 0x9c, 0xea, 0x9f, 0x92, 0xa1, 0x78, 0x05, 0xa2,
0x7c, 0x10, 0x15, 0xec, 0x56, 0xcc, 0x7e, 0x47, 0x1a, 0x48, 0x8e, 0x6f,
0x1b, 0x91, 0xf7, 0xaa, 0x5f, 0x38, 0x3c, 0xad, 0xfc, 0x12, 0xe8, 0x56,
0xb2, 0x02, 0x34, 0x6a, 0xf8, 0x22, 0x6b, 0x1a, 0x88, 0x21, 0x37, 0xdc,
0x3c, 0x5a, 0x57, 0xf0, 0xd2, 0x81, 0x5c, 0x1f, 0xcd, 0x4b, 0xb4, 0x6f,
0xa9, 0x15, 0x7f, 0xdf, 0xfd, 0x79, 0xec, 0x3a, 0x10, 0xa8, 0x24, 0xcc,
0xc1, 0xeb, 0x3c, 0xe0, 0xb6, 0xb4, 0x39, 0x6a, 0xe2, 0x36, 0x59, 0x00,
0x16, 0xba, 0x69, 0x00, 0x01, 0x00, 0x01, 0x42, 0x08, 0x65, 0x73, 0x53,
0x44, 0x49, 0x60, 0x00, 0x06
};
/**
* Root CA card key reference
*/
static u8 root_ca_keyref[] = { 0x02, 0x0f };
/**
* ICC card private key reference
*/
static u8 icc_priv_keyref[] = { 0x02, 0x1f };
/**
* Intermediate CA card key reference
*/
static u8 cvc_intca_keyref[] =
{ 0x65, 0x73, 0x53, 0x44, 0x49, 0x60, 0x00, 0x06 };
/**
* In memory key reference for selecting IFD sent certificate
*/
static u8 cvc_ifd_keyref[] =
{ 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };
/**
* Serial number for IFD Terminal application
*/
static u8 sn_ifd[] = { 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };
/**
* Serial number for ICC card.
* This buffer is to be filled at runtime
*/
static u8 sn_icc[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
/************ internal functions **********************************/
/**
* Select a file from card, process fci and read data.
*
* This is done by mean of iso_select_file() and iso_read_binary()
*
* @param card pointer to sc_card data
* @param path pathfile
* @param file pointer to resulting file descriptor
* @param buffer pointer to buffer where to store file contents
* @param length length of buffer data
* @return SC_SUCCESS if ok; else error code
*/
int dnie_read_file(sc_card_t * card,
const sc_path_t * path,
sc_file_t ** file, u8 ** buffer, size_t * length)
{
u8 *data;
char *msg = NULL;
int res = SC_SUCCESS;
size_t fsize = 0; /* file size */
sc_context_t *ctx = NULL;
if (!card || !card->ctx)
return SC_ERROR_INVALID_ARGUMENTS;
ctx = card->ctx;
LOG_FUNC_CALLED(card->ctx);
if (!buffer || !length || !path) /* check received arguments */
LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
/* select file by mean of iso7816 ops */
res = card->ops->select_file(card, path, file);
if (res != SC_SUCCESS) {
msg = "select_file failed";
goto dnie_read_file_err;
}
/* iso's select file calls if needed process_fci, so arriving here
* we have file structure filled.
*/
if ((*file)->type == SC_FILE_TYPE_DF) {
/* just a DF, no need to read_binary() */
*buffer = NULL;
*length = 0;
res = SC_SUCCESS;
msg = "File is a DF: no need to read_binary()";
goto dnie_read_file_end;
}
fsize = (*file)->size;
/* reserve enought space to read data from card */
if (fsize <= 0) {
res = SC_ERROR_FILE_TOO_SMALL;
msg = "provided buffer size is too small";
goto dnie_read_file_err;
}
data = calloc(fsize, sizeof(u8));
if (data == NULL) {
res = SC_ERROR_OUT_OF_MEMORY;
msg = "cannot reserve requested buffer size";
goto dnie_read_file_err;
}
/* call sc_read_binary() to retrieve data */
sc_log(ctx, "read_binary(): expected '%d' bytes", fsize);
res = sc_read_binary(card, 0, data, fsize, 0L);
if (res < 0) { /* read_binary returns number of bytes readed */
res = SC_ERROR_CARD_CMD_FAILED;
msg = "read_binary() failed";
goto dnie_read_file_err;
}
*buffer = data;
*length = res;
/* arriving here means success */
res = SC_SUCCESS;
goto dnie_read_file_end;
dnie_read_file_err:
if (*file)
sc_file_free(*file);
dnie_read_file_end:
if (msg)
sc_log(ctx, msg);
LOG_FUNC_RETURN(ctx, res);
}
/**
* Read SM required certificates from card.
*
* This function uses received path to read a certificate file from
* card.
* No validation is done except that received data is effectively a certificate
* @param card Pointer to card driver structure
* @param certpat path to requested certificate
* @param cert where to store resultig data
* @return SC_SUCCESS if ok, else error code
*/
static int dnie_read_certificate(sc_card_t * card, char *certpath, X509 ** cert)
{
sc_file_t *file = NULL;
sc_path_t *path = NULL;
u8 *buffer = NULL;
char *msg = NULL;
size_t bufferlen = 0;
int res = SC_SUCCESS;
LOG_FUNC_CALLED(card->ctx);
path = (sc_path_t *) calloc(1, sizeof(sc_path_t));
if (!path) {
msg = "Cannot allocate path data for cert read";
res = SC_ERROR_OUT_OF_MEMORY;
goto read_cert_end;
}
sc_format_path(certpath, path);
res = dnie_read_file(card, path, &file, &buffer, &bufferlen);
if (res != SC_SUCCESS) {
msg = "Cannot get intermediate CA cert";
goto read_cert_end;
}
*cert = d2i_X509(NULL, (const unsigned char **)&buffer, bufferlen);
if (*cert == NULL) { /* received data is not a certificate */
res = SC_ERROR_OBJECT_NOT_VALID;
msg = "Readed data is not a certificate";
goto read_cert_end;
}
res = SC_SUCCESS;
read_cert_end:
if (file) {
sc_file_free(file);
file = NULL;
buffer = NULL;
bufferlen = 0;
}
if (msg)
sc_log(card->ctx, msg);
LOG_FUNC_RETURN(card->ctx, res);
}
/************ implementation of cwa provider methods **************/
/**
* Retrieve Root CA public key.
*
* Just returns (as local SM authentication) static data
* @param card Pointer to card driver structure
* @param root_ca_key pointer to resulting returned key
* @return SC_SUCCESS if ok; else error code
*/
static int dnie_get_root_ca_pubkey(sc_card_t * card, EVP_PKEY ** root_ca_key)
{
int res=SC_SUCCESS;
RSA *root_ca_rsa=NULL;
LOG_FUNC_CALLED(card->ctx);
/* compose root_ca_public key with data provided by Dnie Manual */
*root_ca_key = EVP_PKEY_new();
root_ca_rsa = RSA_new();
if (!*root_ca_key || !root_ca_rsa) {
sc_log(card->ctx, "Cannot create data for root CA public key");
return SC_ERROR_OUT_OF_MEMORY;
}
root_ca_rsa->n = BN_bin2bn(icc_root_ca_modulus,
sizeof(icc_root_ca_modulus), root_ca_rsa->n);
root_ca_rsa->e = BN_bin2bn(icc_root_ca_public_exponent,
sizeof(icc_root_ca_public_exponent),
root_ca_rsa->e);
res = EVP_PKEY_assign_RSA(*root_ca_key, root_ca_rsa);
if (!res) {
if (*root_ca_key)
EVP_PKEY_free(*root_ca_key); /*implies root_ca_rsa free() */
sc_log(card->ctx, "Cannot compose root CA public key");
return SC_ERROR_INTERNAL;
}
LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
}
/**
* Retrieve IFD (application) CVC intermediate CA certificate and length.
*
* Returns a byte array with the intermediate CA certificate
* (in CardVerifiable Certificate format) to be sent to the
* card in External Authentication process
* As this is local provider, just points to provided static data,
* and allways return success
*
* @param card Pointer to card driver Certificate
* @param cert Where to store resulting byte array
* @param length len of returned byte array
* @return SC_SUCCESS if ok; else error code
*/
static int dnie_get_cvc_ca_cert(sc_card_t * card, u8 ** cert, size_t * length)
{
LOG_FUNC_CALLED(card->ctx);
*cert = C_CV_CA_CS_AUT_cert;
*length = sizeof(C_CV_CA_CS_AUT_cert);
LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
}
/**
* Retrieve IFD (application) CVC certificate and length.
*
* Returns a byte array with the application's certificate
* (in CardVerifiable Certificate format) to be sent to the
* card in External Authentication process
* As this is local provider, just points to provided static data,
* and allways return success
*
* @param card Pointer to card driver Certificate
* @param cert Where to store resulting byte array
* @param length len of returned byte array
* @return SC_SUCCESS if ok; else error code
*/
static int dnie_get_cvc_ifd_cert(sc_card_t * card, u8 ** cert, size_t * length)
{
LOG_FUNC_CALLED(card->ctx);
*cert = C_CV_IFDUser_AUT_cert;
*length = sizeof(C_CV_IFDUser_AUT_cert);
LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
}
/**
* Get IFD (Terminal) private key data.
*
* As this is a local (in memory) provider, just get data specified in
* DNIe's manual and compose an OpenSSL private key structure
*
* Notice that resulting data should be keept in memory as little as possible
* Erasing them once used
*
* @param card pointer to card driver structure
* @param ifd_privkey where to store IFD private key
* @return SC_SUCCESS if ok; else error code
*/
static int dnie_get_ifd_privkey(sc_card_t * card, EVP_PKEY ** ifd_privkey)
{
RSA *ifd_rsa=NULL;
int res=SC_SUCCESS;
LOG_FUNC_CALLED(card->ctx);
/* compose ifd_private key with data provided in Annex 3 of DNIe Manual */
*ifd_privkey = EVP_PKEY_new();
ifd_rsa = RSA_new();
if (!*ifd_privkey || !ifd_rsa) {
sc_log(card->ctx, "Cannot create data for IFD private key");
return SC_ERROR_OUT_OF_MEMORY;
}
ifd_rsa->n = BN_bin2bn(ifd_modulus, sizeof(ifd_modulus), ifd_rsa->n);
ifd_rsa->e =
BN_bin2bn(ifd_public_exponent, sizeof(ifd_public_exponent),
ifd_rsa->e);
ifd_rsa->d =
BN_bin2bn(ifd_private_exponent, sizeof(ifd_private_exponent),
ifd_rsa->d);
res = EVP_PKEY_assign_RSA(*ifd_privkey, ifd_rsa);
if (!res) {
if (*ifd_privkey)
EVP_PKEY_free(*ifd_privkey); /* implies ifd_rsa free() */
sc_log(card->ctx, "Cannot compose IFD private key");
return SC_ERROR_INTERNAL;
}
LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
}
/**
* Get ICC intermediate CA Certificate from card.
*
* @param card Pointer to card driver structure
* @param cert where to store resulting certificate
* @return SC_SUCCESS if ok; else error code
*/
static int dnie_get_icc_intermediate_ca_cert(sc_card_t * card, X509 ** cert)
{
return dnie_read_certificate(card, "3F006020", cert);
}
/**
* Get ICC (card) certificate.
*
* @param card Pointer to card driver structure
* @param cert where to store resulting certificate
* @return SC_SUCCESS if ok; else error code
*/
static int dnie_get_icc_cert(sc_card_t * card, X509 ** cert)
{
return dnie_read_certificate(card, "3F00601F", cert);
}
/**
* Retrieve key reference for Root CA to validate CVC intermediate CA certs.
*
* This is required in the process of On card external authenticate
* @param card Pointer to card driver structure
* @param buf where to store resulting key reference
* @param len where to store buffer length
* @return SC_SUCCESS if ok; else error code
*/
static int dnie_get_root_ca_pubkey_ref(sc_card_t * card, u8 ** buf,
size_t * len)
{
*buf = root_ca_keyref;
*len = sizeof(root_ca_keyref);
return SC_SUCCESS;
}
/**
* Retrieve public key reference for intermediate CA to validate IFD cert.
*
* This is required in the process of On card external authenticate
* As this driver is for local SM authentication SC_SUCCESS is allways returned
*
* @param card Pointer to card driver structure
* @param buf where to store resulting key reference
* @param len where to store buffer length
* @return SC_SUCCESS if ok; else error code
*/
static int dnie_get_intermediate_ca_pubkey_ref(sc_card_t * card, u8 ** buf,
size_t * len)
{
*buf = cvc_intca_keyref;
*len = sizeof(cvc_intca_keyref);
return SC_SUCCESS;
}
/**
* Retrieve public key reference for IFD certificate.
*
* This tells the card with in memory key reference is to be used
* when CVC cert is sent for external auth procedure
* As this driver is for local SM authentication SC_SUCCESS is allways returned
*
* @param card pointer to card driver structure
* @param buf where to store data to be sent
* @param len where to store data length
* @return SC_SUCCESS if ok; else error code
*/
static int dnie_get_ifd_pubkey_ref(sc_card_t * card, u8 ** buf, size_t * len)
{
*buf = cvc_ifd_keyref;
*len = sizeof(cvc_ifd_keyref);
return SC_SUCCESS;
}
/**
* Retrieve key reference for ICC privkey.
*
* In local SM stablishment, just retrieve key reference from static
* data tables and just return success
*
* @param card pointer to card driver structure
* @param buf where to store data
* @param len where to store data length
* @return SC_SUCCESS if ok; else error
*/
static int dnie_get_icc_privkey_ref(sc_card_t * card, u8 ** buf, size_t * len)
{
*buf = icc_priv_keyref;
*len = sizeof(icc_priv_keyref);
return SC_SUCCESS;
}
/**
* Retrieve SN.IFD (8 bytes left padded with zeroes if required).
*
* In DNIe local SM procedure, just read it from static data and
* return SC_SUCCESS
*
* @param card pointer to card structure
* @param buf where to store result (8 bytes)
* @return SC_SUCCESS if ok; else error
*/
static int dnie_get_sn_ifd(sc_card_t * card, u8 ** buf)
{
*buf = sn_ifd;
return SC_SUCCESS;
}
/* Retrieve SN.ICC (8 bytes left padded with zeroes if needed).
*
* As DNIe reads serial number at startup, no need to read again
* Just retrieve it from cache and return success
*
* @param card pointer to card structure
* @param buf where to store result (8 bytes)
* @return SC_SUCCESS if ok; else error
*/
static int dnie_get_sn_icc(sc_card_t * card, u8 ** buf)
{
int res=SC_SUCCESS;
sc_serial_number_t serial;
res = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial);
LOG_TEST_RET(card->ctx, res, "Error in gettting serial number");
/* copy into sn_icc buffer.Remember that dnie sn has 7 bytes length */
memset(&sn_icc[0], 0, sizeof(sn_icc));
memcpy(&sn_icc[1], serial.value, 7);
/* return data */
*buf = &sn_icc[0];
return SC_SUCCESS;
}
/**
* CWA-14890 SM stablisment pre-operations.
*
* DNIe needs to get icc serial number at the begin of the sm creation
* (to avoid breaking key references) so get it an store into serialnr
* cache here.
*
* In this way if get_sn_icc is called(), we make sure that no APDU
* command is to be sent to card, just retrieve it from cache
*
* @param card pointer to card driver structure
* @param provider pointer to SM data provider for DNIe
* @return SC_SUCCESS if OK. else error code
*/
static int dnie_create_pre_ops(sc_card_t * card, cwa_provider_t * provider)
{
sc_serial_number_t serial;
/* make sure that this cwa provider is used with a working DNIe card */
if (card->type != SC_CARD_TYPE_DNIE_USER)
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_CARD);
/* ensure that Card Serial Number is properly cached */
return sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial);
}
/**
* Main entry point for DNIe CWA14890 SM data provider.
*
* Return a pointer to DNIe data provider with proper function pointers
*
* @param card pointer to card driver data structure
* @return cwa14890 DNIe data provider if success, null on error
*/
cwa_provider_t *dnie_get_cwa_provider(sc_card_t * card)
{
cwa_provider_t *res = cwa_get_default_provider(card);
if (!res)
return NULL;
/* set up proper data */
/* pre and post operations */
res->cwa_create_pre_ops = dnie_create_pre_ops;
res->cwa_create_post_ops = NULL;
/* Get ICC intermediate CA path */
res->cwa_get_icc_intermediate_ca_cert =
dnie_get_icc_intermediate_ca_cert;
/* Get ICC certificate path */
res->cwa_get_icc_cert = dnie_get_icc_cert;
/* Obtain RSA public key from RootCA */
res->cwa_get_root_ca_pubkey = dnie_get_root_ca_pubkey;
/* Obtain RSA IFD private key */
res->cwa_get_ifd_privkey = dnie_get_ifd_privkey;
/* Retrieve CVC intermediate CA certificate and length */
res->cwa_get_cvc_ca_cert = dnie_get_cvc_ca_cert;
/* Retrieve CVC IFD certificate and length */
res->cwa_get_cvc_ifd_cert = dnie_get_cvc_ifd_cert;
/* Get public key references for Root CA to validate intermediate CA cert */
res->cwa_get_root_ca_pubkey_ref = dnie_get_root_ca_pubkey_ref;
/* Get public key reference for IFD intermediate CA certificate */
res->cwa_get_intermediate_ca_pubkey_ref =
dnie_get_intermediate_ca_pubkey_ref;
/* Get public key reference for IFD CVC certificate */
res->cwa_get_ifd_pubkey_ref = dnie_get_ifd_pubkey_ref;
/* Get ICC private key reference */
res->cwa_get_icc_privkey_ref = dnie_get_icc_privkey_ref;
/* Get IFD Serial Number */
res->cwa_get_sn_ifd = dnie_get_sn_ifd;
/* Get ICC Serial Number */
res->cwa_get_sn_icc = dnie_get_sn_icc;
/************** operations related with APDU encoding ******************/
/* pre and post operations */
res->cwa_encode_pre_ops = NULL;
res->cwa_encode_post_ops = NULL;
/************** operations related APDU response decoding **************/
/* pre and post operations */
res->cwa_decode_pre_ops = NULL;
res->cwa_decode_post_ops = NULL;
return res;
}
static int dnie_transmit_apdu_internal(sc_card_t * card, sc_apdu_t * apdu)
{
u8 *buf = NULL; /* use for store partial le responses */
int res = SC_SUCCESS;
cwa_provider_t *provider = NULL;
if ((card == NULL) || (card->ctx == NULL) || (apdu == NULL))
return SC_ERROR_INVALID_ARGUMENTS;
LOG_FUNC_CALLED(card->ctx);
provider = GET_DNIE_PRIV_DATA(card)->cwa_provider;
buf = calloc(2048, sizeof(u8));
if (!buf)
LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
/* check if envelope is needed */
if (apdu->lc <= card->max_send_size) {
int tmp;
/* no envelope needed */
sc_log(card->ctx, "envelope tx is not required");
tmp = apdu->cse; /* save original apdu type */
/* if SM is on, assure rx buffer exists and force get_response */
if (provider->status.session.state == CWA_SM_ACTIVE) {
if (tmp == SC_APDU_CASE_3_SHORT)
apdu->cse = SC_APDU_CASE_4_SHORT;
if (apdu->resplen == 0) { /* no response buffer: create */
apdu->resp = buf;
apdu->resplen = 2048;
apdu->le = card->max_recv_size;
}
}
/* call std sc_transmit_apdu */
res = sc_transmit_apdu(card, apdu);
/* and restore original apdu type */
apdu->cse = tmp;
} else {
size_t e_txlen = 0;
size_t index = 0;
sc_apdu_t *e_apdu = NULL;
u8 *e_tx = NULL;
/* envelope needed */
sc_log(card->ctx, "envelope tx required: lc:%d", apdu->lc);
e_apdu = calloc(1, sizeof(sc_apdu_t)); /* enveloped apdu */
e_tx = calloc(7 + apdu->datalen, sizeof(u8)); /* enveloped data */
if (!e_apdu || !e_tx)
LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
/* copy apdu info into enveloped data */
*(e_tx + 0) = apdu->cla; /* apdu header */
*(e_tx + 1) = apdu->ins;
*(e_tx + 2) = apdu->p1;
*(e_tx + 3) = apdu->p2;
*(e_tx + 4) = 0x00; /* length in extended format */
*(e_tx + 5) = 0xff & (apdu->lc >> 8);
*(e_tx + 6) = 0xff & apdu->lc;
memcpy(e_tx + 7, apdu->data, apdu->lc);
e_txlen = 7 + apdu->lc;
/* sc_log(card->ctx, "Data to be enveloped & sent: (%d bytes)\n%s\n===============================================================",e_txlen,sc_dump_hex(e_tx,e_txlen)); */
/* split apdu in n chunks of max_send_size len */
for (index = 0; index < e_txlen; index += card->max_send_size) {
size_t len = MIN(card->max_send_size, e_txlen - index);
sc_log(card->ctx, "envelope tx offset:%04X size:%02X",
index, len);
/* compose envelope apdu command */
sc_format_apdu(card, e_apdu, apdu->cse, 0xC2, 0x00,
0x00);
e_apdu->cla = 0x90; /* propietary CLA */
e_apdu->data = e_tx + index;
e_apdu->lc = len;
e_apdu->datalen = len;
e_apdu->le = apdu->le;
e_apdu->resp = apdu->resp;
e_apdu->resplen = apdu->resplen;
/* if SM is ON, ensure resp exists, and force getResponse() */
if (provider->status.session.state == CWA_SM_ACTIVE) {
/* set up proper apdu type */
if (e_apdu->cse == SC_APDU_CASE_3_SHORT)
e_apdu->cse = SC_APDU_CASE_4_SHORT;
/* if no response buffer: create */
if (apdu->resplen == 0) {
e_apdu->resp = buf;
e_apdu->resplen = 2048;
e_apdu->le = card->max_recv_size;
}
}
/* send data chunk bypassing apdu wrapping */
res = sc_transmit_apdu(card, e_apdu);
LOG_TEST_RET(card->ctx, res,
"Error in envelope() send apdu");
} /* for */
/* last apdu sent contains response to enveloped cmd */
apdu->resp = e_apdu->resp;
apdu->resplen = e_apdu->resplen;
res = SC_SUCCESS;
}
LOG_FUNC_RETURN(card->ctx, res);
}
/**
* APDU Wrapping routine.
*
* Called before sc_transmit_apdu() to allowing APDU wrapping
* If set to NULL no wrapping process will be done
* Usefull on Secure Messaging APDU encode/decode
* If returned value is greater than zero, do_single_transmit()
* will be called, else means either SC_SUCCESS or error code
*
* NOTE:
* DNIe doesn't handle apdu chaining; instead apdus with
* lc>max_send_size are sent by mean of envelope() apdu command
* So we use this method for
* - encode and decode SM if SM is on
* - use envelope instead of apdu chain if lc>max_send_size
*
* @param card Pointer to Card Structure
* @param apdu to be wrapped
* @return
* - positive: use OpenSC's sc_transmit_apdu()
* - negative: error
* - zero: success: no need to further transmission
*/
static int dnie_wrap_apdu(sc_card_t * card, sc_apdu_t * apdu)
{
int res = SC_SUCCESS;
sc_apdu_t wrapped;
sc_context_t *ctx;
cwa_provider_t *provider = NULL;
int retries = 3;
if ((card == NULL) || (card->ctx == NULL) || (apdu == NULL))
return SC_ERROR_INVALID_ARGUMENTS;
ctx=card->ctx;
LOG_FUNC_CALLED(ctx);
provider = GET_DNIE_PRIV_DATA(card)->cwa_provider;
for (retries=3; retries>0; retries--) {
/* preserve original apdu to take care of retransmission */
memcpy(&wrapped, apdu, sizeof(sc_apdu_t));
/* SM is active, encode apdu */
if (provider->status.session.state == CWA_SM_ACTIVE) {
wrapped.resp = NULL;
wrapped.resplen = 0; /* let get_response() assign space */
res = cwa_encode_apdu(card, provider, apdu, &wrapped);
LOG_TEST_RET(ctx, res,
"Error in cwa_encode_apdu process");
}
/* send apdu via envelope() cmd if needed */
res = dnie_transmit_apdu_internal(card, &wrapped);
/* check for tx errors */
LOG_TEST_RET(ctx, res, "Error in dnie_transmit_apdu process");
/* parse response and handle SM related errors */
res=card->ops->check_sw(card,wrapped.sw1,wrapped.sw2);
if ( res == SC_ERROR_SM ) {
sc_log(ctx,"Detected SM error/collision. Try %d",retries);
switch(provider->status.session.state) {
/* No SM or creating: collision with other process
just retry as SM error reset ICC SM state */
case CWA_SM_NONE:
case CWA_SM_INPROGRESS:
continue;
/* SM was active: force restart SM and retry */
case CWA_SM_ACTIVE:
res=cwa_create_secure_channel(card, provider, CWA_SM_COLD);
LOG_TEST_RET(ctx,res,"Cannot re-enable SM");
continue;
}
}
/* if SM is active; decode apdu */
if (provider->status.session.state == CWA_SM_ACTIVE) {
apdu->resp = NULL;
apdu->resplen = 0; /* let cwa_decode_response() eval & create size */
res = cwa_decode_response(card, provider, &wrapped, apdu);
LOG_TEST_RET(ctx, res, "Error in cwa_decode_response process");
} else {
/* memcopy result to original apdu */
memcpy(apdu, &wrapped, sizeof(sc_apdu_t));
}
LOG_FUNC_RETURN(ctx, res);
}
sc_log(ctx,"Too many retransmissions. Abort and return");
LOG_FUNC_RETURN(ctx, SC_ERROR_INTERNAL);
}
int dnie_transmit_apdu(sc_card_t * card, sc_apdu_t * apdu)
{
int res = SC_SUCCESS;
res = dnie_wrap_apdu(card, apdu);
if (res <= 0) return res;
return sc_transmit_apdu(card, apdu);
}
#endif /* HAVE_OPENSSL */
/* _ end of cwa-dnie.c - */

60
src/libopensc/cwa-dnie.h Normal file
View File

@ -0,0 +1,60 @@
/**
* cwa-dnie.h: Defines dnie_transmit_apdu wrapper for sc_transmit_apdu
*
* This work is derived from many sources at OpenSC Project site,
* (see references), and the information made public for Spanish
* Direccion General de la Policia y de la Guardia Civil
*
* 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
*/
#ifndef __CWADNIE_H__
#define __CWADNIE_H__
#ifdef ENABLE_OPENSSL
#include "libopensc/opensc.h"
#include "cwa14890.h"
#ifdef ENABLE_DNIE_UI
#include "user-interface.h"
#endif
/**
* OpenDNIe private data declaration
*
* Defines internal data used in OpenDNIe code
*/
typedef struct dnie_private_data_st {
/* sc_serial_number_t *serialnumber; < Cached copy of card serial number NOT USED AT THE MOMENT */
int rsa_key_ref; /**< Key id reference being used in sec operation */
u8 *cache; /**< Cache buffer for read_binary() operation */
size_t cachelen; /**< length of cache buffer */
cwa_provider_t *cwa_provider;
#ifdef ENABLE_DNIE_UI
struct ui_context ui_ctx;
#endif
} dnie_private_data_t;
/**
* DNIe Card Driver private data
*/
#define GET_DNIE_PRIV_DATA(card) ((dnie_private_data_t *) ((card)->drv_data))
#define GET_DNIE_UI_CTX(card) (((dnie_private_data_t *) ((card)->drv_data))->ui_ctx)
int dnie_transmit_apdu(sc_card_t * card, sc_apdu_t * apdu);
#endif
#endif

2136
src/libopensc/cwa14890.c Normal file

File diff suppressed because it is too large Load Diff

415
src/libopensc/cwa14890.h Normal file
View File

@ -0,0 +1,415 @@
/**
* cwa14890.h: Defines, Typedefs and prototype functions for SM Messaging according CWA-14890 standard.
*
* Copyright (C) 2010 Juan Antonio Martinez <jonsito@terra.es>
*
* This work is derived from many sources at OpenSC Project site,
* (see references), and the information made public for Spanish
* Direccion General de la Policia y de la Guardia Civil
*
* 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
*/
#ifndef __CWA14890_H__
#define __CWA14890_H__
#ifdef ENABLE_OPENSSL
/* Secure Messaging state indicator */
#define CWA_SM_NONE 0x00 /** No SM channel defined */
#define CWA_SM_INPROGRESS 0x01 /** SM channel is being created: don't use */
#define CWA_SM_ACTIVE 0x02 /** SM channel is active */
/* Flags for setting SM status */
#define CWA_SM_OFF 0x00 /** Disable SM channel */
#define CWA_SM_COLD 0x01 /** force creation of a new SM channel */
#define CWA_SM_WARM 0x02 /** Create new SM channel only if state is NONE */
/* TAGS for encoded APDU's */
#define CWA_SM_PLAIN_TAG 0x81 /** Plain value (to be protected by CC) */
#define CWA_SM_CRYPTO_TAG 0x87 /** Padding-content + cryptogram */
#define CWA_SM_MAC_TAG 0x8E /** Cryptographic checksum (MAC) */
#define CWA_SM_LE_TAG 0x97 /** Le (to be protected by CC ) */
#define CWA_SM_STATUS_TAG 0x99 /** Processing status (SW1-SW2 mac protected ) */
/*************** data structures for CWA14890 SM handling **************/
#include "libopensc/types.h"
#include <openssl/x509.h>
#include <openssl/des.h>
/**
* Structure used to compose BER-TLV encoded data
* according to iso7816-4 sect 5.2.2.
*
* Notice that current implementation does not handle properly
* multibyte tag id. Just asume that tag is 1-byte lenght
* Also, encodings for data lenght longer than 0x01000000 bytes
* are not supported (tag 0x84)
*/
typedef struct cwa_tlv_st {
u8 *buf; /** local copy of TLV byte array */
size_t buflen; /** lengt of buffer */
unsigned int tag; /** tag ID */
size_t len; /** lenght of data field */
u8 *data; /** pointer to start of data in buf buffer */
} cwa_tlv_t;
/**
* Structure used to handle keys and sequence counter once SM session
* is stablished
*/
typedef struct cwa_sm_session_st {
/* variables used once SM is started */
int state; /** one of NONE, INPROGRESS, or ACTIVE */
u8 kenc[16]; /** key used for data encoding */
u8 kmac[16]; /** key for mac checksum calculation */
u8 ssc[8]; /** send sequence counter */
} cwa_sm_session_t;
/**
* Estructure used to compose and store variables related to SM setting
* and encode/decode apdu messages.
*/
typedef struct cwa_sm_status_st {
/* variables used in SM establishment */
u8 kicc[32];
u8 kifd[32];
u8 rndicc[8]; /** 8 bytes random number generated by card */
u8 rndifd[8]; /** 8 bytes random number generated by application */
u8 sig[128]; /** buffer to store & compute signatures (1024 bits) */
cwa_sm_session_t session; /** current session data */
} cwa_sm_status_t;
/**
* Data and function pointers to provide information to create and handle
* Secure Channel.
*/
typedef struct cwa_provider_st {
/************ data related with SM operations *************************/
cwa_sm_status_t status; /** sm status for this provider */
/************ operations related with secure channel creation *********/
/* pre and post operations */
/**
* CWA-14890 SM stablisment pre-operations.
*
* This code is called before any operation required in
* standard cwa14890 SM stablisment process. It's usually
* used for adquiring/initialize data to be used in the
* process (i.e: retrieve card serial number), to make sure
* that no extra apdu is sent during the SM stablishment procedure
*
* @param card pointer to card driver structure
* @param provider pointer to SM data provider for DNIe
* @return SC_SUCCESS if OK. else error code
*/
int (*cwa_create_pre_ops) (sc_card_t * card,
struct cwa_provider_st * provider);
/**
* CWA-14890 SM stablisment post-operations.
*
* This code is called after sucessfull SM chanel stablishment
* procedure, and before returning from create_sm_chanel() function
* May be use for store data, trace, logs and so
*
* @param card pointer to card driver structure
* @param provider pointer to SM data provider for DNIe
* @return SC_SUCCESS if OK. else error code
*/
int (*cwa_create_post_ops) (sc_card_t * card,
struct cwa_provider_st * provider);
/**
* Get ICC (card) intermediate CA Certificate.
*
* @param card Pointer to card driver structure
* @param cert where to store resulting certificate
* @return SC_SUCCESS if ok; else error code
*/
int (*cwa_get_icc_intermediate_ca_cert) (sc_card_t * card,
X509 ** cert);
/**
* Get ICC (card) certificate.
*
* @param card Pointer to card driver structure
* @param cert where to store resulting certificate
* @return SC_SUCCESS if ok; else error code
*/
int (*cwa_get_icc_cert) (sc_card_t * card, X509 ** cert);
/**
* Obtain RSA public key from RootCA.
*
* @param root_ca_key pointer to resulting returned key
* @return SC_SUCCESS if ok; else error code
*/
int (*cwa_get_root_ca_pubkey) (sc_card_t * card, EVP_PKEY ** key);
/**
* Get RSA IFD (Terminal) private key data.
*
* Notice that resulting data should be keept in memory as little
* as possible Erasing them once used
*
* @param card pointer to card driver structure
* @param ifd_privkey where to store IFD private key
* @return SC_SUCCESS if ok; else error code
*/
int (*cwa_get_ifd_privkey) (sc_card_t * card, EVP_PKEY ** key);
/* TODO:
* CVC handling routines should be grouped in just retrieve CVC
* certificate. The key reference, as stated by CWA should be
* extracted from CVC...
*
* But to do this, an special OpenSSL with PACE extensions is
* needed. In the meantime, let's use binary buffers to get
* CVC and key references, until an CV_CERT hancling API
* become available in standard OpenSSL
*
*@see http://openpace.sourceforge.net
*/
/**
* Retrieve IFD (application) CVC intermediate CA certificate and length.
*
* Returns a byte array with the intermediate CA certificate
* (in CardVerifiable Certificate format) to be sent to the
* card in External Authentication process
*
* @param card Pointer to card driver Certificate
* @param cert Where to store resulting byte array
* @param length len of returned byte array
* @return SC_SUCCESS if ok; else error code
*/
int (*cwa_get_cvc_ca_cert) (sc_card_t * card, u8 ** cert,
size_t * lenght);
/**
* Retrieve IFD (application) CVC certificate and length.
*
* Returns a byte array with the application's certificate
* (in CardVerifiable Certificate format) to be sent to the
* card in External Authentication process
*
* @param card Pointer to card driver Certificate
* @param cert Where to store resulting byte array
* @param length len of returned byte array
* @return SC_SUCCESS if ok; else error code
*/
int (*cwa_get_cvc_ifd_cert) (sc_card_t * card, u8 ** cert,
size_t * lenght);
/**
* Retrieve public key reference for Root CA to validate CVC intermediate CA certs.
*
* This is required in the process of On card external authenticate
* @param card Pointer to card driver structure
* @param buf where to store resulting key reference
* @param len where to store buffer length
* @return SC_SUCCESS if ok; else error code
*/
int (*cwa_get_root_ca_pubkey_ref) (sc_card_t * card, u8 ** buf,
size_t * len);
/**
* Get public key reference for intermediate CA to validate IFD cert.
*
* This is required in the process of On card external authenticate
*
* @param card Pointer to card driver structure
* @param buf where to store resulting key reference
* @param len where to store buffer length
* @return SC_SUCCESS if ok; else error code
*/
int (*cwa_get_intermediate_ca_pubkey_ref) (sc_card_t * card, u8 ** buf,
size_t * len);
/**
* Retrieve public key reference for IFD certificate.
*
* This tells the card with in memory key reference is to be used
* when CVC cert is sent for external auth procedure
*
* @param card pointer to card driver structure
* @param buf where to store data to be sent
* @param len where to store data length
* @return SC_SUCCESS if ok; else error code
*/
int (*cwa_get_ifd_pubkey_ref) (sc_card_t * card, u8 ** buf,
size_t * len);
/**
* Retrieve key reference for ICC private key.
*
* @param card pointer to card driver structure
* @param buf where to store data
* @param len where to store data length
* @return SC_SUCCESS if ok; else error
*/
int (*cwa_get_icc_privkey_ref) (sc_card_t * card, u8 ** buf,
size_t * len);
/**
* Retrieve SN.IFD - Terminal Serial Number.
*
* Result SN is 8 bytes long left padded with zeroes if required.
*
* @param card pointer to card structure
* @param buf where to store result (8 bytes)
* @return SC_SUCCESS if ok; else error
*/
int (*cwa_get_sn_ifd) (sc_card_t * card, u8 ** buf);
/**
* Get SN.ICC - Card Serial Number.
*
* Result value is 8 bytes long left padded with zeroes if needed)
*
* @param card pointer to card structure
* @param buf where to store result (8 bytes)
* @return SC_SUCCESS if ok; else error
*/
int (*cwa_get_sn_icc) (sc_card_t * card, u8 ** buf);
/************** operations related with APDU encoding ******************/
/**
* Operation to be done before any APDU encode procedure.
*
* @param card Pointer to card driver data structure
* @param provider pointer to cwa1890 SM provider
* @param from APDU to be encoded
* @param to resulting APDU to be sent to encode procedure
* @return SC_SUCCESS if OK, else error code
*/
int (*cwa_encode_pre_ops) (sc_card_t * card,
struct cwa_provider_st * provider,
sc_apdu_t * from, sc_apdu_t * to);
/**
* Operation to be done after APDU encode process finished ok.
*
* @param card Pointer to card driver data structure
* @param provider pointer to cwa1890 SM provider
* @param from encoded APDU
* @param to resulting encoded APDU to be returned to libopensc
* @return SC_SUCCESS if OK, else error code
*/
int (*cwa_encode_post_ops) (sc_card_t * card,
struct cwa_provider_st * provider,
sc_apdu_t * from, sc_apdu_t * to);
/************** operations related APDU response decoding **************/
/**
* Operation to be done before any APDU Response decode procedure.
*
* @param card Pointer to card driver data structure
* @param provider pointer to cwa1890 SM provider
* @param from APDU Response to be decoded
* @param to resulting APDU response to be sent to decode procedure
* @return SC_SUCCESS if OK, else error code
*/
int (*cwa_decode_pre_ops) (sc_card_t * card,
struct cwa_provider_st * provider,
sc_apdu_t * from, sc_apdu_t * to);
/**
* Operation to be done after APDU Response decode process finished ok.
*
* @param card Pointer to card driver data structure
* @param provider pointer to cwa1890 SM provider
* @param from decoded APDU Response
* @param to resulting APDU Response to be returned to libopensc
* @return SC_SUCCESS if OK, else error code
*/
int (*cwa_decode_post_ops) (sc_card_t * card,
struct cwa_provider_st * provider,
sc_apdu_t * from, sc_apdu_t * to);
} cwa_provider_t;
/************************** external function prototypes ******************/
/**
* Create Secure channel.
*
* Based on Several documents:
* - "Understanding the DNIe"
* - "Manual de comandos del DNIe"
* - ISO7816-4 and CWA14890-{1,2}
*
* @param card card info structure
* @param provider pointer to cwa provider
* @param flag Requested SM final state (OFF,COLD,WARM)
* @return SC_SUCCESS if OK; else error code
*/
extern int cwa_create_secure_channel(sc_card_t * card,
cwa_provider_t * provider, int flag);
/**
* Decode an APDU response.
*
* Calling this functions means that It's has been verified
* That apdu response comes in TLV encoded format and needs decoding
* Based on section 9 of CWA-14890 and Sect 6 of iso7816-4 standards
* And DNIe's manual
*
* @param card card info structure
* @param provider cwa provider data to handle SM channel
* @param from apdu to be decoded
* @param to where to store decoded apdu
* @return SC_SUCCESS if ok; else error code
*/
extern int cwa_decode_response(sc_card_t * card,
cwa_provider_t * provider,
sc_apdu_t * from, sc_apdu_t * to);
/**
* Encode an APDU.
*
* Calling this functions means that It's has been verified
* That source apdu needs encoding
* Based on section 9 of CWA-14890 and Sect 6 of iso7816-4 standards
* And DNIe's manual
*
* @param card card info structure
* @param provider cwa provider data to handle SM channel
* @param from apdu to be encoded
* @param to Where to store encoded apdu
* @return SC_SUCCESS if ok; else error code
*/
extern int cwa_encode_apdu(sc_card_t * card,
cwa_provider_t * provider,
sc_apdu_t * from, sc_apdu_t * to);
/**
* Gets a default cwa_provider structure.
*
* @param card Pointer to card driver information
* @return default cwa_provider data, or null on error
*/
extern cwa_provider_t *cwa_get_default_provider(sc_card_t * card);
#endif /* ENABLE_OPENSSL */
#endif

274
src/libopensc/pkcs15-dnie.c Normal file
View File

@ -0,0 +1,274 @@
/**
* PKCS15 emulation layer for DNIe card.
*
* Copyright (C) 2011, Andre Zepezauer <andre.zepezauer@student.uni-halle.de>
* Copyright (C) 2011, Juan Antonio Martinez <jonsito@terra.es>
*
* 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
*/
#include <stdlib.h>
#include <string.h>
#include "config.h"
#include "libopensc/log.h"
#include "libopensc/asn1.h"
#include "libopensc/pkcs15.h"
/* Card driver related */
extern int dnie_match_card(struct sc_card *card);
/* Helper functions to get the pkcs15 stuff bound. */
static
int dump_ef(sc_card_t * card, const char *path, u8 * buf, size_t * buf_len)
{
int rv;
sc_file_t *file = sc_file_new();
sc_format_path(path, &file->path);
sc_select_file(card, &file->path, &file);
if (file->size > *buf_len)
return SC_ERROR_BUFFER_TOO_SMALL;
rv = sc_read_binary(card, 0, buf, file->size, 0);
if (rv < 0)
return rv;
*buf_len = rv;
return SC_SUCCESS;
}
static const struct sc_asn1_entry c_asn1_odf[] = {
{"privateKeys", SC_ASN1_STRUCT, SC_ASN1_CTX | 0 | SC_ASN1_CONS, 0, NULL,
NULL},
{"publicKeys", SC_ASN1_STRUCT, SC_ASN1_CTX | 1 | SC_ASN1_CONS, 0, NULL,
NULL},
{"trustedPublicKeys", SC_ASN1_STRUCT, SC_ASN1_CTX | 2 | SC_ASN1_CONS, 0,
NULL, NULL},
{"secretKeys", SC_ASN1_STRUCT, SC_ASN1_CTX | 3 | SC_ASN1_CONS, 0, NULL,
NULL},
{"certificates", SC_ASN1_STRUCT, SC_ASN1_CTX | 4 | SC_ASN1_CONS, 0,
NULL, NULL},
{"trustedCertificates", SC_ASN1_STRUCT, SC_ASN1_CTX | 5 | SC_ASN1_CONS,
0, NULL, NULL},
{"usefulCertificates", SC_ASN1_STRUCT, SC_ASN1_CTX | 6 | SC_ASN1_CONS,
0, NULL, NULL},
{"dataObjects", SC_ASN1_STRUCT, SC_ASN1_CTX | 7 | SC_ASN1_CONS, 0, NULL,
NULL},
{"authObjects", SC_ASN1_STRUCT, SC_ASN1_CTX | 8 | SC_ASN1_CONS, 0, NULL,
NULL},
{NULL, 0, 0, 0, NULL, NULL}
};
static const unsigned int odf_indexes[] = {
SC_PKCS15_PRKDF,
SC_PKCS15_PUKDF,
SC_PKCS15_PUKDF_TRUSTED,
SC_PKCS15_SKDF,
SC_PKCS15_CDF,
SC_PKCS15_CDF_TRUSTED,
SC_PKCS15_CDF_USEFUL,
SC_PKCS15_DODF,
SC_PKCS15_AODF,
};
static
int parse_odf(const u8 * buf, size_t buflen, struct sc_pkcs15_card *p15card)
{
const u8 *p = buf;
size_t left = buflen;
int r, i, type;
sc_path_t path;
struct sc_asn1_entry asn1_obj_or_path[] = {
{"path", SC_ASN1_PATH, SC_ASN1_CONS | SC_ASN1_SEQUENCE, 0,
&path, NULL},
{NULL, 0, 0, 0, NULL, NULL}
};
struct sc_asn1_entry asn1_odf[10];
sc_path_t *path_prefix = calloc(1, sizeof(sc_path_t));
sc_format_path("3F005015", path_prefix);
sc_copy_asn1_entry(c_asn1_odf, asn1_odf);
for (i = 0; asn1_odf[i].name != NULL; i++)
sc_format_asn1_entry(asn1_odf + i, asn1_obj_or_path, NULL, 0);
while (left > 0) {
r = sc_asn1_decode_choice(p15card->card->ctx, asn1_odf, p, left,
&p, &left);
if (r == SC_ERROR_ASN1_END_OF_CONTENTS)
break;
if (r < 0)
return r;
type = r;
r = sc_pkcs15_make_absolute_path(path_prefix, &path);
if (r < 0)
return r;
r = sc_pkcs15_add_df(p15card, odf_indexes[type], &path);
if (r)
return r;
}
return 0;
}
static int sc_pkcs15emu_dnie_init(sc_pkcs15_card_t * p15card)
{
u8 buf[1024];
sc_pkcs15_df_t *df;
sc_pkcs15_object_t *p15_obj;
size_t len = sizeof(buf);
int rv;
sc_context_t *ctx = p15card->card->ctx;
LOG_FUNC_CALLED(ctx);
/* Check for correct card driver (i.e. iso7816) */
if (strcmp(p15card->card->driver->short_name, "dnie") != 0)
return SC_ERROR_WRONG_CARD;
/* Check for correct card atr */
if (dnie_match_card(p15card->card) != 1)
return SC_ERROR_WRONG_CARD;
/* Set root path of this application */
p15card->file_app = sc_file_new();
sc_format_path("3F00", &p15card->file_app->path);
/* Load TokenInfo */
rv = dump_ef(p15card->card, "3F0050155032", buf, &len);
if (rv != SC_SUCCESS) {
sc_log(ctx, "Reading of EF.TOKENINFO failed: %d", rv);
LOG_FUNC_RETURN(ctx, rv);
}
rv = sc_pkcs15_parse_tokeninfo(p15card->card->ctx, p15card->tokeninfo,
buf, len);
if (rv != SC_SUCCESS) {
sc_log(ctx, "Decoding of EF.TOKENINFO failed: %d", rv);
LOG_FUNC_RETURN(ctx, rv);
}
/* Only accept the original stuff */
if (strcmp(p15card->tokeninfo->manufacturer_id, "DGP-FNMT") != 0)
LOG_FUNC_RETURN(ctx, SC_ERROR_WRONG_CARD);
/* Load ODF */
rv = dump_ef(p15card->card, "3F0050155031", buf, &len);
if (rv != SC_SUCCESS) {
sc_log(ctx, "Reading of ODF failed: %d", rv);
LOG_FUNC_RETURN(ctx, rv);
}
rv = parse_odf(buf, len, p15card);
if (rv != SC_SUCCESS) {
sc_log(ctx, "Decoding of ODF failed: %d", rv);
LOG_FUNC_RETURN(ctx, rv);
}
/* Decode EF.PrKDF, EF.PuKDF and EF.CDF */
for (df = p15card->df_list; df != NULL; df = df->next) {
if (df->type == SC_PKCS15_PRKDF) {
rv = sc_pkcs15_parse_df(p15card, df);
if (rv != SC_SUCCESS) {
sc_log(ctx,
"Decoding of EF.PrKDF (%s) failed: %d",
sc_print_path(&df->path), rv);
}
}
if (df->type == SC_PKCS15_PUKDF) {
rv = sc_pkcs15_parse_df(p15card, df);
if (rv != SC_SUCCESS) {
sc_log(ctx,
"Decoding of EF.PuKDF (%s) failed: %d",
sc_print_path(&df->path), rv);
}
}
if (df->type == SC_PKCS15_CDF) {
rv = sc_pkcs15_parse_df(p15card, df);
if (rv != SC_SUCCESS) {
sc_log(ctx,
"Decoding of EF.CDF (%s) failed: %d",
sc_print_path(&df->path), rv);
}
}
if (df->type == SC_PKCS15_DODF) {
rv = sc_pkcs15_parse_df(p15card, df);
if (rv != SC_SUCCESS) {
sc_log(ctx,
"Decoding of EF.DODF (%s) failed: %d",
sc_print_path(&df->path), rv);
}
}
}
/* Perform required fixes */
p15_obj = p15card->obj_list;
while (p15_obj != NULL) {
/* Add missing 'auth_id' to private objects */
if ((p15_obj->flags & SC_PKCS15_CO_FLAG_PRIVATE)
&& (p15_obj->auth_id.len == 0)) {
p15_obj->auth_id.value[0] = 0x01;
p15_obj->auth_id.len = 1;
}
/* Remove found public keys as cannot be read_binary()'d */
if ( p15_obj->df && (p15_obj->df->type == SC_PKCS15_PUKDF) ) {
sc_pkcs15_object_t *puk = p15_obj;
p15_obj = p15_obj->next;
sc_pkcs15_remove_object(p15card, puk);
sc_pkcs15_free_object(puk);
} else {
p15_obj = p15_obj->next;
}
}
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}
/********************************************/
/* Public Functions When called as DLL Module*/
/********************************************/
const char *sc_driver_version()
{
return "0.12.3-svn"; /* defined in config.h of OpenSC */
}
int bind(sc_pkcs15_card_t * p15card, sc_pkcs15emu_opt_t * options)
{
/* Check for correct card driver (i.e. iso7816) */
if (strcmp(p15card->card->driver->short_name, "dnie") != 0)
return SC_ERROR_WRONG_CARD;
/* Check for correct card */
if (dnie_match_card(p15card->card) != 1)
return SC_ERROR_WRONG_CARD;
return sc_pkcs15emu_dnie_init(p15card);
}
/****************************************/
/* public functions for in-built module */
/****************************************/
int sc_pkcs15emu_dnie_init_ex(sc_pkcs15_card_t * p15card,
sc_pkcs15emu_opt_t * opts)
{
int r=SC_SUCCESS;
sc_context_t *ctx = p15card->card->ctx;
LOG_FUNC_CALLED(ctx);
/* if no check flag execute unconditionally */
if (opts && opts->flags & SC_PKCS15EMU_FLAGS_NO_CHECK)
LOG_FUNC_RETURN(ctx, sc_pkcs15emu_dnie_init(p15card));
/* check for proper card */
r = dnie_match_card(p15card->card);
if (r == 0)
LOG_FUNC_RETURN(ctx, SC_ERROR_WRONG_CARD);
/* ok: initialize and return */
LOG_FUNC_RETURN(ctx, sc_pkcs15emu_dnie_init(p15card));
}

View File

@ -67,6 +67,8 @@ extern int sc_pkcs15emu_itacns_init_ex(sc_pkcs15_card_t *,
sc_pkcs15emu_opt_t *);
extern int sc_pkcs15emu_sc_hsm_init_ex(sc_pkcs15_card_t *,
sc_pkcs15emu_opt_t *);
extern int sc_pkcs15emu_dnie_init_ex(sc_pkcs15_card_t *,
sc_pkcs15emu_opt_t *);
static struct {
const char * name;
@ -90,6 +92,7 @@ static struct {
{ "pteid", sc_pkcs15emu_pteid_init_ex },
{ "oberthur", sc_pkcs15emu_oberthur_init_ex },
{ "sc-hsm", sc_pkcs15emu_sc_hsm_init_ex },
{ "dnie", sc_pkcs15emu_dnie_init_ex },
{ NULL, NULL }
};
@ -113,6 +116,11 @@ int sc_pkcs15_is_emulation_only(sc_card_t *card)
case SC_CARD_TYPE_OPENPGP_V1:
case SC_CARD_TYPE_OPENPGP_V2:
case SC_CARD_TYPE_SC_HSM:
case SC_CARD_TYPE_DNIE_BASE:
case SC_CARD_TYPE_DNIE_BLANK:
case SC_CARD_TYPE_DNIE_ADMIN:
case SC_CARD_TYPE_DNIE_USER:
case SC_CARD_TYPE_DNIE_TERMINATED:
return 1;
default:
return 0;

View File

@ -0,0 +1,317 @@
/**
* user-interface.c: Support for GUI functions
*
* This file contains code for several related user-interface
* functions:
* - Ask user confirmation
* - Let user enter pin
*
* Copyright (C) 2010 Juan Antonio Martinez <jonsito@terra.es>
*
* 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
*/
#define __USER_INTERFACE_C__
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <sys/stat.h>
#ifdef _WIN32
#define UNICODE
#include <windows.h>
#endif
#ifdef __APPLE__
#include <Carbon/Carbon.h>
#endif
/* default titles */
#define USER_CONSENT_TITLE "Confirm"
#define USER_PIN_TITLE "PIN Request"
#define USER_PIN_PROMPT "Enter PIN:"
#include "libopensc/opensc.h"
#include "libopensc/log.h"
#include "libopensc/user-interface.h"
#include "libopensc/cwa-dnie.h"
#ifdef ENABLE_DNIE_UI
/**
* Messages used on pinentry protocol
*/
char *user_consent_msgs[] = { "SETTITLE", "SETDESC", "CONFIRM", "BYE" };
char *user_pin_msgs[] = { "SETTITLE", "SETPROMPT", "GETPIN", "BYE" };
static int ui_ask_user_pin(
sc_context_t *ctx, /* Card context */
const char *title, /* Title of the window */
const char *msg, /* Text to be shown to the user */
char *pinbuf, /* Where to store the user entered data */
size_t *pinlen) { /* buffer length; on return user data length */
/* TODO: write :-) */
return SC_ERROR_NOT_SUPPORTED;
}
/**
* Ask user for pin.
*
* Check the user pin configuration,
* Invoke proper gui app and check result
*
* @param card pointer to sc_card structure
* @param title Text to appear in the window header
* @param pin Structure to handle/store pin related data
* @return SC_SUCCESS if user accepts , else error code
*/
int sc_ask_user_pin(struct sc_card * card, const char *title, struct sc_pin_cmd_pin *pin) {
char *pinbuf=NULL;
size_t pinlen=0;
int res=SC_ERROR_INTERNAL;
char *msg=NULL;
if ( (card==NULL) || (card->ctx==NULL) )
return SC_ERROR_INVALID_ARGUMENTS;
LOG_FUNC_CALLED(card->ctx);
if (pin==NULL) LOG_FUNC_RETURN(card->ctx,SC_ERROR_INVALID_ARGUMENTS);
/* use a temporary buffer to ask for pin */
if (pin->max_length<=0) {
msg="Invalid pin max lenght";
res=SC_ERROR_INVALID_ARGUMENTS;
goto ask_user_pin_end;
}
pinlen=pin->max_length;
pinbuf= calloc(pin->max_length, sizeof(char));
if (!pinbuf) {
msg="Cannot create pin buffer";
res=SC_ERROR_OUT_OF_MEMORY;
goto ask_user_pin_end;
}
res= ui_ask_user_pin(
card->ctx,
(title==NULL)?USER_PIN_TITLE:title,
(pin->prompt==NULL)?USER_PIN_PROMPT:pin->prompt,
pinbuf,
&pinlen);
if (res!=SC_SUCCESS) {
msg="Error in ui_ask_user_pin";
goto ask_user_pin_end;
}
/* TODO: parse received data and fill result structure */
/* arriving here means success */
res=SC_SUCCESS;
ask_user_pin_end:
if (msg!=NULL) sc_log(card->ctx,msg);
if (pinbuf!=NULL) {
memset(pinbuf,0,pinlen);
free(pinbuf);
}
LOG_FUNC_RETURN(card->ctx,res);
}
/**
* Ask for user consent.
*
* Check for user consent configuration,
* Invoke proper gui app and check result
*
* @param card pointer to sc_card structure
* @param title Text to appear in the window header
* @param text Message to show to the user
* @return SC_SUCCESS on user consent OK , else error code
*/
int sc_ask_user_consent(struct sc_card * card, const char *title, const char *message)
{
#ifdef __APPLE__
CFOptionFlags result; /* result code from the message box */
/* convert the strings from char* to CFStringRef */
CFStringRef header_ref; /* to store title */
CFStringRef message_ref; /* to store message */
#endif
#ifdef linux
pid_t pid;
FILE *fin=NULL;
FILE *fout=NULL; /* to handle pipes as streams */
struct stat st_file; /* to verify that executable exists */
int srv_send[2]; /* to send data from server to client */
int srv_recv[2]; /* to receive data from client to server */
char outbuf[1024]; /* to compose and send messages */
char buf[1024]; /* to store client responses */
int n = 0; /* to iterate on to-be-sent messages */
#endif
int res = SC_ERROR_INTERNAL; /* by default error :-( */
char *msg = NULL; /* to makr errors */
if ((card == NULL) || (card->ctx == NULL))
return SC_ERROR_INVALID_ARGUMENTS;
LOG_FUNC_CALLED(card->ctx);
if ((title==NULL) || (message==NULL))
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
if (GET_DNIE_UI_CTX(card).user_consent_enabled == 0) {
sc_log(card->ctx,
"User Consent is disabled in configuration file");
LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
}
#ifdef _WIN32
/* in Windows, do not use pinentry, but MessageBox system call */
res = MessageBox (
NULL,
TEXT(message),
TEXT(title),
MB_ICONWARNING | MB_OKCANCEL | MB_DEFBUTTON2 | MB_APPLMODAL
);
if ( res == IDOK )
LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_ALLOWED);
#elif __APPLE__
/* Also in Mac OSX use native functions */
/* convert the strings from char* to CFStringRef */
header_ref = CFStringCreateWithCString( NULL, title, strlen(title) );
message_ref = CFStringCreateWithCString( NULL,message, strlen(message) );
/* Displlay user notification alert */
CFUserNotificationDisplayAlert(
0, /* no timeout */
kCFUserNotificationNoteAlertLevel, /* Alert level */
NULL, /* IconURL, use default, you can change */
/* it depending message_type flags */
NULL, /* SoundURL (not used) */
NULL, /* localization of strings */
header_ref, /* header. Cannot be null */
message_ref, /* message text */
CFSTR("Cancel"), /* default ( "OK" if null) button text */
CFSTR("OK"), /* second button title */
NULL, /* third button title, null--> no other button */
&result /* response flags */
);
/* Clean up the strings */
CFRelease( header_ref );
CFRelease( message_ref );
/* Return 0 only if "OK" is selected */
if( result == kCFUserNotificationAlternateResponse )
LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_ALLOWED);
#elif linux
/* check that user_consent_app exists. TODO: check if executable */
res = stat(GET_DNIE_UI_CTX(card).user_consent_app, &st_file);
if (res != 0) {
sc_log(card->ctx, "Invalid pinentry application: %s\n",
GET_DNIE_UI_CTX(card).user_consent_app);
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
}
/* just a simple bidirectional pipe+fork+exec implementation */
/* In a pipe, xx[0] is for reading, xx[1] is for writing */
if (pipe(srv_send) < 0) {
msg = "pipe(srv_send)";
goto do_error;
}
if (pipe(srv_recv) < 0) {
msg = "pipe(srv_recv)";
goto do_error;
}
pid = fork();
switch (pid) {
case -1: /* error */
msg = "fork()";
goto do_error;
case 0: /* child */
/* make our pipes, our new stdin & stderr, closing older ones */
dup2(srv_send[0], STDIN_FILENO); /* map srv send for input */
dup2(srv_recv[1], STDOUT_FILENO); /* map srv_recv for output */
/* once dup2'd pipes are no longer needed on client; so close */
close(srv_send[0]);
close(srv_send[1]);
close(srv_recv[0]);
close(srv_recv[1]);
/* call exec() with proper user_consent_app from configuration */
/* if ok should never return */
execlp(GET_DNIE_UI_CTX(card).user_consent_app, GET_DNIE_UI_CTX(card).user_consent_app, (char *)NULL);
res = SC_ERROR_INTERNAL;
msg = "execlp() error"; /* exec() failed */
goto do_error;
default: /* parent */
/* Close the pipe ends that the child uses to read from / write to
* so when we close the others, an EOF will be transmitted properly.
*/
close(srv_send[0]);
close(srv_recv[1]);
/* use iostreams to take care on newlines and text based data */
fin = fdopen(srv_recv[0], "r");
if (fin == NULL) {
msg = "fdopen(in)";
goto do_error;
}
fout = fdopen(srv_send[1], "w");
if (fout == NULL) {
msg = "fdopen(out)";
goto do_error;
}
/* read and ignore first line */
fflush(stdin);
for (n = 0; n<4; n++) {
char *pt;
memset(outbuf, 0, sizeof(outbuf));
if (n==0) snprintf(outbuf,1023,"%s %s\n",user_consent_msgs[0],title);
else if (n==1) snprintf(outbuf,1023,"%s %s\n",user_consent_msgs[1],message);
else snprintf(outbuf,1023,"%s\n",user_consent_msgs[n]);
/* send message */
fputs(outbuf, fout);
fflush(fout);
/* get response */
memset(buf, 0, sizeof(buf));
pt=fgets(buf, sizeof(buf) - 1, fin);
if (pt==NULL) {
res = SC_ERROR_INTERNAL;
msg = "fgets() Unexpected IOError/EOF";
goto do_error;
}
if (strstr(buf, "OK") == NULL) {
res = SC_ERROR_NOT_ALLOWED;
msg = "fail/cancel";
goto do_error;
}
}
} /* switch */
/* arriving here means signature has been accepted by user */
res = SC_SUCCESS;
msg = NULL;
do_error:
/* close out channel to force client receive EOF and also die */
if (fout != NULL) fclose(fout);
if (fin != NULL) fclose(fin);
#else
#error "Don't know how to handle user consent in this (rare) Operating System"
#endif
if (msg != NULL)
sc_log(card->ctx, "%s", msg);
LOG_FUNC_RETURN(card->ctx, res);
}
#endif

View File

@ -0,0 +1,66 @@
/**
* user-interface.c: Support for GUI functions
*
* This file contains code for several related user-interface
* functions:
* - Ask user confirmation
* - Let user enter pin
*
* Copyright (C) 2010 Juan Antonio Martinez <jonsito@terra.es>
*
* 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
*/
#ifndef __USER_INTERFACE_H__
#define __USER_INTERFACE_H__
/**
* To handle user interface routines
*/
typedef struct ui_context {
int user_consent_enabled;
char *user_consent_app;
} ui_context_t;
struct sc_card;
struct sc_pin_cmd_pin;
/**
* Ask for user consent.
*
* Check for user consent configuration,
* invoke proper gui app and check result
*
* @param card pointer to sc_card structure
* @param title Text to appear in the window header
* @param text Message to show to the user
* @return SC_SUCCESS if user accepts , else error code
*/
int sc_ask_user_consent(struct sc_card * card, const char *title, const char *message);
/**
* Ask user for pin.
*
* Check the user pin configuration,
* invoke proper gui app and check result
*
* @param card pointer to sc_card structure
* @param title Text to appear in the window header
* @param pin Structure to handle/store pin related data
* @return SC_SUCCESS if user accepts , else error code
*/
int sc_ask_user_pin(struct sc_card * card, const char *title, struct sc_pin_cmd_pin *pin);
#endif

View File

@ -7,7 +7,8 @@ noinst_HEADERS = util.h
bin_PROGRAMS = opensc-tool opensc-explorer pkcs15-tool pkcs15-crypt \
pkcs11-tool cardos-tool eidenv openpgp-tool iasecc-tool
if ENABLE_OPENSSL
bin_PROGRAMS += cryptoflex-tool pkcs15-init netkey-tool piv-tool westcos-tool sc-hsm-tool
bin_PROGRAMS += cryptoflex-tool pkcs15-init netkey-tool piv-tool \
westcos-tool sc-hsm-tool dnie-tool
endif
# compile with $(PTHREAD_CFLAGS) to allow debugging with gdb
@ -48,6 +49,8 @@ iasecc_tool_SOURCES = iasecc-tool.c util.c
iasecc_tool_LDADD = $(OPTIONAL_OPENSSL_LIBS)
sc_hsm_tool_SOURCES = sc-hsm-tool.c util.c
sc_hsm_tool_LDADD = $(OPTIONAL_OPENSSL_LIBS)
dnie_tool_SOURCES = dnie-tool.c util.c
dnie_tool_LDADD = $(OPTIONAL_OPENSSL_LIBS)
if WIN32
opensc_tool_SOURCES += $(top_builddir)/win32/versioninfo.rc
@ -65,4 +68,5 @@ westcos_tool_SOURCES += $(top_builddir)/win32/versioninfo.rc
openpgp_tool_SOURCES += $(top_builddir)/win32/versioninfo.rc
iasecc_tool_SOURCES += $(top_builddir)/win32/versioninfo.rc
sc_hsm_tool_SOURCES += $(top_builddir)/win32/versioninfo.rc
sc_hsm_tool_SOURCES += $(top_builddir)/win32/versioninfo.rc
endif

View File

@ -3,7 +3,7 @@ TOPDIR = ..\..
!INCLUDE $(TOPDIR)\win32\Make.rules.mak
TARGETS = opensc-tool.exe opensc-explorer.exe pkcs15-tool.exe pkcs15-crypt.exe \
pkcs11-tool.exe cardos-tool.exe eidenv.exe sc-hsm-tool.exe openpgp-tool.exe \
pkcs11-tool.exe cardos-tool.exe eidenv.exe sc-hsm-tool.exe openpgp-tool.exe dnie-tool.exe \
$(PROGRAMS_OPENSSL)
$(TARGETS): $(TOPDIR)\win32\versioninfo.res util.obj

244
src/tools/dnie-tool.c Normal file
View File

@ -0,0 +1,244 @@
/*
* dnie-tool.c: DNIe tool
*
* Copyright (C) 2011 Juan Antonio Martinez <jonsito@terra.es>
*
* Based on file rutoken-tool.c from Pavel Mironchik <rutoken@rutoken.ru>
* and Eugene Hermann <rutoken@rutoken.ru>
*
* 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
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include "libopensc/opensc.h"
#include "libopensc/errors.h"
#include "libopensc/cardctl.h"
#include "libopensc/pkcs15.h"
#include "util.h"
/* win32 needs this in open(2) */
#ifndef O_BINARY
#define O_BINARY 0
#endif
static const char *app_name = "dnie-tool";
#define OP_NONE 0 /* no operation requested */
#define OP_GET_DATA 1 /* retrieve DNIe number, apellidos, nombre */
#define OP_GET_IDESP 2 /* retrieve IDESP */
#define OP_GET_VERSION 4 /* retrieve DNIe version number */
#define OP_GET_SERIALNR 8 /* Get SerialNumber */
static const struct option options[] = {
{"reader", 1, NULL, 'r'},
{"driver", 1, NULL, 'c'},
{"wait", 0, NULL, 'w'},
{"pin", 1, NULL, 'p'},
{"idesp", 0, NULL, 'i'},
{"version", 0, NULL, 'V'},
{"data", 0, NULL, 'd'},
{"serial", 0, NULL, 's'},
{"all", 0, NULL, 'a'},
{"verbose", 0, NULL, 'v'},
{NULL, 0, NULL, 0 }
};
static const char *option_help[] = {
"Uses reader number <arg> [0]",
"Uses reader driver <arg> [auto-detect]",
"Wait for a card to be inserted",
"Specify PIN",
"Retrieve IDESP",
"Gets DNIe software version",
"Show DNIe number, Name, and SurName",
"Show DNIe serial number",
"Display all the information available",
"Verbose operation. Use several times to enable debug output."
};
/* Get DNIe device extra information */
int main(int argc, char* argv[])
{
int opt_wait = 0;
const char *opt_pin = NULL;
const char *opt_reader = NULL;
const char *opt_driver = NULL;
int opt_operation = OP_NONE;
int verbose = 0;
int err = 0;
sc_context_t *ctx = NULL;
sc_context_param_t ctx_param;
sc_card_t *card = NULL;
int c, long_optind, r, tries_left;
char *data[] = { NULL, NULL, NULL, NULL, NULL };
sc_serial_number_t serial;
while (1) {
c = getopt_long(argc, argv, "r:c:wp:iVdsav",
options, &long_optind);
if (c == -1)
break;
switch (c) {
case '?':
util_print_usage_and_die(app_name, options, option_help, NULL);
case 'r':
opt_reader = optarg;
break;
case 'c':
opt_driver = optarg;
break;
case 'w':
opt_wait = 1;
break;
case 'p':
opt_pin = optarg;
break;
case 'i':
opt_operation |= OP_GET_IDESP;
break;
case 'V':
opt_operation |= OP_GET_VERSION;
break;
case 'd':
opt_operation |= OP_GET_DATA;
break;
case 's':
opt_operation |= OP_GET_SERIALNR;
break;
case 'a':
opt_operation = OP_GET_IDESP | OP_GET_VERSION | OP_GET_DATA | OP_GET_SERIALNR;
break;
case 'v':
verbose++;
break;
}
}
memset(&ctx_param, 0, sizeof(ctx_param));
ctx_param.app_name = app_name;
r = sc_context_create(&ctx, &ctx_param);
if (r) {
fprintf(stderr, "Error: Failed to establish context: %s\n",
sc_strerror(r));
return -1;
}
if (verbose > 1) {
ctx->debug = verbose;
sc_ctx_log_to_file(ctx,"stderr");
}
if (opt_driver != NULL) {
err = sc_set_card_driver(ctx, opt_driver);
if (err) {
fprintf(stderr, "Driver '%s' not found!\n",
opt_driver);
err = -1;
goto dnie_tool_end;
}
}
if (util_connect_card(ctx, &card, opt_reader, opt_wait, verbose) ) {
fprintf(stderr, "Error: Cannot connect with card\n");
err = -1;
goto dnie_tool_end;
}
if ( strcmp(card->name,"dnie") ) {
fprintf(stderr, "Error: Card sems not to be a DNIe\n");
err=-1;
goto dnie_tool_end;
}
if ( opt_pin ) {
/* verify */
r = sc_verify(card, SC_AC_CHV, 0,
(u8*)opt_pin, strlen(opt_pin), &tries_left);
if (r) {
fprintf(stderr, "Error: PIN verification failed: %s",
sc_strerror(r));
if (r == SC_ERROR_PIN_CODE_INCORRECT)
fprintf(stderr, " (tries left %d)", tries_left);
putc('\n', stderr);
err=-1;
goto dnie_tool_end;
}
}
if (opt_operation==0) {
fprintf(stderr,"Error: No operation specified");
err = -1;
goto dnie_tool_end;
}
if (opt_operation & 0x0f) {
r = sc_card_ctl(card, SC_CARDCTL_DNIE_GET_INFO, data);
if ( r != SC_SUCCESS ) {
fprintf(stderr, "Error: Get info failed: %s\n", sc_strerror(r));
err = -1;
goto dnie_tool_end;
}
}
if (opt_operation & OP_GET_DATA) {
printf("DNIe Number: %s\n",data[0]);
printf("SurName: %s\n",data[1]);
printf("Name: %s\n",data[2]);
}
if (opt_operation & OP_GET_IDESP) {
if (data[3]==NULL)
printf("IDESP: (No disponible)\n");
else printf("IDESP: %s\n",data[3]);
}
if (opt_operation & OP_GET_VERSION) {
if (data[4]==NULL)
printf("DNIe Version: (No disponible)\n");
else printf("DNIe Version: %s\n",data[4]);
}
if (opt_operation & OP_GET_SERIALNR) {
r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial);
if ( r != SC_SUCCESS ) {
fprintf(stderr,"Error: Get serial failed: %s\n",sc_strerror(r));
err = -1;
goto dnie_tool_end;
}
printf("Serial number: ");
util_hex_dump(stdout, serial.value, serial.len, NULL);
putchar('\n');
}
dnie_tool_end:
if (card) {
/* sc_lock and sc_connect_card in util_connect_card */
sc_unlock(card);
sc_disconnect_card(card);
}
if (ctx)
sc_release_context(ctx);
return err;
}

4
win32/OpenSC.wxs.in Executable file → Normal file
View File

@ -106,6 +106,9 @@
<Component Id="sc_hsm_tool.exe" Guid="*" Win64="$(var.Win64YesNo)">
<File Source="$(var.SOURCE_DIR)\src\tools\sc-hsm-tool.exe" Vital="yes"/>
</Component>
<Component Id="dnie_tool.exe" Guid="*" Win64="$(var.Win64YesNo)">
<File Source="$(var.SOURCE_DIR)\src\tools\dnie-tool.exe" Vital="yes"/>
</Component>
<Component Id="openpgp_tool.exe" Guid="*" Win64="$(var.Win64YesNo)">
<File Source="$(var.SOURCE_DIR)\src\tools\openpgp-tool.exe" Vital="yes"/>
</Component>
@ -215,6 +218,7 @@
<ComponentRef Id="opensc_tool.exe"/>
<ComponentRef Id="pkcs11_tool.exe"/>
<ComponentRef Id="pkcs15_init.exe"/>
<ComponentRef Id="dnie_tool.exe"/>
<ComponentRef Id="pkcs15_tool.exe"/>
<ComponentRef Id="pkcs15_crypt.exe"/>
<ComponentRef Id="sc_hsm_tool.exe"/>