- added support for verifying terminal's signature including auxiliary data (experimental, currently disabled)

- debugging openssl where possible/needed
- using openssl instead of opensc for asn1


git-svn-id: https://vsmartcard.svn.sourceforge.net/svnroot/vsmartcard@556 96b47cad-a561-4643-ad3b-153ac7d7599c
This commit is contained in:
frankmorgner
2011-10-17 11:28:47 +00:00
parent 1fc1aa6ca1
commit 290fe90f3c
2 changed files with 181 additions and 99 deletions

View File

@@ -539,7 +539,7 @@ main (int argc, char **argv)
if (i < 0)
goto err;
printf("Established PACE channel with %s.\n",
npa_secret_name(pace_input.pin_id));
npa_secret_name(pace_input.pin_id), file);
if (dotranslate) {
FILE *input;
@@ -547,8 +547,10 @@ main (int argc, char **argv)
input = stdin;
else {
input = fopen(file, "r");
if (!input)
if (!input) {
perror("Opening file with APDUs");
goto err;
}
}
i = npa_translate_apdus(&sctx, card, input);

View File

@@ -28,6 +28,7 @@
#include <openssl/buffer.h>
#include <openssl/cv_cert.h>
#include <openssl/eac.h>
#include <openssl/ta.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/objects.h>
@@ -38,16 +39,25 @@
#define ASN1_APP_IMP_OPT(stname, field, type, tag) ASN1_EX_TYPE(ASN1_TFLG_IMPTAG|ASN1_TFLG_APPLICATION|ASN1_TFLG_OPTIONAL, tag, stname, field, type)
#define ASN1_APP_IMP(stname, field, type, tag) ASN1_EX_TYPE(ASN1_TFLG_IMPTAG|ASN1_TFLG_APPLICATION, tag, stname, field, type)
typedef CVC_DISCRETIONARY_DATA_TEMPLATES APDU_DISCRETIONARY_DATA_TEMPLATES;
DECLARE_ASN1_FUNCTIONS(APDU_DISCRETIONARY_DATA_TEMPLATES)
ASN1_ITEM_TEMPLATE(APDU_DISCRETIONARY_DATA_TEMPLATES) =
ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_IMPTAG|ASN1_TFLG_APPLICATION, 0x7,
APDU_DISCRETIONARY_DATA_TEMPLATES,
CVC_DISCRETIONARY_DATA_TEMPLATES)
ASN1_ITEM_TEMPLATE_END(APDU_DISCRETIONARY_DATA_TEMPLATES)
IMPLEMENT_ASN1_FUNCTIONS(APDU_DISCRETIONARY_DATA_TEMPLATES)
/*
* MSE:Set AT
*/
typedef struct npa_mse_set_at_cd_st {
ASN1_OBJECT *cryptographic_mechanism_reference;
ASN1_INTEGER *key_reference1;
ASN1_INTEGER *key_reference2;
CVC_DISCRETIONARY_DATA_TEMPLATE *auxiliary_data;
ASN1_OCTET_STRING *key_reference1;
ASN1_OCTET_STRING *key_reference2;
ASN1_OCTET_STRING *eph_pub_key;
APDU_DISCRETIONARY_DATA_TEMPLATES *auxiliary_data;
CVC_CHAT *chat;
} NPA_MSE_SET_AT_C;
ASN1_SEQUENCE(NPA_MSE_SET_AT_C) = {
@@ -56,19 +66,21 @@ ASN1_SEQUENCE(NPA_MSE_SET_AT_C) = {
ASN1_IMP_OPT(NPA_MSE_SET_AT_C, cryptographic_mechanism_reference, ASN1_OBJECT, 0),
/* 0x83
* Reference of a public key / secret key */
ASN1_IMP_OPT(NPA_MSE_SET_AT_C, key_reference1, ASN1_INTEGER, 3),
ASN1_IMP_OPT(NPA_MSE_SET_AT_C, key_reference1, ASN1_OCTET_STRING, 3),
/* 0x84
* Reference of a private key / Reference for computing a session key */
ASN1_IMP_OPT(NPA_MSE_SET_AT_C, key_reference2, ASN1_INTEGER, 4),
/* 0x67
* Auxiliary authenticated data */
ASN1_APP_IMP_OPT(NPA_MSE_SET_AT_C, auxiliary_data, CVC_DISCRETIONARY_DATA_TEMPLATE, 7),
ASN1_IMP_OPT(NPA_MSE_SET_AT_C, key_reference2, ASN1_OCTET_STRING, 4),
/* 0x91
* Ephemeral Public Key */
ASN1_IMP_OPT(NPA_MSE_SET_AT_C, eph_pub_key, ASN1_OCTET_STRING, 0x11),
/* 0x67
* Auxiliary authenticated data */
ASN1_OPT(NPA_MSE_SET_AT_C, auxiliary_data, APDU_DISCRETIONARY_DATA_TEMPLATES),
/*ASN1_APP_IMP_OPT(NPA_MSE_SET_AT_C, auxiliary_data, ASN1_OCTET_STRING, 7),*/
/* Certificate Holder Authorization Template */
ASN1_OPT(NPA_MSE_SET_AT_C, chat, CVC_CHAT),
} ASN1_SEQUENCE_END(NPA_MSE_SET_AT_C)
DECLARE_ASN1_FUNCTIONS(NPA_MSE_SET_AT_C)
IMPLEMENT_ASN1_FUNCTIONS(NPA_MSE_SET_AT_C)
@@ -93,6 +105,7 @@ ASN1_SEQUENCE(NPA_GEN_AUTH_C_BODY) = {
* Authentication Token */
ASN1_IMP_OPT(NPA_GEN_AUTH_C_BODY, auth_token, ASN1_OCTET_STRING, 5),
} ASN1_SEQUENCE_END(NPA_GEN_AUTH_C_BODY)
DECLARE_ASN1_FUNCTIONS(NPA_GEN_AUTH_C_BODY)
IMPLEMENT_ASN1_FUNCTIONS(NPA_GEN_AUTH_C_BODY)
typedef NPA_GEN_AUTH_C_BODY NPA_GEN_AUTH_C;
@@ -103,6 +116,7 @@ ASN1_ITEM_TEMPLATE(NPA_GEN_AUTH_C) =
ASN1_TFLG_IMPTAG|ASN1_TFLG_APPLICATION,
0x1c, NPA_GEN_AUTH_C, NPA_GEN_AUTH_C_BODY)
ASN1_ITEM_TEMPLATE_END(NPA_GEN_AUTH_C)
DECLARE_ASN1_FUNCTIONS(NPA_GEN_AUTH_C)
IMPLEMENT_ASN1_FUNCTIONS(NPA_GEN_AUTH_C)
/* Protocol Response Data */
@@ -134,6 +148,7 @@ ASN1_SEQUENCE(NPA_GEN_AUTH_R_BODY) = {
* Previous Certification Authority Reference */
ASN1_IMP_OPT(NPA_GEN_AUTH_R_BODY, prev_car, ASN1_OCTET_STRING, 8),
} ASN1_SEQUENCE_END(NPA_GEN_AUTH_R_BODY)
DECLARE_ASN1_FUNCTIONS(NPA_GEN_AUTH_R_BODY)
IMPLEMENT_ASN1_FUNCTIONS(NPA_GEN_AUTH_R_BODY)
typedef NPA_GEN_AUTH_R_BODY NPA_GEN_AUTH_R;
@@ -144,6 +159,7 @@ ASN1_ITEM_TEMPLATE(NPA_GEN_AUTH_R) =
ASN1_TFLG_IMPTAG|ASN1_TFLG_APPLICATION,
0x1c, NPA_GEN_AUTH_R, NPA_GEN_AUTH_R_BODY)
ASN1_ITEM_TEMPLATE_END(NPA_GEN_AUTH_R)
DECLARE_ASN1_FUNCTIONS(NPA_GEN_AUTH_R)
IMPLEMENT_ASN1_FUNCTIONS(NPA_GEN_AUTH_R)
@@ -166,6 +182,10 @@ struct npa_sm_ctx {
BUF_MEM *auxiliary_data;
/** Nonce generated in TA */
BUF_MEM *nonce;
/** CAR of the card's most recent imported certificate */
BUF_MEM *cur_car;
/** CHR of the certificate to be imported */
BUF_MEM *next_car;
};
static int npa_sm_encrypt(sc_card_t *card, const struct sm_ctx *ctx,
@@ -192,8 +212,8 @@ static int reset_ssc(struct npa_sm_ctx *eacsmctx);
static struct npa_sm_ctx *
npa_sm_ctx_create(EAC_CTX *ctx, const unsigned char *certificate_description,
size_t certificate_description_length,
const unsigned char *id_icc, size_t id_icc_length
)
const unsigned char *id_icc, size_t id_icc_length,
const unsigned char *car, size_t car_length)
{
struct npa_sm_ctx *out = malloc(sizeof *out);
if (!out)
@@ -214,7 +234,12 @@ npa_sm_ctx_create(EAC_CTX *ctx, const unsigned char *certificate_description,
if (!out->id_icc)
goto err;
out->cur_car = BUF_MEM_create_init(car, car_length);
if (!out->cur_car)
goto err;
out->nonce = NULL;
out->next_car = NULL;
out->eph_pub_key = NULL;
out->auxiliary_data = NULL;
@@ -253,7 +278,7 @@ int get_ef_card_access(sc_card_t *card,
sc_file_t *file = NULL;
u8 *p;
if (!ef_cardaccess || !length_ef_cardaccess) {
if (!card || !ef_cardaccess || !length_ef_cardaccess) {
r = SC_ERROR_INVALID_ARGUMENTS;
goto err;
}
@@ -325,11 +350,13 @@ static int npa_mse_set_at(struct sm_ctx *oldnpactx, sc_card_t *card,
sc_apdu_t apdu;
unsigned char *d = NULL;
NPA_MSE_SET_AT_C *data = NULL;
int r, tries;
int r, tries, class, tag;
long length;
const unsigned char *p;
memset(&apdu, 0, sizeof apdu);
if (!sw1 || !sw2) {
if (!card || !sw1 || !sw2) {
r = SC_ERROR_INVALID_ARGUMENTS;
goto err;
}
@@ -358,6 +385,7 @@ static int npa_mse_set_at(struct sm_ctx *oldnpactx, sc_card_t *card,
if (!ASN1_INTEGER_set(data->key_reference1, secret_key)) {
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Error setting key reference 1 of MSE:Set AT data");
ssl_error(card->ctx);
r = SC_ERROR_INTERNAL;
goto err;
}
@@ -366,16 +394,17 @@ static int npa_mse_set_at(struct sm_ctx *oldnpactx, sc_card_t *card,
r = i2d_NPA_MSE_SET_AT_C(data, &d);
if (r < 0) {
p = d;
if (r < 0
|| (0x80 & ASN1_get_object(&p, &length, &tag, &class, r))) {
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Error encoding MSE:Set AT APDU data");
ssl_error(card->ctx);
r = SC_ERROR_INTERNAL;
goto err;
}
/* The tag/length for the sequence (0x30) is omitted in the command apdu. */
/* XXX is there a OpenSSL way to get the value only or even a define for
* the tag? */
apdu.data = sc_asn1_find_tag(card->ctx, d, r, 0x30, &apdu.datalen);
apdu.lc = apdu.datalen;
apdu.data = p;
apdu.datalen = length;
apdu.lc = length;
bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "MSE:Set AT command data", apdu.data, apdu.datalen);
@@ -457,6 +486,7 @@ static int npa_gen_auth_1_encrypted_nonce(struct sm_ctx *oldnpactx,
}
r = i2d_NPA_GEN_AUTH_C(c_data, &d);
if (r < 0) {
ssl_error(card->ctx);
r = SC_ERROR_INTERNAL;
goto err;
}
@@ -484,6 +514,7 @@ static int npa_gen_auth_1_encrypted_nonce(struct sm_ctx *oldnpactx,
if (!d2i_NPA_GEN_AUTH_R(&r_data,
(const unsigned char **) &apdu.resp, apdu.resplen)) {
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not parse general authenticate response data.");
ssl_error(card->ctx);
r = SC_ERROR_INTERNAL;
goto err;
}
@@ -547,11 +578,13 @@ static int npa_gen_auth_2_map_nonce(struct sm_ctx *oldnpactx,
if (!c_data->mapping_data
|| !M_ASN1_OCTET_STRING_set(
c_data->mapping_data, in, in_len)) {
ssl_error(card->ctx);
r = SC_ERROR_INTERNAL;
goto err;
}
r = i2d_NPA_GEN_AUTH_C(c_data, &d);
if (r < 0) {
ssl_error(card->ctx);
r = SC_ERROR_INTERNAL;
goto err;
}
@@ -579,6 +612,7 @@ static int npa_gen_auth_2_map_nonce(struct sm_ctx *oldnpactx,
if (!d2i_NPA_GEN_AUTH_R(&r_data,
(const unsigned char **) &apdu.resp, apdu.resplen)) {
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not parse general authenticate response data.");
ssl_error(card->ctx);
r = SC_ERROR_INTERNAL;
goto err;
}
@@ -642,11 +676,13 @@ static int npa_gen_auth_3_perform_key_agreement(
if (!c_data->eph_pub_key
|| !M_ASN1_OCTET_STRING_set(
c_data->eph_pub_key, in, in_len)) {
ssl_error(card->ctx);
r = SC_ERROR_INTERNAL;
goto err;
}
r = i2d_NPA_GEN_AUTH_C(c_data, &d);
if (r < 0) {
ssl_error(card->ctx);
r = SC_ERROR_INTERNAL;
goto err;
}
@@ -674,6 +710,7 @@ static int npa_gen_auth_3_perform_key_agreement(
if (!d2i_NPA_GEN_AUTH_R(&r_data,
(const unsigned char **) &apdu.resp, apdu.resplen)) {
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not parse general authenticate response data.");
ssl_error(card->ctx);
r = SC_ERROR_INTERNAL;
goto err;
}
@@ -740,11 +777,13 @@ static int npa_gen_auth_4_mutual_authentication(
if (!c_data->auth_token
|| !M_ASN1_OCTET_STRING_set(
c_data->auth_token, in, in_len)) {
ssl_error(card->ctx);
r = SC_ERROR_INTERNAL;
goto err;
}
r = i2d_NPA_GEN_AUTH_C(c_data, &d);
if (r < 0) {
ssl_error(card->ctx);
r = SC_ERROR_INTERNAL;
goto err;
}
@@ -772,6 +811,7 @@ static int npa_gen_auth_4_mutual_authentication(
if (!d2i_NPA_GEN_AUTH_R(&r_data,
(const unsigned char **) &apdu.resp, apdu.resplen)) {
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not parse general authenticate response data.");
ssl_error(card->ctx);
r = SC_ERROR_INTERNAL;
goto err;
}
@@ -787,7 +827,6 @@ static int npa_gen_auth_4_mutual_authentication(
}
p = r_data->auth_token->data;
l = r_data->auth_token->length;
/* XXX CAR sould be returned as result in some way */
if (r_data->cur_car) {
bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "Most recent Certificate Authority Reference",
r_data->cur_car->data, r_data->cur_car->length);
@@ -948,10 +987,9 @@ int EstablishPACEChannel(struct sm_ctx *oldnpactx, sc_card_t *card,
BIO *bio_stdout = NULL;
CVC_CERTIFICATE_DESCRIPTION *desc = NULL;
int r;
const unsigned char *pp;
if (!card)
return SC_ERROR_CARD_NOT_PRESENT;
if (!pace_output || !sctx)
if (!card || !pace_output || !sctx)
return SC_ERROR_INVALID_ARGUMENTS;
/* show description in advance to give the user more time to read it...
@@ -959,10 +997,11 @@ int EstablishPACEChannel(struct sm_ctx *oldnpactx, sc_card_t *card,
if (pace_input.certificate_description_length &&
pace_input.certificate_description) {
const unsigned char *pp = pace_input.certificate_description;
pp = pace_input.certificate_description;
if (!d2i_CVC_CERTIFICATE_DESCRIPTION(&desc,
&pp, pace_input.certificate_description_length)) {
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not parse certificate description.");
ssl_error(card->ctx);
r = SC_ERROR_INTERNAL;
goto err;
}
@@ -1021,9 +1060,10 @@ int EstablishPACEChannel(struct sm_ctx *oldnpactx, sc_card_t *card,
goto err;
}
if (!d2i_CVC_CHAT(&chat, (const unsigned char **) &pace_input.chat,
pace_input.chat_length)) {
pp = pace_input.chat;
if (!d2i_CVC_CHAT(&chat, &pp, pace_input.chat_length)) {
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not parse card holder authorization template (CHAT).");
ssl_error(card->ctx);
r = SC_ERROR_INTERNAL;
goto err;
}
@@ -1069,7 +1109,8 @@ int EstablishPACEChannel(struct sm_ctx *oldnpactx, sc_card_t *card,
}
enc_nonce = BUF_MEM_new();
if (!enc_nonce) {
r = SC_ERROR_INTERNAL;
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,
@@ -1227,12 +1268,15 @@ int EstablishPACEChannel(struct sm_ctx *oldnpactx, sc_card_t *card,
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->id_icc_length,
pace_output->recent_car,
pace_output->recent_car_length);
if (!sctx->priv_data) {
r = SC_ERROR_OUT_OF_MEMORY;
goto err;
@@ -1346,7 +1390,7 @@ npa_sm_encrypt(sc_card_t *card, const struct sm_ctx *ctx,
u8 *p = NULL;
int r;
if (!ctx || !enc || !ctx->priv_data) {
if (!card || !ctx || !enc || !ctx->priv_data) {
r = SC_ERROR_INVALID_ARGUMENTS;
goto err;
}
@@ -1390,7 +1434,7 @@ npa_sm_decrypt(sc_card_t *card, const struct sm_ctx *ctx,
u8 *p = NULL;
int r;
if (!ctx || !enc || !ctx->priv_data || !data) {
if (!card || !ctx || !enc || !ctx->priv_data || !data) {
r = SC_ERROR_INVALID_ARGUMENTS;
goto err;
}
@@ -1434,7 +1478,7 @@ npa_sm_authenticate(sc_card_t *card, const struct sm_ctx *ctx,
u8 *p = NULL, *ssc = NULL;
int r;
if (!ctx || !ctx->priv_data || !macdata) {
if (!card || !ctx || !ctx->priv_data || !macdata) {
r = SC_ERROR_INVALID_ARGUMENTS;
goto err;
}
@@ -1477,7 +1521,7 @@ npa_sm_verify_authentication(sc_card_t *card, const struct sm_ctx *ctx,
char *p;
BUF_MEM *my_mac = NULL;
if (!ctx || !ctx->priv_data) {
if (!card || !ctx || !ctx->priv_data) {
r = SC_ERROR_INVALID_ARGUMENTS;
goto err;
}
@@ -1512,38 +1556,33 @@ err:
return r;
}
static CVC_CERT *
cert_from_apdudata(const unsigned char *data, size_t len)
static int
add_tag(unsigned char **asn1new, int constructed, int tag,
int xclass, const unsigned char *data, size_t len)
{
/* there MUST be a more elegant way to do this... */
CVC_CERT *cert = NULL;
long int asn1datalen = len;
int tag, xclass;
const unsigned char *p = data;
unsigned char *p;
int newlen;
cert = CVC_CERT_new();
if (!cert)
goto err;
if (!asn1new || !data)
return -1;
if (0x80 & ASN1_get_object(&p, &asn1datalen, &tag, &xclass, len)
|| !d2i_CVC_CERT_BODY(&cert->body, &data, (p-data)+asn1datalen))
goto err;
newlen = ASN1_object_size(constructed, len, tag);
if (newlen < 0)
return newlen;
p += asn1datalen;
if (0x80 & ASN1_get_object(&p, &asn1datalen, &tag, &xclass, len-(p-data))
|| tag != 0x37)
goto err;
cert->signature = ASN1_OCTET_STRING_new();
if (!cert->signature
|| !ASN1_OCTET_STRING_set(cert->signature, p, asn1datalen))
goto err;
p = OPENSSL_realloc(*asn1new, newlen);
if (!p)
return -1;
*asn1new = p;
return cert;
ASN1_put_object(&p, constructed, len, tag, xclass);
memcpy(p, data, len);
err:
if (cert)
CVC_CERT_free(cert);
return newlen;
}
extern int
cvc_certificate_extension_print(BIO *bio,
CVC_DISCRETIONARY_DATA_TEMPLATE *extension, int indent);
static int
npa_sm_pre_transmit(sc_card_t *card, const struct sm_ctx *ctx,
sc_apdu_t *apdu)
@@ -1555,25 +1594,35 @@ npa_sm_pre_transmit(sc_card_t *card, const struct sm_ctx *ctx,
BUF_MEM *signature = NULL;
unsigned char *sequence = NULL;
NPA_MSE_SET_AT_C *msesetat = NULL;
const unsigned char *p;
if (!ctx) {
if (!card || !ctx || !apdu || !ctx->priv_data) {
r = SC_ERROR_INVALID_ARGUMENTS;
goto err;
}
struct npa_sm_ctx *eacsmctx = ctx->priv_data;
if (!ctx) {
r = SC_ERROR_INVALID_ARGUMENTS;
goto err;
}
if (apdu && apdu->ins == 0x2a && apdu->p1 == 0x00 && apdu->p2 == 0xbe) {
if (apdu->ins == 0x22 && apdu->p1 == 0x81 && apdu->p2 == 0xbe) {
/* MSE:Set DST
* setup certificate verification for TA */
if (!eacsmctx->cur_car || !eacsmctx->cur_car->length != apdu->datalen
|| memcmp(eacsmctx->cur_car->data, apdu->data, apdu->datalen) != 0) {
r = SC_ERROR_INVALID_DATA;
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE,
"CAR doesn't match the most recent imported certificate");
goto err;
}
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "CAR matches the most recent imported certificate");
} else if (apdu->ins == 0x2a && apdu->p1 == 0x00 && apdu->p2 == 0xbe) {
/* PSO:Verify Certificate
* check certificate description to match given certificate
* TODO take MSE:Set DST (sent before) into account */
cvc_cert = cert_from_apdudata(apdu->data, apdu->datalen);
* check certificate description to match given certificate */
if (!cvc_cert || !cvc_cert->body) {
len = add_tag(&cert, 1, 0x21, V_ASN1_APPLICATION, apdu->data, apdu->datalen);
p = cert;
if (len < 0 || !d2i_CVC_CERT(&cvc_cert, &p, len)
|| !cvc_cert || !cvc_cert->body) {
r = SC_ERROR_INVALID_DATA;
goto err;
}
@@ -1599,8 +1648,8 @@ npa_sm_pre_transmit(sc_card_t *card, const struct sm_ctx *ctx,
}
switch (CVC_check_description(cvc_cert,
eacsmctx->certificate_description->data,
eacsmctx->certificate_description->length)) {
eacsmctx->certificate_description->data,
eacsmctx->certificate_description->length)) {
case 1:
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE,
"Certificate Description matches Certificate");
@@ -1628,9 +1677,7 @@ npa_sm_pre_transmit(sc_card_t *card, const struct sm_ctx *ctx,
break;
}
len = i2d_CVC_CERT(cvc_cert, &cert);
if (len < 0
|| !TA_STEP2_import_certificate(eacsmctx->ctx, cert, len)) {
if (!TA_STEP2_import_certificate(eacsmctx->ctx, cert, len)) {
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE,
"Error importing certificate");
ssl_error(card->ctx);
@@ -1638,18 +1685,32 @@ npa_sm_pre_transmit(sc_card_t *card, const struct sm_ctx *ctx,
goto err;
}
} else if (apdu && apdu->ins == 0x22 && apdu->p1 == 0x81 && apdu->p2 == 0xa4) {
if (eacsmctx->next_car)
BUF_MEM_free(eacsmctx->next_car);
if (cvc_cert->body->certificate_holder_reference) {
eacsmctx->next_car = BUF_MEM_create_init(apdu->data, apdu->datalen);
if (!eacsmctx->next_car) {
r = SC_ERROR_OUT_OF_MEMORY;
goto err;
}
} else {
eacsmctx->next_car = NULL;
}
#if 0
} else if (apdu->ins == 0x22 && apdu->p1 == 0x81 && apdu->p2 == 0xa4) {
/* MSE:Set AT
* fetch auxiliary data and terminal's compressed ephemeral public key
* for CA */
len = ASN1_object_size(1, apdu->datalen, V_ASN1_SEQUENCE);
sequence = malloc(len);
unsigned char *p = sequence;
const unsigned char *pp = sequence;
ASN1_put_object(&p, 1, apdu->datalen, V_ASN1_SEQUENCE,V_ASN1_UNIVERSAL);
memcpy(p, apdu->data, apdu->datalen);
if (!d2i_NPA_MSE_SET_AT_C(&msesetat, &pp, len)) {
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not parse MSE:Set AT.");
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Parse MSE:Set AT.");
len = add_tag(&sequence, 1, V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL, apdu->data, apdu->datalen);
p = sequence;
bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "sequence", sequence,
len);
if (len < 0 || !d2i_NPA_MSE_SET_AT_C(&msesetat, &p, len)) {
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not parse MSE:Set AT. %d", len);
ssl_error(card->ctx);
r = SC_ERROR_INTERNAL;
goto err;
}
@@ -1663,7 +1724,7 @@ npa_sm_pre_transmit(sc_card_t *card, const struct sm_ctx *ctx,
goto err;
}
eacsmctx->auxiliary_data->length =
i2d_CVC_DISCRETIONARY_DATA_TEMPLATE(msesetat->auxiliary_data,
i2d_APDU_DISCRETIONARY_DATA_TEMPLATES(msesetat->auxiliary_data,
(unsigned char **) &eacsmctx->auxiliary_data->data);
if ((int) eacsmctx->auxiliary_data->length < 0) {
r = SC_ERROR_OUT_OF_MEMORY;
@@ -1683,7 +1744,8 @@ npa_sm_pre_transmit(sc_card_t *card, const struct sm_ctx *ctx,
goto err;
}
}
} else if (apdu && apdu->ins == 0x82 && apdu->p1 == 0x00 && apdu->p2 == 0x00) {
} else if (apdu->ins == 0x82 && apdu->p1 == 0x00 && apdu->p2 == 0x00) {
/* External Authenticate
* check terminal's signature */
@@ -1714,6 +1776,9 @@ npa_sm_pre_transmit(sc_card_t *card, const struct sm_ctx *ctx,
break;
}
}
#else
}
#endif
r = increment_ssc(ctx->priv_data);
@@ -1742,25 +1807,36 @@ static int
npa_sm_finish(sc_card_t *card, const struct sm_ctx *ctx,
sc_apdu_t *apdu)
{
if (!ctx || !ctx->priv_data)
if (!card || !ctx || !ctx->priv_data || !apdu || !card)
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL,
SC_ERROR_INVALID_ARGUMENTS);
struct npa_sm_ctx *eacsmctx = ctx->priv_data;
if (apdu && apdu->ins == 0x84 && apdu->p1 == 0x00 && apdu->p2 == 0x00 && apdu->le == 8
&& apdu->sw1 == 0x90 && apdu->sw2 == 0x00 && apdu->resplen == 8) {
/* Get Challenge
* copy challenge to EAC context */
struct npa_sm_ctx *eacsmctx = ctx->priv_data;
if (apdu->sw1 == 0x90 && apdu->sw2 == 0x00) {
if (apdu->ins == 0x2a && apdu->p1 == 0x00 && apdu->p2 == 0xbe) {
/* PSO:Verify Certificate
* copy the currently imported certificate's CHR to the current CAR */
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Saving MRTD's nonce to later verify Terminal's signature");
if (eacsmctx->cur_car)
BUF_MEM_free(eacsmctx->cur_car);
eacsmctx->cur_car = eacsmctx->next_car;
eacsmctx->next_car = NULL;
if (eacsmctx->nonce)
BUF_MEM_free(eacsmctx->nonce);
} else if (apdu->ins == 0x84 && apdu->p1 == 0x00 && apdu->p2 == 0x00
&& apdu->le == 8 && apdu->resplen == 8) {
/* Get Challenge
* copy challenge to EAC context */
eacsmctx->nonce = BUF_MEM_create_init(apdu->resp, apdu->resplen);
if (!eacsmctx->nonce)
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL,
SC_ERROR_OUT_OF_MEMORY);
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Saving MRTD's nonce to later verify Terminal's signature");
if (eacsmctx->nonce)
BUF_MEM_free(eacsmctx->nonce);
eacsmctx->nonce = BUF_MEM_create_init(apdu->resp, apdu->resplen);
if (!eacsmctx->nonce)
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL,
SC_ERROR_OUT_OF_MEMORY);
}
}
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, 0);
@@ -1784,6 +1860,10 @@ npa_sm_clear_free(const struct sm_ctx *ctx)
BUF_MEM_free(eacsmctx->eph_pub_key);
if (eacsmctx->auxiliary_data)
BUF_MEM_free(eacsmctx->auxiliary_data);
if (eacsmctx->cur_car)
BUF_MEM_free(eacsmctx->cur_car);
if (eacsmctx->next_car)
BUF_MEM_free(eacsmctx->next_car);
free(eacsmctx);
}
}