From 290fe90f3cd832a48f12a15c8977ded9384bcb3e Mon Sep 17 00:00:00 2001 From: frankmorgner Date: Mon, 17 Oct 2011 11:28:47 +0000 Subject: [PATCH] - 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 --- npa/src/npa-tool.c | 6 +- npa/src/npa.c | 274 +++++++++++++++++++++++++++++---------------- 2 files changed, 181 insertions(+), 99 deletions(-) diff --git a/npa/src/npa-tool.c b/npa/src/npa-tool.c index 87aab8b..b95e236 100644 --- a/npa/src/npa-tool.c +++ b/npa/src/npa-tool.c @@ -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); diff --git a/npa/src/npa.c b/npa/src/npa.c index adb052d..726be64 100644 --- a/npa/src/npa.c +++ b/npa/src/npa.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -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); } }