A card that needs longer than FWT to answer replies with S(WTX) carrying a
multiplier, and ISO 14443-4 has the timeout become FWT * WTXM for that
exchange. iso14443b_apdu() multiplied the shift instead:
uint32_t fwt_temp = (s_iso14b_fwt * wtxm);
iso14b_set_timeout((32 << fwt_temp));
(32 << fwi) is the FWT in ETUs - the form iso14b_set_fwt() uses, and the
one the client prints in hf 14b info - so this computed 32 << (fwi * wtxm).
With the fwi of 8 that a passport reports, wtxm 1 happens to come out
right, wtxm 2 is 256 times too long, and wtxm 4 shifts a uint32_t by 32.
That is undefined, and on ARM it leaves 0, so the read that follows gives
up before the card has answered and the client reports
APDU: no APDU response
Found on a Polish ePassport that would not read. Every short command
answered - SELECT, an unsupported instruction, a malformed MSE - and only
MSE:Set AT with P1P2 C1A4 was silent, which is the one command in the
exchange that starts the PACE ECDH setup and so the only one that ever
asks for more time. Older passports read because they ask for a smaller
multiplier, where the wrong formula still produces a usable number.
Tested on RDV4 against that document: the MSE:Set AT that returned nothing
now answers 9000, and hf emrtd dump completes in 3 seconds with PACE
(ECDH, Generic Mapping, 3DES-CBC-CBC, NIST P-256), every data group read
and every EF_SOD hash matching.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Saves 1040 bytes of .bss (BigBuf on AT91), removes a second copy of every
byte, and fixes a full/empty ambiguity where filling the ring to exactly
sizeof(us_rxfifo) left low == high, so usart_rxdata_available() returned 0
and the next bank overwrote 1 kB of received data.