Exemple #1
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;
}
Exemple #2
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);
}