Example #1
0
/**
 * Changes the provider to use the new PIN (DNIe 3.0)
 * channel.
 *
 * @param card the card to change the cwa provider for
 */
void dnie_change_cwa_provider_to_pin(sc_card_t * card)
{
	cwa_provider_t * res = GET_DNIE_PRIV_DATA(card)->cwa_provider;

	/* redefine different IFD data for PIN channel */
	res->cwa_get_cvc_ifd_cert = dnie_get_cvc_ifd_cert_pin;
	res->cwa_get_ifd_privkey = dnie_get_ifd_privkey_pin;
	res->cwa_get_ifd_pubkey_ref = dnie_get_ifd_pubkey_ref_pin;
	res->cwa_get_sn_ifd = dnie_get_sn_ifd_pin;
}
Example #2
0
int dnie_transmit_apdu(sc_card_t * card, sc_apdu_t * apdu)
{
	int res = SC_SUCCESS;
	sc_context_t *ctx;
	cwa_provider_t *provider = NULL;
	ctx=card->ctx;
	provider = GET_DNIE_PRIV_DATA(card)->cwa_provider;
	if ((provider->status.session.state == CWA_SM_ACTIVE) &&
		(card->sm_ctx.sm_mode == SM_MODE_TRANSMIT)) {
		res = sc_transmit_apdu(card, apdu);
		LOG_TEST_RET(ctx, res, "Error in dnie_wrap_apdu process");
		res = cwa_decode_response(card, provider, apdu);
		LOG_TEST_RET(ctx, res, "Error in cwa_decode_response process");
	}
	else
		res = sc_transmit_apdu(card, apdu);
	return res;
}
Example #3
0
/**
 * APDU Wrapping routine.
 *
 * Called before sc_transmit_apdu() to allowing APDU wrapping
 * If set to NULL no wrapping process will be done
 * Usefull on Secure Messaging APDU encode/decode
 * If returned value is greater than zero, do_single_transmit()
 * will be called, else means either SC_SUCCESS or error code
 *
 * NOTE:
 * DNIe doesn't handle apdu chaining; instead apdus with
 * lc>max_send_size are sent by mean of envelope() apdu command
 * So we use this method for
 * - encode and decode SM if SM is on
 * - use envelope instead of apdu chain if lc>max_send_size
 *
 * @param card Pointer to Card Structure
 * @param apdu to be wrapped
 * @return
 * - positive: use OpenSC's sc_transmit_apdu()
 * - negative: error
 * - zero: success: no need to further transmission
 */
static int dnie_wrap_apdu(sc_card_t * card, sc_apdu_t * apdu)
{
    int res = SC_SUCCESS;
    sc_apdu_t wrapped;
    sc_context_t *ctx;
    cwa_provider_t *provider = NULL;
    int retries = 3;

    if ((card == NULL) || (card->ctx == NULL) || (apdu == NULL))
        return SC_ERROR_INVALID_ARGUMENTS;
    ctx=card->ctx;
    LOG_FUNC_CALLED(ctx);
    provider = GET_DNIE_PRIV_DATA(card)->cwa_provider;
    for (retries=3; retries>0; retries--) {
        /* preserve original apdu to take care of retransmission */
        memcpy(&wrapped, apdu, sizeof(sc_apdu_t));
        /* SM is active, encode apdu */
        if (provider->status.session.state == CWA_SM_ACTIVE) {
            wrapped.resp = NULL;
            wrapped.resplen = 0;	/* let get_response() assign space */
            res = cwa_encode_apdu(card, provider, apdu, &wrapped);
            LOG_TEST_RET(ctx, res,
                         "Error in cwa_encode_apdu process");
        }
        /* send apdu via envelope() cmd if needed */
        res = dnie_transmit_apdu_internal(card, &wrapped);
        /* check for tx errors */
        LOG_TEST_RET(ctx, res, "Error in dnie_transmit_apdu process");

        /* parse response and handle SM related errors */
        res=card->ops->check_sw(card,wrapped.sw1,wrapped.sw2);
        if ( res == SC_ERROR_SM ) {
            sc_log(ctx,"Detected SM error/collision. Try %d",retries);
            switch(provider->status.session.state) {
            /* No SM or creating: collision with other process
               just retry as SM error reset ICC SM state */
            case CWA_SM_NONE:
            case CWA_SM_INPROGRESS:
                continue;
            /* SM was active: force restart SM and retry */
            case CWA_SM_ACTIVE:
                res=cwa_create_secure_channel(card, provider, CWA_SM_COLD);
                LOG_TEST_RET(ctx,res,"Cannot re-enable SM");
                continue;
            }
        }

        /* if SM is active; decode apdu */
        if (provider->status.session.state == CWA_SM_ACTIVE) {
            apdu->resp = NULL;
            apdu->resplen = 0;	/* let cwa_decode_response() eval & create size */
            res = cwa_decode_response(card, provider, &wrapped, apdu);
            LOG_TEST_RET(ctx, res, "Error in cwa_decode_response process");
        } else {
            /* memcopy result to original apdu */
            memcpy(apdu, &wrapped, sizeof(sc_apdu_t));
        }
        LOG_FUNC_RETURN(ctx, res);
    }
    sc_log(ctx,"Too many retransmissions. Abort and return");
    LOG_FUNC_RETURN(ctx, SC_ERROR_INTERNAL);
}
Example #4
0
static int dnie_transmit_apdu_internal(sc_card_t * card, sc_apdu_t * apdu)
{
    u8 buf[2048];		/* use for store partial le responses */
    int res = SC_SUCCESS;
    cwa_provider_t *provider = NULL;
    if ((card == NULL) || (card->ctx == NULL) || (apdu == NULL))
        return SC_ERROR_INVALID_ARGUMENTS;
    LOG_FUNC_CALLED(card->ctx);
    provider = GET_DNIE_PRIV_DATA(card)->cwa_provider;
    memset(buf, 0, sizeof(buf));

    /* check if envelope is needed */
    if (apdu->lc <= card->max_send_size) {
        int tmp;
        /* no envelope needed */
        sc_log(card->ctx, "envelope tx is not required");

        tmp = apdu->cse;	/* save original apdu type */
        /* if SM is on, assure rx buffer exists and force get_response */
        if (provider->status.session.state == CWA_SM_ACTIVE) {
            if (tmp == SC_APDU_CASE_3_SHORT)
                apdu->cse = SC_APDU_CASE_4_SHORT;
            if (apdu->resplen == 0) {	/* no response buffer: create */
                apdu->resp = buf;
                apdu->resplen = 2048;
                apdu->le = card->max_recv_size;
            }
        }
        /* call std sc_transmit_apdu */
        res = sc_transmit_apdu(card, apdu);
        /* and restore original apdu type */
        apdu->cse = tmp;
    } else {

        size_t e_txlen = 0;
        size_t index = 0;
        sc_apdu_t *e_apdu = NULL;
        u8 *e_tx = NULL;

        /* envelope needed */
        sc_log(card->ctx, "envelope tx required: lc:%d", apdu->lc);

        e_apdu = calloc(1, sizeof(sc_apdu_t));	/* enveloped apdu */
        e_tx = calloc(7 + apdu->datalen, sizeof(u8));	/* enveloped data */
        if (!e_apdu || !e_tx)
            LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);

        /* copy apdu info into enveloped data */
        *(e_tx + 0) = apdu->cla;	/* apdu header */
        *(e_tx + 1) = apdu->ins;
        *(e_tx + 2) = apdu->p1;
        *(e_tx + 3) = apdu->p2;
        *(e_tx + 4) = 0x00;	/* length in extended format */
        *(e_tx + 5) = 0xff & (apdu->lc >> 8);
        *(e_tx + 6) = 0xff & apdu->lc;
        memcpy(e_tx + 7, apdu->data, apdu->lc);
        e_txlen = 7 + apdu->lc;
        /* sc_log(card->ctx, "Data to be enveloped & sent: (%d bytes)\n%s\n===============================================================",e_txlen,sc_dump_hex(e_tx,e_txlen)); */
        /* split apdu in n chunks of max_send_size len */
        for (index = 0; index < e_txlen; index += card->max_send_size) {
            size_t len = MIN(card->max_send_size, e_txlen - index);
            sc_log(card->ctx, "envelope tx offset:%04X size:%02X",
                   index, len);

            /* compose envelope apdu command */
            sc_format_apdu(card, e_apdu, apdu->cse, 0xC2, 0x00,
                           0x00);
            e_apdu->cla = 0x90;	/* propietary CLA */
            e_apdu->data = e_tx + index;
            e_apdu->lc = len;
            e_apdu->datalen = len;
            e_apdu->le = apdu->le;
            e_apdu->resp = apdu->resp;
            e_apdu->resplen = apdu->resplen;
            /* if SM is ON, ensure resp exists, and force getResponse() */
            if (provider->status.session.state == CWA_SM_ACTIVE) {
                /* set up proper apdu type */
                if (e_apdu->cse == SC_APDU_CASE_3_SHORT)
                    e_apdu->cse = SC_APDU_CASE_4_SHORT;
                /* if no response buffer: create */
                if (apdu->resplen == 0) {
                    e_apdu->resp = buf;
                    e_apdu->resplen = 2048;
                    e_apdu->le = card->max_recv_size;
                }
            }
            /* send data chunk bypassing apdu wrapping */
            res = sc_transmit_apdu(card, e_apdu);
            LOG_TEST_RET(card->ctx, res,
                         "Error in envelope() send apdu");
        }		/* for */
        /* last apdu sent contains response to enveloped cmd */
        apdu->resp = e_apdu->resp;
        apdu->resplen = e_apdu->resplen;
        res = SC_SUCCESS;
    }
    LOG_FUNC_RETURN(card->ctx, res);
}