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; }
/** * 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); }