implemente PKCS#15 emulator for nPA
This commit is contained in:
@@ -19,5 +19,23 @@ app default {
|
|||||||
card_driver npa {
|
card_driver npa {
|
||||||
# The location of the driver library
|
# The location of the driver library
|
||||||
module = @libdir@/libcardnpa.@DYN_LIB_EXT@;
|
module = @libdir@/libcardnpa.@DYN_LIB_EXT@;
|
||||||
# }
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# PKCS #15
|
||||||
|
framework pkcs15 {
|
||||||
|
# additional settings per driver
|
||||||
|
#
|
||||||
|
# For pkcs15 emulators loaded from an external shared
|
||||||
|
# library/DLL, you need to specify the path name of the module
|
||||||
|
# and customize the card_atr example above correctly.
|
||||||
|
#
|
||||||
|
emulate npa {
|
||||||
|
# The location of the driver library
|
||||||
|
module = @libdir@/libpkcs15npa.@DYN_LIB_EXT@;
|
||||||
|
|
||||||
|
function = sc_pkcs15emu_npa_init_ex;
|
||||||
|
can = 222222;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,11 @@ libcardnpa_la_LIBADD = $(OPENSC_LIBS) libnpa.la
|
|||||||
libcardnpa_la_CFLAGS = $(OPENSSL_CFLAGS) $(OPENPACE_CFLAGS) $(OPENSC_CFLAGS)
|
libcardnpa_la_CFLAGS = $(OPENSSL_CFLAGS) $(OPENPACE_CFLAGS) $(OPENSC_CFLAGS)
|
||||||
libcardnpa_la_LDFLAGS = -no-undefined
|
libcardnpa_la_LDFLAGS = -no-undefined
|
||||||
|
|
||||||
|
libpkcs15npa_la_SOURCES = pkcs15-npa.c
|
||||||
|
libpkcs15npa_la_LIBADD = $(OPENSC_LIBS) libcardnpa.la libnpa.la
|
||||||
|
libpkcs15npa_la_CFLAGS = $(OPENSSL_CFLAGS) $(OPENPACE_CFLAGS) $(OPENSC_CFLAGS)
|
||||||
|
libpkcs15npa_la_LDFLAGS = -no-undefined
|
||||||
|
|
||||||
npa_tool_SOURCES = npa-tool.c $(BUILT_SOURCES)
|
npa_tool_SOURCES = npa-tool.c $(BUILT_SOURCES)
|
||||||
npa_tool_LDADD = libnpa.la $(OPENSC_LIBS) $(OPENPACE_LIBS) $(OPENSSL_LIBS)
|
npa_tool_LDADD = libnpa.la $(OPENSC_LIBS) $(OPENPACE_LIBS) $(OPENSSL_LIBS)
|
||||||
npa_tool_CFLAGS = $(OPENSSL_CFLAGS) $(OPENPACE_CFLAGS) $(OPENSC_CFLAGS)
|
npa_tool_CFLAGS = $(OPENSSL_CFLAGS) $(OPENPACE_CFLAGS) $(OPENSC_CFLAGS)
|
||||||
@@ -56,7 +61,7 @@ npa-tool.1: npa-tool.ggo
|
|||||||
bin_PROGRAMS = npa-tool
|
bin_PROGRAMS = npa-tool
|
||||||
noinst_PROGRAMS = example
|
noinst_PROGRAMS = example
|
||||||
|
|
||||||
lib_LTLIBRARIES = libnpa.la libcardnpa.la
|
lib_LTLIBRARIES = libnpa.la libcardnpa.la libpkcs15npa.la
|
||||||
|
|
||||||
noinst_HEADERS = \
|
noinst_HEADERS = \
|
||||||
sslutil.h \
|
sslutil.h \
|
||||||
|
|||||||
258
npa/src/pkcs15-npa.c
Normal file
258
npa/src/pkcs15-npa.c
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
/*
|
||||||
|
* pkcs15-npa.c: PKCS#15 emulation for German ID card
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 Frank Morgner <morgner@informatik.hu-berlin.de>
|
||||||
|
*
|
||||||
|
* 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 "libopensc/log.h"
|
||||||
|
#include "libopensc/opensc.h"
|
||||||
|
#include "libopensc/pace.h"
|
||||||
|
#include "libopensc/pkcs15.h"
|
||||||
|
#include "card-npa.h"
|
||||||
|
#include <npa/npa.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
static int npa_detect_card(sc_pkcs15_card_t *p15card)
|
||||||
|
{
|
||||||
|
int r = SC_ERROR_WRONG_CARD;
|
||||||
|
|
||||||
|
if (p15card && p15card->card
|
||||||
|
&& (p15card->card->type == SC_CARD_TYPE_NPA
|
||||||
|
|| p15card->card->type == SC_CARD_TYPE_NPA_TEST
|
||||||
|
|| p15card->card->type == SC_CARD_TYPE_NPA_ONLINE)) {
|
||||||
|
r = SC_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int npa_add_pin(sc_pkcs15_card_t *p15card,
|
||||||
|
const char *label, int max_tries,
|
||||||
|
unsigned int flags, size_t min_length,
|
||||||
|
size_t max_length, unsigned char reference,
|
||||||
|
unsigned char auth_id, const struct sc_path *path)
|
||||||
|
{
|
||||||
|
struct sc_pkcs15_auth_info pin_info;
|
||||||
|
struct sc_pkcs15_object pin_obj;
|
||||||
|
memset(&pin_info, 0, sizeof pin_info);
|
||||||
|
memset(&pin_obj, 0, sizeof(pin_obj));
|
||||||
|
|
||||||
|
strncpy(pin_obj.label, label, sizeof pin_obj.label);
|
||||||
|
pin_obj.label[(sizeof pin_obj.label) - 1]= '\0';
|
||||||
|
if (auth_id) {
|
||||||
|
pin_obj.auth_id.len = sizeof auth_id;
|
||||||
|
memcpy(&pin_obj.auth_id.value, &auth_id, sizeof auth_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
pin_info.auth_id.len = sizeof reference;
|
||||||
|
memcpy(&pin_info.auth_id.value, &reference, sizeof reference);
|
||||||
|
pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN;
|
||||||
|
pin_info.auth_method = SC_AC_CHV;
|
||||||
|
pin_info.tries_left = -1;
|
||||||
|
pin_info.max_tries = max_tries;
|
||||||
|
if (path)
|
||||||
|
memcpy(&pin_info.path, path, sizeof *path);
|
||||||
|
|
||||||
|
pin_info.attrs.pin.flags = flags;
|
||||||
|
pin_info.attrs.pin.type = SC_PKCS15_PIN_TYPE_ASCII_NUMERIC;
|
||||||
|
pin_info.attrs.pin.min_length = min_length;
|
||||||
|
pin_info.attrs.pin.max_length = max_length;
|
||||||
|
pin_info.attrs.pin.reference = reference;
|
||||||
|
|
||||||
|
return sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int npa_add_pins(sc_pkcs15_card_t *p15card)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
const sc_path_t *mf = sc_get_mf_path();
|
||||||
|
sc_path_t df_esign;
|
||||||
|
|
||||||
|
r = sc_path_set(&df_esign, SC_PATH_TYPE_PATH,
|
||||||
|
df_esign_path, sizeof df_esign_path, 0, 0);
|
||||||
|
if (r != SC_SUCCESS)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
r = npa_add_pin(p15card, "MRZ", -1,
|
||||||
|
SC_PKCS15_PIN_FLAG_CASE_SENSITIVE
|
||||||
|
| SC_PKCS15_PIN_FLAG_INITIALIZED
|
||||||
|
| SC_PKCS15_PIN_FLAG_SO_PIN
|
||||||
|
| SC_PKCS15_PIN_FLAG_UNBLOCK_DISABLED
|
||||||
|
| SC_PKCS15_PIN_FLAG_CHANGE_DISABLED,
|
||||||
|
90, 90, PACE_PIN_ID_MRZ, 0, mf);
|
||||||
|
if (r != SC_SUCCESS)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
r = npa_add_pin(p15card, "CAN", -1,
|
||||||
|
SC_PKCS15_PIN_FLAG_CASE_SENSITIVE
|
||||||
|
| SC_PKCS15_PIN_FLAG_INITIALIZED
|
||||||
|
| SC_PKCS15_PIN_FLAG_SO_PIN
|
||||||
|
| SC_PKCS15_PIN_FLAG_UNBLOCK_DISABLED,
|
||||||
|
6, 6, PACE_PIN_ID_CAN, 0, mf);
|
||||||
|
if (r != SC_SUCCESS)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
r = npa_add_pin(p15card, "eID PIN", 3,
|
||||||
|
SC_PKCS15_PIN_FLAG_CASE_SENSITIVE
|
||||||
|
| SC_PKCS15_PIN_FLAG_INITIALIZED,
|
||||||
|
5, 6, PACE_PIN_ID_PIN, PACE_PIN_ID_PUK, mf);
|
||||||
|
if (r != SC_SUCCESS)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
r = npa_add_pin(p15card, "PUK", -1,
|
||||||
|
SC_PKCS15_PIN_FLAG_CASE_SENSITIVE
|
||||||
|
| SC_PKCS15_PIN_FLAG_INITIALIZED
|
||||||
|
| SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN
|
||||||
|
| SC_PKCS15_PIN_FLAG_UNBLOCK_DISABLED
|
||||||
|
| SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN
|
||||||
|
| SC_PKCS15_PIN_FLAG_CHANGE_DISABLED,
|
||||||
|
10, 10, PACE_PIN_ID_PUK, 0, mf);
|
||||||
|
if (r != SC_SUCCESS)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
r = npa_add_pin(p15card, "eSign PIN", 3,
|
||||||
|
SC_PKCS15_PIN_FLAG_CASE_SENSITIVE
|
||||||
|
| SC_PKCS15_PIN_FLAG_LOCAL
|
||||||
|
| SC_PKCS15_PIN_FLAG_INTEGRITY_PROTECTED
|
||||||
|
| SC_PKCS15_PIN_FLAG_INITIALIZED,
|
||||||
|
6, 6, NPA_PIN_ID_ESIGN_PIN, PACE_PIN_ID_PUK, &df_esign);
|
||||||
|
if (r != SC_SUCCESS)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
err:
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char npa_manufacturer[] = "Bundesdruckerei GmbH";
|
||||||
|
|
||||||
|
static int npa_add_cardlabels(sc_pkcs15_card_t *p15card)
|
||||||
|
{
|
||||||
|
if (!p15card || !p15card->tokeninfo)
|
||||||
|
return SC_ERROR_INTERNAL;
|
||||||
|
|
||||||
|
/* manufacturer ID */
|
||||||
|
free(p15card->tokeninfo->manufacturer_id);
|
||||||
|
p15card->tokeninfo->manufacturer_id = strdup(npa_manufacturer);
|
||||||
|
if (!p15card->tokeninfo->manufacturer_id)
|
||||||
|
return SC_ERROR_NOT_ENOUGH_MEMORY;
|
||||||
|
|
||||||
|
/* card label */
|
||||||
|
free(p15card->tokeninfo->label);
|
||||||
|
if (p15card->card && p15card->card->name) {
|
||||||
|
p15card->tokeninfo->label = strdup(p15card->card->name);
|
||||||
|
if (!p15card->tokeninfo->label)
|
||||||
|
return SC_ERROR_NOT_ENOUGH_MEMORY;
|
||||||
|
} else {
|
||||||
|
p15card->tokeninfo->label = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SC_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int npa_get_cert(sc_pkcs15_card_t *p15card, const char *can)
|
||||||
|
{
|
||||||
|
struct establish_pace_channel_input pace_input;
|
||||||
|
struct establish_pace_channel_output pace_output;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (!p15card || !p15card->card || !p15card->card->reader) {
|
||||||
|
r = SC_ERROR_INTERNAL;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(p15card->card->reader->capabilities & SC_READER_CAP_PACE_ESIGN)) {
|
||||||
|
sc_log(p15card->card->ctx, "No comfort reader (CAT-K) found\n");
|
||||||
|
r = SC_ERROR_NOT_SUPPORTED;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&pace_input, 0, sizeof pace_input);
|
||||||
|
memset(&pace_output, 0, sizeof pace_output);
|
||||||
|
pace_input.chat = esign_chat;
|
||||||
|
pace_input.chat_length = sizeof esign_chat;
|
||||||
|
pace_input.pin_id = PACE_PIN_ID_CAN;
|
||||||
|
if (can) {
|
||||||
|
pace_input.pin = (const unsigned char *) can;
|
||||||
|
pace_input.pin_length = strlen(can);
|
||||||
|
}
|
||||||
|
npa_get_cache(p15card->card, pace_input.pin_id, &pace_input.pin,
|
||||||
|
&pace_input.pin_length, &pace_output.ef_cardaccess,
|
||||||
|
&pace_output.ef_cardaccess_length);
|
||||||
|
|
||||||
|
r = perform_pace(p15card->card, pace_input, &pace_output, EAC_TR_VERSION_2_02);
|
||||||
|
if (r != SC_SUCCESS)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
/* TODO read certificate */
|
||||||
|
r = SC_ERROR_OBJECT_NOT_FOUND;
|
||||||
|
|
||||||
|
err:
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sc_pkcs15emu_npa_init_ex(sc_pkcs15_card_t *p15card,
|
||||||
|
sc_pkcs15emu_opt_t *opts)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
const char *can = NULL;
|
||||||
|
|
||||||
|
if (!p15card || !p15card->card) {
|
||||||
|
r = SC_ERROR_INTERNAL;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts && (opts->flags & SC_PKCS15EMU_FLAGS_NO_CHECK)) {
|
||||||
|
/* don't do a card check */
|
||||||
|
} else {
|
||||||
|
r = npa_detect_card(p15card);
|
||||||
|
if (r != SC_SUCCESS)
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = npa_add_cardlabels(p15card);
|
||||||
|
if (r != SC_SUCCESS)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
r = npa_add_pins(p15card);
|
||||||
|
if (r != SC_SUCCESS)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
if (opts) {
|
||||||
|
can = scconf_get_str(opts->blk, "can", NULL);
|
||||||
|
npa_set_cache(p15card->card, PACE_PIN_ID_CAN,
|
||||||
|
(const unsigned char *) can, strlen(can), NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
r = npa_get_cert(p15card, can);
|
||||||
|
if (r != SC_SUCCESS) {
|
||||||
|
sc_log(p15card->card->ctx, "No certificate found, will continue anyway\n");
|
||||||
|
r = SC_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
err:
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *sc_driver_version(void)
|
||||||
|
{
|
||||||
|
/** TODO fix the version check in opensc/src/libopensc/pkcs15-syn.c:271
|
||||||
|
* here we choose 0.9.3 simply to pass the bogus check */
|
||||||
|
static const char version[] = "0.9.3";
|
||||||
|
return version;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user