v3.19.2: the three-status-words disambiguation (envelope SW vs por.sw)
The script author read por.sw as the envelope SW, so a por.sw expectation on an applet's own TAR failed with (none). - docs/test-scripts.md: a 'The three status words (envelope SW / PoR status / R-APDU SW)' table in the authoring section - where each one comes from, the script field and the report row - plus a cross-reference from the por check paragraph; help EN/RU 8.9 points at it. - a failed por.sw check on a response_type: 'raw' decode carries the check detail 'the response is application data - an applet's own TAR has no R-APDU SW; assert it with data' (the PWA renders check details). - the runner's log prints APP DATA=<hex> (no R-APDU SW) for application responses instead of the misleading R-APDU SW=(none) data=...; the compact/scripting lines are unchanged. - the step editor's custom-PoR block gets a one-line hint about the same. Tests: 821 frontend + 730 Python; sw cache simple-v391.
This commit is contained in:
+23
-1
@@ -34,6 +34,26 @@ and the card's preset):
|
||||
| PoR transport + expected PoR | `scp80.check.por`/`check.data` (inline) or `expect SEND SHORT MESSAGE` + `por` check | pick per the SPI2 the applet expects |
|
||||
| Delivery timing | a `status` action when the card delivers on poll | the runner never polls by itself |
|
||||
|
||||
### The three status words (envelope SW · PoR status · R-APDU SW)
|
||||
|
||||
An SCP80 step carries three different "SW" values; keep them apart when
|
||||
writing checks:
|
||||
|
||||
| Where it comes from | What it means | Script field | Report row |
|
||||
|---|---|---|---|
|
||||
| the **ENVELOPE** exchange | the card's answer to the command that was sent (`9000` executed, `91XX` a proactive command is pending, `62XX`/`63XX` a warning) | the action's `check.sw` | `SW` |
|
||||
| the **PoR status** | the SCP80 security-processing verdict inside the response packet (`por_ok`, `cntr_low`, `rc_cc_ds_failed`, `tar_unknown`, …) | `por.status` (or `"por": "ok"`) | `PoR status` |
|
||||
| the **R-APDU SW** | the response payload's own status word - the last executed command's / GET RESPONSE's status in the compact form (TS 102 226 §5.1.2 Table 5.1), or the last R-APDU's in the scripting (`AB`/`AF`) form | `por.sw` | `PoR SW` |
|
||||
|
||||
`por.sw` is a child of the **response payload**, not of the envelope: it
|
||||
exists only when the addressed TAR is a **remote-management application**
|
||||
(ISD / RFM). A third-party applet's **own TAR** answers with
|
||||
application-defined bytes - the platform passes them through unchanged - so
|
||||
there is no R-APDU SW to check: `por.sw` reports `(none)` and the whole
|
||||
secured data is exposed as `por.data`. Assert such a response with `data`
|
||||
and leave `sw` empty; the step's `check.sw` still asserts the envelope
|
||||
exchange.
|
||||
|
||||
### Worksheet 1 - RFM update → file change → REFRESH (full FCN)
|
||||
|
||||
```json
|
||||
@@ -283,7 +303,9 @@ command-details byte 3 (one byte, exact/mask).
|
||||
SHORT MESSAGE is decoded with that step's keyset, SPI and counter. `status`
|
||||
is the decoded response status name (`por_ok`, `cntr_low`,
|
||||
`rc_cc_ds_failed`, …; `ok` is accepted for `por_ok`); `sw` is the R-APDU
|
||||
status word and `data` the R-APDU response data (exact/mask) - both come from
|
||||
status word **inside the response payload** - not the envelope's, see
|
||||
*The three status words* in the authoring section - and `data` the R-APDU
|
||||
response data (exact/mask); both come from
|
||||
the decoded response (scripting `AB`/`AF`/compact forms). An applet's **own
|
||||
TAR** answers with its application-defined bytes: when the data cannot be the
|
||||
compact remote response (its command count exceeds the command script that
|
||||
|
||||
@@ -564,7 +564,7 @@
|
||||
<p class="text-sm mb-2"><strong>Тест-скрипт</strong> — упорядоченный список <strong>действий</strong> и <strong>ожиданий</strong> проактивных команд, выполняемый на подключённой карте на стороне сервера. Пока запуск активен, карта принадлежит скрипту: остальные операции с картой отклоняются (HTTP 409), фоновый опрос STATUS приостанавливается; отчёт о запуске хранится в памяти (в том числе после перезагрузки страницы) до нажатия <strong>Очистить отчёт</strong>. Скрипты хранятся в <strong>хранилище на сервере</strong> (<code class="font-mono text-sm">~/.pysim-simple-server/test_scripts.json</code>, <code class="font-mono text-sm">--test-scripts</code>), поэтому все браузеры работают с одним набором; изменения записываются в хранилище по мере правки (кнопки «Сохранить» нет — черновик без валидного шага остаётся локальным); экспорт/импорт JSON остаётся для резервных копий и переноса скриптов между стендами (старый экспорт из localStorage импортируется как есть).</p>
|
||||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||||
<li><strong>Действия</strong> — <em>Envelope</em> (Event Download: сырой тип события + данные, с опциональным переопределением источника — 82 терминал / 83 сеть) или <em>Event</em> (семантические формы: Location status, Access technology change, Network rejection, Data connection status change — поля редактируются как объект JSON в редакторе шагов, а для остальных событий форма события на вкладке «Телефон» показывает готовый hex), <em>Menu Selection</em> (item id 1–255 или текст пункта с точным/частичным совпадением, по умолчанию без учёта регистра — выбор <em>«Учёт регистра»</em> в редакторе шагов включает точное совпадение; текст подбирается по меню карты, которое следует за параметрами установки апплета), <em>UPDATE/READ файла</em> (путь + режим; чтение проверяет данные файла), <em>сырой APDU</em> (без авто-обработчика), <em>SCP80</em> (C-APDU или готовый защищённый пакет, опциональные переопределения номера keyset (kvn) / TAR / SPI1 / SPI2 и формат команды — компактный или обёрнутый в шаблон Command Scripting TS 102 226 §5.2.1 <em>expanded</em> (AA) / <em>expanded AE 80</em>; ключи и счётчик берутся из пресета карты, подобранного по ICCID подключённой карты — запуск называет пресет в хранилище, поэтому всегда используются его keysets, TAR и счётчик — а счётчик записывается обратно после запуска) и <em>STATUS</em> (при <em>попытках</em> > 1 опрашивает, пока карта не объявит команду). У каждого действия есть проверка ответа: ожидаемые SW и данные (точно или маска с подстановкой <code class="font-mono text-sm">?</code> — <code class="font-mono text-sm">91??</code>) и проверка PoR для SCP80 (<em>любой / без PoR / por_ok</em> или своя проверка декодированного PoR — статус / SW / данные; транспорт через SEND SHORT MESSAGE работает так же).</li>
|
||||
<li><strong>Ожидания</strong> — карта должна объявить проактивную команду на предыдущем шаге (SW <code class="font-mono text-sm">91XX</code>, TS 102 221 §7.4.2.1 / TS 102 223 §6.3); <code class="font-mono text-sm">9000</code> означает «команды нет» и считается ошибкой — добавьте действие STATUS, если апплет выдаёт команду при опросе. Проверяются тип команды, квалификатор и содержимое: текст / пункт / raw, проверка <em>Alpha</em> (идентификатор Alpha команды, тег <code class="font-mono text-sm">05</code>/<code class="font-mono text-sm">85</code> — отличается от текстовой строки <code class="font-mono text-sm">8D</code>), проверка <em>SMS TPDU</em> (submit-TPDU команды SEND SHORT MESSAGE: получатель / PID / DCS / UDL / данные — для собственного SMS апплета), проверка <em>PoR</em> (SEND SHORT MESSAGE несёт PoR, когда пакет запросил PoR-in-submit, бит SPI2 <code class="font-mono text-sm">20</code>: статус ответа, SW R-APDU и данные ответа; перед этим должен выполниться шаг SCP80) и проверка <em>Files</em> (File List команды REFRESH, например квалификатор <code class="font-mono text-sm">00</code> = NAA initialization with full file change notification). <strong>TERMINAL RESPONSE</strong> (результат, идентификатор пункта, текст, доп. TLV) является частью инструкции.</li>
|
||||
<li><strong>Ожидания</strong> — карта должна объявить проактивную команду на предыдущем шаге (SW <code class="font-mono text-sm">91XX</code>, TS 102 221 §7.4.2.1 / TS 102 223 §6.3); <code class="font-mono text-sm">9000</code> означает «команды нет» и считается ошибкой — добавьте действие STATUS, если апплет выдаёт команду при опросе. Проверяются тип команды, квалификатор и содержимое: текст / пункт / raw, проверка <em>Alpha</em> (идентификатор Alpha команды, тег <code class="font-mono text-sm">05</code>/<code class="font-mono text-sm">85</code> — отличается от текстовой строки <code class="font-mono text-sm">8D</code>), проверка <em>SMS TPDU</em> (submit-TPDU команды SEND SHORT MESSAGE: получатель / PID / DCS / UDL / данные — для собственного SMS апплета), проверка <em>PoR</em> (SEND SHORT MESSAGE несёт PoR, когда пакет запросил PoR-in-submit, бит SPI2 <code class="font-mono text-sm">20</code>: статус ответа, SW R-APDU и данные ответа; перед этим должен выполниться шаг SCP80 — SW R-APDU находится <em>внутри</em> полезной нагрузки ответа: собственный TAR апплета возвращает данные приложения, поэтому проверяйте данные, а SW оставляйте пустым) и проверка <em>Files</em> (File List команды REFRESH, например квалификатор <code class="font-mono text-sm">00</code> = NAA initialization with full file change notification). <strong>TERMINAL RESPONSE</strong> (результат, идентификатор пункта, текст, доп. TLV) является частью инструкции.</li>
|
||||
<li><strong>Уровни ошибок</strong> — несовпадение помечает шаг как <em>Ошибка</em> (скрипт останавливается) или <em>Предупреждение</em> (продолжает); каждая проверка показывается с ожидаемым и фактическим значением.</li>
|
||||
<li><strong>Шаблоны</strong> — Empty, <em>Обзор меню STK</em>, <em>Апплет через SCP80</em>; редактор шагов — формный (поля действия Event вводятся объектом JSON), отдельные скрипты экспортируются/импортируются как JSON.</li>
|
||||
</ul>
|
||||
|
||||
+1
-1
@@ -563,7 +563,7 @@
|
||||
<p class="text-sm mb-2">A <strong>test script</strong> is an ordered list of <strong>actions</strong> and proactive-command <strong>expectations</strong> executed server-side on the equipped card. While a run is active the card belongs to the script: other card actions are refused (HTTP 409) and background STATUS polling is paused; the run report is kept in memory (also after reloading the page) until <strong>Clear report</strong>. Scripts live in the <strong>server-side store</strong> (<code class="font-mono text-sm">~/.pysim-simple-server/test_scripts.json</code>, <code class="font-mono text-sm">--test-scripts</code>), so every browser manages the same set; edits are written to the store as you change them (there is no Save button — a draft without a valid step stays local until it is valid); JSON export/import remains for backup and for moving scripts between benches (the old localStorage export imports as-is).</p>
|
||||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||||
<li><strong>Actions</strong> — <em>Envelope</em> (Event Download: raw event type + data, with an optional source override — 82 terminal / 83 network) or <em>Event</em> (the semantic forms: Location status, Access technology change, Network rejection, Data connection status change — the fields are edited as a JSON object in the step editor, and the Phone tab's event form shows the built hex for the other events), <em>Menu Selection</em> (item id 1–255, or the item's text with an exact/contains match, case-insensitive by default — the step editor's <em>Match case</em> choice switches to an exact-case match; the text is resolved against the card's menu, which follows the applet's install parameters), <em>UPDATE/READ file</em> (path + mode; reads verify the file data), <em>raw APDU</em> (no auto-handler), <em>SCP80</em> (C-APDU or a pre-built secured packet, optional keyset number (kvn) / TAR / SPI1 / SPI2 overrides and a command format — compact, or the TS 102 226 §5.2.1 Command Scripting template <em>expanded</em> (AA) / <em>expanded AE 80</em> around the C-APDU; the keys and the counter come from the card preset matched by the equipped card's ICCID — the run names the stored preset, so it always uses its keysets, TARs and counter — and the counter is written back to it after the run) and <em>STATUS</em> (with <em>attempts</em> > 1 it polls until the card announces a command). Every action has a response check: expected SW and data (exact, or a mask with <code class="font-mono text-sm">?</code> nibble wildcards — <code class="font-mono text-sm">91??</code>) plus a PoR check for SCP80 (<em>any / no PoR / por_ok</em>, or a custom assertion of the decoded PoR — status / SW / data; the SEND SHORT MESSAGE transport works the same).</li>
|
||||
<li><strong>Expectations</strong> — the card must have announced a proactive command in the previous step (SW <code class="font-mono text-sm">91XX</code>, TS 102 221 §7.4.2.1 / TS 102 223 §6.3); a <code class="font-mono text-sm">9000</code> means “no command” and is an error — add a STATUS action when the applet delivers on poll. The command type, qualifier and contents are verified: text / item / raw checks, an <em>Alpha</em> check (the command's Alpha identifier, tag <code class="font-mono text-sm">05</code>/<code class="font-mono text-sm">85</code> — distinct from the <code class="font-mono text-sm">8D</code> text string), an <em>SMS TPDU</em> check (the submit TPDU of a SEND SHORT MESSAGE: destination / PID / DCS / UDL / user data — for an applet's own SMS), a <em>PoR</em> check (a SEND SHORT MESSAGE carries the PoR when the packet requested PoR-in-submit, SPI2 bit <code class="font-mono text-sm">20</code>: the response status, the R-APDU SW and the response data; make sure an SCP80 step ran first) and a <em>Files</em> check (the File List of a REFRESH, e.g. qualifier <code class="font-mono text-sm">00</code> = NAA initialization with full file change notification). The scripted <strong>TERMINAL RESPONSE</strong> (result, item identifier, text, extra TLVs) is part of the instruction.</li>
|
||||
<li><strong>Expectations</strong> — the card must have announced a proactive command in the previous step (SW <code class="font-mono text-sm">91XX</code>, TS 102 221 §7.4.2.1 / TS 102 223 §6.3); a <code class="font-mono text-sm">9000</code> means “no command” and is an error — add a STATUS action when the applet delivers on poll. The command type, qualifier and contents are verified: text / item / raw checks, an <em>Alpha</em> check (the command's Alpha identifier, tag <code class="font-mono text-sm">05</code>/<code class="font-mono text-sm">85</code> — distinct from the <code class="font-mono text-sm">8D</code> text string), an <em>SMS TPDU</em> check (the submit TPDU of a SEND SHORT MESSAGE: destination / PID / DCS / UDL / user data — for an applet's own SMS), a <em>PoR</em> check (a SEND SHORT MESSAGE carries the PoR when the packet requested PoR-in-submit, SPI2 bit <code class="font-mono text-sm">20</code>: the response status, the R-APDU SW and the response data; make sure an SCP80 step ran first — the R-APDU SW lives <em>inside</em> the response payload: an applet's own TAR returns application data, so check its data and leave the SW empty) and a <em>Files</em> check (the File List of a REFRESH, e.g. qualifier <code class="font-mono text-sm">00</code> = NAA initialization with full file change notification). The scripted <strong>TERMINAL RESPONSE</strong> (result, item identifier, text, extra TLVs) is part of the instruction.</li>
|
||||
<li><strong>Fail levels</strong> — a mismatch flags the step as <em>Error</em> (terminates the script) or <em>Warning</em> (continues); each check is reported with expected vs actual values.</li>
|
||||
<li><strong>Templates</strong> — Empty, <em>STK menu browsing</em>, <em>Applet via SCP80</em>; the step editor is form-based (the event action's fields are a JSON object) and individual scripts export/import as JSON.</li>
|
||||
</ul>
|
||||
|
||||
+4
-1
@@ -1877,7 +1877,7 @@
|
||||
// ===== Version =====
|
||||
// Single source of truth for the PWA version: shown in the header and used
|
||||
// by the server version check in pysimConnect().
|
||||
const SIMPLE_VERSION = '3.19.1';
|
||||
const SIMPLE_VERSION = '3.19.2';
|
||||
document.getElementById('app-version').textContent = 'v' + SIMPLE_VERSION;
|
||||
|
||||
// ===== Tab switching =====
|
||||
@@ -7442,6 +7442,8 @@ function testStepRender() {
|
||||
html += testFormRow('PoR status', testFormInput('test-f-porstatus', porObj.status, 'por_ok'));
|
||||
html += testFormRow('PoR SW (hex)', testFormInput('test-f-por-sw', porObj.sw && porObj.sw.value, '6A88'));
|
||||
html += testFormRow('PoR data (hex)', testFormInput('test-f-por-data', porObj.data && porObj.data.value, 'AA??'));
|
||||
html += '<p class="mt-1 text-xs text-gray-400 dark:text-slate-500">'
|
||||
+ esc(t("PoR SW is the R-APDU SW inside a remote-management TAR's response; an applet's own TAR returns application data - assert it with PoR data and leave SW empty.")) + '</p>';
|
||||
}
|
||||
}
|
||||
html += testFormRow('On mismatch', testFormSelect('test-f-fail', step.on_fail || 'error', [
|
||||
@@ -21194,6 +21196,7 @@ const LANG_RU = {
|
||||
'PoR status': 'Статус PoR',
|
||||
'PoR SW (hex)': 'SW PoR (hex)',
|
||||
'PoR data (hex)': 'Данные PoR (hex)',
|
||||
"PoR SW is the R-APDU SW inside a remote-management TAR's response; an applet's own TAR returns application data - assert it with PoR data and leave SW empty.": 'SW PoR — это SW R-APDU внутри ответа remote-management TAR; собственный TAR апплета возвращает данные приложения — проверяйте «Данные PoR», оставив SW пустым.',
|
||||
'PoR check: status, SW or data is required': 'Проверка PoR: нужен status, SW или data',
|
||||
'Command format': 'Формат команды',
|
||||
'Compact': 'Компактный',
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
const CACHE = 'simple-v390';
|
||||
const CACHE = 'simple-v391';
|
||||
const URLS = [
|
||||
'index.html',
|
||||
'help.html',
|
||||
|
||||
@@ -250,6 +250,9 @@ test('the SCP80 step form renders the format select and the custom PoR fields',
|
||||
assert.match(body, /<option value="custom" selected>/);
|
||||
assert.match(body, /id="test-f-porstatus" value="por_ok"/);
|
||||
assert.match(body, /id="test-f-por-sw" value=""/);
|
||||
// the block explains where PoR SW comes from (the applet-TAR confusion)
|
||||
assert.ok(body.includes('R-APDU SW inside a remote-management'), body);
|
||||
assert.ok(body.includes('leave SW empty'), body);
|
||||
// the pre-built packet source has no format select (the wrapper applies
|
||||
// to a C-APDU only)
|
||||
_testEditStep = { type: 'action', kind: 'scp80', params: { source: 'sp', sp: 'AABB' } };
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "pysim-simple-server"
|
||||
version = "3.19.1"
|
||||
version = "3.19.2"
|
||||
description = "HTTP REST server wrapping pysim for the SIMple PWA"
|
||||
requires-python = ">=3.8"
|
||||
# pysim is a git-only dependency installed explicitly by setup.bat/setup.sh.
|
||||
|
||||
@@ -34,7 +34,7 @@ from osmocom.tlv import BER_TLV_IE
|
||||
from osmocom.utils import rpad
|
||||
|
||||
|
||||
VERSION = '3.19.1'
|
||||
VERSION = '3.19.2'
|
||||
|
||||
MAX_ENVELOPE_SEGMENTS = 5 # max SMS segments for outgoing C-APDU in ENVELOPE
|
||||
|
||||
@@ -5839,9 +5839,14 @@ def _por_check_results(spec, por, level, prefix='PoR'):
|
||||
actual or '(none)', level))
|
||||
if 'sw' in spec:
|
||||
actual = str((por.get('decoded') or {}).get('last_status_word') or '')
|
||||
checks.append(_test_check_result(
|
||||
prefix + ' SW', testscript.match_value(spec['sw'], actual),
|
||||
spec['sw']['value'], actual or '(none)', level))
|
||||
ok = testscript.match_value(spec['sw'], actual)
|
||||
detail = None
|
||||
if not ok and por.get('response_type') == 'raw':
|
||||
detail = ("the response is application data - an applet's own TAR "
|
||||
"has no R-APDU SW; assert it with 'data'")
|
||||
checks.append(_test_check_result(prefix + ' SW', ok,
|
||||
spec['sw']['value'], actual or '(none)',
|
||||
level, detail=detail))
|
||||
if 'data' in spec:
|
||||
actual = str((por.get('decoded') or {}).get('last_response_data') or '')
|
||||
checks.append(_test_check_result(
|
||||
@@ -6024,9 +6029,13 @@ def _test_run_scp80(server, step, ctx):
|
||||
_test_log('PoR[inline] status=%s TAR=%s CNTR=%s%s raw=%s'
|
||||
% (por.get('response_status'), por.get('tar'),
|
||||
por.get('cntr'), extra, por.get('raw') or data))
|
||||
_test_log('R-APDU SW=%s data=%s'
|
||||
% (dec.get('last_status_word') or '(none)',
|
||||
dec.get('last_response_data') or '(none)'))
|
||||
if por.get('response_type') == 'raw':
|
||||
_test_log('APP DATA=%s (no R-APDU SW)'
|
||||
% (dec.get('last_response_data') or '(none)'))
|
||||
else:
|
||||
_test_log('R-APDU SW=%s data=%s'
|
||||
% (dec.get('last_status_word') or '(none)',
|
||||
dec.get('last_response_data') or '(none)'))
|
||||
elif data:
|
||||
_test_log('PoR[inline] undecodable raw=%s' % data)
|
||||
else:
|
||||
@@ -6284,9 +6293,13 @@ def _test_run_expect(server, step, pending, ctx=None):
|
||||
_test_log('PoR[sms-submit] status=%s TAR=%s CNTR=%s raw=%s'
|
||||
% (por.get('response_status'), por.get('tar'),
|
||||
por.get('cntr'), por.get('raw') or '(none)'))
|
||||
_test_log('R-APDU SW=%s data=%s'
|
||||
% (dec.get('last_status_word') or '(none)',
|
||||
dec.get('last_response_data') or '(none)'))
|
||||
if por.get('response_type') == 'raw':
|
||||
_test_log('APP DATA=%s (no R-APDU SW)'
|
||||
% (dec.get('last_response_data') or '(none)'))
|
||||
else:
|
||||
_test_log('R-APDU SW=%s data=%s'
|
||||
% (dec.get('last_status_word') or '(none)',
|
||||
dec.get('last_response_data') or '(none)'))
|
||||
else:
|
||||
_test_log('PoR[sms-submit] none (no decodable PDU or no scp80 '
|
||||
'context)')
|
||||
|
||||
@@ -1106,6 +1106,31 @@ class TestRunnerActions(RunnerTestCase):
|
||||
# the live alfa-dsa applet's response (2026-10-04): the secured data
|
||||
# `80 01 10` is the applet's own, so the compact parse must not claim
|
||||
# 128 commands - the runner exposes it as the PoR data
|
||||
preset = {'kic': '15', 'kid': '15', 'kicKey': 'AA' * 16,
|
||||
'kidKey': 'BB' * 16, 'counter': '00000001',
|
||||
'tars': preset_tars()}
|
||||
buf = io.StringIO()
|
||||
with mock.patch.object(S, '_build_secured_packet', return_value=('AA' * 10, {})), \
|
||||
mock.patch.object(S, '_send_secured_packet',
|
||||
return_value={'success': True, 'sw': '9000',
|
||||
'response_data': self.APP_POR_RAW}):
|
||||
with contextlib.redirect_stderr(buf):
|
||||
run = self.run_script(FakeServer(FakeScc()), [
|
||||
{'type': 'action', 'kind': 'scp80', 'params': {'apdu': '01'},
|
||||
'check': {'por': {'status': 'por_ok', 'data': '800110'}}},
|
||||
], preset)
|
||||
self.assertEqual(run['status'], 'ok', run['steps'])
|
||||
labels = {c['label']: c for c in run['steps'][0]['checks']}
|
||||
self.assertTrue(labels['PoR status']['ok'], labels)
|
||||
self.assertTrue(labels['PoR data']['ok'], labels)
|
||||
self.assertEqual(run['steps'][0]['por']['response_type'], 'raw')
|
||||
# the log names application data instead of inventing an R-APDU line
|
||||
self.assertIn('APP DATA=800110 (no R-APDU SW)', buf.getvalue())
|
||||
self.assertNotIn('R-APDU SW=', buf.getvalue())
|
||||
|
||||
def test_scp80_por_sw_check_on_applet_data_reports_the_hint(self):
|
||||
# a `por.sw` expectation cannot be satisfied by an applet's own TAR -
|
||||
# the report explains why on the check row (the live confusion)
|
||||
preset = {'kic': '15', 'kid': '15', 'kicKey': 'AA' * 16,
|
||||
'kidKey': 'BB' * 16, 'counter': '00000001',
|
||||
'tars': preset_tars()}
|
||||
@@ -1115,13 +1140,13 @@ class TestRunnerActions(RunnerTestCase):
|
||||
'response_data': self.APP_POR_RAW}):
|
||||
run = self.run_script(FakeServer(FakeScc()), [
|
||||
{'type': 'action', 'kind': 'scp80', 'params': {'apdu': '01'},
|
||||
'check': {'por': {'status': 'por_ok', 'data': '800110'}}},
|
||||
'check': {'por': {'sw': '9000'}}},
|
||||
], preset)
|
||||
self.assertEqual(run['status'], 'ok', run['steps'])
|
||||
labels = {c['label']: c for c in run['steps'][0]['checks']}
|
||||
self.assertTrue(labels['PoR status']['ok'], labels)
|
||||
self.assertTrue(labels['PoR data']['ok'], labels)
|
||||
self.assertEqual(run['steps'][0]['por']['response_type'], 'raw')
|
||||
self.assertNotEqual(run['status'], 'ok')
|
||||
sw_check = [c for c in run['steps'][0]['checks'] if c['label'] == 'PoR SW'][0]
|
||||
self.assertFalse(sw_check['ok'])
|
||||
self.assertIn('application data', sw_check.get('detail') or '')
|
||||
self.assertIn("assert it with 'data'", sw_check.get('detail') or '')
|
||||
|
||||
def test_scp80_format_wraps_the_apdu(self):
|
||||
# `format` wraps the C-APDU in the expanded Command Scripting template
|
||||
|
||||
Reference in New Issue
Block a user