diff --git a/npa/Makefile.am b/npa/Makefile.am index 871599e..6628066 100644 --- a/npa/Makefile.am +++ b/npa/Makefile.am @@ -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' \ diff --git a/npa/configure.ac b/npa/configure.ac index ada0638..817038e 100644 --- a/npa/configure.ac +++ b/npa/configure.ac @@ -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" diff --git a/npa/src/Makefile.am b/npa/src/Makefile.am index c8de471..5cc968d 100644 --- a/npa/src/Makefile.am +++ b/npa/src/Makefile.am @@ -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 diff --git a/npa/src/example.c b/npa/src/example.c index 7560e24..8b39a4d 100644 --- a/npa/src/example.c +++ b/npa/src/example.c @@ -17,10 +17,14 @@ * npa. If not, see . */ -/* 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 #include #include @@ -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); diff --git a/npa/src/sm.c b/npa/src/iso-sm.c similarity index 74% rename from npa/src/sm.c rename to npa/src/iso-sm.c index a7947c9..4f30130 100644 --- a/npa/src/sm.c +++ b/npa/src/iso-sm.c @@ -16,13 +16,68 @@ * You should have received a copy of the GNU General Public License along with * ccid. If not, see . */ -#include "scutil.h" -#include "sm.h" +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include +#include +#include #include #include +/* @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; } diff --git a/npa/src/npa-tool.c b/npa/src/npa-tool.c index 2d68ad6..c421a09 100644 --- a/npa/src/npa-tool.c +++ b/npa/src/npa-tool.c @@ -16,6 +16,10 @@ * You should have received a copy of the GNU General Public License along with * npa. If not, see . */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include "cmdline.h" #include "config.h" #include @@ -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); diff --git a/npa/src/npa.c b/npa/src/npa.c index 73f06e6..4ce566a 100644 --- a/npa/src/npa.c +++ b/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 . */ -#include "npa.h" -#include "scutil.h" -#include "sm.h" +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include "sslutil.h" +#include #include #include #include -#include #include #include #include #include +#include +#include +#include #include #include #include @@ -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; diff --git a/npa/src/npa/sm.h b/npa/src/npa/iso-sm.h similarity index 59% rename from npa/src/npa/sm.h rename to npa/src/npa/iso-sm.h index 7e8773c..b72c3f7 100644 --- a/npa/src/npa/sm.h +++ b/npa/src/npa/iso-sm.h @@ -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 } diff --git a/npa/src/npa/npa.h b/npa/src/npa/npa.h index 7659106..bb763a3 100644 --- a/npa/src/npa/npa.h +++ b/npa/src/npa/npa.h @@ -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 enum s_type from \c . * @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; diff --git a/npa/src/scutil.c b/npa/src/scutil.c index 6cf7a15..ed4803f 100644 --- a/npa/src/scutil.c +++ b/npa/src/scutil.c @@ -16,10 +16,14 @@ * You should have received a copy of the GNU General Public License along with * ccid. If not, see . */ -#include "scutil.h" +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include #include #include -#include int initialize(int reader_id, const char *cdriver, int verbose, sc_context_t **ctx, sc_reader_t **reader) diff --git a/npa/src/sslutil.c b/npa/src/sslutil.c deleted file mode 100644 index 6b7bab5..0000000 --- a/npa/src/sslutil.c +++ /dev/null @@ -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 . - */