93 lines
3.5 KiB
Python
93 lines
3.5 KiB
Python
"""Tests for the ST25TN512 / ST25TN01K (ST NFC Forum Type 2) models."""
|
|
import asyncio
|
|
import pytest
|
|
|
|
from pm3py.sim.frame import RFFrame
|
|
from pm3py.transponders.hf.iso14443a.base import _compute_bcc
|
|
from pm3py.transponders.hf.iso14443a.st.st25tn import ST25TN512, ST25TN01K
|
|
|
|
UID = b"\x02\x11\x22\x33\x44\x55\x66"
|
|
|
|
|
|
def run(coro):
|
|
return asyncio.new_event_loop().run_until_complete(coro)
|
|
|
|
|
|
def select(tag):
|
|
run(tag.handle_frame(RFFrame.from_hex("26")))
|
|
uid = tag._uid
|
|
ct = b"\x88" + uid[0:3]
|
|
run(tag.handle_frame(RFFrame.from_bytes(b"\x93\x70" + ct + bytes([_compute_bcc(ct)]))))
|
|
run(tag.handle_frame(RFFrame.from_bytes(b"\x95\x70" + uid[3:7] + bytes([_compute_bcc(uid[3:7])]))))
|
|
assert tag.state == "ACTIVE"
|
|
|
|
|
|
def activate(cls, **kw):
|
|
tag = cls(uid=UID, **kw)
|
|
run(tag.power_on())
|
|
select(tag)
|
|
return tag
|
|
|
|
|
|
class TestIdentity:
|
|
def test_st_uid_prefix_autogen(self):
|
|
assert ST25TN512()._uid[0] == 0x02 # ST manufacturer code
|
|
|
|
def test_atqa_sak(self):
|
|
tag = ST25TN512(uid=UID)
|
|
run(tag.power_on())
|
|
assert run(tag.handle_frame(RFFrame.from_hex("26"))).data == b"\x44\x00"
|
|
select(tag) # reaches ACTIVE with SAK 0x00
|
|
|
|
def test_cc_defaults(self):
|
|
assert ST25TN512(uid=UID)._get_page(3) == b"\xE1\x10\x08\x00"
|
|
assert ST25TN01K(uid=UID)._get_page(3) == b"\xE1\x10\x14\x00"
|
|
|
|
def test_read_returns_uid(self):
|
|
tag = activate(ST25TN512)
|
|
resp = run(tag.handle_frame(RFFrame.from_bytes(b"\x30\x00")))
|
|
assert resp.data[0:3] == UID[0:3]
|
|
|
|
def test_product_id_block(self):
|
|
tag = activate(ST25TN512)
|
|
assert run(tag.handle_frame(RFFrame.from_bytes(b"\x30\x2D"))).data[0:4] == b"\x91\x90\x13\x05"
|
|
tag = activate(ST25TN01K)
|
|
assert run(tag.handle_frame(RFFrame.from_bytes(b"\x30\x2D"))).data[0:4] == b"\x90\x90\x13\x05"
|
|
|
|
|
|
class TestCommands:
|
|
def test_no_fast_read_version_pwd(self):
|
|
tag = activate(ST25TN512)
|
|
assert run(tag.handle_frame(RFFrame.from_bytes(b"\x3A\x00\x03"))) is None
|
|
assert run(tag.handle_frame(RFFrame.from_bytes(b"\x60"))) is None
|
|
assert run(tag.handle_frame(RFFrame.from_bytes(b"\x1B\x00\x00\x00\x00"))) is None
|
|
|
|
def test_write_readback(self):
|
|
tag = activate(ST25TN512)
|
|
assert run(tag.handle_frame(RFFrame.from_bytes(b"\xA2\x05\xDE\xAD\xBE\xEF"))).data == b"\x0A"
|
|
assert run(tag.handle_frame(RFFrame.from_bytes(b"\x30\x05"))).data[0:4] == b"\xDE\xAD\xBE\xEF"
|
|
|
|
def test_product_id_read_only(self):
|
|
tag = activate(ST25TN512)
|
|
assert run(tag.handle_frame(RFFrame.from_bytes(b"\xA2\x2D\x01\x02\x03\x04"))).data == b"\x00"
|
|
|
|
def test_kill_pwd_reads_zero(self):
|
|
tag = activate(ST25TN512)
|
|
assert run(tag.handle_frame(RFFrame.from_bytes(b"\x30\x2F"))).data[0:4] == bytes(4)
|
|
|
|
|
|
class TestKill:
|
|
def test_kill_with_correct_password(self):
|
|
tag = activate(ST25TN512, kill_password=b"\x11\x22\x33\x44")
|
|
# wrong password → NAK
|
|
assert run(tag.handle_frame(RFFrame.from_bytes(b"\xA2\x30\x00\x00\x00\x00"))).data == b"\x00"
|
|
# correct → ACK, killed on next boot
|
|
assert run(tag.handle_frame(RFFrame.from_bytes(b"\xA2\x30\x11\x22\x33\x44"))).data == b"\x0A"
|
|
run(tag.power_on())
|
|
assert tag.killed
|
|
assert run(tag.handle_frame(RFFrame.from_hex("26"))) is None
|
|
|
|
def test_kill_disabled(self):
|
|
tag = activate(ST25TN512, kill_password=b"\x00\x00\x00\x00", kill_enabled=False)
|
|
assert run(tag.handle_frame(RFFrame.from_bytes(b"\xA2\x30\x00\x00\x00\x00"))).data == b"\x00"
|