using patched OpenSC enabled with PACE to use the reader's capabilities
sourcecode can be fetched from here https://github.com/frankmorgner/OpenSC git-svn-id: https://vsmartcard.svn.sourceforge.net/svnroot/vsmartcard@696 96b47cad-a561-4643-ad3b-153ac7d7599c
This commit is contained in:
@@ -24,8 +24,7 @@ libopensc_la_SOURCES = \
|
||||
\
|
||||
pkcs15.c pkcs15-cert.c pkcs15-data.c pkcs15-pin.c \
|
||||
pkcs15-prkey.c pkcs15-pubkey.c pkcs15-sec.c \
|
||||
pkcs15-wrap.c pkcs15-algo.c pkcs15-cache.c pkcs15-syn.c \
|
||||
pkcs15-gemsafeV1.c \
|
||||
pkcs15-algo.c pkcs15-cache.c pkcs15-syn.c \
|
||||
\
|
||||
muscle.c muscle-filesystem.c \
|
||||
\
|
||||
@@ -45,7 +44,7 @@ libopensc_la_SOURCES = \
|
||||
pkcs15-tcos.c pkcs15-esteid.c pkcs15-postecert.c pkcs15-gemsafeGPK.c \
|
||||
pkcs15-actalis.c pkcs15-atrust-acos.c pkcs15-tccardos.c pkcs15-piv.c \
|
||||
pkcs15-esinit.c pkcs15-westcos.c pkcs15-pteid.c pkcs15-oberthur.c \
|
||||
pkcs15-itacns.c \
|
||||
pkcs15-itacns.c pkcs15-gemsafeV1.c \
|
||||
compression.c p15card-helper.c
|
||||
if WIN32
|
||||
libopensc_la_SOURCES += $(top_builddir)/win32/versioninfo.rc
|
||||
|
||||
@@ -45,9 +45,9 @@ saved_CPPFLAGS="$CPPFLAGS"
|
||||
saved_LIBS="$LIBS"
|
||||
CPPFLAGS="$CPPFLAGS $OPENSSL_CFLAGS"
|
||||
LIBS="$LDFLAGS $OPENSC_LIBS $OPENSSL_LIBS"
|
||||
AC_MSG_CHECKING([for sc_bytes2apdu])
|
||||
AC_TRY_LINK_FUNC(sc_bytes2apdu, [ AC_MSG_RESULT([yes]) ],
|
||||
[ AC_MSG_ERROR([libopensc >= 0.12.1 not found, use ./configure 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 (https://github.com/frankmorgner/OpenSC) not found, use ./configure OPENSC_LIBS=...]) ])
|
||||
|
||||
AC_CHECK_HEADERS(openssl/evp.h, [], [ AC_MSG_ERROR([openssl/evp.h not found, install OpenSSL or use ./configure OPENSSL_CFLAGS=...]) ])
|
||||
AC_MSG_CHECKING([for EVP_read_pw_string_min])
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
* APDU encrypted and authenticated to the card using sm_transmit_apdu. */
|
||||
#include <npa/npa.h>
|
||||
#include <npa/scutil.h>
|
||||
#include <openssl/pace.h>
|
||||
#include <string.h>
|
||||
|
||||
static int reader_num = -1;
|
||||
@@ -80,7 +79,7 @@ main (int argc, char **argv)
|
||||
pace_input.pin_length = pin ? strlen(pin) : 0;
|
||||
|
||||
r = EstablishPACEChannel(NULL, card, pace_input, &pace_output,
|
||||
&sctx);
|
||||
&sctx, EAC_TR_VERSION_2_02);
|
||||
if (r < 0)
|
||||
goto err;
|
||||
printf("Established PACE channel with PIN.\n");
|
||||
|
||||
@@ -198,7 +198,7 @@ int npa_translate_apdus(struct sm_ctx *sctx, sc_card_t *card, FILE *input)
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int r, oindex = 0;
|
||||
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;
|
||||
@@ -299,7 +299,7 @@ main (int argc, char **argv)
|
||||
}
|
||||
break;
|
||||
case OPT_TRVERSION:
|
||||
if (sscanf(optarg, "%d", (int *) &pace_input.tr_version) != 1) {
|
||||
if (sscanf(optarg, "%d", (int *) &tr_version) != 1) {
|
||||
parse_error(argv[0], options, option_help, optarg, oindex);
|
||||
exit(2);
|
||||
}
|
||||
@@ -414,7 +414,7 @@ main (int argc, char **argv)
|
||||
npa_secret_name(pace_input.pin_id), pace_input.pin);
|
||||
|
||||
r = EstablishPACEChannel(NULL, card, pace_input, &pace_output,
|
||||
&sctx);
|
||||
&sctx, tr_version);
|
||||
|
||||
secret++;
|
||||
} while (0 > r && secret <= maxsecret);
|
||||
@@ -443,7 +443,7 @@ main (int argc, char **argv)
|
||||
pace_input.pin_length = 0;
|
||||
}
|
||||
r = EstablishPACEChannel(NULL, card, pace_input, &pace_output,
|
||||
&tmpctx);
|
||||
&tmpctx, tr_version);
|
||||
if (r < 0)
|
||||
goto err;
|
||||
printf("Established PACE channel with CAN.\n");
|
||||
@@ -457,7 +457,7 @@ main (int argc, char **argv)
|
||||
pace_input.pin_length = 0;
|
||||
}
|
||||
r = EstablishPACEChannel(&tmpctx, card, pace_input, &pace_output,
|
||||
&sctx);
|
||||
&sctx, tr_version);
|
||||
if (r < 0)
|
||||
goto err;
|
||||
printf("Established PACE channel with PIN. PIN resumed.\n");
|
||||
@@ -473,7 +473,7 @@ main (int argc, char **argv)
|
||||
pace_input.pin_length = 0;
|
||||
}
|
||||
r = EstablishPACEChannel(NULL, card, pace_input, &pace_output,
|
||||
&sctx);
|
||||
&sctx, tr_version);
|
||||
if (r < 0)
|
||||
goto err;
|
||||
printf("Established PACE channel with PUK.\n");
|
||||
@@ -494,7 +494,7 @@ main (int argc, char **argv)
|
||||
pace_input.pin_length = 0;
|
||||
}
|
||||
r = EstablishPACEChannel(NULL, card, pace_input, &pace_output,
|
||||
&sctx);
|
||||
&sctx, tr_version);
|
||||
if (r < 0)
|
||||
goto err;
|
||||
printf("Established PACE channel with PIN.\n");
|
||||
@@ -539,7 +539,7 @@ main (int argc, char **argv)
|
||||
}
|
||||
|
||||
r = EstablishPACEChannel(NULL, card, pace_input, &pace_output,
|
||||
&sctx);
|
||||
&sctx, tr_version);
|
||||
if (r < 0)
|
||||
goto err;
|
||||
printf("Established PACE channel with %s.\n",
|
||||
|
||||
402
npa/src/npa.c
402
npa/src/npa.c
@@ -973,7 +973,7 @@ get_psec(sc_card_t *card, const char *pin, size_t length_pin, enum s_type pin_id
|
||||
int EstablishPACEChannel(struct sm_ctx *oldnpactx, sc_card_t *card,
|
||||
struct establish_pace_channel_input pace_input,
|
||||
struct establish_pace_channel_output *pace_output,
|
||||
struct sm_ctx *sctx)
|
||||
struct sm_ctx *sctx, enum eac_tr_version tr_version)
|
||||
{
|
||||
u8 *p = NULL;
|
||||
EAC_CTX *eac_ctx = NULL;
|
||||
@@ -1075,222 +1075,226 @@ int EstablishPACEChannel(struct sm_ctx *oldnpactx, sc_card_t *card,
|
||||
}
|
||||
}
|
||||
|
||||
if (!pace_output->ef_cardaccess_length || !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.");
|
||||
if (card->reader->capabilities & SC_READER_CAP_PACE) {
|
||||
r = sc_perform_pace(card, &pace_input, pace_output);
|
||||
} else {
|
||||
if (!pace_output->ef_cardaccess_length || !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.");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "EF.CardAccess", pace_output->ef_cardaccess,
|
||||
pace_output->ef_cardaccess_length);
|
||||
|
||||
eac_ctx = EAC_CTX_new();
|
||||
if (!eac_ctx
|
||||
|| !EAC_CTX_init_ef_cardaccess(pace_output->ef_cardaccess,
|
||||
pace_output->ef_cardaccess_length, eac_ctx)) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not parse EF.CardAccess.");
|
||||
ssl_error(card->ctx);
|
||||
r = SC_ERROR_INTERNAL;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "EF.CardAccess", pace_output->ef_cardaccess,
|
||||
pace_output->ef_cardaccess_length);
|
||||
|
||||
eac_ctx = EAC_CTX_new();
|
||||
if (!eac_ctx
|
||||
|| !EAC_CTX_init_ef_cardaccess(pace_output->ef_cardaccess,
|
||||
pace_output->ef_cardaccess_length, eac_ctx)) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not parse EF.CardAccess.");
|
||||
ssl_error(card->ctx);
|
||||
r = SC_ERROR_INTERNAL;
|
||||
goto err;
|
||||
}
|
||||
eac_ctx->tr_version = tr_version;
|
||||
|
||||
eac_ctx->tr_version = pace_input.tr_version;
|
||||
r = npa_mse_set_at(oldnpactx, 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) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not select protocol proberties "
|
||||
"(MSE: Set AT failed).");
|
||||
goto err;
|
||||
}
|
||||
enc_nonce = BUF_MEM_new();
|
||||
if (!enc_nonce) {
|
||||
ssl_error(card->ctx);
|
||||
r = SC_ERROR_OUT_OF_MEMORY;
|
||||
goto err;
|
||||
}
|
||||
r = npa_gen_auth_1_encrypted_nonce(oldnpactx, 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 "
|
||||
"(General Authenticate step 1 failed).");
|
||||
goto err;
|
||||
}
|
||||
bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "Encrypted nonce from MRTD", (u8 *)enc_nonce->data, enc_nonce->length);
|
||||
enc_nonce->max = enc_nonce->length;
|
||||
|
||||
r = npa_mse_set_at(oldnpactx, 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) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not select protocol proberties "
|
||||
"(MSE: Set AT failed).");
|
||||
goto err;
|
||||
}
|
||||
enc_nonce = BUF_MEM_new();
|
||||
if (!enc_nonce) {
|
||||
ssl_error(card->ctx);
|
||||
r = SC_ERROR_OUT_OF_MEMORY;
|
||||
goto err;
|
||||
}
|
||||
r = npa_gen_auth_1_encrypted_nonce(oldnpactx, 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 "
|
||||
"(General Authenticate step 1 failed).");
|
||||
goto err;
|
||||
}
|
||||
bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "Encrypted nonce from MRTD", (u8 *)enc_nonce->data, enc_nonce->length);
|
||||
enc_nonce->max = enc_nonce->length;
|
||||
sec = get_psec(card, (char *) pace_input.pin, pace_input.pin_length,
|
||||
pace_input.pin_id);
|
||||
if (!sec) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not encode PACE secret.");
|
||||
ssl_error(card->ctx);
|
||||
r = SC_ERROR_INTERNAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
sec = get_psec(card, (char *) pace_input.pin, pace_input.pin_length,
|
||||
pace_input.pin_id);
|
||||
if (!sec) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not encode PACE secret.");
|
||||
ssl_error(card->ctx);
|
||||
r = SC_ERROR_INTERNAL;
|
||||
goto err;
|
||||
}
|
||||
if (!PACE_STEP2_dec_nonce(eac_ctx, sec, enc_nonce)) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not decrypt MRTD's nonce.");
|
||||
ssl_error(card->ctx);
|
||||
r = SC_ERROR_INTERNAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!PACE_STEP2_dec_nonce(eac_ctx, sec, enc_nonce)) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not decrypt MRTD's nonce.");
|
||||
ssl_error(card->ctx);
|
||||
r = SC_ERROR_INTERNAL;
|
||||
goto err;
|
||||
}
|
||||
mdata_opp = BUF_MEM_new();
|
||||
mdata = PACE_STEP3A_generate_mapping_data(eac_ctx);
|
||||
if (!mdata || !mdata_opp) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not generate mapping data.");
|
||||
ssl_error(card->ctx);
|
||||
r = SC_ERROR_INTERNAL;
|
||||
goto err;
|
||||
}
|
||||
r = npa_gen_auth_2_map_nonce(oldnpactx, 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 "
|
||||
"(General Authenticate step 2 failed).");
|
||||
goto err;
|
||||
}
|
||||
mdata_opp->max = mdata_opp->length;
|
||||
bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "Mapping data from MRTD", (u8 *) mdata_opp->data, mdata_opp->length);
|
||||
|
||||
mdata_opp = BUF_MEM_new();
|
||||
mdata = PACE_STEP3A_generate_mapping_data(eac_ctx);
|
||||
if (!mdata || !mdata_opp) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not generate mapping data.");
|
||||
ssl_error(card->ctx);
|
||||
r = SC_ERROR_INTERNAL;
|
||||
goto err;
|
||||
}
|
||||
r = npa_gen_auth_2_map_nonce(oldnpactx, 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 "
|
||||
"(General Authenticate step 2 failed).");
|
||||
goto err;
|
||||
}
|
||||
mdata_opp->max = mdata_opp->length;
|
||||
bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "Mapping data from MRTD", (u8 *) mdata_opp->data, mdata_opp->length);
|
||||
if (!PACE_STEP3A_map_generator(eac_ctx, mdata_opp)) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not map generator.");
|
||||
ssl_error(card->ctx);
|
||||
r = SC_ERROR_INTERNAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!PACE_STEP3A_map_generator(eac_ctx, mdata_opp)) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not map generator.");
|
||||
ssl_error(card->ctx);
|
||||
r = SC_ERROR_INTERNAL;
|
||||
goto err;
|
||||
}
|
||||
pub = PACE_STEP3B_generate_ephemeral_key(eac_ctx);
|
||||
pub_opp = BUF_MEM_new();
|
||||
if (!pub || !pub_opp) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not generate ephemeral domain parameter or "
|
||||
"ephemeral key pair.");
|
||||
ssl_error(card->ctx);
|
||||
r = SC_ERROR_INTERNAL;
|
||||
goto err;
|
||||
}
|
||||
r = npa_gen_auth_3_perform_key_agreement(oldnpactx, 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 "
|
||||
"(General Authenticate step 3 failed).");
|
||||
goto err;
|
||||
}
|
||||
pub_opp->max = pub_opp->length;
|
||||
bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "Ephemeral public key from MRTD", (u8 *) pub_opp->data, pub_opp->length);
|
||||
|
||||
pub = PACE_STEP3B_generate_ephemeral_key(eac_ctx);
|
||||
pub_opp = BUF_MEM_new();
|
||||
if (!pub || !pub_opp) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not generate ephemeral domain parameter or "
|
||||
"ephemeral key pair.");
|
||||
ssl_error(card->ctx);
|
||||
r = SC_ERROR_INTERNAL;
|
||||
goto err;
|
||||
}
|
||||
r = npa_gen_auth_3_perform_key_agreement(oldnpactx, 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 "
|
||||
"(General Authenticate step 3 failed).");
|
||||
goto err;
|
||||
}
|
||||
pub_opp->max = pub_opp->length;
|
||||
bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "Ephemeral public key from MRTD", (u8 *) pub_opp->data, pub_opp->length);
|
||||
|
||||
|
||||
if (!PACE_STEP3B_compute_shared_secret(eac_ctx, pub_opp)
|
||||
|| !PACE_STEP3C_derive_keys(eac_ctx)) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not compute ephemeral shared secret or "
|
||||
"derive keys for encryption and authentication.");
|
||||
ssl_error(card->ctx);
|
||||
r = SC_ERROR_INTERNAL;
|
||||
goto err;
|
||||
}
|
||||
token = PACE_STEP3D_compute_authentication_token(eac_ctx, pub_opp);
|
||||
token_opp = BUF_MEM_new();
|
||||
if (!token || !token_opp) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not compute authentication token.");
|
||||
ssl_error(card->ctx);
|
||||
r = SC_ERROR_INTERNAL;
|
||||
goto err;
|
||||
}
|
||||
r = npa_gen_auth_4_mutual_authentication(oldnpactx, 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);
|
||||
if (!PACE_STEP3B_compute_shared_secret(eac_ctx, pub_opp)
|
||||
|| !PACE_STEP3C_derive_keys(eac_ctx)) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not compute ephemeral shared secret or "
|
||||
"derive keys for encryption and authentication.");
|
||||
ssl_error(card->ctx);
|
||||
r = SC_ERROR_INTERNAL;
|
||||
goto err;
|
||||
}
|
||||
token = PACE_STEP3D_compute_authentication_token(eac_ctx, pub_opp);
|
||||
token_opp = BUF_MEM_new();
|
||||
if (!token || !token_opp) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not compute authentication token.");
|
||||
ssl_error(card->ctx);
|
||||
r = SC_ERROR_INTERNAL;
|
||||
goto err;
|
||||
}
|
||||
r = npa_gen_auth_4_mutual_authentication(oldnpactx, 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);
|
||||
|
||||
if (r < 0) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not exchange authentication token with card "
|
||||
"(General Authenticate step 4 failed).");
|
||||
goto err;
|
||||
}
|
||||
token_opp->max = token_opp->length;
|
||||
if (r < 0) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not exchange authentication token with card "
|
||||
"(General Authenticate step 4 failed).");
|
||||
goto err;
|
||||
}
|
||||
token_opp->max = token_opp->length;
|
||||
|
||||
if (!PACE_STEP3D_verify_authentication_token(eac_ctx, token_opp)) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not verify authentication token.");
|
||||
ssl_error(card->ctx);
|
||||
r = SC_ERROR_INTERNAL;
|
||||
goto err;
|
||||
}
|
||||
if (!PACE_STEP3D_verify_authentication_token(eac_ctx, token_opp)) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not verify authentication token.");
|
||||
ssl_error(card->ctx);
|
||||
r = SC_ERROR_INTERNAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Initialize secure channel */
|
||||
if (!EAC_CTX_set_encryption_ctx(eac_ctx, EAC_ID_PACE)) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not initialize encryption.");
|
||||
ssl_error(card->ctx);
|
||||
r = SC_ERROR_INTERNAL;
|
||||
goto err;
|
||||
}
|
||||
/* Initialize secure channel */
|
||||
if (!EAC_CTX_set_encryption_ctx(eac_ctx, EAC_ID_PACE)) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not initialize encryption.");
|
||||
ssl_error(card->ctx);
|
||||
r = SC_ERROR_INTERNAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Identifier for ICC and PCD */
|
||||
comp_pub = EAC_Comp(eac_ctx, EAC_ID_PACE, pub);
|
||||
comp_pub_opp = EAC_Comp(eac_ctx, EAC_ID_PACE, pub_opp);
|
||||
if (!comp_pub || !comp_pub_opp) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not compress public keys for identification.");
|
||||
ssl_error(card->ctx);
|
||||
r = SC_ERROR_INTERNAL;
|
||||
goto err;
|
||||
}
|
||||
p = realloc(pace_output->id_icc, comp_pub_opp->length);
|
||||
if (!p) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Not enough memory for ID ICC.\n");
|
||||
r = SC_ERROR_OUT_OF_MEMORY;
|
||||
goto err;
|
||||
}
|
||||
pace_output->id_icc = p;
|
||||
pace_output->id_icc_length = comp_pub_opp->length;
|
||||
/* Flawfinder: ignore */
|
||||
memcpy(pace_output->id_icc, comp_pub_opp->data, comp_pub_opp->length);
|
||||
bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "ID ICC", pace_output->id_icc,
|
||||
pace_output->id_icc_length);
|
||||
p = realloc(pace_output->id_pcd, comp_pub->length);
|
||||
if (!p) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Not enough memory for ID PCD.\n");
|
||||
r = SC_ERROR_OUT_OF_MEMORY;
|
||||
goto err;
|
||||
}
|
||||
pace_output->id_pcd = p;
|
||||
pace_output->id_pcd_length = comp_pub->length;
|
||||
/* Flawfinder: ignore */
|
||||
memcpy(pace_output->id_pcd, comp_pub->data, comp_pub->length);
|
||||
bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "ID PCD", pace_output->id_pcd,
|
||||
pace_output->id_pcd_length);
|
||||
/* Identifier for ICC and PCD */
|
||||
comp_pub = EAC_Comp(eac_ctx, EAC_ID_PACE, pub);
|
||||
comp_pub_opp = EAC_Comp(eac_ctx, EAC_ID_PACE, pub_opp);
|
||||
if (!comp_pub || !comp_pub_opp) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not compress public keys for identification.");
|
||||
ssl_error(card->ctx);
|
||||
r = SC_ERROR_INTERNAL;
|
||||
goto err;
|
||||
}
|
||||
p = realloc(pace_output->id_icc, comp_pub_opp->length);
|
||||
if (!p) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Not enough memory for ID ICC.\n");
|
||||
r = SC_ERROR_OUT_OF_MEMORY;
|
||||
goto err;
|
||||
}
|
||||
pace_output->id_icc = p;
|
||||
pace_output->id_icc_length = comp_pub_opp->length;
|
||||
/* Flawfinder: ignore */
|
||||
memcpy(pace_output->id_icc, comp_pub_opp->data, comp_pub_opp->length);
|
||||
bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "ID ICC", pace_output->id_icc,
|
||||
pace_output->id_icc_length);
|
||||
p = realloc(pace_output->id_pcd, comp_pub->length);
|
||||
if (!p) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Not enough memory for ID PCD.\n");
|
||||
r = SC_ERROR_OUT_OF_MEMORY;
|
||||
goto err;
|
||||
}
|
||||
pace_output->id_pcd = p;
|
||||
pace_output->id_pcd_length = comp_pub->length;
|
||||
/* Flawfinder: ignore */
|
||||
memcpy(pace_output->id_pcd, comp_pub->data, comp_pub->length);
|
||||
bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "ID PCD", pace_output->id_pcd,
|
||||
pace_output->id_pcd_length);
|
||||
|
||||
if(pace_output->recent_car && pace_output->recent_car_length
|
||||
&& !EAC_CTX_init_ta(eac_ctx, NULL, 0, NULL, 0,
|
||||
pace_output->recent_car, pace_output->recent_car_length)) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not initialize TA.\n");
|
||||
ssl_error(card->ctx);
|
||||
r = SC_ERROR_INTERNAL;
|
||||
goto err;
|
||||
}
|
||||
eac_ctx->ta_ctx->flags |= TA_FLAG_SKIP_TIMECHECK;
|
||||
if(pace_output->recent_car && pace_output->recent_car_length
|
||||
&& !EAC_CTX_init_ta(eac_ctx, NULL, 0, NULL, 0,
|
||||
pace_output->recent_car, pace_output->recent_car_length)) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not initialize TA.\n");
|
||||
ssl_error(card->ctx);
|
||||
r = SC_ERROR_INTERNAL;
|
||||
goto err;
|
||||
}
|
||||
eac_ctx->ta_ctx->flags |= TA_FLAG_SKIP_TIMECHECK;
|
||||
|
||||
sctx->priv_data = npa_sm_ctx_create(eac_ctx,
|
||||
pace_input.certificate_description,
|
||||
pace_input.certificate_description_length,
|
||||
pace_output->id_icc,
|
||||
pace_output->id_icc_length,
|
||||
pace_output->recent_car,
|
||||
pace_output->recent_car_length);
|
||||
if (!sctx->priv_data) {
|
||||
r = SC_ERROR_OUT_OF_MEMORY;
|
||||
goto err;
|
||||
sctx->priv_data = npa_sm_ctx_create(eac_ctx,
|
||||
pace_input.certificate_description,
|
||||
pace_input.certificate_description_length,
|
||||
pace_output->id_icc,
|
||||
pace_output->id_icc_length,
|
||||
pace_output->recent_car,
|
||||
pace_output->recent_car_length);
|
||||
if (!sctx->priv_data) {
|
||||
r = SC_ERROR_OUT_OF_MEMORY;
|
||||
goto err;
|
||||
}
|
||||
sctx->authenticate = npa_sm_authenticate;
|
||||
sctx->encrypt = npa_sm_encrypt;
|
||||
sctx->decrypt = npa_sm_decrypt;
|
||||
sctx->verify_authentication = npa_sm_verify_authentication;
|
||||
sctx->pre_transmit = npa_sm_pre_transmit;
|
||||
sctx->post_transmit = npa_sm_post_transmit;
|
||||
sctx->finish = npa_sm_finish;
|
||||
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;
|
||||
}
|
||||
sctx->authenticate = npa_sm_authenticate;
|
||||
sctx->encrypt = npa_sm_encrypt;
|
||||
sctx->decrypt = npa_sm_decrypt;
|
||||
sctx->verify_authentication = npa_sm_verify_authentication;
|
||||
sctx->pre_transmit = npa_sm_pre_transmit;
|
||||
sctx->post_transmit = npa_sm_post_transmit;
|
||||
sctx->finish = npa_sm_finish;
|
||||
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:
|
||||
if (enc_nonce)
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
|
||||
#include <npa/sm.h>
|
||||
#include <libopensc/opensc.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/eac.h>
|
||||
#include <openssl/pace.h>
|
||||
|
||||
@@ -107,70 +106,6 @@ extern "C" {
|
||||
const char *npa_secret_name(enum s_type pin_id);
|
||||
|
||||
|
||||
/**
|
||||
* Input data for EstablishPACEChannel()
|
||||
*/
|
||||
struct establish_pace_channel_input {
|
||||
/** Version of TR-03110 to use with PACE */
|
||||
enum eac_tr_version tr_version;
|
||||
|
||||
/** Type of secret (CAN, MRZ, PIN or PUK). You may use <tt>enum s_type</tt> from \c <openssl/pace.h> */
|
||||
unsigned char pin_id;
|
||||
|
||||
/** Length of \a chat */
|
||||
size_t chat_length;
|
||||
/** Card holder authorization template */
|
||||
const unsigned char *chat;
|
||||
|
||||
/** Length of \a pin */
|
||||
size_t pin_length;
|
||||
/** Secret */
|
||||
const unsigned char *pin;
|
||||
|
||||
/** Length of \a certificate_description */
|
||||
size_t certificate_description_length;
|
||||
/** Certificate description */
|
||||
const unsigned char *certificate_description;
|
||||
};
|
||||
|
||||
/**
|
||||
* Output data for EstablishPACEChannel()
|
||||
*/
|
||||
struct establish_pace_channel_output {
|
||||
/** PACE result (TR-03119) */
|
||||
unsigned int result;
|
||||
|
||||
/** MSE: Set AT status byte */
|
||||
unsigned char mse_set_at_sw1;
|
||||
/** MSE: Set AT status byte */
|
||||
unsigned char mse_set_at_sw2;
|
||||
|
||||
/** Length of \a ef_cardaccess */
|
||||
size_t ef_cardaccess_length;
|
||||
/** EF.CardAccess */
|
||||
unsigned char *ef_cardaccess;
|
||||
|
||||
/** Length of \a recent_car */
|
||||
size_t recent_car_length;
|
||||
/** Most recent certificate authority reference */
|
||||
unsigned char *recent_car;
|
||||
|
||||
/** Length of \a previous_car */
|
||||
size_t previous_car_length;
|
||||
/** Previous certificate authority reference */
|
||||
unsigned char *previous_car;
|
||||
|
||||
/** Length of \a id_icc */
|
||||
size_t id_icc_length;
|
||||
/** ICC identifier */
|
||||
unsigned char *id_icc;
|
||||
|
||||
/** Length of \a id_pcd */
|
||||
size_t id_pcd_length;
|
||||
/** PCD identifier */
|
||||
unsigned char *id_pcd;
|
||||
};
|
||||
|
||||
#ifdef BUERGERCLIENT_WORKAROUND
|
||||
int get_ef_card_access(sc_card_t *card,
|
||||
u8 **ef_cardaccess, size_t *length_ef_cardaccess);
|
||||
@@ -203,13 +138,14 @@ int GetReadersPACECapabilities(u8 *bitmap);
|
||||
* @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,
|
||||
struct establish_pace_channel_input pace_input,
|
||||
struct establish_pace_channel_output *pace_output,
|
||||
struct sm_ctx *sctx);
|
||||
struct sm_ctx *sctx, enum eac_tr_version tr_version);
|
||||
|
||||
/**
|
||||
* @brief Sends a reset retry counter APDU
|
||||
|
||||
Reference in New Issue
Block a user