use OpenSC's hooks to wrap and unwrap SM APDUs
sm_transmit_apdu is obsolete. libnpa and OpenSC can be used in parallel now. libnpa modifies OpenSC's card handle to add SM on the fly to any OpenSC command. This, for example, allows PKCS#XX commands in a SM channel established by libnpa.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
SUBDIRS = src m4 doc win32
|
||||
|
||||
EXTRA_DIST = libnpa.pc.in apdus test_vicc_with_npa.sh
|
||||
EXTRA_DIST = libnpa.pc.in apdus test_vicc_with_npa-tool.sh
|
||||
|
||||
do_subst = $(SED) \
|
||||
-e 's,[@]PACKAGE_NAME[@],$(PACKAGE_NAME),g' \
|
||||
|
||||
@@ -55,9 +55,9 @@ test -z "$OPENSC_LIBS" && OPENSC_LIBS="-lopensc"
|
||||
saved_LIBS="$LIBS"
|
||||
LIBS="$LDFLAGS $OPENSC_LIBS"
|
||||
|
||||
AC_MSG_CHECKING([for sc_perform_pace])
|
||||
AC_TRY_LINK_FUNC(sc_perform_pace, [ AC_MSG_RESULT([yes]) ],
|
||||
[ AC_MSG_ERROR([libopensc with PACE (git clone git://github.com/frankmorgner/OpenSC.git) not found, use ./configure OPENSC_LIBS=...]) ])
|
||||
AC_MSG_CHECKING([for iasecc_sm_external_authentication])
|
||||
AC_TRY_LINK_FUNC(iasecc_sm_external_authentication, [ AC_MSG_RESULT([yes]) ],
|
||||
[ AC_MSG_ERROR([libopensc configured with SM (git clone git://github.com/frankmorgner/OpenSC.git) not found, use ./configure OPENSC_LIBS=...]) ])
|
||||
|
||||
LIBS="$saved_LIBS"
|
||||
|
||||
|
||||
@@ -14,9 +14,9 @@ MAINTAINERCLEANFILES = $(BUILT_SOURCES) npa-tool.ggo $(dist_man1_MANS)
|
||||
|
||||
dist_man1_MANS = npa-tool.1
|
||||
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/src/npa -I$(top_srcdir)/src/opensc/src
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/src/opensc/src -DENABLE_SM
|
||||
|
||||
libnpa_la_SOURCES = sm.c scutil.c npa.c sslutil.c
|
||||
libnpa_la_SOURCES = iso-sm.c scutil.c npa.c
|
||||
libnpa_la_LIBADD = $(OPENSSL_LIBS) $(OPENPACE_LIBS) $(OPENSC_LIBS)
|
||||
libnpa_la_CFLAGS = $(OPENSSL_CFLAGS) $(OPENPACE_CFLAGS)
|
||||
libnpa_la_LDFLAGS = -no-undefined
|
||||
@@ -56,6 +56,6 @@ noinst_HEADERS = \
|
||||
sslutil.h
|
||||
|
||||
nobase_include_HEADERS = \
|
||||
npa/sm.h \
|
||||
npa/iso-sm.h \
|
||||
npa/npa.h \
|
||||
npa/scutil.h
|
||||
|
||||
@@ -17,10 +17,14 @@
|
||||
* npa. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* This example shows how to use the library functions EstablishPACEChannel to
|
||||
/* This example shows how to use the library functions perform_pace to
|
||||
* get a secure channel to the nPA. We use the builtin function npa_change_pin
|
||||
* to modify the PIN using the secure channel. Then we transmit an arbitrary
|
||||
* APDU encrypted and authenticated to the card using sm_transmit_apdu. */
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <npa/npa.h>
|
||||
#include <npa/scutil.h>
|
||||
#include <string.h>
|
||||
@@ -46,11 +50,9 @@ main (int argc, char **argv)
|
||||
sc_apdu_t apdu;
|
||||
u8 buf[0xffff];
|
||||
|
||||
struct sm_ctx sctx;
|
||||
struct establish_pace_channel_input pace_input;
|
||||
struct establish_pace_channel_output pace_output;
|
||||
|
||||
memset(&sctx, 0, sizeof sctx);
|
||||
memset(&pace_input, 0, sizeof pace_input);
|
||||
memset(&pace_output, 0, sizeof pace_output);
|
||||
|
||||
@@ -78,13 +80,12 @@ main (int argc, char **argv)
|
||||
pace_input.pin = (unsigned char *) pin;
|
||||
pace_input.pin_length = pin ? strlen(pin) : 0;
|
||||
|
||||
r = EstablishPACEChannel(NULL, card, pace_input, &pace_output,
|
||||
&sctx, EAC_TR_VERSION_2_02);
|
||||
r = perform_pace(card, pace_input, &pace_output, EAC_TR_VERSION_2_02);
|
||||
if (r < 0)
|
||||
goto err;
|
||||
printf("Established PACE channel with PIN.\n");
|
||||
|
||||
r = npa_change_pin(&sctx, card, newpin, newpin ? strlen(newpin) : 0);
|
||||
r = npa_change_pin(card, newpin, newpin ? strlen(newpin) : 0);
|
||||
if (r < 0)
|
||||
goto err;
|
||||
printf("Changed PIN.\n");
|
||||
@@ -104,14 +105,13 @@ main (int argc, char **argv)
|
||||
apdu.resplen = sizeof buf;
|
||||
|
||||
/* Transmit the APDU with SM */
|
||||
r = sm_transmit_apdu(&sctx, card, &apdu);
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
|
||||
|
||||
err:
|
||||
fprintf(r < 0 ? stderr : stdout, "%s\n", sc_strerror(r));
|
||||
|
||||
/* Free up memory and wipe it if necessary (e.g. for keys stored in sm_ctx) */
|
||||
sm_ctx_clear_free(&sctx);
|
||||
if (pace_output.ef_cardaccess)
|
||||
free(pace_output.ef_cardaccess);
|
||||
if (pace_output.recent_car)
|
||||
@@ -123,6 +123,7 @@ err:
|
||||
if (pace_output.id_pcd)
|
||||
free(pace_output.id_pcd);
|
||||
|
||||
sm_stop(card);
|
||||
sc_reset(card, 1);
|
||||
sc_disconnect_card(card);
|
||||
sc_release_context(ctx);
|
||||
|
||||
@@ -16,13 +16,68 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ccid. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "scutil.h"
|
||||
#include "sm.h"
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <libopensc/asn1.h>
|
||||
#include <libopensc/log.h>
|
||||
#include <npa/iso-sm.h>
|
||||
#include <npa/scutil.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* @brief Protect an APDU with Secure Messaging
|
||||
*
|
||||
* If secure messaging (SM) is activated in \a sctx and \a apdu is not already
|
||||
* SM protected, \a apdu is processed with the following steps:
|
||||
* \li call to \a sctx->pre_transmit
|
||||
* \li encrypt \a apdu calling \a sctx->encrypt
|
||||
* \li authenticate \a apdu calling \a sctx->authenticate
|
||||
* \li copy the SM protected data to \a sm_apdu
|
||||
*
|
||||
* Data for authentication or encryption is always padded before the callback
|
||||
* functions are called
|
||||
*
|
||||
* @param[in] card
|
||||
* @param[in] apdu
|
||||
* @param[in,out] sm_apdu
|
||||
*
|
||||
* @return \c SC_SUCCESS or error code if an error occurred
|
||||
*/
|
||||
static int iso_get_sm_apdu(struct sc_card *card, struct sc_apdu *apdu, struct sc_apdu **sm_apdu);
|
||||
|
||||
/* @brief Remove Secure Messaging from an APDU
|
||||
*
|
||||
* If secure messaging (SM) is activated in \a sctx and \a apdu is not already
|
||||
* SM protected, \a apdu is processed with the following steps:
|
||||
* \li verify SM protected \a apdu calling \a sctx->verify_authentication
|
||||
* \li decrypt SM protected \a apdu calling \a sctx->decrypt
|
||||
* \li copy decrypted/authenticated data and status bytes to \a apdu
|
||||
*
|
||||
* Callback functions must not remove padding.
|
||||
*
|
||||
* @param[in] card
|
||||
* @param[in,out] apdu
|
||||
* @param[in,out] sm_apdu will be freed when done.
|
||||
*
|
||||
* @return \c SC_SUCCESS or error code if an error occurred
|
||||
*/
|
||||
static int iso_free_sm_apdu(struct sc_card *card, struct sc_apdu *apdu, struct sc_apdu **sm_apdu);
|
||||
|
||||
/**
|
||||
* @brief Cleans up allocated ressources of the ISO SM driver
|
||||
*
|
||||
* \c iso_sm_close() is designed as SM card operation. However, have in mind
|
||||
* that this card operation is not called automatically for \c
|
||||
* sc_disconnect_card() .
|
||||
*
|
||||
* @param[in] card
|
||||
*
|
||||
* @return \c SC_SUCCESS or error code if an error occurred
|
||||
*/
|
||||
static int iso_sm_close(struct sc_card *card);
|
||||
|
||||
static const struct sc_asn1_entry c_sm_capdu[] = {
|
||||
{ "Padding-content indicator followed by cryptogram",
|
||||
SC_ASN1_OCTET_STRING, SC_ASN1_CTX|0x07, SC_ASN1_OPTIONAL, NULL, NULL },
|
||||
@@ -73,7 +128,7 @@ add_iso_pad(const u8 *data, size_t datalen, int block_size, u8 **padded)
|
||||
}
|
||||
|
||||
static int
|
||||
add_padding(const struct sm_ctx *ctx, const u8 *data, size_t datalen,
|
||||
add_padding(const struct iso_sm_ctx *ctx, const u8 *data, size_t datalen,
|
||||
u8 **padded)
|
||||
{
|
||||
u8 *p;
|
||||
@@ -97,7 +152,7 @@ add_padding(const struct sm_ctx *ctx, const u8 *data, size_t datalen,
|
||||
}
|
||||
|
||||
static int
|
||||
no_padding(u8 padding_indicator, const u8 *data, size_t datalen)
|
||||
rm_padding(u8 padding_indicator, const u8 *data, size_t datalen)
|
||||
{
|
||||
if (!datalen || !data)
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
@@ -108,6 +163,7 @@ no_padding(u8 padding_indicator, const u8 *data, size_t datalen)
|
||||
case SM_NO_PADDING:
|
||||
len = datalen;
|
||||
break;
|
||||
|
||||
case SM_ISO_PADDING:
|
||||
len = datalen;
|
||||
|
||||
@@ -121,6 +177,7 @@ no_padding(u8 padding_indicator, const u8 *data, size_t datalen)
|
||||
return SC_ERROR_INVALID_DATA;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
@@ -184,7 +241,7 @@ static int prefix_buf(u8 prefix, u8 *buf, size_t buflen, u8 **cat)
|
||||
return buflen + 1;
|
||||
}
|
||||
|
||||
static int format_data(sc_card_t *card, const struct sm_ctx *ctx,
|
||||
static int format_data(sc_card_t *card, const struct iso_sm_ctx *ctx,
|
||||
const u8 *data, size_t datalen,
|
||||
struct sc_asn1_entry *formatted_encrypted_data_entry,
|
||||
u8 **formatted_data, size_t *formatted_data_len)
|
||||
@@ -236,7 +293,7 @@ err:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int format_head(const struct sm_ctx *ctx, const sc_apdu_t *apdu,
|
||||
static int format_head(const struct iso_sm_ctx *ctx, const sc_apdu_t *apdu,
|
||||
u8 **formatted_head)
|
||||
{
|
||||
if (!apdu || !formatted_head)
|
||||
@@ -255,16 +312,17 @@ static int format_head(const struct sm_ctx *ctx, const sc_apdu_t *apdu,
|
||||
return add_padding(ctx, *formatted_head, 4, formatted_head);
|
||||
}
|
||||
|
||||
static int sm_encrypt(const struct sm_ctx *ctx, sc_card_t *card,
|
||||
const sc_apdu_t *apdu, sc_apdu_t *sm_apdu)
|
||||
static int sm_encrypt(const struct iso_sm_ctx *ctx, sc_card_t *card,
|
||||
const sc_apdu_t *apdu, sc_apdu_t **psm_apdu)
|
||||
{
|
||||
struct sc_asn1_entry sm_capdu[4];
|
||||
u8 *p, *le = NULL, *sm_data = NULL, *fdata = NULL, *mac_data = NULL,
|
||||
*asn1 = NULL, *mac = NULL;
|
||||
*asn1 = NULL, *mac = NULL, *resp_data = NULL;
|
||||
size_t sm_data_len, fdata_len, mac_data_len, asn1_len, mac_len, le_len;
|
||||
int r;
|
||||
sc_apdu_t *sm_apdu = NULL;
|
||||
|
||||
if (!apdu || !ctx || !card || !card->reader || !sm_apdu) {
|
||||
if (!apdu || !ctx || !card || !card->reader || !psm_apdu) {
|
||||
r = SC_ERROR_INVALID_ARGUMENTS;
|
||||
goto err;
|
||||
}
|
||||
@@ -277,6 +335,11 @@ static int sm_encrypt(const struct sm_ctx *ctx, sc_card_t *card,
|
||||
|
||||
sc_copy_asn1_entry(c_sm_capdu, sm_capdu);
|
||||
|
||||
sm_apdu = malloc(sizeof(sc_apdu_t));
|
||||
if (!sm_apdu) {
|
||||
r = SC_ERROR_OUT_OF_MEMORY;
|
||||
goto err;
|
||||
}
|
||||
sm_apdu->control = apdu->control;
|
||||
sm_apdu->flags = apdu->flags;
|
||||
sm_apdu->cla = apdu->cla|0x0C;
|
||||
@@ -426,40 +489,51 @@ static int sm_encrypt(const struct sm_ctx *ctx, sc_card_t *card,
|
||||
r = sc_asn1_encode(card->ctx, sm_capdu, (u8 **) &sm_data, &sm_data_len);
|
||||
if (r < 0)
|
||||
goto err;
|
||||
if (sm_apdu->datalen < sm_data_len) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Data for SM APDU too long");
|
||||
sm_apdu->data = sm_data;
|
||||
sm_apdu->datalen = sm_data_len;
|
||||
sm_apdu->lc = sm_data_len;
|
||||
sm_apdu->le = 0;
|
||||
if (apdu->cse & SC_APDU_EXT) {
|
||||
sm_apdu->cse = SC_APDU_CASE_4_EXT;
|
||||
#if OPENSC_NOT_BOGUS_ANYMORE
|
||||
sm_apdu->resplen = 0xffff+1;
|
||||
#else
|
||||
sm_apdu->resplen = SC_MAX_EXT_APDU_BUFFER_SIZE;
|
||||
#endif
|
||||
} else {
|
||||
sm_apdu->cse = SC_APDU_CASE_4_SHORT;
|
||||
#if OPENSC_NOT_BOGUS_ANYMORE
|
||||
sm_apdu->resplen = 0xff+1;
|
||||
#else
|
||||
sm_apdu->resplen = SC_MAX_APDU_BUFFER_SIZE;
|
||||
#endif
|
||||
}
|
||||
resp_data = malloc(sm_apdu->resplen);
|
||||
if (!resp_data) {
|
||||
r = SC_ERROR_OUT_OF_MEMORY;
|
||||
goto err;
|
||||
}
|
||||
/* Flawfinder: ignore */
|
||||
memcpy((u8 *) sm_apdu->data, sm_data, sm_data_len);
|
||||
sm_apdu->datalen = sm_data_len;
|
||||
sm_apdu->lc = sm_apdu->datalen;
|
||||
sm_apdu->le = 0;
|
||||
if (apdu->cse & SC_APDU_EXT)
|
||||
sm_apdu->cse = SC_APDU_CASE_4_EXT;
|
||||
else
|
||||
sm_apdu->cse = SC_APDU_CASE_4_SHORT;
|
||||
sm_apdu->resp = resp_data;
|
||||
bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "ASN.1 encoded encrypted APDU data", sm_apdu->data, sm_apdu->datalen);
|
||||
|
||||
*psm_apdu = sm_apdu;
|
||||
|
||||
err:
|
||||
if (fdata)
|
||||
free(fdata);
|
||||
if (asn1)
|
||||
free(asn1);
|
||||
if (mac_data)
|
||||
free(mac_data);
|
||||
if (mac)
|
||||
free(mac);
|
||||
if (le)
|
||||
free(le);
|
||||
if (sm_data)
|
||||
free(fdata);
|
||||
free(asn1);
|
||||
free(mac_data);
|
||||
free(mac);
|
||||
free(le);
|
||||
if (r < 0) {
|
||||
free(resp_data);
|
||||
free(sm_apdu);
|
||||
free(sm_data);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int sm_decrypt(const struct sm_ctx *ctx, sc_card_t *card,
|
||||
static int sm_decrypt(const struct iso_sm_ctx *ctx, sc_card_t *card,
|
||||
const sc_apdu_t *sm_apdu, sc_apdu_t *apdu)
|
||||
{
|
||||
int r;
|
||||
@@ -520,7 +594,7 @@ static int sm_decrypt(const struct sm_ctx *ctx, sc_card_t *card,
|
||||
goto err;
|
||||
buf_len = r;
|
||||
|
||||
r = no_padding(ctx->padding_indicator, data, buf_len);
|
||||
r = rm_padding(ctx->padding_indicator, data, buf_len);
|
||||
if (r < 0) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not remove padding");
|
||||
goto err;
|
||||
@@ -572,42 +646,35 @@ err:
|
||||
return r;
|
||||
}
|
||||
|
||||
int sm_transmit_apdu(struct sm_ctx *sctx, sc_card_t *card,
|
||||
sc_apdu_t *apdu)
|
||||
static int iso_add_sm(struct iso_sm_ctx *sctx, sc_card_t *card,
|
||||
sc_apdu_t *apdu, sc_apdu_t **sm_apdu)
|
||||
{
|
||||
sc_apdu_t sm_apdu;
|
||||
u8 rbuf[0xffff], sbuf[0xffff];
|
||||
|
||||
if (!card)
|
||||
if (!card || !sctx)
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
|
||||
sm_apdu.data = sbuf;
|
||||
sm_apdu.datalen = sizeof sbuf;
|
||||
sm_apdu.resp = rbuf;
|
||||
sm_apdu.resplen = sizeof rbuf;
|
||||
|
||||
if (!sctx || !sctx->active) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Secure messaging disabled.");
|
||||
return sc_transmit_apdu(card, apdu);
|
||||
}
|
||||
|
||||
if ((apdu->cla & 0x0C) == 0x0C) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Given APDU is already protected with some secure messaging. Deactivating own SM context.");
|
||||
sctx->active = 0;
|
||||
return sc_transmit_apdu(card, apdu);
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Given APDU is already protected with some secure messaging. Closing own SM context.");
|
||||
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, iso_sm_close(card),
|
||||
"Could not close ISO SM session");
|
||||
return SC_ERROR_SM_NOT_APPLIED;
|
||||
}
|
||||
|
||||
if (sctx->pre_transmit)
|
||||
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, sctx->pre_transmit(card, sctx, apdu),
|
||||
"Could not complete SM specific pre transmit routine");
|
||||
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, sm_encrypt(sctx, card, apdu, &sm_apdu),
|
||||
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, sm_encrypt(sctx, card, apdu, sm_apdu),
|
||||
"Could not encrypt APDU");
|
||||
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, sc_transmit_apdu(card, &sm_apdu),
|
||||
"Could not transmit SM APDU");
|
||||
|
||||
return SC_SUCCESS;
|
||||
}
|
||||
|
||||
static int iso_rm_sm(struct iso_sm_ctx *sctx, sc_card_t *card,
|
||||
sc_apdu_t *sm_apdu, sc_apdu_t *apdu)
|
||||
{
|
||||
if (sctx->post_transmit)
|
||||
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, sctx->post_transmit(card, sctx, &sm_apdu),
|
||||
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, sctx->post_transmit(card, sctx, sm_apdu),
|
||||
"Could not complete SM specific post transmit routine");
|
||||
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, sm_decrypt(sctx, card, &sm_apdu, apdu),
|
||||
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, sm_decrypt(sctx, card, sm_apdu, apdu),
|
||||
"Could not decrypt APDU");
|
||||
if (sctx->finish)
|
||||
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, sctx->finish(card, sctx, apdu),
|
||||
@@ -616,8 +683,92 @@ int sm_transmit_apdu(struct sm_ctx *sctx, sc_card_t *card,
|
||||
return SC_SUCCESS;
|
||||
}
|
||||
|
||||
void sm_ctx_clear_free(const struct sm_ctx *sctx)
|
||||
int iso_sm_close(struct sc_card *card)
|
||||
{
|
||||
if (card) {
|
||||
iso_sm_ctx_clear_free(card->sm_ctx.info.cmd_data);
|
||||
card->sm_ctx.info.cmd_data = NULL;
|
||||
}
|
||||
|
||||
return SC_SUCCESS;
|
||||
}
|
||||
|
||||
int iso_get_sm_apdu(struct sc_card *card, struct sc_apdu *apdu, struct sc_apdu **sm_apdu)
|
||||
{
|
||||
return iso_add_sm(card->sm_ctx.info.cmd_data, card, apdu, sm_apdu);
|
||||
}
|
||||
|
||||
int iso_free_sm_apdu(struct sc_card *card, struct sc_apdu *apdu, struct sc_apdu **sm_apdu)
|
||||
{
|
||||
if (!sm_apdu)
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
|
||||
struct sc_apdu *p = *sm_apdu;
|
||||
|
||||
int r = iso_rm_sm(card->sm_ctx.info.cmd_data, card, p, apdu);
|
||||
|
||||
if (p) {
|
||||
free((unsigned char *) p->data);
|
||||
free((unsigned char *) p->resp);
|
||||
}
|
||||
free(*sm_apdu);
|
||||
*sm_apdu = NULL;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
struct iso_sm_ctx *iso_sm_ctx_create(void)
|
||||
{
|
||||
struct iso_sm_ctx *sctx = malloc(sizeof *sctx);
|
||||
if (!sctx)
|
||||
return NULL;
|
||||
|
||||
sctx->priv_data = NULL;
|
||||
sctx->padding_indicator = SM_ISO_PADDING;
|
||||
sctx->block_length = 0;
|
||||
sctx->authenticate = NULL;
|
||||
sctx->verify_authentication = NULL;
|
||||
sctx->encrypt = NULL;
|
||||
sctx->decrypt = NULL;
|
||||
sctx->pre_transmit = NULL;
|
||||
sctx->post_transmit = NULL;
|
||||
sctx->finish = NULL;
|
||||
sctx->clear_free = NULL;
|
||||
|
||||
return sctx;
|
||||
}
|
||||
|
||||
void iso_sm_ctx_clear_free(struct iso_sm_ctx *sctx)
|
||||
{
|
||||
if (sctx && sctx->clear_free)
|
||||
sctx->clear_free(sctx);
|
||||
free(sctx);
|
||||
}
|
||||
|
||||
int iso_sm_start(struct sc_card *card, struct iso_sm_ctx *sctx)
|
||||
{
|
||||
if (!card)
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
|
||||
if (card->sm_ctx.ops.close)
|
||||
card->sm_ctx.ops.close(card);
|
||||
|
||||
card->sm_ctx.info.cmd_data = sctx;
|
||||
card->sm_ctx.ops.close = iso_sm_close;
|
||||
card->sm_ctx.ops.free_sm_apdu = iso_free_sm_apdu;
|
||||
card->sm_ctx.ops.get_sm_apdu = iso_get_sm_apdu;
|
||||
card->sm_ctx.sm_mode = SM_MODE_TRANSMIT;
|
||||
}
|
||||
|
||||
int sm_stop(struct sc_card *card)
|
||||
{
|
||||
int r = SC_SUCCESS;
|
||||
|
||||
if (card) {
|
||||
if (card->sm_ctx.ops.close)
|
||||
r = card->sm_ctx.ops.close(card);
|
||||
card->sm_ctx.sm_mode = SM_MODE_NONE;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -16,6 +16,10 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* npa. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "cmdline.h"
|
||||
#include "config.h"
|
||||
#include <eac/pace.h>
|
||||
@@ -103,7 +107,7 @@ err:
|
||||
return r;
|
||||
}
|
||||
|
||||
int npa_translate_apdus(struct sm_ctx *sctx, sc_card_t *card, FILE *input)
|
||||
int npa_translate_apdus(sc_card_t *card, FILE *input)
|
||||
{
|
||||
u8 buf[4 + 3 + 0xffff + 3];
|
||||
char *read = NULL;
|
||||
@@ -150,7 +154,7 @@ int npa_translate_apdus(struct sm_ctx *sctx, sc_card_t *card, FILE *input)
|
||||
apdu.resp = buf;
|
||||
apdu.resplen = sizeof buf;
|
||||
|
||||
r = sm_transmit_apdu(sctx, card, &apdu);
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
if (r < 0) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE_TOOL,
|
||||
"Could not send C-APDU: %s", sc_strerror(r));
|
||||
@@ -173,7 +177,6 @@ main (int argc, char **argv)
|
||||
{
|
||||
int r, oindex = 0, tr_version = EAC_TR_VERSION_2_02;
|
||||
size_t channeldatalen;
|
||||
struct sm_ctx sctx, tmpctx;
|
||||
struct establish_pace_channel_input pace_input;
|
||||
struct establish_pace_channel_output pace_output;
|
||||
struct timeval tv;
|
||||
@@ -184,8 +187,6 @@ main (int argc, char **argv)
|
||||
|
||||
struct gengetopt_args_info cmdline;
|
||||
|
||||
memset(&sctx, 0, sizeof sctx);
|
||||
memset(&tmpctx, 0, sizeof tmpctx);
|
||||
memset(&pace_input, 0, sizeof pace_input);
|
||||
memset(&pace_output, 0, sizeof pace_output);
|
||||
|
||||
@@ -319,8 +320,7 @@ main (int argc, char **argv)
|
||||
(unsigned int) tv.tv_sec, (unsigned int) tv.tv_usec,
|
||||
npa_secret_name(pace_input.pin_id), pace_input.pin);
|
||||
|
||||
r = EstablishPACEChannel(NULL, card, pace_input, &pace_output,
|
||||
&sctx, tr_version);
|
||||
r = perform_pace(card, pace_input, &pace_output, tr_version);
|
||||
|
||||
secret++;
|
||||
} while (0 > r && secret <= maxsecret);
|
||||
@@ -348,8 +348,7 @@ main (int argc, char **argv)
|
||||
pace_input.pin = NULL;
|
||||
pace_input.pin_length = 0;
|
||||
}
|
||||
r = EstablishPACEChannel(NULL, card, pace_input, &pace_output,
|
||||
&tmpctx, tr_version);
|
||||
r = perform_pace(card, pace_input, &pace_output, tr_version);
|
||||
if (r < 0)
|
||||
goto err;
|
||||
printf("Established PACE channel with CAN.\n");
|
||||
@@ -362,8 +361,7 @@ main (int argc, char **argv)
|
||||
pace_input.pin = NULL;
|
||||
pace_input.pin_length = 0;
|
||||
}
|
||||
r = EstablishPACEChannel(&tmpctx, card, pace_input, &pace_output,
|
||||
&sctx, tr_version);
|
||||
r = perform_pace(card, pace_input, &pace_output, tr_version);
|
||||
if (r < 0)
|
||||
goto err;
|
||||
printf("Established PACE channel with PIN. PIN resumed.\n");
|
||||
@@ -378,13 +376,12 @@ main (int argc, char **argv)
|
||||
pace_input.pin = NULL;
|
||||
pace_input.pin_length = 0;
|
||||
}
|
||||
r = EstablishPACEChannel(NULL, card, pace_input, &pace_output,
|
||||
&sctx, tr_version);
|
||||
r = perform_pace(card, pace_input, &pace_output, tr_version);
|
||||
if (r < 0)
|
||||
goto err;
|
||||
printf("Established PACE channel with PUK.\n");
|
||||
|
||||
r = npa_unblock_pin(&sctx, card);
|
||||
r = npa_unblock_pin(card);
|
||||
if (r < 0)
|
||||
goto err;
|
||||
printf("Unblocked PIN.\n");
|
||||
@@ -399,13 +396,12 @@ main (int argc, char **argv)
|
||||
pace_input.pin = NULL;
|
||||
pace_input.pin_length = 0;
|
||||
}
|
||||
r = EstablishPACEChannel(NULL, card, pace_input, &pace_output,
|
||||
&sctx, tr_version);
|
||||
r = perform_pace(card, pace_input, &pace_output, tr_version);
|
||||
if (r < 0)
|
||||
goto err;
|
||||
printf("Established PACE channel with PIN.\n");
|
||||
|
||||
r = npa_change_pin(&sctx, card, newpin, newpin ? strlen(newpin) : 0);
|
||||
r = npa_change_pin(card, newpin, newpin ? strlen(newpin) : 0);
|
||||
if (r < 0)
|
||||
goto err;
|
||||
printf("Changed PIN.\n");
|
||||
@@ -499,21 +495,20 @@ main (int argc, char **argv)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
r = EstablishPACEChannel(NULL, card, pace_input, &pace_output,
|
||||
&sctx, tr_version);
|
||||
r = perform_pace(card, pace_input, &pace_output, tr_version);
|
||||
if (r < 0)
|
||||
goto err;
|
||||
printf("Established PACE channel with %s.\n",
|
||||
npa_secret_name(pace_input.pin_id));
|
||||
|
||||
if (cmdline.cv_certificate_given || cmdline.private_key_given) {
|
||||
r = perform_terminal_authentication(&sctx, card, certs, certs_lens,
|
||||
r = perform_terminal_authentication(card, certs, certs_lens,
|
||||
privkey, privkey_len, auxiliary_data, auxiliary_data_len);
|
||||
if (r < 0)
|
||||
goto err;
|
||||
printf("Performed Terminal Authentication.\n");
|
||||
|
||||
r = perform_chip_authentication(&sctx, card);
|
||||
r = perform_chip_authentication(card);
|
||||
if (r < 0)
|
||||
goto err;
|
||||
printf("Performed Chip Authentication.\n");
|
||||
@@ -530,7 +525,7 @@ main (int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
r = npa_translate_apdus(&sctx, card, input);
|
||||
r = npa_translate_apdus(card, input);
|
||||
if (r < 0)
|
||||
goto err;
|
||||
fclose(input);
|
||||
@@ -540,8 +535,6 @@ main (int argc, char **argv)
|
||||
|
||||
err:
|
||||
cmdline_parser_free(&cmdline);
|
||||
sm_ctx_clear_free(&sctx);
|
||||
sm_ctx_clear_free(&tmpctx);
|
||||
if (pace_output.ef_cardaccess)
|
||||
free(pace_output.ef_cardaccess);
|
||||
if (pace_output.recent_car)
|
||||
@@ -567,6 +560,7 @@ err:
|
||||
if (cvc_cert)
|
||||
CVC_CERT_free(cvc_cert);
|
||||
|
||||
sm_stop(card);
|
||||
sc_reset(card, 1);
|
||||
sc_disconnect_card(card);
|
||||
sc_release_context(ctx);
|
||||
|
||||
273
npa/src/npa.c
273
npa/src/npa.c
@@ -16,18 +16,22 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ccid. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "npa.h"
|
||||
#include "scutil.h"
|
||||
#include "sm.h"
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "sslutil.h"
|
||||
#include <eac/ca.h>
|
||||
#include <eac/cv_cert.h>
|
||||
#include <eac/eac.h>
|
||||
#include <eac/pace.h>
|
||||
#include <eac/ca.h>
|
||||
#include <eac/ta.h>
|
||||
#include <libopensc/asn1.h>
|
||||
#include <libopensc/log.h>
|
||||
#include <libopensc/opensc.h>
|
||||
#include <npa/iso-sm.h>
|
||||
#include <npa/npa.h>
|
||||
#include <npa/scutil.h>
|
||||
#include <openssl/asn1t.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/buffer.h>
|
||||
@@ -235,22 +239,22 @@ extern BUF_MEM *BUF_MEM_create(size_t len);
|
||||
extern BUF_MEM *BUF_MEM_create_init(const void *buf, size_t len);
|
||||
|
||||
|
||||
static int npa_sm_encrypt(sc_card_t *card, const struct sm_ctx *ctx,
|
||||
static int npa_sm_encrypt(sc_card_t *card, const struct iso_sm_ctx *ctx,
|
||||
const u8 *data, size_t datalen, u8 **enc);
|
||||
static int npa_sm_decrypt(sc_card_t *card, const struct sm_ctx *ctx,
|
||||
static int npa_sm_decrypt(sc_card_t *card, const struct iso_sm_ctx *ctx,
|
||||
const u8 *enc, size_t enclen, u8 **data);
|
||||
static int npa_sm_authenticate(sc_card_t *card, const struct sm_ctx *ctx,
|
||||
static int npa_sm_authenticate(sc_card_t *card, const struct iso_sm_ctx *ctx,
|
||||
const u8 *data, size_t datalen, u8 **outdata);
|
||||
static int npa_sm_verify_authentication(sc_card_t *card, const struct sm_ctx *ctx,
|
||||
static int npa_sm_verify_authentication(sc_card_t *card, const struct iso_sm_ctx *ctx,
|
||||
const u8 *mac, size_t maclen,
|
||||
const u8 *macdata, size_t macdatalen);
|
||||
static int npa_sm_pre_transmit(sc_card_t *card, const struct sm_ctx *ctx,
|
||||
static int npa_sm_pre_transmit(sc_card_t *card, const struct iso_sm_ctx *ctx,
|
||||
sc_apdu_t *apdu);
|
||||
static int npa_sm_post_transmit(sc_card_t *card, const struct sm_ctx *ctx,
|
||||
static int npa_sm_post_transmit(sc_card_t *card, const struct iso_sm_ctx *ctx,
|
||||
sc_apdu_t *sm_apdu);
|
||||
static int npa_sm_finish(sc_card_t *card, const struct sm_ctx *ctx,
|
||||
static int npa_sm_finish(sc_card_t *card, const struct iso_sm_ctx *ctx,
|
||||
sc_apdu_t *apdu);
|
||||
static void npa_sm_clear_free(const struct sm_ctx *ctx);
|
||||
static void npa_sm_clear_free(const struct iso_sm_ctx *ctx);
|
||||
|
||||
|
||||
char npa_default_flags = 0;
|
||||
@@ -295,7 +299,7 @@ err:
|
||||
}
|
||||
|
||||
|
||||
int GetReadersPACECapabilities(u8 *bitmap)
|
||||
int get_pace_capabilities(u8 *bitmap)
|
||||
{
|
||||
if (!bitmap)
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
@@ -311,7 +315,7 @@ int GetReadersPACECapabilities(u8 *bitmap)
|
||||
/** Read an EF.
|
||||
* @note MF must be selected before calling this function.
|
||||
* */
|
||||
static int get_ef(struct sm_ctx *npactx, sc_card_t *card, unsigned char sfid,
|
||||
static int get_ef(sc_card_t *card, unsigned char sfid,
|
||||
u8 **ef, size_t *ef_len)
|
||||
{
|
||||
int r;
|
||||
@@ -322,6 +326,7 @@ static int get_ef(struct sm_ctx *npactx, sc_card_t *card, unsigned char sfid,
|
||||
sc_apdu_t apdu;
|
||||
sc_file_t *file = NULL;
|
||||
u8 *p;
|
||||
struct iso_sm_ctx *iso_sm_ctx = card->sm_ctx.info.cmd_data;
|
||||
|
||||
if (!card || !ef || !ef_len) {
|
||||
r = SC_ERROR_INVALID_ARGUMENTS;
|
||||
@@ -330,12 +335,14 @@ static int get_ef(struct sm_ctx *npactx, sc_card_t *card, unsigned char sfid,
|
||||
*ef_len = 0;
|
||||
|
||||
if (read > SC_MAX_APDU_BUFFER_SIZE-2
|
||||
|| (npactx && read > (((SC_MAX_APDU_BUFFER_SIZE-2
|
||||
|| (card->sm_ctx.sm_mode == SM_MODE_TRANSMIT
|
||||
&& read > (((SC_MAX_APDU_BUFFER_SIZE-2
|
||||
/* for encrypted APDUs we usually get authenticated status
|
||||
* bytes (4B), a MAC (11B) and a cryptogram with padding
|
||||
* indicator (3B without data). The cryptogram is always
|
||||
* padded to the block size. */
|
||||
-18) / npactx->block_length) * npactx->block_length - 1)))
|
||||
-18) / iso_sm_ctx->block_length)
|
||||
* iso_sm_ctx->block_length - 1)))
|
||||
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_EXT,
|
||||
ISO_READ_BINARY, ISO_P1_FLAG_SFID|sfid, 0);
|
||||
else
|
||||
@@ -352,10 +359,7 @@ static int get_ef(struct sm_ctx *npactx, sc_card_t *card, unsigned char sfid,
|
||||
apdu.resplen = read;
|
||||
apdu.le = read;
|
||||
|
||||
if (!npactx)
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
else
|
||||
r = sm_transmit_apdu(npactx, card, &apdu);
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
/* emulate the behaviour of sc_read_binary */
|
||||
if (r >= 0)
|
||||
r = apdu.resplen;
|
||||
@@ -378,22 +382,8 @@ static int get_ef(struct sm_ctx *npactx, sc_card_t *card, unsigned char sfid,
|
||||
}
|
||||
*ef = p;
|
||||
|
||||
if (!npactx)
|
||||
r = sc_read_binary(card, *ef_len,
|
||||
*ef + *ef_len, read, 0);
|
||||
else {
|
||||
if (*ef_len > 0x7fff) {
|
||||
r = SC_ERROR_OFFSET_TOO_LARGE;
|
||||
goto err;
|
||||
}
|
||||
apdu.p1 = (*ef_len >> 8) & 0x7F;
|
||||
apdu.p2 = *ef_len & 0xFF;
|
||||
apdu.resp = *ef + *ef_len;
|
||||
r = sm_transmit_apdu(npactx, card, &apdu);
|
||||
/* emulate the behaviour of sc_read_binary */
|
||||
if (r >= 0)
|
||||
r = apdu.resplen;
|
||||
}
|
||||
r = sc_read_binary(card, *ef_len,
|
||||
*ef + *ef_len, read, 0);
|
||||
}
|
||||
|
||||
/* test cards only return an empty FCI template,
|
||||
@@ -413,10 +403,10 @@ err:
|
||||
return r;
|
||||
}
|
||||
|
||||
int get_ef_card_access(struct sm_ctx *oldnpactx, sc_card_t *card,
|
||||
int get_ef_card_access(sc_card_t *card,
|
||||
u8 **ef_cardaccess, size_t *length_ef_cardaccess)
|
||||
{
|
||||
return get_ef(oldnpactx, card, SFID_EF_CARDACCESS, ef_cardaccess, length_ef_cardaccess);
|
||||
return get_ef(card, SFID_EF_CARDACCESS, ef_cardaccess, length_ef_cardaccess);
|
||||
}
|
||||
|
||||
static int format_mse_cdata(struct sc_context *ctx, int protocol,
|
||||
@@ -532,7 +522,7 @@ err:
|
||||
}
|
||||
|
||||
#define ISO_MSE 0x22
|
||||
static int npa_mse(struct sm_ctx *oldnpactx, sc_card_t *card,
|
||||
static int npa_mse(sc_card_t *card,
|
||||
unsigned char p1, unsigned char p2, int protocol,
|
||||
const unsigned char *key_reference1, size_t key_reference1_len,
|
||||
const unsigned char *key_reference2, size_t key_reference2_len,
|
||||
@@ -562,10 +552,7 @@ static int npa_mse(struct sm_ctx *oldnpactx, sc_card_t *card,
|
||||
apdu.lc = r;
|
||||
|
||||
|
||||
if (oldnpactx)
|
||||
r = sm_transmit_apdu(oldnpactx, card, &apdu);
|
||||
else
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
if (r < 0)
|
||||
goto err;
|
||||
|
||||
@@ -587,28 +574,26 @@ err:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int npa_mse_set_at(struct sm_ctx *oldnpactx, sc_card_t *card,
|
||||
unsigned char p1, int protocol,
|
||||
static int npa_mse_set_at(sc_card_t *card, unsigned char p1, int protocol,
|
||||
const unsigned char *key_reference1, size_t key_reference1_len,
|
||||
const unsigned char *key_reference2, size_t key_reference2_len,
|
||||
const unsigned char *eph_pub_key, size_t eph_pub_key_len,
|
||||
const unsigned char *auxiliary_data, size_t auxiliary_data_len,
|
||||
const CVC_CHAT *chat, u8 *sw1, u8 *sw2)
|
||||
{
|
||||
return npa_mse(oldnpactx, card, p1, 0xa4, protocol, key_reference1,
|
||||
return npa_mse(card, p1, 0xa4, protocol, key_reference1,
|
||||
key_reference1_len, key_reference2, key_reference2_len,
|
||||
eph_pub_key, eph_pub_key_len, auxiliary_data, auxiliary_data_len,
|
||||
chat, sw1, sw2);
|
||||
}
|
||||
|
||||
static int npa_mse_set_at_pace(struct sm_ctx *oldnpactx, sc_card_t *card,
|
||||
int protocol, enum s_type secret_key, const CVC_CHAT *chat, u8 *sw1,
|
||||
u8 *sw2)
|
||||
static int npa_mse_set_at_pace(sc_card_t *card, int protocol,
|
||||
enum s_type secret_key, const CVC_CHAT *chat, u8 *sw1, u8 *sw2)
|
||||
{
|
||||
int r, tries;
|
||||
char key = secret_key;
|
||||
|
||||
r = npa_mse_set_at(oldnpactx, card, 0xC1, protocol, &key, sizeof key, NULL,
|
||||
r = npa_mse_set_at(card, 0xC1, protocol, &key, sizeof key, NULL,
|
||||
0, NULL, 0, NULL, 0, chat, sw1, sw2);
|
||||
|
||||
if (*sw1 == 0x63) {
|
||||
@@ -639,8 +624,8 @@ static int npa_mse_set_at_pace(struct sm_ctx *oldnpactx, sc_card_t *card,
|
||||
|
||||
#define ISO_GENERAL_AUTHENTICATE 0x86
|
||||
#define ISO_COMMAND_CHAINING 0x10
|
||||
static int npa_gen_auth_1_encrypted_nonce(struct sm_ctx *oldnpactx,
|
||||
sc_card_t *card, u8 **enc_nonce, size_t *enc_nonce_len)
|
||||
static int npa_gen_auth_1_encrypted_nonce(sc_card_t *card,
|
||||
u8 **enc_nonce, size_t *enc_nonce_len)
|
||||
{
|
||||
sc_apdu_t apdu;
|
||||
NPA_GEN_AUTH_PACE_C *c_data = NULL;
|
||||
@@ -672,10 +657,7 @@ static int npa_gen_auth_1_encrypted_nonce(struct sm_ctx *oldnpactx,
|
||||
|
||||
apdu.resplen = sizeof resp;
|
||||
apdu.resp = resp;
|
||||
if (oldnpactx)
|
||||
r = sm_transmit_apdu(oldnpactx, card, &apdu);
|
||||
else
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
if (r < 0)
|
||||
goto err;
|
||||
|
||||
@@ -725,9 +707,9 @@ err:
|
||||
|
||||
return r;
|
||||
}
|
||||
static int npa_gen_auth_2_map_nonce(struct sm_ctx *oldnpactx,
|
||||
sc_card_t *card, const u8 *in, size_t in_len, u8 **map_data_out,
|
||||
size_t *map_data_out_len)
|
||||
static int npa_gen_auth_2_map_nonce(sc_card_t *card,
|
||||
const u8 *in, size_t in_len,
|
||||
u8 **map_data_out, size_t *map_data_out_len)
|
||||
{
|
||||
sc_apdu_t apdu;
|
||||
NPA_GEN_AUTH_PACE_C *c_data = NULL;
|
||||
@@ -767,10 +749,7 @@ static int npa_gen_auth_2_map_nonce(struct sm_ctx *oldnpactx,
|
||||
|
||||
apdu.resplen = sizeof resp;
|
||||
apdu.resp = resp;
|
||||
if (oldnpactx)
|
||||
r = sm_transmit_apdu(oldnpactx, card, &apdu);
|
||||
else
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
if (r < 0)
|
||||
goto err;
|
||||
|
||||
@@ -820,9 +799,9 @@ err:
|
||||
|
||||
return r;
|
||||
}
|
||||
static int npa_gen_auth_3_perform_key_agreement(
|
||||
struct sm_ctx *oldnpactx, sc_card_t *card,
|
||||
const u8 *in, size_t in_len, u8 **eph_pub_key_out, size_t *eph_pub_key_out_len)
|
||||
static int npa_gen_auth_3_perform_key_agreement(sc_card_t *card,
|
||||
const u8 *in, size_t in_len,
|
||||
u8 **eph_pub_key_out, size_t *eph_pub_key_out_len)
|
||||
{
|
||||
sc_apdu_t apdu;
|
||||
NPA_GEN_AUTH_PACE_C *c_data = NULL;
|
||||
@@ -862,10 +841,7 @@ static int npa_gen_auth_3_perform_key_agreement(
|
||||
|
||||
apdu.resplen = sizeof resp;
|
||||
apdu.resp = resp;
|
||||
if (oldnpactx)
|
||||
r = sm_transmit_apdu(oldnpactx, card, &apdu);
|
||||
else
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
if (r < 0)
|
||||
goto err;
|
||||
|
||||
@@ -915,10 +891,10 @@ err:
|
||||
|
||||
return r;
|
||||
}
|
||||
static int npa_gen_auth_4_mutual_authentication(
|
||||
struct sm_ctx *oldnpactx, sc_card_t *card,
|
||||
const u8 *in, size_t in_len, u8 **auth_token_out,
|
||||
size_t *auth_token_out_len, u8 **recent_car, size_t *recent_car_len,
|
||||
static int npa_gen_auth_4_mutual_authentication(sc_card_t *card,
|
||||
const u8 *in, size_t in_len,
|
||||
u8 **auth_token_out, size_t *auth_token_out_len,
|
||||
u8 **recent_car, size_t *recent_car_len,
|
||||
u8 **prev_car, size_t *prev_car_len)
|
||||
{
|
||||
sc_apdu_t apdu;
|
||||
@@ -958,10 +934,7 @@ static int npa_gen_auth_4_mutual_authentication(
|
||||
|
||||
apdu.resplen = sizeof resp;
|
||||
apdu.resp = resp;
|
||||
if (oldnpactx)
|
||||
r = sm_transmit_apdu(oldnpactx, card, &apdu);
|
||||
else
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
if (r < 0)
|
||||
goto err;
|
||||
|
||||
@@ -1037,9 +1010,8 @@ err:
|
||||
}
|
||||
|
||||
int
|
||||
npa_reset_retry_counter(struct sm_ctx *ctx, sc_card_t *card,
|
||||
enum s_type pin_id, int ask_for_secret,
|
||||
const char *new, size_t new_len)
|
||||
npa_reset_retry_counter(sc_card_t *card, enum s_type pin_id,
|
||||
int ask_for_secret, const char *new, size_t new_len)
|
||||
{
|
||||
sc_apdu_t apdu;
|
||||
char *p = NULL;
|
||||
@@ -1079,7 +1051,7 @@ npa_reset_retry_counter(struct sm_ctx *ctx, sc_card_t *card,
|
||||
apdu.cse = SC_APDU_CASE_1;
|
||||
}
|
||||
|
||||
r = sm_transmit_apdu(ctx, card, &apdu);
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
|
||||
if (p) {
|
||||
OPENSSL_cleanse(p, new_len);
|
||||
@@ -1133,10 +1105,10 @@ get_psec(sc_card_t *card, const char *pin, size_t length_pin, enum s_type pin_id
|
||||
return r;
|
||||
}
|
||||
|
||||
int EstablishPACEChannel(struct sm_ctx *oldnpactx, sc_card_t *card,
|
||||
static int establish_pace_channel(sc_card_t *card,
|
||||
struct establish_pace_channel_input pace_input,
|
||||
struct establish_pace_channel_output *pace_output,
|
||||
struct sm_ctx *sctx, enum eac_tr_version tr_version)
|
||||
struct iso_sm_ctx *sctx, enum eac_tr_version tr_version)
|
||||
{
|
||||
u8 *p = NULL;
|
||||
EAC_CTX *eac_ctx = NULL;
|
||||
@@ -1245,7 +1217,7 @@ int EstablishPACEChannel(struct sm_ctx *oldnpactx, sc_card_t *card,
|
||||
r = card->reader->ops->perform_pace(card->reader, &pace_input, pace_output);
|
||||
} else {
|
||||
if (!pace_output->ef_cardaccess_length || !pace_output->ef_cardaccess) {
|
||||
r = get_ef_card_access(oldnpactx, card, &pace_output->ef_cardaccess,
|
||||
r = get_ef_card_access(card, &pace_output->ef_cardaccess,
|
||||
&pace_output->ef_cardaccess_length);
|
||||
if (r < 0) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not get EF.CardAccess.");
|
||||
@@ -1274,7 +1246,7 @@ int EstablishPACEChannel(struct sm_ctx *oldnpactx, sc_card_t *card,
|
||||
|
||||
eac_ctx->tr_version = tr_version;
|
||||
|
||||
r = npa_mse_set_at_pace(oldnpactx, card, eac_ctx->pace_ctx->protocol,
|
||||
r = npa_mse_set_at_pace(card, eac_ctx->pace_ctx->protocol,
|
||||
pace_input.pin_id, chat, &pace_output->mse_set_at_sw1,
|
||||
&pace_output->mse_set_at_sw2);
|
||||
if (r < 0) {
|
||||
@@ -1289,7 +1261,7 @@ int EstablishPACEChannel(struct sm_ctx *oldnpactx, sc_card_t *card,
|
||||
r = SC_ERROR_OUT_OF_MEMORY;
|
||||
goto err;
|
||||
}
|
||||
r = npa_gen_auth_1_encrypted_nonce(oldnpactx, card, (u8 **) &enc_nonce->data,
|
||||
r = npa_gen_auth_1_encrypted_nonce(card, (u8 **) &enc_nonce->data,
|
||||
&enc_nonce->length);
|
||||
if (r < 0) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not get encrypted nonce from card "
|
||||
@@ -1323,7 +1295,7 @@ int EstablishPACEChannel(struct sm_ctx *oldnpactx, sc_card_t *card,
|
||||
r = SC_ERROR_INTERNAL;
|
||||
goto err;
|
||||
}
|
||||
r = npa_gen_auth_2_map_nonce(oldnpactx, card, (u8 *) mdata->data, mdata->length,
|
||||
r = npa_gen_auth_2_map_nonce(card, (u8 *) mdata->data, mdata->length,
|
||||
(u8 **) &mdata_opp->data, &mdata_opp->length);
|
||||
if (r < 0) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not exchange mapping data with card "
|
||||
@@ -1349,7 +1321,7 @@ int EstablishPACEChannel(struct sm_ctx *oldnpactx, sc_card_t *card,
|
||||
r = SC_ERROR_INTERNAL;
|
||||
goto err;
|
||||
}
|
||||
r = npa_gen_auth_3_perform_key_agreement(oldnpactx, card, (u8 *) pub->data, pub->length,
|
||||
r = npa_gen_auth_3_perform_key_agreement(card, (u8 *) pub->data, pub->length,
|
||||
(u8 **) &pub_opp->data, &pub_opp->length);
|
||||
if (r < 0) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not exchange ephemeral public key with card "
|
||||
@@ -1376,7 +1348,7 @@ int EstablishPACEChannel(struct sm_ctx *oldnpactx, sc_card_t *card,
|
||||
r = SC_ERROR_INTERNAL;
|
||||
goto err;
|
||||
}
|
||||
r = npa_gen_auth_4_mutual_authentication(oldnpactx, card, (u8 *) token->data, token->length,
|
||||
r = npa_gen_auth_4_mutual_authentication(card, (u8 *) token->data, token->length,
|
||||
(u8 **) &token_opp->data, &token_opp->length,
|
||||
&pace_output->recent_car, &pace_output->recent_car_length,
|
||||
&pace_output->previous_car, &pace_output->previous_car_length);
|
||||
@@ -1456,7 +1428,6 @@ int EstablishPACEChannel(struct sm_ctx *oldnpactx, sc_card_t *card,
|
||||
sctx->clear_free = npa_sm_clear_free;
|
||||
sctx->padding_indicator = SM_ISO_PADDING;
|
||||
sctx->block_length = EVP_CIPHER_block_size(eac_ctx->key_ctx->cipher);
|
||||
sctx->active = 1;
|
||||
}
|
||||
|
||||
err:
|
||||
@@ -1495,24 +1466,47 @@ err:
|
||||
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r);
|
||||
}
|
||||
|
||||
static int npa_mse_set_at_ta(struct sm_ctx *npactx, sc_card_t *card,
|
||||
int protocol, const unsigned char *chr, size_t chr_len,
|
||||
int perform_pace(sc_card_t *card,
|
||||
struct establish_pace_channel_input pace_input,
|
||||
struct establish_pace_channel_output *pace_output,
|
||||
enum eac_tr_version tr_version)
|
||||
{
|
||||
int r;
|
||||
struct iso_sm_ctx *sctx = iso_sm_ctx_create();
|
||||
|
||||
if (!sctx)
|
||||
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL,
|
||||
SC_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
r = establish_pace_channel(card, pace_input, pace_output, sctx, tr_version);
|
||||
|
||||
if (r < 0) {
|
||||
iso_sm_ctx_clear_free(sctx);
|
||||
} else {
|
||||
iso_sm_start(card, sctx);
|
||||
}
|
||||
|
||||
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r);
|
||||
}
|
||||
|
||||
static int npa_mse_set_at_ta(sc_card_t *card, int protocol,
|
||||
const unsigned char *chr, size_t chr_len,
|
||||
const unsigned char *eph_pub_key, size_t eph_pub_key_len,
|
||||
const unsigned char *auxiliary_data, size_t auxiliary_data_len)
|
||||
{
|
||||
return npa_mse_set_at(npactx, card, 0x81, protocol, chr, chr_len, NULL, 0,
|
||||
return npa_mse_set_at(card, 0x81, protocol, chr, chr_len, NULL, 0,
|
||||
eph_pub_key, eph_pub_key_len, auxiliary_data, auxiliary_data_len,
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static int npa_mse_set_dst(struct sm_ctx *npactx, sc_card_t *card,
|
||||
static int npa_mse_set_dst(sc_card_t *card,
|
||||
const unsigned char *chr, size_t chr_len)
|
||||
{
|
||||
return npa_mse(npactx, card, 0x81, 0xb6, 0, chr, chr_len, NULL, 0, NULL, 0,
|
||||
NULL, 0, NULL, NULL, NULL);
|
||||
return npa_mse(card, 0x81, 0xb6, 0, chr, chr_len, NULL, 0, NULL, 0, NULL,
|
||||
0, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static int npa_get_challenge(struct sm_ctx *npactx, sc_card_t *card,
|
||||
static int npa_get_challenge(sc_card_t *card,
|
||||
unsigned char *challenge, size_t len)
|
||||
{
|
||||
sc_apdu_t apdu;
|
||||
@@ -1532,10 +1526,7 @@ static int npa_get_challenge(struct sm_ctx *npactx, sc_card_t *card,
|
||||
apdu.resplen = len;
|
||||
apdu.resp = challenge;
|
||||
|
||||
if (npactx)
|
||||
r = sm_transmit_apdu(npactx, card, &apdu);
|
||||
else
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
if (r < 0)
|
||||
goto err;
|
||||
|
||||
@@ -1545,7 +1536,7 @@ err:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int npa_verify(struct sm_ctx *npactx, sc_card_t *card,
|
||||
static int npa_verify(sc_card_t *card,
|
||||
const unsigned char *cert, size_t cert_len)
|
||||
{
|
||||
sc_apdu_t apdu;
|
||||
@@ -1575,10 +1566,7 @@ static int npa_verify(struct sm_ctx *npactx, sc_card_t *card,
|
||||
apdu.datalen = length;
|
||||
apdu.lc = length;
|
||||
|
||||
if (npactx)
|
||||
r = sm_transmit_apdu(npactx, card, &apdu);
|
||||
else
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
if (r < 0)
|
||||
goto err;
|
||||
|
||||
@@ -1588,7 +1576,7 @@ err:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int npa_external_authenticate(struct sm_ctx *npactx, sc_card_t *card,
|
||||
static int npa_external_authenticate(sc_card_t *card,
|
||||
const unsigned char *signature, size_t signature_len)
|
||||
{
|
||||
int r;
|
||||
@@ -1607,10 +1595,7 @@ static int npa_external_authenticate(struct sm_ctx *npactx, sc_card_t *card,
|
||||
apdu.datalen = signature_len;
|
||||
apdu.lc = signature_len;
|
||||
|
||||
if (npactx)
|
||||
r = sm_transmit_apdu(npactx, card, &apdu);
|
||||
else
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
if (r < 0)
|
||||
goto err;
|
||||
|
||||
@@ -1620,7 +1605,7 @@ err:
|
||||
return r;
|
||||
}
|
||||
|
||||
int perform_terminal_authentication(struct sm_ctx *ctx, sc_card_t *card,
|
||||
int perform_terminal_authentication(sc_card_t *card,
|
||||
const unsigned char **certs, const size_t *certs_lens,
|
||||
const unsigned char *privkey, size_t privkey_len,
|
||||
const unsigned char *auxiliary_data, size_t auxiliary_data_len)
|
||||
@@ -1631,11 +1616,11 @@ int perform_terminal_authentication(struct sm_ctx *ctx, sc_card_t *card,
|
||||
CVC_CERT *cvc_cert = NULL;
|
||||
BUF_MEM *nonce = NULL, *signature = NULL;
|
||||
|
||||
if (!card || !ctx->priv_data || !certs_lens || !certs) {
|
||||
if (!card || !card->sm_ctx.info.cmd_data || !certs_lens || !certs) {
|
||||
r = SC_ERROR_INVALID_ARGUMENTS;
|
||||
goto err;
|
||||
}
|
||||
struct npa_sm_ctx *eacsmctx = ctx->priv_data;
|
||||
struct npa_sm_ctx *eacsmctx = card->sm_ctx.info.cmd_data;
|
||||
|
||||
|
||||
while (*certs && *certs_lens) {
|
||||
@@ -1650,7 +1635,7 @@ int perform_terminal_authentication(struct sm_ctx *ctx, sc_card_t *card,
|
||||
}
|
||||
cert = *certs;
|
||||
|
||||
r = npa_mse_set_dst(ctx, card,
|
||||
r = npa_mse_set_dst(card,
|
||||
cvc_cert->body->certificate_authority_reference->data,
|
||||
cvc_cert->body->certificate_authority_reference->length);
|
||||
if (r < 0) {
|
||||
@@ -1659,7 +1644,7 @@ int perform_terminal_authentication(struct sm_ctx *ctx, sc_card_t *card,
|
||||
goto err;
|
||||
}
|
||||
|
||||
r = npa_verify(ctx, card, cert, cert_len);
|
||||
r = npa_verify(card, cert, cert_len);
|
||||
if (r < 0)
|
||||
goto err;
|
||||
|
||||
@@ -1687,7 +1672,7 @@ int perform_terminal_authentication(struct sm_ctx *ctx, sc_card_t *card,
|
||||
}
|
||||
|
||||
|
||||
r = npa_mse_set_at_ta(ctx, card, eacsmctx->ctx->ta_ctx->protocol,
|
||||
r = npa_mse_set_at_ta(card, eacsmctx->ctx->ta_ctx->protocol,
|
||||
cvc_cert->body->certificate_holder_reference->data,
|
||||
cvc_cert->body->certificate_holder_reference->length,
|
||||
eacsmctx->eph_pub_key->data, eacsmctx->eph_pub_key->length,
|
||||
@@ -1704,7 +1689,7 @@ int perform_terminal_authentication(struct sm_ctx *ctx, sc_card_t *card,
|
||||
r = SC_ERROR_INTERNAL;
|
||||
goto err;
|
||||
}
|
||||
r = npa_get_challenge(ctx, card, nonce->data, nonce->length);
|
||||
r = npa_get_challenge(card, nonce->data, nonce->length);
|
||||
if (r < 0) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not get nonce for TA.");
|
||||
goto err;
|
||||
@@ -1728,7 +1713,7 @@ int perform_terminal_authentication(struct sm_ctx *ctx, sc_card_t *card,
|
||||
r = SC_ERROR_INTERNAL;
|
||||
goto err;
|
||||
}
|
||||
r = npa_external_authenticate(ctx, card, signature->data, signature->length);
|
||||
r = npa_external_authenticate(card, signature->data, signature->length);
|
||||
|
||||
err:
|
||||
if (cvc_cert)
|
||||
@@ -1739,15 +1724,14 @@ err:
|
||||
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r);
|
||||
}
|
||||
|
||||
static int npa_mse_set_at_ca(struct sm_ctx *npactx, sc_card_t *card,
|
||||
int protocol)
|
||||
static int npa_mse_set_at_ca(sc_card_t *card, int protocol)
|
||||
{
|
||||
return npa_mse_set_at(npactx, card, 0x41, protocol, NULL, 0, NULL, 0, NULL,
|
||||
0, NULL, 0, NULL, NULL, NULL);
|
||||
return npa_mse_set_at(card, 0x41, protocol, NULL, 0, NULL, 0, NULL, 0,
|
||||
NULL, 0, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static int npa_gen_auth_ca(struct sm_ctx *npactx, sc_card_t *card,
|
||||
const BUF_MEM *eph_pub_key, BUF_MEM **nonce, BUF_MEM **token)
|
||||
static int npa_gen_auth_ca(sc_card_t *card, const BUF_MEM *eph_pub_key,
|
||||
BUF_MEM **nonce, BUF_MEM **token)
|
||||
{
|
||||
sc_apdu_t apdu;
|
||||
NPA_GEN_AUTH_CA_C *c_data = NULL;
|
||||
@@ -1786,10 +1770,7 @@ static int npa_gen_auth_ca(struct sm_ctx *npactx, sc_card_t *card,
|
||||
|
||||
apdu.resplen = sizeof resp;
|
||||
apdu.resp = resp;
|
||||
if (npactx)
|
||||
r = sm_transmit_apdu(npactx, card, &apdu);
|
||||
else
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
if (r < 0)
|
||||
goto err;
|
||||
|
||||
@@ -1837,13 +1818,13 @@ err:
|
||||
return r;
|
||||
}
|
||||
|
||||
int get_ef_card_security(struct sm_ctx *npactx, sc_card_t *card,
|
||||
int get_ef_card_security(sc_card_t *card,
|
||||
u8 **ef_security, size_t *length_ef_security)
|
||||
{
|
||||
return get_ef(npactx, card, SFID_EF_CARDSECURITY, ef_security, length_ef_security);
|
||||
return get_ef(card, SFID_EF_CARDSECURITY, ef_security, length_ef_security);
|
||||
}
|
||||
|
||||
int perform_chip_authentication(struct sm_ctx *ctx, sc_card_t *card)
|
||||
int perform_chip_authentication(sc_card_t *card)
|
||||
{
|
||||
int r;
|
||||
BUF_MEM *picc_pubkey = NULL, *nonce = NULL, *token = NULL,
|
||||
@@ -1851,15 +1832,15 @@ int perform_chip_authentication(struct sm_ctx *ctx, sc_card_t *card)
|
||||
unsigned char *ef_cardsecurity = NULL;
|
||||
size_t ef_cardsecurity_len;
|
||||
|
||||
if (!card || !ctx->priv_data) {
|
||||
if (!card || !card->sm_ctx.info.cmd_data) {
|
||||
r = SC_ERROR_INVALID_ARGUMENTS;
|
||||
goto err;
|
||||
}
|
||||
struct npa_sm_ctx *eacsmctx = ctx->priv_data;
|
||||
struct npa_sm_ctx *eacsmctx = card->sm_ctx.info.cmd_data;
|
||||
|
||||
|
||||
/* Passive Authentication */
|
||||
r = get_ef_card_security(ctx, card, &ef_cardsecurity, &ef_cardsecurity_len);
|
||||
r = get_ef_card_security(card, &ef_cardsecurity, &ef_cardsecurity_len);
|
||||
if (r < 0) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not get EF.CardSecurity.");
|
||||
goto err;
|
||||
@@ -1873,7 +1854,7 @@ int perform_chip_authentication(struct sm_ctx *ctx, sc_card_t *card)
|
||||
}
|
||||
|
||||
|
||||
r = npa_mse_set_at_ca(ctx, card, eacsmctx->ctx->ca_ctx->protocol);
|
||||
r = npa_mse_set_at_ca(card, eacsmctx->ctx->ca_ctx->protocol);
|
||||
if (r < 0) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not select protocol proberties "
|
||||
"(MSE: Set AT failed).");
|
||||
@@ -1888,7 +1869,7 @@ int perform_chip_authentication(struct sm_ctx *ctx, sc_card_t *card)
|
||||
r = SC_ERROR_INTERNAL;
|
||||
goto err;
|
||||
}
|
||||
r = npa_gen_auth_ca(ctx, card, eph_pub_key, &nonce, &token);
|
||||
r = npa_gen_auth_ca(card, eph_pub_key, &nonce, &token);
|
||||
if (r < 0) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "(General Authenticate failed).");
|
||||
goto err;
|
||||
@@ -1977,7 +1958,7 @@ reset_ssc(struct npa_sm_ctx *eacsmctx)
|
||||
}
|
||||
|
||||
static int
|
||||
npa_sm_encrypt(sc_card_t *card, const struct sm_ctx *ctx,
|
||||
npa_sm_encrypt(sc_card_t *card, const struct iso_sm_ctx *ctx,
|
||||
const u8 *data, size_t datalen, u8 **enc)
|
||||
{
|
||||
BUF_MEM *encbuf = NULL, *databuf = NULL;
|
||||
@@ -2018,7 +1999,7 @@ err:
|
||||
}
|
||||
|
||||
static int
|
||||
npa_sm_decrypt(sc_card_t *card, const struct sm_ctx *ctx,
|
||||
npa_sm_decrypt(sc_card_t *card, const struct iso_sm_ctx *ctx,
|
||||
const u8 *enc, size_t enclen, u8 **data)
|
||||
{
|
||||
BUF_MEM *encbuf = NULL, *databuf = NULL;
|
||||
@@ -2059,7 +2040,7 @@ err:
|
||||
}
|
||||
|
||||
static int
|
||||
npa_sm_authenticate(sc_card_t *card, const struct sm_ctx *ctx,
|
||||
npa_sm_authenticate(sc_card_t *card, const struct iso_sm_ctx *ctx,
|
||||
const u8 *data, size_t datalen, u8 **macdata)
|
||||
{
|
||||
BUF_MEM *inbuf = NULL, *macbuf = NULL;
|
||||
@@ -2107,7 +2088,7 @@ err:
|
||||
}
|
||||
|
||||
static int
|
||||
npa_sm_verify_authentication(sc_card_t *card, const struct sm_ctx *ctx,
|
||||
npa_sm_verify_authentication(sc_card_t *card, const struct iso_sm_ctx *ctx,
|
||||
const u8 *mac, size_t maclen,
|
||||
const u8 *macdata, size_t macdatalen)
|
||||
{
|
||||
@@ -2182,7 +2163,7 @@ add_tag(unsigned char **asn1new, int constructed, int tag,
|
||||
return newlen;
|
||||
}
|
||||
static int
|
||||
npa_sm_pre_transmit(sc_card_t *card, const struct sm_ctx *ctx,
|
||||
npa_sm_pre_transmit(sc_card_t *card, const struct iso_sm_ctx *ctx,
|
||||
sc_apdu_t *apdu)
|
||||
{
|
||||
int r;
|
||||
@@ -2396,7 +2377,7 @@ err:
|
||||
}
|
||||
|
||||
static int
|
||||
npa_sm_post_transmit(sc_card_t *card, const struct sm_ctx *ctx,
|
||||
npa_sm_post_transmit(sc_card_t *card, const struct iso_sm_ctx *ctx,
|
||||
sc_apdu_t *sm_apdu)
|
||||
{
|
||||
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL,
|
||||
@@ -2404,7 +2385,7 @@ npa_sm_post_transmit(sc_card_t *card, const struct sm_ctx *ctx,
|
||||
}
|
||||
|
||||
static int
|
||||
npa_sm_finish(sc_card_t *card, const struct sm_ctx *ctx,
|
||||
npa_sm_finish(sc_card_t *card, const struct iso_sm_ctx *ctx,
|
||||
sc_apdu_t *apdu)
|
||||
{
|
||||
if (!card)
|
||||
@@ -2440,7 +2421,7 @@ npa_sm_finish(sc_card_t *card, const struct sm_ctx *ctx,
|
||||
}
|
||||
|
||||
static void
|
||||
npa_sm_clear_free(const struct sm_ctx *ctx)
|
||||
npa_sm_clear_free(const struct iso_sm_ctx *ctx)
|
||||
{
|
||||
if (ctx) {
|
||||
struct npa_sm_ctx *eacsmctx = ctx->priv_data;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @defgroup sm Secure Messaging (SM)
|
||||
* @defgroup sm Interface to Secure Messaging (SM) defined in ISO 7816
|
||||
* @{
|
||||
*/
|
||||
#ifndef _CCID_SM_H
|
||||
@@ -36,10 +36,7 @@ extern "C" {
|
||||
#define SM_NO_PADDING 0x02
|
||||
|
||||
/** Secure messaging context */
|
||||
struct sm_ctx {
|
||||
/** 1 if secure messaging is activated, 0 otherwise */
|
||||
unsigned char active;
|
||||
|
||||
struct iso_sm_ctx {
|
||||
/** data of the specific crypto implementation */
|
||||
void *priv_data;
|
||||
|
||||
@@ -49,64 +46,72 @@ struct sm_ctx {
|
||||
size_t block_length;
|
||||
|
||||
/** Call back function for authentication of data */
|
||||
int (*authenticate)(sc_card_t *card, const struct sm_ctx *ctx,
|
||||
int (*authenticate)(sc_card_t *card, const struct iso_sm_ctx *ctx,
|
||||
const u8 *data, size_t datalen, u8 **outdata);
|
||||
/** Call back function for verifying authentication data */
|
||||
int (*verify_authentication)(sc_card_t *card, const struct sm_ctx *ctx,
|
||||
int (*verify_authentication)(sc_card_t *card, const struct iso_sm_ctx *ctx,
|
||||
const u8 *mac, size_t maclen,
|
||||
const u8 *macdata, size_t macdatalen);
|
||||
|
||||
/** Call back function for encryption of data */
|
||||
int (*encrypt)(sc_card_t *card, const struct sm_ctx *ctx,
|
||||
int (*encrypt)(sc_card_t *card, const struct iso_sm_ctx *ctx,
|
||||
const u8 *data, size_t datalen, u8 **enc);
|
||||
/** Call back function for decryption of data */
|
||||
int (*decrypt)(sc_card_t *card, const struct sm_ctx *ctx,
|
||||
int (*decrypt)(sc_card_t *card, const struct iso_sm_ctx *ctx,
|
||||
const u8 *enc, size_t enclen, u8 **data);
|
||||
|
||||
/** Call back function for actions before encoding and encryption of \a apdu */
|
||||
int (*pre_transmit)(sc_card_t *card, const struct sm_ctx *ctx,
|
||||
int (*pre_transmit)(sc_card_t *card, const struct iso_sm_ctx *ctx,
|
||||
sc_apdu_t *apdu);
|
||||
/** Call back function for actions before decryption and decoding of \a sm_apdu */
|
||||
int (*post_transmit)(sc_card_t *card, const struct sm_ctx *ctx,
|
||||
int (*post_transmit)(sc_card_t *card, const struct iso_sm_ctx *ctx,
|
||||
sc_apdu_t *sm_apdu);
|
||||
/** Call back function for actions after decrypting SM protected APDU */
|
||||
int (*finish)(sc_card_t *card, const struct sm_ctx *ctx,
|
||||
int (*finish)(sc_card_t *card, const struct iso_sm_ctx *ctx,
|
||||
sc_apdu_t *apdu);
|
||||
|
||||
/** Clears and frees private data */
|
||||
void (*clear_free)(const struct sm_ctx *ctx);
|
||||
void (*clear_free)(const struct iso_sm_ctx *ctx);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Secure messaging wrapper for sc_transmit_apdu()
|
||||
* @brief Clears and frees the SM context including private data
|
||||
*
|
||||
* If secure messaging (SM) is activated in \a sctx and \a apdu is not already
|
||||
* SM protected, \a apdu is processed with the following steps:
|
||||
* \li call to \a sctx->pre_transmit
|
||||
* \li encrypt \a apdu calling \a sctx->encrypt
|
||||
* \li authenticate \a apdu calling \a sctx->authenticate
|
||||
* \li transmit SM protected \a apdu
|
||||
* \li verify SM protected \a apdu calling \a sctx->verify_authentication
|
||||
* \li decrypt SM protected \a apdu calling \a sctx->decrypt
|
||||
* \li copy decrypted/authenticated data and status bytes to \a apdu
|
||||
* Calls \a sctx->clear_free() if available
|
||||
*
|
||||
* @param[in] sctx (optional)
|
||||
* @param[in] card
|
||||
* @param[in,out] apdu
|
||||
*
|
||||
*/
|
||||
void iso_sm_ctx_clear_free(struct iso_sm_ctx *sctx);
|
||||
|
||||
/**
|
||||
* @brief Creates a SM context
|
||||
*
|
||||
* @return SM context or NULL if an error occurred
|
||||
*/
|
||||
struct iso_sm_ctx *iso_sm_ctx_create(void);
|
||||
|
||||
/**
|
||||
* @brief Initializes a card for usage of the ISO SM driver
|
||||
*
|
||||
* If a SM module has been assigned previously to the card, it will be cleaned
|
||||
* up.
|
||||
*
|
||||
* @param[in] card
|
||||
* @param[in] sctx will NOT be freed automatically. \a sctx should be present
|
||||
* for the time of the SM session.
|
||||
*
|
||||
* @return \c SC_SUCCESS or error code if an error occurred
|
||||
*/
|
||||
int sm_transmit_apdu(struct sm_ctx *sctx, sc_card_t *card,
|
||||
sc_apdu_t *apdu);
|
||||
int iso_sm_start(struct sc_card *card, struct iso_sm_ctx *sctx);
|
||||
|
||||
/**
|
||||
* @brief Clears and frees private data of the SM context
|
||||
/**
|
||||
* @brief Stops SM and frees allocated ressources.
|
||||
*
|
||||
* Calls \a sctx->clear_free
|
||||
*
|
||||
* @param[in] sctx (optional)
|
||||
* @param[in] card
|
||||
*
|
||||
* @return \c SC_SUCCESS or error code if an error occurred
|
||||
*/
|
||||
void sm_ctx_clear_free(const struct sm_ctx *sctx);
|
||||
int sm_stop(struct sc_card *card);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
@@ -113,53 +113,50 @@ extern "C" {
|
||||
const char *npa_secret_name(enum s_type pin_id);
|
||||
|
||||
|
||||
#ifdef BUERGERCLIENT_WORKAROUND
|
||||
int get_ef_card_access(sc_card_t *card,
|
||||
u8 **ef_cardaccess, size_t *length_ef_cardaccess);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Get the reader's PACE capabilities
|
||||
* @brief Get the PACE capabilities
|
||||
*
|
||||
* @param[in,out] bitmap where to store capabilities bitmap
|
||||
* @note Since this code offers no support for terminal certificate, the bitmap is always \c PACE_BITMAP_PACE|PACE_BITMAP_EID
|
||||
*
|
||||
* @return \c SC_SUCCESS or error code if an error occurred
|
||||
*/
|
||||
int GetReadersPACECapabilities(u8 *bitmap);
|
||||
int get_pace_capabilities(u8 *bitmap);
|
||||
|
||||
/**
|
||||
* @brief Establish secure messaging using PACE
|
||||
*
|
||||
* Modifies \a card to use the ISO SM driver and initializes the data
|
||||
* structures to use the established SM channel.
|
||||
*
|
||||
* Prints certificate description and card holder authorization template if
|
||||
* given in a human readable form to stdout. If no secret is given, the user is
|
||||
* asked for it. Only \a pace_input.pin_id is mandatory, the other members of
|
||||
* \a pace_input can be set to \c 0 or \c NULL.
|
||||
* \a pace_input can be set to \c 0 or \c NULL respectively.
|
||||
*
|
||||
* The buffers in \a pace_output are allocated using \c realloc() and should be
|
||||
* set to NULL, if empty. If an EF.CardAccess is already present, this file is
|
||||
* reused and not fetched from the card.
|
||||
*
|
||||
* @param[in] oldpacectx (optional) Old SM context, if PACE is established in an existing SM channel
|
||||
* @param[in] card
|
||||
* @param[in,out] card
|
||||
* @param[in] pace_input
|
||||
* @param[in,out] pace_output
|
||||
* @param[out] sctx
|
||||
* @param[in] tr_version Version of TR-03110 to use with PACE
|
||||
*
|
||||
* @return \c SC_SUCCESS or error code if an error occurred
|
||||
*/
|
||||
int EstablishPACEChannel(struct sm_ctx *oldpacectx, sc_card_t *card,
|
||||
int perform_pace(sc_card_t *card,
|
||||
struct establish_pace_channel_input pace_input,
|
||||
struct establish_pace_channel_output *pace_output,
|
||||
struct sm_ctx *sctx, enum eac_tr_version tr_version);
|
||||
enum eac_tr_version tr_version);
|
||||
|
||||
int perform_terminal_authentication(struct sm_ctx *ctx, sc_card_t *card,
|
||||
int perform_terminal_authentication(sc_card_t *card,
|
||||
const unsigned char **certs, const size_t *certs_lens,
|
||||
const unsigned char *privkey, size_t privkey_len,
|
||||
const unsigned char *auxiliary_data, size_t auxiliary_data_len);
|
||||
|
||||
int perform_chip_authentication(struct sm_ctx *ctx, sc_card_t *card);
|
||||
int perform_chip_authentication(sc_card_t *card);
|
||||
|
||||
/**
|
||||
* @brief Sends a reset retry counter APDU
|
||||
@@ -169,7 +166,6 @@ int perform_chip_authentication(struct sm_ctx *ctx, sc_card_t *card);
|
||||
* operation to be authorized either by an established PACE channel or by the
|
||||
* effective authorization of the terminal's certificate.
|
||||
*
|
||||
* @param[in] ctx (optional) NPA SM context
|
||||
* @param[in] card
|
||||
* @param[in] pin_id Type of secret (usually PIN or CAN). You may use <tt>enum s_type</tt> from \c <openssl/pace.h>.
|
||||
* @param[in] ask_for_secret whether to ask the user for the secret (\c 1) or not (\c 0)
|
||||
@@ -178,26 +174,24 @@ int perform_chip_authentication(struct sm_ctx *ctx, sc_card_t *card);
|
||||
*
|
||||
* @return \c SC_SUCCESS or error code if an error occurred
|
||||
*/
|
||||
int npa_reset_retry_counter(struct sm_ctx *ctx, sc_card_t *card,
|
||||
int npa_reset_retry_counter(sc_card_t *card,
|
||||
enum s_type pin_id, int ask_for_secret,
|
||||
const char *new, size_t new_len);
|
||||
/**
|
||||
* @brief Send APDU to unblock the PIN
|
||||
*
|
||||
* @param[in] ctx (optional) NPA SM context
|
||||
* @param[in] card
|
||||
*/
|
||||
#define npa_unblock_pin(ctx, card) \
|
||||
npa_reset_retry_counter(ctx, card, PACE_PIN, 0, NULL, 0)
|
||||
#define npa_unblock_pin(card) \
|
||||
npa_reset_retry_counter(card, PACE_PIN, 0, NULL, 0)
|
||||
/** Send APDU to set a new PIN
|
||||
*
|
||||
* @param[in] ctx (optional) NPA SM context
|
||||
* @param[in] card
|
||||
* @param[in] newp (optional) new PIN
|
||||
* @param[in] newplen (optional) length of \a new
|
||||
*/
|
||||
#define npa_change_pin(ctx, card, newp, newplen) \
|
||||
npa_reset_retry_counter(ctx, card, PACE_PIN, 1, newp, newplen)
|
||||
#define npa_change_pin(card, newp, newplen) \
|
||||
npa_reset_retry_counter(card, PACE_PIN, 1, newp, newplen)
|
||||
|
||||
#define NPA_FLAG_DISABLE_CHECKS 1
|
||||
extern char npa_default_flags;
|
||||
|
||||
@@ -16,10 +16,14 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ccid. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "scutil.h"
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <libopensc/log.h>
|
||||
#include <npa/scutil.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <libopensc/log.h>
|
||||
|
||||
int initialize(int reader_id, const char *cdriver, int verbose,
|
||||
sc_context_t **ctx, sc_reader_t **reader)
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Frank Morgner
|
||||
*
|
||||
* This file is part of ccid.
|
||||
*
|
||||
* ccid is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU General Public License as published by the Free Software
|
||||
* Foundation, either version 3 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* ccid 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 General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* ccid. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
Reference in New Issue
Block a user