6bea57599c
A suite may carry `start_reset` (store schema v2, default false; the editor's
"Start with card reset" checkbox): before the run, the server physically
resets the card and runs the full re-initialization - `_card_reset_reinit`
(extracted from the eSIM profile-switch reinit) does reset_card() + equip +
_apply_equipped_card + the shell registration probe.
The reset runs in _test_suite_run_request before the preset/ADM checks:
- the run's preset must still match the post-reset ICCID (a mismatch refuses
the start with a re-select hint),
- a require_adm suite re-verifies the ADM for the new card session (the
latch is per session).
The suite report carries start_reset + reset {ok, iccid, ms}; the PWA shows
"started with a card reset" in the report header and a RESET badge in the
suite list. Mid-run resets stay fatal.
Documented caveat: the init drain consumes the card's initial proactive
commands, so a script cannot catch the first command after the reset (they
stay in the proactive log).
Docs: test-scripts.md, api.md, help EN/RU, repo AGENTS.
Tests: 843 frontend + 827 Python; sw cache simple-v413.
701 lines
200 KiB
HTML
701 lines
200 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="ru">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>SIMple — Справка</title>
|
||
<link rel="stylesheet" href="style.css">
|
||
</head>
|
||
<body class="bg-neutral-50 dark:bg-slate-900 text-gray-800 dark:text-slate-200">
|
||
|
||
<div class="flex">
|
||
|
||
<aside class="sticky top-0 h-screen overflow-y-auto w-72 shrink-0 border-r border-gray-300 dark:border-slate-700 px-4 py-6">
|
||
<a href="index.html" class="block text-xs text-gray-400 hover:text-gray-600 dark:text-slate-500 dark:hover:text-slate-300 mb-4">← Назад к приложению</a>
|
||
<nav id="toc" class="text-sm"></nav>
|
||
</aside>
|
||
|
||
<main class="flex-1 min-w-0 px-6 py-8">
|
||
<h1 class="text-2xl font-bold text-heading mb-6">SIMple <span class="text-xs text-gray-400 dark:text-slate-500 ml-2">Документация</span></h1>
|
||
<section class="mb-10">
|
||
<h2 id="overview" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">1. Обзор</h2>
|
||
<p class="mb-3">SIMple — инструментарий для специалистов по UICC/SIM-картам: автономный Progressive Web App (PWA), закрывающий весь цикл лабораторной работы — <strong>APDU-верстак</strong> (конструкторы SIM/USIM RFM и Expanded Script, команды GlobalPlatform RAM, парсер C-APDU/R-APDU и декодер ответов), <strong>OTA-лаборатория</strong> (защищённые пакеты SCP80 и установка Java Card RAM, а также терминальная сторона HTTP OTA — SCP81: эмуляция BIP-каналов, PSK-TLS-сервер администрирования и выполнение скриптов APDU), <strong>симулятор</strong> (меню SIM Toolkit, proactive-команды и события, редактирование TERMINAL PROFILE, журнал C-AT-диалога), <strong>тест-скрипты карты</strong> и <strong>профайлер карты</strong> (профили и неизменяемые снимки с таймингами, точное сравнение снимков, декодер FCP/FCI).</p>
|
||
<p class="mb-3">Приложение — один статический файл <code class="font-mono text-sm">index.html</code>. Все вычисления выполняются в браузере; доступ к карте — через локальный HTTP-сервер (<code class="font-mono text-sm">pysim-simple-server</code>), оборачивающий библиотеку <a href="https://osmocom.org/projects/pysim" class="text-blue-600 dark:text-blue-400 hover:underline">pySim</a>.</p>
|
||
<pre class="font-mono text-xs bg-gray-100 dark:bg-slate-800 rounded p-3 mb-3">Браузер (SIMple PWA) → HTTP :8080 → pysim-simple-server → pySim → PC/SC → ридер → UICC/SIM</pre>
|
||
<p class="mb-3">Стандарты, на которые опирается приложение:</p>
|
||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||
<li>ETSI TS 102 221 — интерфейс UICC-терминал (CLA 00, файлы USIM)</li>
|
||
<li>ETSI TS 102 222 — административные команды</li>
|
||
<li>ETSI TS 102 223 — Card Application Toolkit (CAT, проактивные команды)</li>
|
||
<li>ETSI TS 102 225 — структура защищённых пакетов для (U)SIM toolkit</li>
|
||
<li>ETSI TS 102 226 — структура удалённых APDU для UICC-приложений</li>
|
||
<li>ETSI TS 151 011 — интерфейс SIM-ME (CLA A0)</li>
|
||
<li>3GPP TS 131 111 — USIM Application Toolkit (USAT)</li>
|
||
<li>3GPP TS 31.102 — характеристики приложения USIM</li>
|
||
<li>3GPP TS 23.038 — алфавит GSM 7-bit и DCS</li>
|
||
<li>3GPP TS 24.008 / 24.301 / 24.501 — коды причин NAS</li>
|
||
<li>GlobalPlatform Card Specification v2.3.1</li>
|
||
<li>GlobalPlatform GPC v2.2 Amendment B v1.1 — Remote Application Management over HTTP</li>
|
||
<li>ISO/IEC 7816-4 — команды обмена</li>
|
||
<li>ISO/IEC 9797-1 — алгоритмы MAC</li>
|
||
</ul>
|
||
|
||
<h3 id="interface" class="text-lg font-medium mb-2">1.1 Интерфейс</h3>
|
||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||
<li><strong>Шапка</strong> — версия приложения, кнопка <strong>INSTALL PWA</strong> (появляется, когда браузер предлагает установку, для офлайн-работы), ссылки на проект на GitHub и на эту справку, переключатель языка <strong>EN/RU</strong> и переключатель тёмной/светлой <strong>темы</strong>. Рядом с заголовком небольшой индикатор показывает состояние сервера/карты (серая точка = подключение, красная = нет сервера, значки карты = нет карты / инициализация / карта готова), ICCID подключённой карты, компактный значок <strong>ADM ✓</strong> (зелёный, администраторский PIN подтверждён) или <strong>ADM ✗</strong> (красный, не подтверждён) для текущей сессии карты — со значком ключа в конце (<strong>ADM ✓ ⚿</strong>), если в пресете карты с этим ICCID есть ключ ADM — и серые маркеры <strong>SCP80</strong> / <strong>SCP81</strong>, появляющиеся, когда в этом пресете заполнены SCP80 (keyset и три записи TAR с их MSL) или SCP81 (PSK identity/ключ).</li>
|
||
<li>Выбор языка и темы хранится в <code class="font-mono text-sm">localStorage</code> и сохраняется между перезагрузками.</li>
|
||
<li>Вкладки верхнего уровня: <strong>Remote APDU</strong> (<strong>SIM RFM</strong>, <strong>USIM RFM</strong>, <strong>RAM/GP</strong>, <strong>Expanded Script</strong>, <strong>«Пуш/триггер»</strong>, <strong>«Разбор»</strong> (<strong>«Разбор C-APDU»</strong>, <strong>«Разбор R-APDU»</strong>)), <strong>SCP80</strong> (<strong>Secured Packet</strong>, <strong>RAM</strong>, <strong>TAR-сканер</strong>), <strong>SCP81</strong> (<strong>«Слушатель»</strong>, <strong>«Скрипты»</strong>), <strong>«Карты»</strong>, <strong>«Профайлер»</strong> (вкладки <strong>«Профили»</strong>, <strong>«Снимки карт»</strong>, <strong>«Пользовательские файлы»</strong>), <strong>«Картридер»</strong> (<strong>Файловый менеджер</strong>, <strong>Командная строка pySim</strong>, <strong>Отправка APDU</strong>) и <strong>«Симулятор»</strong>.</li>
|
||
<li>Ссылка <strong>справка</strong> открывает эту документацию на разделе, соответствующем текущему представлению (например, вкладка «Профайлер» открывает §7).</li>
|
||
</ul>
|
||
|
||
|
||
</section>
|
||
<section class="mb-10">
|
||
<h2 id="c-apdu" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">2. Вкладка Remote APDU</h2>
|
||
<p class="mb-3">Построение командных APDU (C-APDU). Шесть подвкладок охватывают разные поколения карт, наборы команд и инструменты разбора: <strong>SIM RFM</strong>, <strong>USIM RFM</strong>, <strong>RAM/GP</strong>, <strong>Expanded Script</strong>, <strong>«Пуш/триггер»</strong> и <strong>«Разбор»</strong> — последняя содержит подвкладки <strong>«Разбор C-APDU»</strong> и <strong>«Разбор R-APDU»</strong>.</p>
|
||
|
||
<h3 id="sim-rfm" class="text-lg font-medium mb-2">2.1 SIM RFM</h3>
|
||
<p class="mb-2">CLA = <code class="font-mono text-sm">A0</code> (GSM 11.11 / TS 151 011, ISO 7816-4). Удалённое управление файлами классических SIM-карт.</p>
|
||
<p class="mb-2">Команды собираются в виде <strong>цепочки</strong>: нажмите кнопку <code class="font-mono text-sm">+ SELECT</code> (или другую командную кнопку), чтобы добавить строку, заполните её поля — предпросмотр цепочки (над кнопкой упаковки) обновится автоматически. Добавьте строку <strong>GET RESPONSE</strong>, чтобы получить данные после SELECT. Кнопка <strong>Упаковать в Secured packet</strong> упаковывает всю цепочку в пакет SCP80 и устанавливает TAR SCP80 в <strong>UICC RFM TAR</strong> выбранного пресета (по умолчанию <code class="font-mono text-sm">B00000</code>) — TAR UICC Shared File System RFM: MF выбирается неявно, ADF недоступны, поэтому пути SELECT адресуют файлы от MF.</p>
|
||
<table class="w-full text-sm mb-3 border-collapse">
|
||
<thead><tr class="border-b border-gray-300 dark:border-slate-700">
|
||
<th class="text-left py-1 px-2">Команда</th><th class="text-left py-1 px-2">INS</th><th class="text-left py-1 px-2">Описание</th>
|
||
</tr></thead>
|
||
<tbody>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">SELECT</td><td class="py-1 px-2 font-mono">A4</td><td class="py-1 px-2">Выбор EF/DF по FID, пути, AID или цепочке</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">UPDATE RECORD</td><td class="py-1 px-2 font-mono">DC</td><td class="py-1 px-2">Обновление записи</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">UPDATE BINARY</td><td class="py-1 px-2 font-mono">D6</td><td class="py-1 px-2">Обновление бинарных данных</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">READ RECORD</td><td class="py-1 px-2 font-mono">B2</td><td class="py-1 px-2">Чтение записи</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">READ BINARY</td><td class="py-1 px-2 font-mono">B0</td><td class="py-1 px-2">Чтение бинарных данных</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">ERASE BINARY</td><td class="py-1 px-2 font-mono">0E</td><td class="py-1 px-2">Стирание бинарных данных</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">ACTIVATE FILE</td><td class="py-1 px-2 font-mono">44</td><td class="py-1 px-2">Активация файла</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">DEACTIVATE FILE</td><td class="py-1 px-2 font-mono">04</td><td class="py-1 px-2">Деактивация файла</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">VERIFY PIN</td><td class="py-1 px-2 font-mono">20</td><td class="py-1 px-2">Проверка PIN1 или PIN2</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">CHANGE PIN</td><td class="py-1 px-2 font-mono">24</td><td class="py-1 px-2">Смена PIN1 или PIN2</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">DISABLE PIN</td><td class="py-1 px-2 font-mono">26</td><td class="py-1 px-2">Отключение PIN</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">ENABLE PIN</td><td class="py-1 px-2 font-mono">28</td><td class="py-1 px-2">Включение PIN</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">UNBLOCK PIN</td><td class="py-1 px-2 font-mono">2C</td><td class="py-1 px-2">Разблокировка PIN с помощью PUK</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">SEARCH RECORD (SEEK)</td><td class="py-1 px-2 font-mono">A2</td><td class="py-1 px-2">Поиск образца в линейном фиксированном EF; P2 задаёт тип 1/2 и режим (TS 151 011 §9.2.7)</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">INCREASE</td><td class="py-1 px-2 font-mono">32</td><td class="py-1 px-2">Прибавить значение к последней увеличенной/обновлённой записи циклического EF (значение 3 байта, TS 151 011 §9.2.8)</td></tr>
|
||
<tr><td class="py-1 px-2 font-mono">GET RESPONSE</td><td class="py-1 px-2 font-mono">C0</td><td class="py-1 px-2">Получение данных, на которые указывает предшествующий <code class="font-mono text-sm">61XX</code>/<code class="font-mono text-sm">9FXX</code></td></tr>
|
||
</tbody>
|
||
</table>
|
||
<h4 id="sim-select-methods" class="font-medium mb-1">Методы SELECT</h4>
|
||
<table class="w-full text-sm mb-3 border-collapse">
|
||
<thead><tr class="border-b border-gray-300 dark:border-slate-700">
|
||
<th class="text-left py-1 px-2">Метод</th><th class="text-left py-1 px-2">P1</th><th class="text-left py-1 px-2">P2</th><th class="text-left py-1 px-2">Ввод</th>
|
||
</tr></thead>
|
||
<tbody>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">По FID</td><td class="py-1 px-2 font-mono">00</td><td class="py-1 px-2 font-mono">00</td><td class="py-1 px-2">FID (4 hex)</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">По полному пути от MF</td><td class="py-1 px-2 font-mono">08</td><td class="py-1 px-2 font-mono">00</td><td class="py-1 px-2">Полный путь от MF</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">По DF name / AID</td><td class="py-1 px-2 font-mono">04</td><td class="py-1 px-2 font-mono">00</td><td class="py-1 px-2">AID</td></tr>
|
||
<tr><td class="py-1 px-2">Цепочка</td><td class="py-1 px-2 font-mono">00</td><td class="py-1 px-2 font-mono">00</td><td class="py-1 px-2">FID через запятую; токен <code class="font-mono text-sm">C0</code> (или <code class="font-mono text-sm">C0:NN</code>) вставляет GET RESPONSE</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<p class="text-sm mb-3">Для record-команд режим P2: <strong>Absolute (04)</strong>, <strong>Next (02)</strong> или <strong>Previous (03)</strong>. Если за Case 4 командой сразу следует строка GET RESPONSE, сборщик цепочки автоматически убирает её байт Le (ETSI TS 102 226 §5.1.1). В правой колонке — панель конвертации (IMSI, MSISDN, ICCID, SPN, PLMN, nibble swap). См. <a href="#conversion" class="text-blue-600 dark:text-blue-400 hover:underline">§2.5</a>.</p>
|
||
<p class="text-sm mb-3"><strong>→ Расширенный скрипт</strong> отправляет собранную цепочку в конструктор Expanded Script строками C-APDU (строки GET RESPONSE отбрасываются — расширенный формат их не использует, TS 102 226 §5.2.1.1). Приложение UICC Shared File System RFM (TAR <code class="font-mono text-sm">B00000</code>) доступно и в компактном, и в расширенном формате — если TAR не настроен на автоопределение формата, используются разные значения TAR (TS 102 226 §7.0/§5.3).</p>
|
||
|
||
<h4 id="rfm-file-picker" class="font-medium mb-1">Выбор файла для SELECT</h4>
|
||
<p class="text-sm mb-2">У каждой строки SELECT под полями метода есть выбор файла: поле фильтра, переключатель <strong>all files</strong>, корень начала сессии с текущим DF и список файлов, сгруппированный по корню (<code class="font-mono text-sm">MF</code>, <code class="font-mono text-sm">ADF.USIM</code>, …). Выбор файла заполняет поля текущего метода; если метод не может выразить выбор, помощник переключается на подходящий — предпочитая <strong>path</strong> (один SELECT), затем <strong>chain</strong> — и пишет об этом в строке примечания, например файл из другого DF становится <code class="font-mono text-sm">7F106F40</code> (путь от MF) или <code class="font-mono text-sm">7F20,6F46</code> (относительная цепочка FID).</p>
|
||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||
<li><strong>Источник списка</strong>: при подключённой карте приоритет у загруженного дерева файлового менеджера (имена карты и проверенное наличие; отсутствующие файлы скрываются). Без карты и для незагруженных ветвей используется поставляемый стандартный список — <code class="font-mono text-sm">uicc_files.json</code>, собранный из профилей/классов приложений pySim скриптом <code class="font-mono text-sm">pysim_simple_server/uicc_files.py</code> и проверяемый тестом. До запуска <strong>«Проверить все файлы»</strong> в файловом менеджере список соответствует спецификациям. Пользовательские файлы добавляются всегда.</li>
|
||
<li><strong>Начало сессии</strong>: неявный текущий DF зависит от <em>TAR</em>, на который отправляется защищённый пакет — приложение UICC Shared File System RFM начинает с MF (TS 102 226 §7.2), приложение ADF RFM — со своего ADF (§7.3). По умолчанию помощник берёт MF для обоих конструкторов; можно изменить для каждой строки (выберите ADF для работы в сессии ADF).</li>
|
||
<li><strong>Path</strong> — последовательность FID от MF <em>без</em> идентификатора MF (ISO 7816-4: «select from the MF — path without the MF identifier»); вариант USIM <strong>from current DF</strong> использует относительный хвост. <strong>Chain</strong> остаётся относительным к текущему DF и следует порядку поиска FID из TS 102 221 §11.1.1.2 (дети → родитель → соседи), поэтому переход к общему предку не нужен.</li>
|
||
<li>Корни ADF не выбираются: приложение выбирается по AID, и метод <strong>By AID</strong> остаётся ручным (TS 102 226 §7.1 запрещает P1=<code class="font-mono text-sm">04</code> для RFM).</li>
|
||
</ul>
|
||
|
||
<h3 id="usim-rfm" class="text-lg font-medium mb-2">2.2 USIM RFM</h3>
|
||
<p class="mb-2">CLA = <code class="font-mono text-sm">00</code> (ETSI TS 102 221). Тот же сборщик цепочки и набор команд, что и SIM, плюс административные команды UICC и формы SEARCH RECORD / INCREASE из TS 102 221:</p>
|
||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||
<li><strong>SELECT</strong> по умолчанию запрашивает FCP (P2=<code class="font-mono text-sm">04</code>) и добавляет Le=<code class="font-mono text-sm">00</code>; флажок <strong>Silent (P2=0C)</strong> выбирает файл без запроса FCP (без Le, без данных ответа).</li>
|
||
<li><strong>По пути</strong> предлагает выбор <strong>from MF</strong> (P1=<code class="font-mono text-sm">08</code>) или <strong>from current DF</strong> (P1=<code class="font-mono text-sm">09</code>); текущий DF сессии ADF RFM — ADF.USIM.</li>
|
||
<li><strong>Упаковать в Secured packet</strong> устанавливает TAR SCP80 в <strong>ADF RFM TAR</strong> выбранного пресета (по умолчанию <code class="font-mono text-sm">B00001</code>), привязанный к AID ADF (ADF.USIM).</li>
|
||
<li><strong>SEARCH RECORD</strong> (TS 102 221 §11.1.7) — простые режимы (P2=<code class="font-mono text-sm">10</code>/<code class="font-mono text-sm">12</code>, P1 = номер записи) и расширенный режим (P2=<code class="font-mono text-sm">18</code>) с 2-байтовым search indication; <strong>INCREASE</strong> (§11.1.8) принимает необязательный SFI и прибавляемое значение.</li>
|
||
<li><strong>CREATE FILE</strong> / <strong>DELETE FILE</strong> / <strong>RESIZE FILE</strong> (ETSI TS 102 222 §6.3/6.4/6.10) принимают шаблон FCP; кнопка <strong>Build template</strong> собирает структурный каркас (file descriptor, FID, LCSI, размер и разрешающее компактное правило доступа <code class="font-mono text-sm">8C 02 7F 00</code> — проверьте его для своей карты). RESIZE FILE использует CLA <code class="font-mono text-sm">80</code> (TS 102 222 Table 1: <code class="font-mono text-sm">'8X'</code>/<code class="font-mono text-sm">'CX'</code>).</li>
|
||
<li><strong>SET DATA</strong> / <strong>RETRIEVE DATA</strong> (TS 102 221 §11.3) работают с BER-TLV EF: P2 выбирает первый/следующий/повторный блок (+SFI), поле тега необязательно (<code class="font-mono text-sm">5C</code> — список размещённых тегов).</li>
|
||
<li>Каждый переход SELECT в цепочке запрашивает FCP, если не отмечен как silent.</li>
|
||
</ul>
|
||
|
||
<h3 id="ber-tlv" class="text-lg font-medium mb-2">2.3 Expanded Script</h3>
|
||
<p class="mb-2">Построение формата Expanded Remote Application data по ETSI TS 102 226 §5.2.1.</p>
|
||
<h4 id="ber-format" class="font-medium mb-1">Формат</h4>
|
||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||
<li><strong>Definite (AA)</strong>: <code class="font-mono text-sm">AA</code> + длина + Command TLV</li>
|
||
<li><strong>Indefinite (AE)</strong>: <code class="font-mono text-sm">AE</code> + <code class="font-mono text-sm">80</code> + Command TLV + <code class="font-mono text-sm">00 00</code></li>
|
||
</ul>
|
||
<h4 id="ber-command-tlvs" class="font-medium mb-1">Command TLV</h4>
|
||
<table class="w-full text-sm mb-3 border-collapse">
|
||
<thead><tr class="border-b border-gray-300 dark:border-slate-700">
|
||
<th class="text-left py-1 px-2">Тип</th><th class="text-left py-1 px-2">Тег</th><th class="text-left py-1 px-2">Описание</th>
|
||
</tr></thead>
|
||
<tbody>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">C-APDU</td><td class="py-1 px-2 font-mono">22</td><td class="py-1 px-2">Любая команда удалённого управления: hex APDU или команда, собранная редакторами SIM RFM / USIM RFM / RAM-GP (TS 102 226 §5.2.1.0; GET RESPONSE в этом формате не используется, §5.2.1.1)</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">Immediate Action</td><td class="py-1 px-2 font-mono">81</td><td class="py-1 px-2">Проактивная команда или action indicator</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">Error Action</td><td class="py-1 px-2 font-mono">82</td><td class="py-1 px-2">Условное восстановление при ошибках с action indicator или проактивной командой</td></tr>
|
||
<tr><td class="py-1 px-2">Script Chaining</td><td class="py-1 px-2 font-mono">83</td><td class="py-1 px-2">Многопакетное выполнение скрипта с флагами First/Intermediary/Last</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<p class="text-sm mb-3">Сборщик Immediate Action предлагает action indicator (<code class="font-mono text-sm">81</code>/<code class="font-mono text-sm">82</code>), структурированный сборщик проактивных команд (REFRESH, DISPLAY TEXT, PLAY TONE с авто-генерацией COMPREHENSION-TLV), или ручной hex-ввод.</p>
|
||
<p class="text-sm mb-3">Строка <strong>C-APDU</strong> начинает в режиме <strong>Hex</strong> (вставьте любую команду) и может переключиться на одно-строчный редактор <strong>SIM RFM</strong>, <strong>USIM RFM</strong> или <strong>RAM/GP</strong>, который собирает команду из полей — итоговый APDU оборачивается в TLV <code class="font-mono text-sm">22</code> и показывается рядом с выбором. GET RESPONSE там не предлагается: расширенный формат не несёт GET RESPONSE (TS 102 226 §5.2.1.1). Кнопка <strong>→ Расширенный скрипт</strong> в представлениях SIM RFM / USIM RFM / RAM-GP добавляет их команды строками C-APDU.</p>
|
||
<p class="text-sm mb-3">Только три проактивные команды допустимы как Immediate Action (TS 102 226 Table 5.5): REFRESH, DISPLAY TEXT и PLAY TONE — поведение карты для любой другой проактивной команды не определено.</p>
|
||
|
||
<h4 id="ber-error-action" class="font-medium mb-2 text-base">Error Action TLV (Tag 82)</h4>
|
||
<p class="text-sm mb-2">Восстановление при ошибках по TS 102 226 §5.2.1.3 — одна из четырёх форм:</p>
|
||
<ul class="text-sm list-disc pl-5 mb-2">
|
||
<li><strong>Проактивная команда:</strong> набор COMPREHENSION-TLV с DISPLAY TEXT или PLAY TONE (в Error Action допустимы только эти две, TS 102 226 Table 5.9)</li>
|
||
<li><strong>Без действия:</strong> <code class="font-mono text-sm">82 00</code></li>
|
||
<li><strong>Ссылка на запись EFRMA:</strong> <code class="font-mono text-sm">82 01 <ref></code> с номером записи <code class="font-mono text-sm">01</code>–<code class="font-mono text-sm">7F</code></li>
|
||
<li><strong>Произвольный hex:</strong> произвольное значение TLV</li>
|
||
</ul>
|
||
|
||
<h4 id="ber-script-chaining" class="font-medium mb-2 text-base">Script Chaining TLV (Tag 83)</h4>
|
||
<p class="text-sm mb-2">Многопакетное выполнение скрипта с сохранением контекста (TS 102 226 §5.2.1.4). TLV имеет вид <code class="font-mono text-sm">83 01 <флаг></code>, присутствует один раз и только как первый Command TLV; допускается для RFM и RAM:</p>
|
||
<ul class="text-sm list-disc pl-5 mb-2">
|
||
<li><code class="font-mono text-sm">01</code> — первый скрипт, удалить информацию цепочки при сбросе карты</li>
|
||
<li><code class="font-mono text-sm">11</code> — первый скрипт, сохранить информацию цепочки при сбросе карты (только RFM)</li>
|
||
<li><code class="font-mono text-sm">02</code> — последующий скрипт, далее будут ещё</li>
|
||
<li><code class="font-mono text-sm">03</code> — последующий скрипт, последний</li>
|
||
</ul>
|
||
<p class="text-sm mb-3">При цепочке сессия команд выходит за рамки одного шаблона: UICC сохраняет контекст файла/PIN (RFM) или сессию приложения (RAM, например цепочку STORE DATA) до последнего скрипта.</p>
|
||
|
||
<h4 id="expanded-response" class="font-medium mb-2 text-base">Декодирование ответов (TS 102 226 §5.2.2)</h4>
|
||
<p class="text-sm mb-2">Входящие ответы Proof of Receipt декодируются сервером — формат expanded Remote Application response data (TS 102 226 §5.2.2) или компактный формат. Представление Secured Packet показывает результат после <strong>Отправить на карту</strong> (см. <a href="#secured-packet" class="text-blue-600 dark:text-blue-400 hover:underline">§3.1</a>): статус PoR (TAR, счётчик, сырой PoR), а статусное слово и данные ответа последней команды подставляются в подвкладку <strong>«Разбор R-APDU»</strong> (Remote APDU → «Разбор»).</p>
|
||
|
||
<h3 id="ram-gp" class="text-lg font-medium mb-2">2.4 RAM/GP</h3>
|
||
<p class="mb-2">CLA = <code class="font-mono text-sm">80</code> (GlobalPlatform Card Specification v2.3.1). Команды удалённого управления приложениями. Строятся тем же сборщиком цепочки, что и SIM/USIM.</p>
|
||
<table class="w-full text-sm mb-3 border-collapse">
|
||
<thead><tr class="border-b border-gray-300 dark:border-slate-700">
|
||
<th class="text-left py-1 px-2">Команда</th><th class="text-left py-1 px-2">INS</th><th class="text-left py-1 px-2">P1</th><th class="text-left py-1 px-2">Описание</th>
|
||
</tr></thead>
|
||
<tbody>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">INSTALL [for load]</td><td class="py-1 px-2 font-mono">E6</td><td class="py-1 px-2 font-mono">02</td><td class="py-1 px-2">Регистрация загружаемого файла</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">INSTALL [for install]</td><td class="py-1 px-2 font-mono">E6</td><td class="py-1 px-2 font-mono">0C</td><td class="py-1 px-2">Установка приложения или SD</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">INSTALL [make selectable]</td><td class="py-1 px-2 font-mono">E6</td><td class="py-1 px-2 font-mono">08</td><td class="py-1 px-2">Сделать приложение выбираемым</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">INSTALL [registry update]</td><td class="py-1 px-2 font-mono">E6</td><td class="py-1 px-2 font-mono">40</td><td class="py-1 px-2">Обновление реестра</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">INSTALL [extradition]</td><td class="py-1 px-2 font-mono">E6</td><td class="py-1 px-2 font-mono">10</td><td class="py-1 px-2">Перемещение между SD</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">LOAD</td><td class="py-1 px-2 font-mono">E8</td><td class="py-1 px-2 font-mono">80</td><td class="py-1 px-2">Загрузка блока кода (P1=80 последний блок, номер блока в P2)</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">DELETE</td><td class="py-1 px-2 font-mono">E4</td><td class="py-1 px-2 font-mono">00</td><td class="py-1 px-2">Удаление приложения или SD (P2=00 только AID / 80 AID + связанные объекты)</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">GET STATUS</td><td class="py-1 px-2 font-mono">F2</td><td class="py-1 px-2 font-mono">80/40/20/10</td><td class="py-1 px-2">Статус карты</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">GET DATA</td><td class="py-1 px-2 font-mono">CA</td><td class="py-1 px-2 font-mono">tag</td><td class="py-1 px-2">Чтение объектов данных</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">STORE DATA</td><td class="py-1 px-2 font-mono">E2</td><td class="py-1 px-2 font-mono">00/40/80/C0/E0</td><td class="py-1 px-2">Запись данных</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">SET STATUS</td><td class="py-1 px-2 font-mono">F0</td><td class="py-1 px-2 font-mono">80/40/60</td><td class="py-1 px-2">Управление жизненным циклом</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">PUT KEY</td><td class="py-1 px-2 font-mono">D0</td><td class="py-1 px-2 font-mono">key ver</td><td class="py-1 px-2">Замена ключа: P1 = версия ключа, P2 = идентификатор ключа, данные = новый ключевой материал (GP Card Spec §11.8)</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">PUSH</td><td class="py-1 px-2 font-mono">EC</td><td class="py-1 px-2 font-mono">01</td><td class="py-1 px-2">Просьба приложению открыть BIP-канал / CAT_TP-соединение / TCP-соединение или отправить пакет идентификации (TS 102 226 §9)</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">EXTERNAL AUTHENTICATE</td><td class="py-1 px-2 font-mono">82</td><td class="py-1 px-2 font-mono">00</td><td class="py-1 px-2">Аутентификация SCP</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">INTERNAL AUTHENTICATE</td><td class="py-1 px-2 font-mono">88</td><td class="py-1 px-2 font-mono">00</td><td class="py-1 px-2">Challenge-response</td></tr>
|
||
<tr><td class="py-1 px-2 font-mono">GET RESPONSE</td><td class="py-1 px-2 font-mono">C0</td><td class="py-1 px-2 font-mono">00</td><td class="py-1 px-2">Получение данных после <code class="font-mono text-sm">61XX</code> (Le настраивается)</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<h4 id="ram-privileges" class="font-medium mb-1">Привилегии (INSTALL [for install])</h4>
|
||
<p class="text-sm mb-2">Три байта привилегий (таблицы 11-7/8/9 спецификации GP), кодируются как length-value поле внутри данных INSTALL:</p>
|
||
<table class="w-full text-sm mb-3 border-collapse">
|
||
<thead><tr class="border-b border-gray-300 dark:border-slate-700">
|
||
<th class="text-left py-1 px-2">Бит</th><th class="text-left py-1 px-2">Байт 1</th><th class="text-left py-1 px-2">Байт 2</th><th class="text-left py-1 px-2">Байт 3</th>
|
||
</tr></thead>
|
||
<tbody>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">b8</td><td class="py-1 px-2">Security Domain</td><td class="py-1 px-2">Trusted Path</td><td class="py-1 px-2">Receipt Generation</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">b7</td><td class="py-1 px-2">DAP Verification</td><td class="py-1 px-2">Authorized Management</td><td class="py-1 px-2"></td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">b6</td><td class="py-1 px-2">Delegated Management</td><td class="py-1 px-2">Token Verification</td><td class="py-1 px-2"></td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">b5</td><td class="py-1 px-2">Card Lock</td><td class="py-1 px-2">Global Delete</td><td class="py-1 px-2"></td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">b4</td><td class="py-1 px-2">Card Terminate</td><td class="py-1 px-2">Global Lock</td><td class="py-1 px-2"></td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">b3</td><td class="py-1 px-2">Card Reset</td><td class="py-1 px-2">Global Registry</td><td class="py-1 px-2"></td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">b2</td><td class="py-1 px-2">CVM Management</td><td class="py-1 px-2">Final Application</td><td class="py-1 px-2"></td></tr>
|
||
<tr><td class="py-1 px-2 font-mono">b1</td><td class="py-1 px-2">Mandated DAP Verification</td><td class="py-1 px-2"></td><td class="py-1 px-2"></td></tr>
|
||
</tbody>
|
||
</table>
|
||
<h4 id="ram-msl" class="font-medium mb-1">MSL (Minimum Security Level) — байт SPI1 по TS 102 225</h4>
|
||
<table class="w-full text-sm mb-3 border-collapse">
|
||
<thead><tr class="border-b border-gray-300 dark:border-slate-700"><th class="text-left py-1 px-2">Значение</th><th class="text-left py-1 px-2">Описание</th></tr></thead>
|
||
<tbody>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">00</td><td class="py-1 px-2">Нет проверки</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">11</td><td class="py-1 px-2">RC/CC/DS</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">12</td><td class="py-1 px-2">RC/DS/CC</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">15</td><td class="py-1 px-2">RC/DS/CC + MAC</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">16</td><td class="py-1 px-2">RC/DS/CC + MAC + Cipher</td></tr>
|
||
<tr><td class="py-1 px-2 font-mono">19</td><td class="py-1 px-2">RC/DS/CC + MAC + Cipher + DS</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<p class="text-sm mb-3">Полные таблицы GET STATUS P1/P2, тегов GET DATA, DELETE P1, STORE DATA P1 и SET STATUS см. в GlobalPlatform v2.3.1 и ETSI TS 102 226 §8.2.1.3.2.</p>
|
||
<p class="text-sm mb-3"><strong>PUSH</strong> (TS 102 226 §9.2) — это C-APDU (<code class="font-mono text-sm">80 EC 01 P2</code>), адресованный приложению, поддерживающему BIP и/или CAT_TP (не триггер HTTP-администрирования — тот собирается в конструкторе HTTP OTA выше). P2: <code class="font-mono text-sm">01</code> открытие BIP-канала (COMPREHENSION-TLV OPEN CHANNEL, необязательно), <code class="font-mono text-sm">02</code> CAT_TP-соединение (порт назначения в transport level <code class="font-mono text-sm">3C</code> с типом протокола 00, необязательные buffer size <code class="font-mono text-sm">39</code> / channel data <code class="font-mono text-sm">36</code>), <code class="font-mono text-sm">03</code> TCP-соединение (bearer <code class="font-mono text-sm">35</code>, transport level <code class="font-mono text-sm">3C</code> с типом протокола 02 = TCP-клиент, удалённое соединение, адрес назначения <code class="font-mono text-sm">3E</code>, NAA/APN <code class="font-mono text-sm">47</code>), <code class="font-mono text-sm">04</code> пакет идентификации (channel data <code class="font-mono text-sm">36</code>; при отсутствии используется ICCID). Проактивную команду OPEN CHANNEL выдаёт само приложение; успех — <code class="font-mono text-sm">90 00</code>, отказ — <code class="font-mono text-sm">6F 00</code> с Result TLV в данных ответа, некорректные данные отклоняются с <code class="font-mono text-sm">6A 80</code>. P1 <code class="font-mono text-sm">80</code> зарезервирован для приложения.</p>
|
||
|
||
<h3 id="conversion" class="text-lg font-medium mb-2">2.5 Конвертация (боковые панели SIM/USIM)</h3>
|
||
<ul class="list-disc list-inside text-sm space-y-1">
|
||
<li><strong>IMSI → EF.IMSI</strong> — 15-значный IMSI в 9-байтный формат (TS 31.102 §4.2.3).</li>
|
||
<li><strong>MSISDN → BCD</strong> — удалить <code class="font-mono text-sm">+</code>, дополнить нечётную длину символом <code class="font-mono text-sm">f</code>, поменять полубайты.</li>
|
||
<li><strong>ICCID → hex</strong> — поменять полубайты строки ICCID.</li>
|
||
<li><strong>Provider Name → SPN</strong> — GSM 7-bit packed, UCS2 non-BMP или UCS2 BMP (TS 31.102 §4.2.5, TS 23.038).</li>
|
||
<li><strong>PLMN → EF_PLMNsel / PLMNwAcT</strong> — 3-байтный BCD + опциональный селектор технологии доступа.</li>
|
||
<li><strong>Nibble swap</strong> — поменять пары полубайтов hex-строки чётной длины.</li>
|
||
</ul>
|
||
|
||
<h3 id="c-apdu-parser" class="text-lg font-medium mb-2">2.6 Разбор C-APDU</h3>
|
||
<p class="text-sm mb-3">Вставка raw APDU hex и отображение сворачиваемого дерева. Автоматически определяет контейнер: <strong>Expanded Script</strong> (начало <code class="font-mono text-sm">AA</code> или <code class="font-mono text-sm">AE80</code>, декодируется по ETSI TS 102 226 §5.2.1) или <strong>Compact C-APDU chain</strong> (последовательность C-APDU ISO 7816). Каждый узел показывает метку, hex и краткое описание; родительские узлы раскрываются в подэлементы. <strong>«Разбор C-APDU»</strong> и <strong>«Разбор R-APDU»</strong> — две подвкладки раздела <strong>«Разбор»</strong>.</p>
|
||
|
||
<h3 id="push-commands" class="text-lg font-medium mb-2">2.7 Пуш/триггер</h3>
|
||
<p class="text-sm mb-3">Объединяет команды, заставляющие карту выйти в сеть. Три подвкладки переключают формы — <strong>«HTTP OTA Триггер (Push SMS)»</strong>, <strong>«HTTP OTA Store (параметры SD)»</strong> и <strong>«Триггер канала/линка»</strong> — показывается только выбранная форма; обе формы GP используют один набор полей — выбранный режим переключает заголовок формы и её собственные строки (тег параметров SD в Store, Command Scripting template в Trigger) и соответствующую обёртку payload’а. Они из разных спецификаций и доставляются по-разному: триггер администрирования это TLV-сообщение для Security Domain (HTTP OTA), а PUSH §9 это C-APDU (<code class="font-mono text-sm">80 EC 01 P2</code>) для приложения с поддержкой BIP и/или CAT_TP.</p>
|
||
|
||
<h4 id="http-ota" class="font-medium mb-1">Сессия администрирования (HTTP OTA)</h4>
|
||
<p class="text-sm mb-3">Сборка payload’ов Remote Application Management over HTTP по GlobalPlatform <strong>GPC v2.2 Amendment B v1.1</strong> (§4.7). Два режима:</p>
|
||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||
<li><strong>Триггер (Push SMS)</strong> — параметры запуска административной сессии (<code class="font-mono text-sm">81 > 83 > 84/[85]/[86]/89</code>, таблица 4-3). Сообщение, которое просит Security Domain карты исходящим запросом начать HTTP-сессию.</li>
|
||
<li><strong>Store (параметры SD)</strong> — записывает те же параметры как данные карты (параметры Security Domain) командой <strong>STORE DATA в TLV-режиме</strong> (<code class="font-mono text-sm">80 E2 90 00</code>, P1=90 = последний блок + без шифрования + BER-TLV по GP Card Spec v2.3.1 §11.11; данные длиннее короткого APDU разбиваются на цепочку блоков с P1.b8=0), обёрнутые в тег <code class="font-mono text-sm">85</code> по таблице 4-4 (<code class="font-mono text-sm">A5</code> — непроверенный вариант).</li>
|
||
</ul>
|
||
<p class="text-sm mb-2">Разделы соответствуют таблицам спецификации:</p>
|
||
<table class="w-full text-sm mb-3 border-collapse">
|
||
<thead><tr class="border-b border-gray-300 dark:border-slate-700"><th class="text-left py-1 px-2">Раздел</th><th class="text-left py-1 px-2">Tag</th><th class="text-left py-1 px-2">Содержимое</th></tr></thead>
|
||
<tbody>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">Параметры соединения</td><td class="py-1 px-2 font-mono">84</td><td class="py-1 px-2">Любые COMPREHENSION-TLV для открытия TCP-соединения (OPEN CHANNEL по TS 102 223): Device Identities <code class="font-mono text-sm">82</code>, Alpha <code class="font-mono text-sm">05</code>, Command details <code class="font-mono text-sm">81</code>, Bearer <code class="font-mono text-sm">35</code> (<code class="font-mono text-sm">03</code> = bearer по умолчанию), вендорские TLV. Редактор строк + пресеты, редактируемый hex.</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">Параметры безопасности</td><td class="py-1 px-2 font-mono">85</td><td class="py-1 px-2">Таблица 4-6: LV PSK Identity (текст), LV Key version/KID. Идентифицирует ключ PSK TLS (RFC 4279).</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">Политика повтора</td><td class="py-1 px-2 font-mono">86</td><td class="py-1 px-2">Таблица 4-7: счётчик повторов (2 байта, напр. <code class="font-mono text-sm">0003</code>), задержка повторной попытки как timer TLV из TS 102 223 (<code class="font-mono text-sm">25 03 HH MM SS</code>) с полями в полуоктетном порядке TP-SCTS (TS 23.040 §9.1.2.3): <code class="font-mono text-sm">00 10 00</code> = 1 мин, <code class="font-mono text-sm">00 00 02</code> = 20 с; опциональный TLV отчёта о сбое.</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">HTTP POST</td><td class="py-1 px-2 font-mono">89</td><td class="py-1 px-2">Таблицы 4-8/9/10: Host-заголовок (<code class="font-mono text-sm">8A</code>), X-Admin-From agent ID (<code class="font-mono text-sm">8B</code>), URI (<code class="font-mono text-sm">8C</code>) — текст преобразуется в октеты.</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<p class="text-sm mb-2">Флажок <strong>Обёртка в Command Scripting template ('AA')</strong> оборачивает всю команду <code class="font-mono text-sm">81</code> в формат Expanded Remote Application data с определённой длиной (<code class="font-mono text-sm">AA</code>, ETSI TS 102 226 §5.2.1) для TAR-ов, обрабатывающих расширенный формат (RAM-over-HTTP §4.7).</p>
|
||
<p class="text-sm mb-2"><strong>Упаковать в Secured packet</strong> отправляет готовый payload на вкладку SCP80 для заполнения SPI/счётчика — там укажите TAR, который слушает SD (обычно TAR OTASD).</p>
|
||
|
||
<h4 id="push-ts102226" class="font-medium mb-1 mt-3">PUSH по TS 102 226 §9</h4>
|
||
<p class="text-sm mb-2">Подвкладка <strong>«Триггер канала/линка»</strong> собирает запросы §9 тем же кодировщиком, что и строка <strong>PUSH</strong> в цепочке RAM/GP, показывает предпросмотр C-APDU, и предлагает <strong>«Упаковать в Secured packet»</strong> (TAR остаётся ручным: запрос адресован целевому приложению, а не Security Domain, и введённый TAR сохраняется при отправке) и <strong>→ Расширенный скрипт</strong> (оборачивает каждый APDU в Command TLV <code class="font-mono text-sm">22</code> и добавляет их в конструктор Expanded Script).</p>
|
||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||
<li><strong>Открытие BIP-канала</strong> (<code class="font-mono text-sm">01</code>) — собирается в режиме <strong>Fields</strong> из самых употребительных параметров OPEN CHANNEL (Stepping Stones §18.6.1): описание bearer, транспортный протокол (UDP или TCP, клиент UICC, удалённое соединение — только эти значения допускает команда) с портом назначения, адрес назначения, NAA/APN, размер буфера и alpha (флажок <em>прозрачный режим</em> отправляет нулевой alpha, т.е. без подтверждения пользователя); логин/пароль и остальное — в поле дополнительных TLV. <strong>Локальный адрес не отправляется никогда</strong> (§9.2.1 и руководство это запрещают). Режим <strong>Hex</strong> принимает сырые COMPREHENSION-TLV. Проактивную команду OPEN CHANNEL выдаёт само приложение (§9.1.1). SIMalliance Stepping Stones R7 §18.6 рекомендует отправлять его <strong>вместе с CAT_TP-запросом в одном сообщении</strong> (параметры канала — в <code class="font-mono text-sm">01</code>, порт CAT_TP — в <code class="font-mono text-sm">02</code>), поэтому в форме есть флажок <em>«Также запросить установление соединения CAT_TP (02)»</em>; пара передаётся одним скриптом команд (конкатенированные SMS, если больше 140 октетов).</li>
|
||
<li><strong>Установление соединения CAT_TP</strong> (<code class="font-mono text-sm">02</code>) — порт назначения в transport level <code class="font-mono text-sm">3C</code> с типом протокола 00 (обязателен), необязательные buffer size <code class="font-mono text-sm">39</code> / данные идентификации <code class="font-mono text-sm">36</code>. Отдельно он полагается на предустановленные на карте умолчания канала/CAT_TP, против чего предостерегает руководство Stepping Stones; предпочтительна пара выше.</li>
|
||
<li><strong>TCP-соединение</strong> (<code class="font-mono text-sm">03</code>) — bearer <code class="font-mono text-sm">35</code>, transport level <code class="font-mono text-sm">3C</code> с типом протокола 02 = TCP-клиент, удалённое соединение, адрес назначения <code class="font-mono text-sm">3E</code> (<code class="font-mono text-sm">21</code> IPv4 / <code class="font-mono text-sm">57</code> IPv6 / <code class="font-mono text-sm">F0</code> FQDN), NAA/APN <code class="font-mono text-sm">47</code>; порт и адрес обязательны. Это параметры OPEN CHANNEL для TCP, и они обязательны в запросе, поэтому <code class="font-mono text-sm">03</code> <strong>самодостаточен</strong> — сопутствующий <code class="font-mono text-sm">01</code> не нужен. Соединение устанавливается через BIP или, если карта и терминал это поддерживают, через прямое IP-соединение (TS 102 483).</li>
|
||
<li><strong>Пакет идентификации</strong> (<code class="font-mono text-sm">04</code>) не является триггером: он предполагает уже открытый TCP-канал и имеет смысл только как продолжение в том же сообщении, поэтому у TCP-запроса есть флажок <em>«Также отправить пакет идентификации (04)»</em>, добавляющий его (данные необязательны; при пустом значении используется ICCID). <code class="font-mono text-sm">04</code> также остаётся доступным в строке PUSH цепочки RAM/GP для сценариев.</li>
|
||
<li><strong>PoR</strong> — Stepping Stones R7 §18.6.3 рекомендует <em>не</em> запрашивать PoR при успешной отправке (это может помешать обмену ME–карта); запрашивайте его только для разбора сбоя, в режиме SMS-SUBMIT (бит SPI2 <code class="font-mono text-sm">0x20</code> в SCP80).</li>
|
||
</ul>
|
||
|
||
|
||
|
||
<h3 id="response-parser" class="text-lg font-medium mb-2">2.8 «Разбор R-APDU»</h3>
|
||
<p class="mb-3">Декодирует raw-ответ команды: выберите отправленную команду, введите SW (например, <code class="font-mono text-sm">9000</code>) и hex данных ответа, затем нажмите <strong>Декодировать</strong>. Поля также автоматически заполняются статусным словом и данными ответа последней команды после успешного нажатия <strong>Отправить на карту</strong> (см. <a href="#secured-packet" class="text-blue-600 dark:text-blue-400 hover:underline">§3.1</a>).</p>
|
||
<ul class="list-disc list-inside text-sm space-y-1">
|
||
<li><strong>Команда</strong> — группа SIM/USIM (SELECT, STATUS, READ/UPDATE, PIN-операции, CAT-команды типа TERMINAL PROFILE/ENVELOPE/FETCH/TERMINAL RESPONSE, MANAGE CHANNEL, …) или группа RAM/GP (INSTALL, LOAD, DELETE, GET/STORE DATA, auth, SCP-команды).</li>
|
||
<li><strong>Декодирование SW</strong> — статусные слова разрешаются по generic-, UICC- (TS 102 221) и GlobalPlatform-таблицам, контекст определяется автоматически.</li>
|
||
<li><strong>Декодирование привилегий</strong> — ответы GET DATA / INSTALL декодируют байты привилегий в читаемые флаги.</li>
|
||
<li><strong>Данные ответа</strong> — raw hex отображается и интерпретируется согласно команде (например, FCP-шаблоны SELECT).</li>
|
||
<li><strong>Имена AID</strong> — теги с AID (<code class="font-mono text-sm">4F</code>, <code class="font-mono text-sm">84</code>, <code class="font-mono text-sm">C4</code>, <code class="font-mono text-sm">CC</code>) дополняются именем стандартного библиотечного пакета, когда AID — известный пакет JavaCard / ETSI / 3GPP / GlobalPlatform (или подсказкой по RID).</li>
|
||
</ul>
|
||
|
||
|
||
</section>
|
||
<section class="mb-10">
|
||
<h2 id="scp80" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">3. Вкладка SCP80</h2>
|
||
<p class="mb-3">Верхнеуровневая вкладка <strong>SCP80</strong> объединяет разделы, связанные с SCP80. Переключение — тремя переключателями: <strong>Secured Packet</strong>, <strong>RAM</strong> и <strong>TAR-сканер</strong>. Собирает защищённые пакеты SCP80 по ETSI TS 102 225. При подключении карты сервер читает её <strong>EF.ICCID</strong> (2FE2); если в пресете указан тот же номер (цифрами или сырым hex из EF), он автоматически выбирается во всех трёх представлениях SCP80. Вердикт <strong>низкого счётчика</strong> (<code class="font-mono text-sm">cntr_low</code> или предупреждающий ответ ENVELOPE, в котором всё ещё есть такой PoR) <em>не</em> исправляется повторной отправкой: любая операция SCP80/RAM немедленно останавливается. Карта не сообщает свой счётчик (поле CNTR в PoR — копия счётчика пакета), поэтому в уведомлении есть ограниченный пробник <strong>«Синхронизировать счётчик»</strong> — read-only команда с возрастающими значениями счётчика (шаг удваивается, потолок 32 бита, не более 40 пакетов), пока карта не примет одно; затем сохраняется принятое+1 (поиск, остановленный вердиктом безопасности после отказа по счётчику, тоже сохраняет значение — с янтарным предупреждением проверить настройки безопасности) — и кнопка <strong>К пресету</strong> для ручного повышения; больше ничего автоматически не записывается.</p>
|
||
|
||
<h3 id="secured-packet" class="text-lg font-medium mb-2">3.1 Secured Packet</h3>
|
||
<p class="mb-2">Собирает защищённые пакеты SCP80 по ETSI TS 102 225. Селектор <strong>Keyset</strong> рядом с выбором пресета указывает, из какого keyset берутся ключи и счётчик; отправка отклоняется, если в пресете нет такого номера keyset или KIc/KID несут разные номера (TS 102 225 A.2). Селектор недоступен, пока не выбран пресет карты. Кнопка запуска недоступна, пока не выбран пресет карты и один из его keysets. Поле TAR предлагает записи TAR пресета (с описанием и MSL); при применении пресета TAR операции подставляется, а SPI1 берётся из его <strong>MSL</strong> (минимальный SPI1, TS 102 226 §8.2.1.3.2.4 — карта проверяет его до обработки защиты и отвечает <code class="font-mono text-sm">0A</code>, если SPI1 пакета ниже). Значение ниже MSL показывает жёлтое предупреждение под формой; введённый вручную TAR сохраняет SPI1 оператора. Поле <strong>Счётчик</strong> — это переопределение: оно пустое, а следующий счётчик пресета показывается подсказкой (placeholder) — пустое поле позволяет серверу взять счётчик из хранилища и сохранить принятое картой значение; введённое значение используется только для этой отправки и никогда не записывается в пресет, а меньшее значение не откатывает сохранённый счётчик (сохраняются только движения вперёд).</p>
|
||
<h4 id="packet-structure" class="font-medium mb-1">Структура пакета</h4>
|
||
<table class="w-full text-sm mb-3 border-collapse">
|
||
<thead><tr class="border-b border-gray-300 dark:border-slate-700"><th class="text-left py-1 px-2">Поле</th><th class="text-left py-1 px-2">Размер</th><th class="text-left py-1 px-2">Описание</th></tr></thead>
|
||
<tbody>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">CPI</td><td class="py-1 px-2">1</td><td class="py-1 px-2">Command Packet Identifier (02)</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">CPL</td><td class="py-1 px-2">2 (SMS)</td><td class="py-1 px-2">Длина командного пакета (CHL..конец, включая padding)</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">CHI</td><td class="py-1 px-2">1</td><td class="py-1 px-2">Command Header Identifier (01)</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">CHL</td><td class="py-1 px-2">1</td><td class="py-1 px-2">Command Header Length</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">SPI</td><td class="py-1 px-2">2</td><td class="py-1 px-2">Security Parameter Indicator</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">KIc</td><td class="py-1 px-2">1</td><td class="py-1 px-2">Key Identifier для шифрования</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">KID</td><td class="py-1 px-2">1</td><td class="py-1 px-2">Key Identifier для MAC</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">TAR</td><td class="py-1 px-2">3</td><td class="py-1 px-2">Toolkit Application Reference</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">CNTR</td><td class="py-1 px-2">5</td><td class="py-1 px-2">Счётчик повторов</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">PCNTR</td><td class="py-1 px-2">1</td><td class="py-1 px-2">Padding counter</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">RC/CC/DS</td><td class="py-1 px-2">4–8</td><td class="py-1 px-2">CRC (CRC-32) / контрольная сумма (MAC) / цифровая подпись</td></tr>
|
||
<tr><td class="py-1 px-2 font-mono">Secured Data</td><td class="py-1 px-2">пер.</td><td class="py-1 px-2">APDU (с шифрованием при необходимости)</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<h4 id="packet-crypto" class="font-medium mb-1">Крипто</h4>
|
||
<ul class="list-disc list-inside text-sm space-y-1">
|
||
<li><strong>3DES-CBC</strong> шифрование (нулевой ICV), ключи 8/16/24 байта — устарело с Rel-18, но поддерживается для обратной совместимости</li>
|
||
<li><strong>AES-CBC</strong> шифрование (нулевой ICV, дополнение нулями до 16), ключи 16/24/32 байта (TS 102 225 §5.1.2, KIc <code class="font-mono text-sm">x2</code>)</li>
|
||
<li><strong>Retail MAC</strong> (ISO 9797-1, MAC algorithm 3) для контрольной суммы DES/3DES</li>
|
||
<li><strong>AES-CMAC</strong> (NIST SP 800-38B, усечённый до 8 октетов) для контрольной суммы AES (TS 102 225 §5.1.3.1, KID <code class="font-mono text-sm">x2</code>)</li>
|
||
<li><strong>Redundancy Check (RC)</strong> — CRC-32 по тому же кадру заголовка, что и CC (TS 102 225 §5.1.3.2; ключ не нужен, SPI1 b2b1 = <code class="font-mono text-sm">01</code>). Реализована только CRC-32 (как в pySim); кодирование CRC-16 по KID не поддерживается.</li>
|
||
<li>AES требует счётчик с защитой от повтора: биты SPI1 b5 b4 должны быть <code class="font-mono text-sm">10</code> (счётчик больше) или <code class="font-mono text-sm">11</code> (счётчик +1) согласно TS 102 225 §5.1.2/§5.1.3.1</li>
|
||
<li>Байт паддинга настраивается (<code class="font-mono text-sm">00</code> по умолчанию или <code class="font-mono text-sm">FF</code>)</li>
|
||
</ul>
|
||
<p class="text-sm mb-3">Кнопка <strong>Проверить в pySim</strong> сверяет собранный пакет с эталонной реализацией <code class="font-mono text-sm">OtaDialectSms.encode_cmd</code>. Кнопка <strong>Отправить на карту</strong> доставляет пакет через ENVELOPE SMS-PP-DOWNLOAD (при подключении к серверу). 2-байтовый префикс CPL передаётся, когда пакет зашифрован или несёт RC/CC/DS (входит в их входные данные), а также при конкатенации SMS; одиночное незащищённое SMS сохраняет форму pySim, начинающуюся с CHL (TS 31.115 Table 1 NOTE). Под полем пакета показывается его размер и число SMS; пакет, не помещающийся в одно SMS, отправляется <strong>конкатенированной</strong> загрузкой (TS 31.115 §4.3) — пакет делится на части SMS-пользовательских данных (первое SMS 132 октета, последующие по 134; первое дополнительно несёт информационные элементы конкатенации и CPI), и сегменты отправляются по порядку. Более 5 сегментов отклоняется: это практический предел буфера конкатенации карты. Полученный Proof of Receipt декодируется и показывается строкой статуса PoR (статус, TAR, счётчик, сырой PoR); статусное слово и данные ответа последней команды подставляются в подвкладку <strong>«Разбор R-APDU»</strong> (Remote APDU → «Разбор»), а успешный PoR увеличивает счётчик повторов (когда в SPI1 есть проверка счётчика — b5 b4 ≠ 00; без неё счётчик не увеличивается и не сохраняется) и очищает пакет — сервер сохраняет принятый счётчик в пресет, а поле счётчика остаётся пустым (подсказка следует за сохранённым значением), если оператор не ввёл переопределение.</p>
|
||
|
||
<h3 id="ram" class="text-lg font-medium mb-2">3.2 RAM</h3>
|
||
<p class="mb-2">Выполняет операции удалённого управления приложениями (Remote Application Management) как защищённые пакеты SCP80 через SMS-PP-DOWNLOAD ENVELOPE. Карта должна поддерживать SCP03 (AES или 3DES). Пресет карты со вкладки <strong>Карты</strong> обеспечивает ключи, таблицу TAR и счётчик (RAM использует <strong>ISD TAR</strong> пресета, по умолчанию <code class="font-mono text-sm">000000</code>; SPI1 берётся из MSL этого TAR). Селектор <strong>Keyset</strong> рядом с выбором пресета указывает, из какого keyset берутся ключи и счётчик операции. Селектор недоступен, пока не выбран пресет карты. Кнопка запуска недоступна, пока не выбран пресет карты и один из его keysets. Селектор <strong>Формат</strong> фиксирует формат удалённой команды: <strong>Авто (определение)</strong> опрашивает read-only команду GET STATUS в компактном виде и в обоих expanded-кодированиях и оставляет первое, которое карта выполнила; <strong>Компактный</strong> отправляет голую C-APDU; <strong>Expanded (AA, определённая длина)</strong> / <strong>Expanded (AE 80, неопределённая длина)</strong> заворачивают её в шаблон Command Scripting из TS 102 226 §5.2.1 (на живой карте выполняются обе; шаблон, у которого заявленная длина не совпадает с телом, получает Bad format TLV — операция показывает это как ошибку шага). Запросы листингов и реестра следуют этому формату: компактные листинги несут сцепленный GET RESPONSE, а expanded-прогон отправляет те же запросы P2=00 обёрнутыми и без цепочки (форма эталонного загрузчика TCA; Le=’00’ возвращает листинг сразу), и запрос реестра, отклонённый картой в текущем формате, повторяется в остальных — отчёт называет тот, который сработал. Страница следующего вхождения (<code class="font-mono text-sm">P2=03</code>), отклонённая форматом, тоже повторяется в остальных форматах — сначала expanded-кодирования (первым то, что обслужило предыдущую страницу, если оно expanded), компактная командная строка последней: компактная попытка страницы может израсходовать страницу, не доставив её (карта отвечает <code class="font-mono text-sm">61xx</code>, а сцепленный GET RESPONSE отклоняется — все последующие форматы видят вхождение уже использованным) — некоторые карты отдают expanded-страницу только в шаблоне <code class="font-mono text-sm">AA</code> — и пометка <code class="font-mono text-sm">(только первая страница)</code> ставится, только если карта обещала продолжение (<code class="font-mono text-sm">6310</code>), а ни один формат не смог его получить; в режиме <strong>Авто</strong> проводник также опрашивает по AID записи, оставшиеся без деталей (несколько дополнительных пакетов). Блок ресурсов карты также называет предполагаемый <strong>релиз ETSI</strong> карты (версия <code class="font-mono text-sm">uicc.toolkit</code> → REL-N, то же сопоставление, что и в анализе CAP; показывается, только если расширенный реестр вернул версии). Пакет, чей собственный листинг не несёт версии, берёт её у своего экземпляра апплета, если он есть — модульные AID пакета это AID экземпляров апплета, и строка получает соответствующую пометку — так что карта, отклоняющая все формы со списком тегов, всё равно показывает версии пакетов везде, где есть экземпляр апплета.</p>
|
||
|
||
<h4 id="ram-operations" class="font-medium mb-1">Операции</h4>
|
||
<table class="w-full text-sm mb-3 border-collapse">
|
||
<thead><tr class="border-b border-gray-300 dark:border-slate-700"><th class="text-left py-1 px-2">Операция</th><th class="text-left py-1 px-2">Описание</th></tr></thead>
|
||
<tbody>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">Обзор карты (все данные GP)</td><td class="py-1 px-2">Запрос GET STATUS для ISD, приложений, ELF и модулей ELF, а также GET DATA FF21 (расширенные ресурсы карты: число установленных приложений и свободная энергонезависимая/энергозависимая память). Компактный листинг содержит только AID, состояние жизненного цикла и привилегии (версии в устаревшем формате нет); если карта отвергает его (<code class="font-mono text-sm">P2.b2=0</code>, устаревший по GP), запросы повторяются в расширенном формате <code class="font-mono text-sm">E3</code>, а флажок <strong>Запрашивать расширенные данные реестра (связи load-файла и SD)</strong> дополнительно запрашивает их и объединяет расширенные поля: версию исполняемого load-файла, AID load-файла, AID Security Domain, списки модулей, пункты меню STK апплета (SCP Registry Data, TS 102 226 8.2.1.6) и любые другие объекты реестра, которые вернула карта (показываются как есть, без потерь) — он стоит несколько дополнительных защищённых пакетов на каждый обзор и <strong>включён по умолчанию</strong> (запоминается в браузере; снимите флажок, чтобы пропустить). Карты различаются в том, что принимают, поэтому расширенный запрос пробуется в трёх формах — эталонный список тегов (с <code class="font-mono text-sm">EA</code> по TS 102 226), тот же список без <code class="font-mono text-sm">EA</code> и вовсе без списка тегов (форма GlobalPlatformPro) — а обзор сообщает, какая форма сработала и где выполнен откат к компактному списку (версии пакетов тогда недоступны). Если строки ELF всё ещё без версий, формы со списком тегов повторяются для обоих P1=10 и P1=20, пропуская уже отклонённые комбинации, и обход останавливается, как только версия найдена. Результаты отображаются в обзоре (строка успеха минимальна, счётчики — в заголовках разделов) с кнопками <strong>Удалить</strong> для каждого элемента и определённым форматом команд RAM (подсказка при наведении объясняет compact и expanded).</td></tr>
|
||
<tr><td class="py-1 px-2">Установка пакета (.cap файл)</td><td class="py-1 px-2">Отправка <code class="font-mono text-sm">.cap</code> файла на карту через сервер: INSTALL[for load] → LOAD ×N → INSTALL[for install (+make selectable)]. Load-файл делится на LOAD APDU размера <strong>размер блока LOAD</strong> (1–240 байт полезной нагрузки, по умолчанию 240); каждый защищённый пакет доставляется одним SMS или, если он больше, конкатенированной SMS-PP загрузкой до 5 сегментов, так что большой <code>.cap</code> просто занимает несколько SMS. Сразу после выбора файл проверяется и в форме показывается <strong>оценка требований к памяти</strong>: <strong>требование NVRAM</strong> (образ кода + постоянные данные, сумма в стиле C6+C8 из GP Card Spec) и оценка RAM. Там же показаны <strong>библиотеки, с которыми слинкован CAP</strong> (его компонент Import: имя библиотеки, AID и минимальная версия <code class="font-mono text-sm">≥ x.y</code> — имена стандартных библиотек и семейства подставляются, а где известно, даётся подсказка о версии Java Card), идентификаторы пакета и апплетов и разбивка по компонентам (размеры и доли в порядке load-файла) — всё сгруппировано по разделам <strong>Package</strong>, <strong>Requires</strong>, <strong>Memory</strong> и <strong>Components</strong>. Строка <strong>Platform</strong> показывает минимальный уровень Java Card, который должна предоставить карта (выводится из импорта <code class="font-mono text-sm">javacard.framework</code>; флаг <code class="font-mono text-sm">int</code> в заголовке дополнительно требует поддержки int — Java Card 2.2+), и <strong>релиз ETSI</strong>, из которого пришли импорты UICC API (версия <code class="font-mono text-sm">uicc.toolkit</code> → REL-N по корпусу <code class="font-mono text-sm">sim-tools</code> в рабочем каталоге; основание показано в скобках): JCRE проверяет каждый импорт по своим пакетам при верификации load-файла (JC VM spec 4.5.2), поэтому карта со старой платформой отклоняет LOAD сразу после завершения компонента <strong>Import</strong> (в строке шага виден remote SW карты и компонент, который завершил блок, например <em>завершает Import</em>) — меньший размер блока LOAD помогает только если блок превышает буфер карты. Повреждённый файл не проходит анализ, и <strong>Execute</strong> остаётся недоступной до успешного анализа. Оценка носит справочный характер и никогда не используется при установке: NVRAM — это образ кода плюс постоянные данные (сумма в стиле C6+C8 по GP Table 11-48; управление памятью карты, округление и запись в реестре не учитываются, а образ статических полей входит в обе части); рекомендуемый <strong>C6</strong> следует за load-файлом, а рекомендуемые квоты — это десятичные значения в байтах (шестнадцатеричное значение в скобках — это кодирование параметров установки C7/C8: C6 — энергонезависимый код, C7 — энергозависимая RAM, C8 — энергонезависимые данные).</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">Проверка совместимости CAP</td><td class="py-1 px-2">Отвечает на один вопрос, ничего не устанавливая: <strong>может ли эта карта удовлетворить список импортов CAP?</strong> Сервер выполняет проверку формата, INSTALL[for load] и блоки LOAD только до блока, завершающего компонент <strong>Import</strong> — именно там JCRE проверяет список импортов — и останавливается: без флага последнего блока и без INSTALL[for install], поэтому ничего не фиксируется и удалять после этого ничего не нужно. Список <strong>«Версии импортов для проверки»</strong> предзаполняется из анализа CAP: <code class="font-mono text-sm">AID=version</code> переписывает запрошенную версию импорта, <code class="font-mono text-sm">+AID=version</code> добавляет синтетический импорт (запрос возможностей карты: LOAD проходит, только если карта экспортирует этот пакет версии ≥ указанной), а <strong>«Все 0.0»</strong> снимает все требования. Использование в два шага: нажмите «Все 0.0» — если проверка проходит, причиной был список импортов; затем возвращайте по одной строке, чтобы найти пакет и версию, которых не хватает карте. Вердикт явно указывает, что проверяется только <strong>этап LOAD/импортов</strong>: этап связывания (наличие реально вызываемых API) проверяет настоящая установка на INSTALL[for install]. Запуск и результат показываются в окне (как при установке): строки шагов, вердикт и блок деталей по каждому AID — при отказе он называет раздел CAP, который покрывает неудачный блок (диапазон байтов load-файла и компоненты, и завершает ли этот блок <strong>Import</strong>), SW команды с его значением, список импортов ровно в том виде, в каком он проверялся (версии CAP, правки пробы, добавленные синтетические записи, строки без совпадений) и что означает состояние пробы; при успехе — список импортов, который прошёл проверку.</td></tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<h4 id="ram-explorer" class="font-medium mb-1">Обзор карты (Explorer View)</h4>
|
||
<p class="text-sm mb-2">После выполнения «Обзор карты» отображается:</p>
|
||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||
<li><strong>ISD</strong> — AID, жизненный цикл, привилегии (без удаления; ISD нельзя удалить)</li>
|
||
<li><strong>Приложения</strong> — AID, жизненный цикл, привилегии, связанный ELF/SD. Каждое имеет кнопку <strong>Удалить</strong> (GP <code class="font-mono text-sm">DELETE</code> по AID).</li>
|
||
<li><strong>Исполняемые файлы загрузки (ELF) / пакеты</strong> — AID, жизненный цикл, версии, AID модулей. Каждый имеет <strong>Удалить</strong> (только ELF) и <strong>Удалить все</strong> (каскадное: ELF + модули + установленные приложения, P2=<code class="font-mono text-sm">0x80</code>).</li>
|
||
</ul>
|
||
<p class="text-sm mb-3">Стандартные пакетные AID дополняются именем библиотеки (пакеты JavaCard / ETSI / 3GPP / GlobalPlatform, а также AID ISD по умолчанию); неизвестные и вендорские AID остаются без имени.</p>
|
||
<p class="text-sm mb-3">Удаление подтверждается через диалог браузера перед отправкой команды GP <code class="font-mono text-sm">DELETE</code> через SCP80. Обзор автоматически обновляется после успешного удаления.</p>
|
||
|
||
|
||
</section>
|
||
<section class="mb-10">
|
||
<h3 id="tar-probe" class="text-lg font-medium mb-2">3.3 TAR-сканер</h3>
|
||
<p class="mb-2">Третья пилюля вкладки SCP80 показывает, <strong>какие OTA-приложения зарегистрированы на карте</strong>: отправляется <strong>по одному защищённому пакету на каждый выбранный TAR</strong> — стандартные значения из TS 101 220 V18.3.0 Annex D, Table D.1, каждая строка несёт документ-источник — с безобидной C-APDU (по умолчанию <code class="font-mono text-sm">SELECT MF</code>), пресетом и keyset этого представления — каждый проверяемый TAR использует свой <strong>MSL</strong>, если запись есть в пресете, иначе SPI1 из общей формы; TAR, для которого нет ни того, ни другого, отклоняется до отправки. Разрешённый SPI1 должен иметь проверку счётчика (b5b4 ≠ 00) и запрашивать PoR. Кнопка <strong>Execute</strong> недоступна, пока не выбран пресет карты и один из его keysets.</p>
|
||
<p class="mb-2">Список предзаполнен стандартными TAR (все отмечены; кнопки <strong>Выбрать все</strong> / <strong>Снять все</strong> переключают быстро), свои TAR добавляются кнопкой <strong>Добавить TAR</strong> (три hex-байта и необязательное описание). Пользовательские записи хранятся в <code class="font-mono text-sm">localStorage</code> по возможности — их потеря безвредна.</p>
|
||
<p class="mb-2">Каждый TAR классифицируется по ответу карты: <strong>зарегистрировано</strong> (ENVELOPE 9000 + PoR со SW и данными приложения), <strong>принято, нет ответа</strong> (PoR без R-APDU), <strong>принято, нет PoR</strong> (пакет молча отброшен) и <strong>отклонено</strong> (ENVELOPE не 9000, обычно <code class="font-mono text-sm">6200</code> для TAR без зарегистрированного приложения). Таблица результата появляется в окне операции; строка под кнопкой Execute показывает <code class="font-mono text-sm">зарегистрировано N / M</code>.</p>
|
||
<p class="mb-2">Каждый принятый картой пакет <strong>расходует счётчик</strong>, который сохраняется в keyset пресета — проба отклоняется, если в разрешённом SPI1 нет проверки счётчика или в пресете нет такого номера keyset. На живой карте: <code class="font-mono text-sm">000000</code>, <code class="font-mono text-sm">B00000</code> и <code class="font-mono text-sm">B00001</code> зарегистрированы (приложения компактного формата), расширенный формат, USAT, мультиплексирование и CASD отклонены с <code class="font-mono text-sm">6200</code>.</p>
|
||
|
||
<h2 id="cards" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">4. Вкладка «Карты»</h2>
|
||
<p class="mb-2">Хранит пресеты карт на сервере (<code class="font-mono text-sm">~/.pysim-simple-server/card_presets.json</code>; переопределяется <code class="font-mono text-sm">--card-presets</code>), чтобы представление Secured Packet могло автоматически подставлять ключи и параметры, слушатель SCP81 HTTP OTA — находить PSK-ключи, а счётчики SCP80, израсходованные операцией, сохранялись самой операцией — закрытая вкладка или второе окно браузера больше не могут потерять инкремент. Пресет содержит <strong>несколько keysets</strong> — номер keyset задаётся нибблом <code class="font-mono text-sm">b8..b5</code> его KIc/KID (TS 102 225 §5.1.2/A.2): KIc и KID одного keyset должны нести один и тот же номер (01–0F; A.2 отвергает несовпадение), и у каждого keyset на карте свой счётчик (Annex A.1), поэтому счётчики ведутся по keysets. В форме keysets редактируются строками — по одной на номер, с кнопками <strong>Добавить keyset</strong> / <strong>Удалить keyset</strong>; номер в строке вычисляется из байта KIc/KID, а <code class="font-mono text-sm">00</code> («без защиты») не принимается как keyset. Список загружается при подключении PWA и экспортируется/импортируется как JSON (импорт принимает и пресеты старых сборок — плоские и с keysets). «Карты» — верхнеуровневая вкладка: по умолчанию показывается <strong>список пресетов</strong>, а <strong>Добавить пресет</strong> / <strong>Редактировать</strong> открывают <strong>редактор</strong> (отдельное представление) — <strong>Сохранить</strong> сохраняет пресет и возвращает к списку, <strong>Отмена</strong> отменяет правки. При подключении карты читается её EF.ICCID, и пресет с тем же ICCID автоматически выбирается во всех трёх представлениях SCP80; если подключённая карта не совпадает <strong>ни с одним</strong> пресетом — или выбранный пресет принадлежит другой карте — все три представления SCP80 показывают жёлтое предупреждение над выбором пресета. В списке подсвечивается пресет подключённой карты. Поля редактора сгруппированы в блоки с рамкой: <strong>PIN/ADM</strong> (необязательные коды карты — PIN1/PUK1/PIN2/PUK2 по 4–8 десятичных цифр и ключ ADM — сохраняются для будущего использования), <strong>TAR</strong> (таблица TAR), <strong>SCP80 (GSM 03.48, ETSI TS 102 225)</strong> (keysets и их счётчики) и <strong>SCP81 (HTTP OTA)</strong> (пара PSK identity/ключ с пояснением о выборе ключа). В шапке редактора также выбирается <strong>релиз CAT (USAT)</strong> карты — по нему механизм релизов скрывает элементы CAT, появившиеся позже (параметры событий в Симуляторе); «не указан» означает Rel-12, и неуказанный релиз ничего не фильтрует. В шапке отображаются серые маркеры <strong>SCP80</strong>/<strong>SCP81</strong> и значок ключа на бейдже ADM, когда в пресете с ICCID подключённой карты эти поля заполнены.</p>
|
||
<table class="w-full text-sm mb-3 border-collapse">
|
||
<thead><tr class="border-b border-gray-300 dark:border-slate-700"><th class="text-left py-1 px-2">Поле</th><th class="text-left py-1 px-2">Описание</th></tr></thead>
|
||
<tbody>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">Name</td><td class="py-1 px-2">Понятная метка (обязательна)</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">ICCID</td><td class="py-1 px-2">Опциональный идентификатор карты. Кнопка <strong>С карты</strong> подставляет EF.ICCID подключённой карты (активна, только когда ICCID читается); при сохранении ICCID, уже присутствующий в списке, отклоняется (сравнение без пробелов и с учётом сырой hex-формы, конфликтующий пресет называется)</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">PIN1 / PUK1 / PIN2 / PUK2 / ADM</td><td class="py-1 px-2">Необязательные коды карты, сохраняются для будущего использования (пока ничем не используются). PIN/PUK — строго 4–8 десятичных цифр (иначе сохранение отклоняется); ADM — администраторский ключ (4–16 hex-цифр, например десятичный PIN), используется файловым менеджером. Представлениями SCP80/SCP81 не используются</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">KIc / KID</td><td class="py-1 px-2">Индикаторы ключа и алгоритма (например, 15 = индекс 1, 3DES-CBC2; x2 = AES); задаются вместе с ключами</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">TAR / MSL / Description</td><td class="py-1 px-2">Таблица TAR: одна строка на TAR с его MSL (минимальный SPI1, TS 102 226 §8.2.1.3.2.4). Первые три строки — фиксированные роли (предзаполнены, не удаляются) с фиксированными описаниями; дополнительные TAR добавляются кнопкой <strong>Добавить TAR</strong>, несут необязательное описание и могут быть удалены. SPI1 пакета берётся из MSL его TAR</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">ISD compact format</td><td class="py-1 px-2">TAR Issuer Security Domain (TS 101 220, приложение D); используется для операций RAM/GP (представление SCP80 RAM, цепочки RAM/GP); по умолчанию по спецификации <code class="font-mono text-sm">000000</code>, подставляется при пустом значении</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">UICC shared FS RFM compact format</td><td class="py-1 px-2">TAR UICC Shared File System RFM (TS 102 226 §7.2, TS 101 220 приложение D): MF выбирается неявно и доступны только файлы под MF (ADF недоступны); используется представлением SIM RFM; по умолчанию <code class="font-mono text-sm">B00000</code></td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">ADF FS RFM compact format</td><td class="py-1 px-2">TAR ADF RFM (TS 102 226 §7.3, TS 101 220 приложение D): ADF выбирается неявно, TAR привязан к AID приложения — ADF.USIM в представлении USIM RFM; по умолчанию <code class="font-mono text-sm">B00001</code></td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">Счётчик (hex)</td><td class="py-1 px-2">Счётчик повторов (5 байт); свой у каждого keyset, сервер увеличивает и сохраняет его после каждой операции, которая его расходует</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">KIc key / KID key</td><td class="py-1 px-2">16/24/32 hex-символа (ключи 8/16/24 байта 3DES) или 32/48/64 hex-символа (ключи 16/24/32 байта AES)</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">PSK identity</td><td class="py-1 px-2">SCP81 HTTP OTA: идентификатор, который карта присылает в TLS-рукопожатии (например, <code class="font-mono text-sm">89390100000129506903</code>)</td></tr>
|
||
<tr><td class="py-1 px-2">PSK key</td><td class="py-1 px-2">SCP81 HTTP OTA: 32 hex-символа (16 байт) для PSK TLS-слушателя; ключ выбирается по идентификатору, который предъявляет карта</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<p class="text-sm mb-3">Столбец <strong>SCP81</strong> показывает, задана ли в пресете рабочая пара PSK: <strong>✓</strong> (зелёный) — идентификатор и ключ заданы; <strong>⚠</strong> (жёлтый) — задано только одно из двух, и слушатель такой пресет игнорирует; <strong>—</strong> — PSK нет. Идентификатор и ключ PSK задаются вместе. Кнопка <strong>Добавить пресет</strong> открывает редактор с новым пресетом; <strong>Редактировать</strong> загружает пресет строки в редактор, поэтому поля можно менять без повторного ввода карты; <strong>Сохранить</strong> сохраняет и возвращает к списку, <strong>Отмена</strong> отменяет правки; <strong>Удалить</strong> удаляет строку (только в списке). Обмен пресетами: <strong>Экспорт в файл</strong> для выгрузки и <strong>Импорт из файла</strong> для загрузки. Выбранный пресет автоматически заполняет форму Secured Packet и устанавливает TAR для операции (RAM/GP → ISD TAR, SIM RFM → UICC RFM TAR, USIM RFM → ADF RFM TAR); TAR, введённый в форму Secured Packet вручную, сохраняется при отправке - счётчик, ключи и MSL этого TAR по-прежнему берутся из пресета; SPI1 берётся из MSL, а меньшее значение даёт предупреждение (сервер тоже возвращает его как <code class="font-mono text-sm">warning</code>); изменения сразу передаются работающему слушателю SCP81.</p>
|
||
</section>
|
||
|
||
<section class="mb-10">
|
||
<h2 id="scp81" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">5. Вкладка SCP81</h2>
|
||
<p class="mb-3">Управляет HTTP OTA (GP RAM over HTTP, GPC v2.2 Amendment B): BIP-канал карты перенаправляется на цель, которую слушает сервер (или на внешнюю платформу), а терминальная сторона административной сессии эмулируется. Две подвкладки: <strong>«Слушатель»</strong> и <strong>«Скрипты»</strong>.</p>
|
||
<h3 id="scp81-listener" class="text-lg font-medium mb-2">5.1 Слушатель</h3>
|
||
<p class="mb-2">Кнопки <strong>Start</strong> / <strong>Остановить</strong> управляют целью; <strong>Перезапустить скрипт</strong> ставит выбранный скрипт в очередь заново с <code class="font-mono text-sm">force</code>, начиная прогон с первого APDU. Режимы:</p>
|
||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||
<li><strong>PSK TLS сервер</strong> (по умолчанию) — PSK TLS-слушатель на <strong>Хост</strong>:<strong>Порт</strong>, отвечающий PSK-наборами TLS 1.2 из спецификации и ведущий HTTP-диалог административной сессии GP (заголовки <code class="font-mono text-sm">X-Admin-*</code>, <code class="font-mono text-sm">200</code> со строкой команд или <code class="font-mono text-sm">204 No Content</code>). PSK-ключи берутся из пресетов карт (вкладка <strong>«Карты»</strong>): ключ выбирается по идентификатору, который карта присылает в рукопожатии; если ни у одного пресета нет пары, <strong>Start</strong> не запускается. Ключ не сохраняется и не записывается в журнал; незнакомый идентификатор помечается в журнале как <code class="font-mono text-sm">tls-psk-unknown</code>.</li>
|
||
<li><strong>Перенаправление на внешний сервер</strong> — без локального слушателя: каждый BIP-канал подключается к указанной цели (нужны <strong>Хост</strong> и <strong>Порт</strong>), которая завершает TLS и ведёт административный диалог; запрошенный картой адрес только журналируется.</li>
|
||
<li><strong>Проброс (адрес карты)</strong> — без слушателя и без цели: терминал подключает каждый BIP-канал к адресу, который карта запрашивает в OPEN CHANNEL (Other address + порт Transport level, только TCP-клиент, удалённое соединение; спецификации не задают порт по умолчанию, поэтому неполный запрос отклоняет канал). TLS завершается на той платформе, и используется сеть сервера (только для лаборатории).</li>
|
||
<li><strong>Захват (dump)</strong> — принимает TCP-канал карты и записывает всё, что она отправляет (например, TLS ClientHello), не отвечая.</li>
|
||
</ul>
|
||
<p class="mb-2">Блок <strong>Настройки</strong> (по умолчанию свёрнут; при отличии от эталонных значений показывается метка <em>изменены</em>; применяются при <strong>Start</strong>, сохраняются в браузере) открывает HTTP-фрейминг — <strong>Chunked body</strong> / <strong>размер чанка</strong> (0 = весь ответ в одной TLS-записи), заголовок Connection, компактные заголовки (без необязательного пробела после <code class="font-mono text-sm">:</code>, допустимо по RFC 7230 §3.2) и Next-URI (флажок + шаблон; выкл - команда без ответа: карта выполнит команду, не вернёт строку ответа и закроет сессию) — и фрейминг скрипта (неопределённая длина <code class="font-mono text-sm">AE 80 …</code> / определённая <code class="font-mono text-sm">AA</code> в Command Scripting template, теги comprehension-required и необязательный <code class="font-mono text-sm">X-Admin-Targeted-Application</code> со своим флажком). <strong>Показывать события канала</strong> (ENVELOPE Channel status, TS 102 223 §7.5.11) действует во всех режимах. Соединение удерживается между POST-запросами и аккуратно закрывается на 204. У TLS нет настроек: слушатель предлагает TLS 1.0–1.2 и все PSK-наборы, а карта выбирает; строка состояния и TLS-журнал показывают фактически использованные версию и набор, а сбой рукопожатия по причине TLS/набора пишется как <code class="font-mono text-sm">tls-handshake-failed</code>.</p>
|
||
<p class="mb-2"><strong>Сценарий</strong> выбирает список команд, отдаваемый в сессии — <strong>Нет</strong> (оставить настроенный на сервере скрипт) или один из скриптов подвкладки <strong>«Скрипты»</strong>; выбранный список передаётся серверу при старте слушателя.</p>
|
||
<p class="text-sm mb-3">Строка состояния показывает слушатель, согласованный идентификатор и активные каналы (байты in/out). Панель <strong>Script results (R-APDUs)</strong> перечисляет каждый отданный C-APDU с его R-APDU/SW и прогрессом <em>done/total</em> (списки GET STATUS дополняют известные стандартные пакетные AID именем библиотеки); журнал <strong>HTTP OTA log</strong> фиксирует OPEN/CLOSE CHANNEL, SEND/RECEIVE DATA и каждый шаг TLS/HTTP/скрипта (<code class="font-mono text-sm">tls-handshake</code>, <code class="font-mono text-sm">tls-request</code>, <code class="font-mono text-sm">script-send</code>, <code class="font-mono text-sm">script-rapdu</code>, <code class="font-mono text-sm">script-page</code>, <code class="font-mono text-sm">script-done</code>, <code class="font-mono text-sm">data-available</code>, <code class="font-mono text-sm">peer-close</code>), кнопка <strong>Clear</strong> очищает его.</p>
|
||
<h3 id="scp81-scripts" class="text-lg font-medium mb-2">5.2 Скрипты</h3>
|
||
<p class="text-sm mb-2">Именованные списки APDU хранятся локально (<code class="font-mono text-sm">simple_scripts</code>) и передаются серверу при старте слушателя. Каждый список — последовательность hex C-APDU (по одной в строке; допускаются комментарии <code class="font-mono text-sm">#</code>/<code class="font-mono text-sm">;</code>). Кнопка <strong>Новый</strong> создаёт список из шаблона:</p>
|
||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||
<li><strong>Empty</strong> — начать с пустого списка.</li>
|
||
<li><strong>Explore ISD</strong> — эталонная административная последовательность (<code class="font-mono text-sm">GET DATA FF21</code>, листинги GET STATUS ISD/ELF/приложений, <code class="font-mono text-sm">GET DATA 0085</code>); длинные листинги автоматически продолжаются страницами <code class="font-mono text-sm">SW 6310/CAFE</code>.</li>
|
||
<li><strong>Install from .cap</strong> — выберите <code class="font-mono text-sm">.cap</code>, при необходимости SD AID, параметры install/STK и <em>Make selectable</em>; кнопка <strong>Сгенерировать</strong> строит INSTALL [for load] → LOAD ×N → INSTALL [for install]. Файл используется только для генерации APDU — он не сохраняется, как и его имя. При выборе файл проверяется и показывается оценка требований к памяти (требование NVRAM как сумма образа кода и постоянных данных, плюс RAM); также перечисляются требуемые библиотеки, идентификаторы пакета и разбивка по компонентам (сгруппировано по разделам Package / Requires / Memory / Components). <strong>Сгенерировать</strong> недоступна до успешного анализа.</li>
|
||
<li><strong>Delete AID</strong> — список AID (по одному в строке) и P2 (<em>object only</em> / <em>object and related objects</em>) → APDU DELETE.</li>
|
||
</ul>
|
||
<p class="text-sm mb-3">Таблица показывает имя, тип, число APDU и время создания каждого скрипта, а также кнопки <strong>Редактировать</strong> и <strong>Удалить</strong>; в редакторе есть поле имени и текстовая область APDU. В ходе сессии сервер отдаёт по одному C-APDU на каждый POST карты и отслеживает выполнение: карта сообщает статус в следующем POST (<code class="font-mono text-sm">X-Admin-Script-Status</code>), оборвавшаяся сессия досылает только невыполненные APDU (<code class="font-mono text-sm">X-Admin-Resume</code> продолжает, новый диалог начинает заново), а завершённый скрипт закрывается ответом <code class="font-mono text-sm">204 No Content</code>. Конструктор RAM/GP вкладки Remote APDU может отправить цепочку команд прямо в прогон кнопкой <strong>«В очередь SCP81»</strong>.</p>
|
||
</section>
|
||
|
||
<section class="mb-10">
|
||
<h2 id="card-reader" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">6. Вкладка «Картридер» (pySim)</h2>
|
||
<p class="mb-3">Подключение к локальному <a href="https://github.com/anttro/simple" class="text-blue-600 dark:text-blue-400 hover:underline">pysim-simple-server</a> для работы с картой: введите URL сервера (по умолчанию <code class="font-mono text-sm">http://127.0.0.1:8080</code>) и нажмите <strong>Подключиться</strong>. Область статуса показывает состояние ридера/карты, а <strong>Подключить карту</strong> (пере)инициализирует карту после вставки. Подвкладки: <strong>Файловый менеджер</strong>, <strong>Командная строка pySim</strong> и <strong>Отправка APDU</strong>. <strong>«Профайлер»</strong> и <strong>«Симулятор»</strong> — отдельные вкладки верхнего уровня.</p>
|
||
|
||
<h3 id="file-manager" class="text-lg font-medium mb-2">6.1 Файловый менеджер</h3>
|
||
<p class="text-sm mb-2">Дерево файловой системы отображается слева; выбор файла открывает панель деталей справа. Элементы сгруппированы: DF выше EF, сортировка по <strong>FID</strong> или символьному <strong>имени</strong> (пиллы и кнопка <strong>«Проверить все файлы»</strong> закреплены над прокручиваемым деревом; выбор сохраняется в <code class="font-mono text-sm">localStorage</code>). При выборе файла над содержимым также показываются FID, тип файла, размер / структура записей и декодированный FCI — в рамке с символьным именем файла.</p>
|
||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||
<li><strong>Читать сырые данные / Декодировать</strong> — чтение выбранного файла в виде hex-дампа или таблицы декодированных полей (клиентские декодеры EF: IMSI, ICCID, SPN, списки PLMN, LOCI/PSLOCI/EPSLOCI, ADN/MSISDN, таблицы сервисов, SUME, …); серверный pySim JSON того же чтения остаётся доступен в свёрнутом блоке <em>pySim JSON (сервер)</em>. Подсвеченная кнопка — текущий вид; нажатие любой из них (пере)читывает файл. «Декодировать» недоступна, если для файла нет клиентского декодера (проверка по имени/FID до чтения).</li>
|
||
<li><strong>Редактировать сырые данные</strong> — изменение hex-данных, <strong>Сохранить</strong> для записи (или <strong>Отмена</strong>); transparent-файлы редактируются в textarea, record-файлы — по одному полю на запись с флажками выбора. Декодированный вид доступен только для чтения — «Редактировать сырые данные» сначала переключает на hex-вид и при необходимости читает файл.</li>
|
||
<li><strong>Проверить все файлы</strong> — обход всего дерева (включая пользовательские файлы) с пометкой каждого элемента: есть (обычный вид) или нет (красный ✗, без стрелки разворачивания); существующие пустые DF показывают <code class="font-mono text-sm">(пусто)</code>. Отображается прогресс <em>N / всего</em>, обход можно остановить; в конце — сводка «есть/нет». Файлы проверяются только при разворачивании или проверке — просмотр остаётся ленивым.</li>
|
||
<li><strong>ADM</strong> — файлы, требующие администраторский PIN, возвращают <code class="font-mono text-sm">6982</code>/<code class="font-mono text-sm">9804</code>; если в подходящем пресете карты (тот же ICCID) есть ключ ADM, рядом с ошибкой появляется кнопка <strong>«Проверить ADM»</strong>, а значок в заголовке (<code class="font-mono text-sm">ADM ✓/✗ ⚿</code>) становится кликабельным. Каждый неверный ключ расходует попытку: остаток показывается, а повторная попытка требует подтверждения. Заблокированный ADM здесь не восстановить — нужен ключ разблокировки карты.</li>
|
||
</ul>
|
||
|
||
<h3 id="pysim-cmdline" class="text-lg font-medium mb-2">6.2 Командная строка pySim</h3>
|
||
<p class="text-sm mb-3">Выполнение любых команд pySim-shell с подсказками (300 мс) и автодополнением.</p>
|
||
|
||
<h3 id="raw-apdu" class="text-lg font-medium mb-2">6.3 Отправка APDU</h3>
|
||
<p class="text-sm mb-3">Отправка произвольного APDU и просмотр ответа.</p>
|
||
|
||
<h3 id="usage-scenarios" class="text-lg font-medium mb-2">6.4 Сценарии использования</h3>
|
||
|
||
<h4 id="scenario-a" class="font-medium mb-1">Сценарий A — Работа с файлами, не входящими в модель pySim («Пользовательские файлы»)</h4>
|
||
<ol class="list-decimal list-inside text-sm space-y-1 mb-3">
|
||
<li>Получите FID целевого файла (документация вендора или анализ ATR/файловой системы; такие файлы часто отсутствуют в открытых спецификациях).</li>
|
||
<li>Откройте вкладку <strong>«Профайлер»</strong> → подвкладку <strong>«Пользовательские файлы»</strong>.</li>
|
||
<li>Выберите корень, введите путь родительского DF (стандартный DF из дерева или пользовательский DF, любой вложенности — при вводе появляются подсказки), 4-hex FID и псевдоним (например, <code class="font-mono text-sm">EF.SPN</code>).</li>
|
||
<li>Нажмите <strong>Добавить</strong> — файл появится в дереве курсивом (непроверенный).</li>
|
||
<li>Кликните по файлу для проверки существования; при успехе (<code class="font-mono text-sm">9000</code>) он работает как обычный файл.</li>
|
||
<li>Читайте, редактируйте и сохраняйте hex-данные; переключайте <strong>Данные как на карте</strong> / <strong>Декодированные данные</strong>.</li>
|
||
<li>Экспортируйте список пользовательских файлов в JSON для переноса на другие машины.</li>
|
||
</ol>
|
||
|
||
<h4 id="scenario-b" class="font-medium mb-1">Сценарий B — Симуляция реальной сетевой среды для тестирования SIM</h4>
|
||
<p class="text-sm mb-1"><strong>B.1 Ответы на PROVIDE LOCAL INFORMATION (PLI)</strong></p>
|
||
<ol class="list-decimal list-inside text-sm space-y-1 mb-3">
|
||
<li>Откройте <strong>Симулятор</strong> → <strong>Данные для PROVIDE LOCAL INFORMATION</strong>.</li>
|
||
<li>Используйте формы декодирования/кодирования для IMEI (<code class="font-mono text-sm">01</code>), Location Info (<code class="font-mono text-sm">00</code>), Access Technology (<code class="font-mono text-sm">06</code>) и т.д.</li>
|
||
<li>Нажмите <strong>Сохранить</strong> — значения сохранятся на сервере.</li>
|
||
<li>Включите <strong>Опрос</strong> (интервал 30 с), чтобы карта периодически выдавала PLI.</li>
|
||
<li>Сервер вставляет значения словаря в каждый TERMINAL RESPONSE.</li>
|
||
<li>Проверьте в журнале проактивных команд: запись PLI покажет декодированный ответ.</li>
|
||
</ol>
|
||
<p class="text-sm mb-1"><strong>B.2 Симуляция сетевых действий через ENVELOPE (event download)</strong></p>
|
||
<ol class="list-decimal list-inside text-sm space-y-1 mb-3">
|
||
<li>Проверьте список <strong>подписанных событий</strong> (из SET UP EVENT LIST).</li>
|
||
<li>Нажмите <strong>Отправить</strong> на событии (например, Location Status) и заполните форму; будет отправлен <code class="font-mono text-sm">ENVELOPE(Event Download)</code>.</li>
|
||
<li>Для <strong>Network Rejection</strong> выберите тип регистрации → поля местоположения → технологию доступа → причину отклонения.</li>
|
||
<li>Карта может ответить проактивной командой, которую обработчик цепочки зарегистрирует и обработает автоматически.</li>
|
||
</ol>
|
||
<p class="text-sm mb-1"><strong>B.3 Проверка симулированной среды</strong></p>
|
||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||
<li>Журнал проактивных команд показывает полный цикл (команда + байты TERMINAL RESPONSE).</li>
|
||
<li>Кнопка <strong>Отправить STATUS</strong> / автопросмотр поддерживают сессию CAT (цикл дренажа).</li>
|
||
</ul>
|
||
|
||
|
||
|
||
</section>
|
||
<section class="mb-10">
|
||
<h2 id="profiler" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">7. Профайлер</h2>
|
||
<p class="text-sm mb-2">Проверяет соответствие карты именованному <strong>профилю</strong> — упорядоченному набору правил, описывающих ожидаемую файловую систему и (опционально) содержимое файлов. Профили хранятся в <code class="font-mono text-sm">localStorage</code>.</p>
|
||
<h4 class="font-medium mb-1">Список профилей</h4>
|
||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||
<li><strong>Новый профиль</strong> — создаёт пустой набор правил, запросив имя.</li>
|
||
<li><strong>Профиль с карты <ICCID></strong> — сканирует подключённую карту и создаёт по одному правилу на каждый существующий файл (см. ниже), затем открывает редактор. Кнопки, зависящие от карты, содержат ICCID подключённой карты и отключены, пока он не читается.</li>
|
||
<li><strong>Профиль из снимка</strong> — выбирает сохранённый снимок карты и создаёт по правилу на каждый захваченный файл с теми же опциями сканирования (см. ниже), без картридера; имя профиля подставляется из имени снимка.</li>
|
||
<li><strong>Импорт профиля</strong> — загружает набор правил из JSON-файла (имя хранится внутри JSON).</li>
|
||
<li>В каждой строке профиля показаны имя и время создания, а также действия <strong>Проверить карту <ICCID></strong>, <strong>Проверить снимок карты</strong>, <strong>Редактировать</strong>, <strong>Клонировать</strong>, <strong>Экспорт</strong> (скачать JSON) и <strong>Удалить</strong>. <strong>Клонировать</strong> создаёт копию профиля с именем <em>Копия <профиль></em> (с суффиксом <code class="font-mono text-sm">(2)</code>, <code class="font-mono text-sm">(3)</code>…, если такое имя уже занято) и открывает копию в редакторе, чтобы изменить имя и содержимое перед сохранением.</li>
|
||
</ul>
|
||
<h4 class="font-medium mb-1">Правила файловой системы</h4>
|
||
<p class="text-sm mb-2">Правила выполняются последовательно. Редактор показывает символьное имя файла pySim (если известно) рядом с путём правила; <strong>Добавить правило</strong> добавляет правило, <strong>Сохранить</strong> сохраняет изменения. Правило файловой системы задаётся:</p>
|
||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||
<li><strong>Путь</strong> — начинается с <code class="font-mono text-sm">MF</code> (например, <code class="font-mono text-sm">MF/7F10/6F3A</code>) или с AID ADF (например, <code class="font-mono text-sm">A0000000871002/6F07</code>).</li>
|
||
<li><strong>Проверка FCP/FCI</strong> — какая часть информации об управлении файлом проверяется: <strong>Только тип файла (FCP)</strong> (существование + тип файла), <strong>Тип файла + размер (FCP)</strong> (добавляются размер файла либо длина/число записей для record-файлов) или <strong>Полный FCI</strong> (добавляется побайтовое сравнение сырого ответа SELECT — шаблона FCP <code class="font-mono text-sm">'62'</code> — выявляет изменения FID/AID, жизненного цикла, атрибутов безопасности и проприетарных параметров).</li>
|
||
<li><strong>Атрибуты файла</strong> — тип файла, размер, длина записи и число записей из FCP-шаблона (любой можно оставить незаданным).</li>
|
||
<li><strong>Проверить содержимое</strong> (опционально) — <strong>Точное</strong> (точное совпадение hex) или <strong>Маска</strong>, где <code class="font-mono text-sm">?</code> — шаблон на один полубайт (маска без <code class="font-mono text-sm">?</code> — совпадение префикса, например <code class="font-mono text-sm">0891</code> для MCC/MNC из IMSI). Для record-файлов хранится список по записям.</li>
|
||
</ul>
|
||
<p class="text-sm mb-3"><strong>Проверить карту</strong> выполняет каждое правило на подключённой карте и показывает строку прогресса и отчёт прохождения. Рядом с путём файла указывается, что именно проверялось (например, <em>тип файла и размер, содержимое</em> или <em>полный FCI</em>); если часть проверок прошла, а часть нет — каждый аспект помечается (<em>тип файла ✓, размер ✗, содержимое ✓</em>), а расхождения расписываются ниже. Несовпавшие сырые данные (FCI, содержимое, данные записей) показываются как поля только для чтения с моноширинным шрифтом — ожидаемое над фактическим, в одной и той же колонке — для удобного сравнения; расхождения содержимого дополнительно показывают для файлов с декодером декодированное сравнение по полям (только отличающиеся поля, с заголовками колонок «ожидаемое/фактическое» над значениями; если декодированные значения совпадают, вместо таблицы выводится пометка об этом, а сторона, чья запись целиком из FF, показывает в своих ячейках <em>Пусто (только FF)</em>), а для расхождений FCI дополнительно показывается декодированное сравнение по параметрам (размер файла, дескриптор/структура, жизненный цикл, FID, SFI, проприетарные параметры…). Декодированный просмотр FCI также отображается рядом с полем FCI hex при редактировании правила. Если данные FCI повреждены, показывается всё, что удалось декодировать до места ошибки, вместе с явным сообщением об ошибке декодирования. Для record-файлов при расхождении содержимого добавляется пометка <em>совпадающие записи: 1-5, 7-10</em> со списком записей, которые совпали. В отчёте поля расхождений и колонки сравнения FCI подписаны <em>ожидалось (имя профиля)</em> и <em>фактически (ICCID карты)</em>, а в заголовке отчёта выводится <em>Результаты проверки профиля: <профиль> → <ICCID карты></em>. Опция <strong>«Только расхождения»</strong> в заголовке отчёта скрывает все совпавшие файлы и оставляет только несовпадения и ошибки.</p>
|
||
<h4 class="font-medium mb-1">Опции сканирования «Профиль с карты»</h4>
|
||
<p class="text-sm mb-2">Диалог сканирования запрашивает имя профиля и предлагает селектор <strong>«Проверка FCP/FCI»</strong> (те же три режима, по умолчанию <strong>Тип файла + размер (FCP)</strong>), применяемый ко всем создаваемым правилам, а также список <strong>«Игнорировать содержимое файлов»</strong> (все отмечены по умолчанию, кроме <code class="font-mono text-sm">EF.ARR</code>; флажок в заголовке отмечает или снимает весь список) часто перезаписываемых файлов, содержимое которых пропускается: <code class="font-mono text-sm">EF.LOCI</code>, <code class="font-mono text-sm">EF.PSLOCI</code>, <code class="font-mono text-sm">EF.EPSLOCI</code>, <code class="font-mono text-sm">EF.5GS3GPPLOCI</code>, <code class="font-mono text-sm">EF.Keys</code>, <code class="font-mono text-sm">EF.KeysPS</code>, <code class="font-mono text-sm">EF.SMS</code>, <code class="font-mono text-sm">EF.Kc</code>, <code class="font-mono text-sm">EF.KcGPRS</code>, <code class="font-mono text-sm">EF.LOCIGPRS</code>, <code class="font-mono text-sm">EF.CBMID</code>, <code class="font-mono text-sm">EF.SMSS</code>, <code class="font-mono text-sm">EF.ACC</code>, <code class="font-mono text-sm">EF.EPSNSC</code>, <code class="font-mono text-sm">EF.START-HFN</code>, <code class="font-mono text-sm">EF.ARR</code>. Ещё две отмеченные по умолчанию опции <strong>«Сравнивать первые 4 байта для»</strong> <code class="font-mono text-sm">EF.IMSI</code> и <code class="font-mono text-sm">EF.ICCID</code> захватывают содержимое этих файлов как маску только первых 4 байт (снимите для точного сравнения). Строка прогресса показывает <em>N / всего файлов</em> с текущим путём файла во время сканирования; при сканировании опции скрываются, а кнопки блокируются. Правила создаются только для файлов, которые реально существуют на карте (возвращён FCP-шаблон); отсутствующие файлы пропускаются. Пользовательские файлы из подвкладки <strong>«Пользовательские файлы»</strong> включаются с той же проверкой существования. Тот же диалог и опции использует <strong>«Профиль из снимка»</strong>: вместо карты обходятся захваченные файлы выбранного снимка; для файлов, содержимое которых не было захвачено, правило создаётся без проверки содержимого (при последующей проверке профиля они помечаются как непроверяемые).</p>
|
||
|
||
<h4 id="card-snapshots" class="font-medium mb-1">Снимки карт</h4>
|
||
<p class="text-sm mb-2">Представление списка имеет три вкладки — <strong>«Профили»</strong>, <strong>«Снимки карт»</strong> и <strong>«Пользовательские файлы»</strong> (см. ниже). Снимок карты — неизменяемая фиксация файловой системы карты: для каждого существующего файла сохраняются путь, символьное имя, тип, размер (или длина/число записей), сырой FCI из ответа SELECT и содержимое, если файл читается (без списка игнорирования и без масок). ICCID декодируется из EF.ICCID и показывается рядом с именем снимка. Захваченное содержимое показывается вместе с декодированным представлением, где есть декодер — таблица полей для transparent-файлов и однострочная сводка по каждой записи для record-файлов. При сканировании измеряется время каждой команды карты (SELECT, READ BINARY, READ RECORD) от отправки до ответа; снимок хранит min/сред/max по каждому типу команд и общее время сканирования, а в представлении эти значения показываются в сводке под заголовком, время select/read — для каждого файла и время чтения — для каждой записи. Время носит информационный характер и не используется при проверках и сравнении.</p>
|
||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||
<li><strong>Новый снимок: <ICCID></strong> — запрашивает имя и сканирует карту, затем возвращает к списку.</li>
|
||
<li><strong>Импорт снимка</strong> — загружает снимок из JSON-файла.</li>
|
||
<li>В каждой строке снимка — <strong>Открыть</strong>, <strong>Экспорт</strong> и <strong>Удалить</strong>. <strong>Открыть</strong> показывает все захваченные данные только для чтения (сырой FCI с декодированным FCI, содержимое); редактируется только имя снимка.</li>
|
||
<li><strong>Проверить снимок карты</strong> в строке профиля выполняет правила профиля на выбранном из списка снимке, без картридера. Отчёт такой же, как при проверке карты: фактическая сторона подписана именем снимка (<em>фактически (имя снимка)</em>), а в заголовке — <em>Результаты проверки профиля: <профиль> → <имя снимка></em>; файлы, содержимое которых не было захвачено при сканировании, помечаются как непроверяемые ошибки.</li>
|
||
<li><strong>Сравнить снимки</strong> сравнивает два снимка без картридера так же, как проверка профиля, но <strong>всегда точно</strong> (маскирование содержимого не применяется): выберите <em>эталонный</em> снимок и <em>снимок для проверки</em> и получите такой же отчёт; в этом отчёте заголовок — <em>Результаты сравнения снимков: <эталон> → <проверяемый></em>, а поля расхождений и колонки сравнения FCI подписаны именами эталонного и проверяемого снимков вместо expected/actual. Файлы, которые есть только в проверяемом снимке, помечаются как лишние. «К списку» возвращает на вкладку «Снимки карт».</li>
|
||
</ul>
|
||
|
||
</section>
|
||
|
||
|
||
|
||
<h4 id="custom-files" class="font-medium mb-1">Пользовательские файлы</h4>
|
||
<p class="text-sm mb-3">Добавление файлов, не покрытых моделью pySim. Пользовательский файл всегда имеет полный путь от <strong>MF</strong> или ADF (<strong>ADF.USIM</strong>, <strong>ADF.ISIM</strong>): выберите корень, введите путь <strong>родительского DF</strong> (сам корень, стандартный DF из дерева файлового менеджера или пользовательский DF — любой вложенности, с подсказками при вводе; родитель, ещё не встречавшийся в дереве, остаётся допустимым и помечается <code class="font-mono text-sm">⚠</code>), 4-hex <strong>FID</strong> и псевдоним (<code class="font-mono text-sm">EF.…</code>/<code class="font-mono text-sm">DF.…</code>; префикс определяет, EF это или DF). Канонический путь убирает прежнюю неоднозначность, когда один и тот же файл можно было описать и относительно, и абсолютно. Добавленные файлы появляются в дереве «Файловый менеджер»; в каждой строке есть <strong>«Редактировать»</strong> (путь + псевдоним; изменение пути DF перепривязывает дочерние записи — кнопка становится <strong>«Сохранить»</strong>, <strong>«Отмена»</strong> отменяет) и <strong>«Удалить»</strong> (удаление DF удаляет и его дочерние записи после подтверждения). Список сохраняется в <code class="font-mono text-sm">localStorage</code>; обмен — <strong>Экспорт в файл</strong> / <strong>Импорт из файла</strong>; старые относительные пути (например, <code class="font-mono text-sm">a153/4954</code>) разрешаются при загрузке, неразрешимые отбрасываются и отмечаются в списке.</p>
|
||
|
||
<section class="mb-10">
|
||
<h2 id="proactive-uicc" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">8. Симулятор</h2>
|
||
<p class="text-sm mb-3">Работа с сессией Card Application Toolkit. Пять подвкладок: <strong>«Телефон»</strong> (меню STK, STATUS и опрос, подписанные события, журнал проактивных команд), <strong>«Конфигурация TR»</strong> (данные ответов, подставляемые в TERMINAL RESPONSE для проактивных команд), <strong>«eSIM LPA»</strong> (локальные операции с eUICC), <strong>«BIP»</strong> (терминальная сторона BIP поверх TCP, см. <a href="#bip" class="text-blue-600 dark:text-blue-400 hover:underline">§8.10</a>) и <strong>«Тест-скрипт»</strong> (сценарные тест-скрипты карты с ожиданием проактивных команд, см. <a href="#test-script" class="text-blue-600 dark:text-blue-400 hover:underline">§8.9</a>).</p>
|
||
|
||
<h3 id="stk-menu" class="text-lg font-medium mb-2">8.1 Меню STK</h3>
|
||
<p class="text-sm mb-3">Если карта выдала команду SET UP MENU, вверху этого представления появляется блок «Меню STK» с изумрудной кнопкой с названием меню (<strong><название></strong>), открывающей оверлей меню (браузер STK-меню карты). Если карта не задала меню, вместо кнопки показывается «Меню не задано картой»; SET UP MENU без заголовка (alpha identifier необязателен) показывается как <strong>Меню</strong>. Состояние меню обновляется при каждом открытии представления. Пункты меню, для которых карта передала <strong>Next Action Indicator</strong> (TS 102 223 §8.24), показывают его серым суффиксом (например, <code class="font-mono text-sm">→ SET UP MENU</code>) — что карта выполнит при выборе пункта. Интерактивные проактивные команды всегда получают TERMINAL RESPONSE: оверлей ждёт вашего выбора, и если вы не ответили и не нажали <strong>Timeout</strong>, сервер сам отвечает результатом timeout через <code class="font-mono text-sm">--menu-timeout</code> секунд (по умолчанию 60, <code class="font-mono text-sm">0</code> отключает). <strong>Назад</strong> и <strong>Timeout</strong> продолжают диалог с картой: если карта в ответ выдаёт следующую проактивную команду (SELECT ITEM или DISPLAY TEXT), панель показывает её; кэшированное верхнее меню появляется только когда карте больше нечего выполнять. Оверлей также отвечает на запросы карты <strong>GET INKEY</strong> и <strong>GET INPUT</strong> (TS 102 223 §6.4.2/§6.4.3): панель показывает текст карты и поле ввода, ограничения которого заданы командой (длина ответа min–max, цифровая клавиатура, скрытый ввод, подставленный текст по умолчанию, кнопки Да/Нет для GET INKEY, справка, если карта её объявила), а ответ возвращается в Text string внутри TERMINAL RESPONSE в запрошенной кодировке (SMS-алфавит unpacked, UCS2 или packed).</p>
|
||
|
||
<h3 id="subscribed-events" class="text-lg font-medium mb-2">8.2 Подписанные события (SET UP EVENT LIST)</h3>
|
||
<p class="text-sm mb-2">События, которые отслеживает карта. У каждого события есть кнопка <strong>Отправить</strong>, открывающая форму, специфичную для типа события:</p>
|
||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||
<li><strong>События без данных</strong> (User Activity, Idle Screen, Data Available, …) — уведомление в один клик</li>
|
||
<li><strong>Location Status</strong> — выпадающий список: Normal / Limited / No service (тег <code class="font-mono text-sm">9B</code>); для Normal service можно добавить location information (MCC/MNC + LAC + Cell ID)</li>
|
||
<li><strong>Access Technology Change</strong> — 13 типов RAT (тег <code class="font-mono text-sm">BF</code>)</li>
|
||
<li><strong>Network Rejection</strong> — полная адаптивная форма: тип регистрации (LU / GPRS / EPS / 5GS), поля местоположения (MCC, MNC, LAC, RAC, TAC), технология доступа и единый выпадающий список из 53 кодов причин (EMM, GMM, 5GMM и LU), а также необязательные extended cause и extended information (CAG ID / NID / RedCap)</li>
|
||
<li><strong>События звонка</strong> — MT call (transaction identifier, номер вызывающего + TON → Address, subaddress, IMS URI, media type; источник <em>network</em>), Call connected и Call disconnected (transaction identifier, источник near/far, media type и причина — отсутствует, нулевая форма radio link timeout или свои байты), а также необязательная причина IMS-разрыва (SIP / Q.850 + cause)</li>
|
||
<li><strong>Browser termination</strong> (причина user / error), <strong>(I-)WLAN access status</strong> (нет покрытия / покрытие / соединение) и <strong>CSG cell selection</strong> (статус + механизм выбора, access technology, CSG ID, HNB name, PLMN ID; источник <em>network</em>)</li>
|
||
<li><strong>Channel status</strong> (канал + состояние звена + инфо, тег <code class="font-mono text-sm">B8</code>, с необязательными bearer description <code class="font-mono text-sm">B5</code> и local address <code class="font-mono text-sm">BE</code>) и <strong>Data available</strong> (тот же channel status + длина данных канала, тег <code class="font-mono text-sm">B7</code>), <strong>Display parameters changed</strong> (строки/столбцы + флаги sizing/fonts/effects, тег <code class="font-mono text-sm">C0</code>), <strong>Network search mode change</strong> (manual/automatic, тег <code class="font-mono text-sm">E5</code>), <strong>Browsing status</strong> (код ошибки браузера, тег <code class="font-mono text-sm">E4</code>) и <strong>Frames information change</strong> (фрейм по умолчанию + инфо по фреймам, тег <code class="font-mono text-sm">E7</code>)</li>
|
||
<li><strong>IMS registration</strong> (IMPU URI + IMS status code) и <strong>Incoming IMS data</strong> (IARI) — источник <em>network</em>; <strong>CAG cell selection</strong> (статус + механизм, access technology, CAG information list + HRNN list) и <strong>Slices status change</strong> (allowed / rejected / served / partially, access technology, списки allowed / served / rejected S-NSSAI, с маппингом и без, partial NSSAI) — источник <em>network</em></li>
|
||
<li><strong>Data Connection Status Change</strong> (0x1D) — статус (successful / rejected / dropped-deactivated), тип соединения (PDP / PDN / PDU), необязательная причина (E/5G)SM, transaction identifier и location status, а также необязательные date-time, access technology, APN, тип PDP/PDN/PDU и location information (MCC/MNC + LAC + Cell ID) — TS 131 111 §7.5.25</li>
|
||
<li><strong>Poll Interval Negotiation</strong> (0x1C) — предлагает интервал опроса в виде Duration (единица + значение); после отправки показывается ответ UICC (принято / отклонено / изменено + длительность), а значение <em>изменено</em> становится интервалом фонового опроса (TS 102 223 §7.5.22). Форма появляется, когда карта подписана на это событие.</li>
|
||
</ul>
|
||
<p class="text-sm mb-3">Отправка события использует <code class="font-mono text-sm">ENVELOPE(Event Download)</code> по TS 102 223 / TS 131 111. Форма скрывает параметры, появившиеся после <strong>действующего релиза CAT</strong> — релиза пресета подключённой карты (совпадение по ICCID) или Rel-12, если он не указан, — а примечание под формой называет источник и то, что было скрыто (релиз задаётся на вкладке «Карты»). Каждая форма также показывает точные <strong>данные события (hex)</strong>, которые будут отправлены, обновляя их по мере правки полей — скопируйте их в сырой шаг <em>Envelope</em> тест-скрипта, если у события нет семантической формы. Информация о срезах отправляется в одном <code class="font-mono text-sm">ENVELOPE</code> (не более 252 байт внутренних данных) — доставка цепочкой из нескольких ENVELOPE не реализована, поэтому данные должны помещаться в один конверт; конверт с partial NSSAI автоматически помечается как Last Envelope.</p>
|
||
|
||
<h3 id="proactive-log" class="text-lg font-medium mb-2">8.3 Журнал проактивных команд</h3>
|
||
<p class="text-sm mb-2">Хронологический список извлечённых проактивных команд. Каждая строка показывает время, код типа, имя и декодированный квалификатор (для команд, у которых он есть). Раскрытие строки показывает декодированную команду: текст и пункты DISPLAY TEXT / SELECT ITEM / SET UP MENU, параметры BIP-каналов, действия TIMER MANAGEMENT, названия квалификаторов PROVIDE LOCAL INFORMATION (все стандартные, включая ESN 07, MEID 0B и Supported RATs 1A) и SEND SHORT MESSAGE — разбирается SMS TPDU (тип, TP-MR, TP-DA, TP-PID, TP-DCS, срок действия, TP-UDL), а пользовательские данные показываются как текст для текстовых кодировок (GSM 7-бит, UCS2, 8-бит) или как secured-пакет (TS 31.115) при TP-PID = <code class="font-mono text-sm">7F</code> (SIM data download); заголовки конкатенации UDH декодируются. Для команд с данными ответа показывается строка <code class="font-mono text-sm">Ответ:</code> с байтами TERMINAL RESPONSE (без служебных TLV); ответы PROVIDE LOCAL INFORMATION декодируются через словарь данных PLI.</p>
|
||
|
||
<h3 id="terminal-profile" class="text-lg font-medium mb-2">8.4 TERMINAL PROFILE</h3>
|
||
<p class="text-sm mb-3">Блок <strong>TERMINAL PROFILE</strong> (рядом с «STATUS и опрос») содержит кнопки <strong>«Отправить»</strong> (повторная отправка, как «Спасение») и <strong>«Настроить»</strong>. В диалоге настройки: селектор пресетов (модели устройств, например профиль BIP-совместимого аппарата из этого проекта), поле hex и форма с флажком на каждый бит профиля по <strong>TS 102 223 §5.2</strong> / <strong>TS 31.111 §5.2</strong> (байты 1–39; для битов 3GPP используются имена из TS 31.111); каждый байт — вертикальный список битов в порядке спецификации (<strong>b1 — младший бит, первая строка таблицы</strong>); биты, образующие числовое поле по спецификации (байт 11 — число soft keys, байт 13 — число BIP-каналов, байты 14/15 — высота/ширина экрана, байт 16 — уменьшение ширины в меню, байт 19 — версия TIA/EIA-136, байт 24 — максимум кадров), показываются одним числовым полем на весь диапазон битов, а в подсказке байта 11 отмечено зарезервированное значение <code class="font-mono text-sm">'FF'</code>; блоки размещены фиксированными группами (байты 1–12 в 2 колонки, 13–16 в 4, 17–18 в 2, 19–21 в 3, 22–25 в 2, 26–28 в 3, 29–30 в 2, далее по одному в строке); переключение бита обновляет hex, а правка hex перерисовывает форму — поле hex основное, неизвестные байты и биты сохраняются. Кнопка <strong>«Применить»</strong> отправляет новое значение на сервер (и далее на карту), сбрасывая STK-сессию как «Спасение»; изменение хранится только в памяти (значение <code class="font-mono text-sm">--terminal-profile</code> — стартовое по умолчанию). Правила вывода характеристик устройства из TP (поколение связи, бездисплейные модемы, семейство стандартов) собраны в <code class="font-mono text-sm">docs/TERMINAL_PROFILE.md</code>.</p>
|
||
|
||
<h3 id="status-polling" class="text-lg font-medium mb-2">8.5 Опрос STATUS</h3>
|
||
<p class="text-sm mb-3">Кнопка <strong>Отправить STATUS</strong> отправляет STATUS (F2) вручную. Фоновый <strong>опрос включён по умолчанию</strong> (CAT-терминал опрашивает карту в режиме ожидания, TS 102 221 §14.6.2): после интервала бездействия (аргумент сервера <code class="font-mono text-sm">--poll-interval</code>, 1–255 с, по умолчанию 30 с, <code class="font-mono text-sm">0</code> отключает опрос) сервер отправляет STATUS и обрабатывает любую ожидающую проактивную команду. Переключатель включает и выключает опрос; команда карты <strong>POLL INTERVAL</strong> обновляет интервал (TS 102 223 §6.4.6; TERMINAL RESPONSE сообщает фактически используемый интервал), а после <strong>POLLING OFF</strong> переключатель показывает <strong>OFF</strong> янтарным цветом до нового POLL INTERVAL — ручная кнопка <strong>Отправить STATUS</strong> продолжает работать (на presence detection и ручной STATUS POLLING OFF не влияет). При извлечении карты опрос отключается и включается снова при следующем equip.</p>
|
||
|
||
<h3 id="pli-dict" class="text-lg font-medium mb-2">8.6 «Конфигурация TR» — данные ответа PROVIDE LOCAL INFORMATION</h3>
|
||
<p class="text-sm mb-2">Редактируемые hex-значения для всех 22 квалификаторов PLI (TS 102 223 §8.6 + TS 131 111). У десяти квалификаторов есть встроенные формы декодирования/кодирования:</p>
|
||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||
<li><strong>00</strong> Location Info (MCC, MNC, LAC/TAC, Cell ID)</li>
|
||
<li><strong>01</strong> IMEI · <strong>03</strong> Дата/время/TZ · <strong>04</strong> Язык · <strong>05</strong> Timing Advance</li>
|
||
<li><strong>06</strong> Access Technology · <strong>08</strong> IMEISV · <strong>09</strong> Search Mode</li>
|
||
<li><strong>0A</strong> Battery · <strong>0E</strong> Multiple Access Technologies</li>
|
||
</ul>
|
||
<p class="text-sm mb-3">Значения хранятся на сервере до перезапуска. Когда карта выдаёт PLI, сервер вставляет значения словаря в TERMINAL RESPONSE — в том числе в ответ тест-скрипта.</p>
|
||
|
||
<h3 id="network-simulation" class="text-lg font-medium mb-2">8.7 Симуляция сети</h3>
|
||
<p class="text-sm mb-2">Воспроизводит шаблоны записи реального телефона при смене сетевых условий (исследование трасс в <code class="font-mono text-sm">projects/UICC_NAA.md</code>): подключение EPS, потеря сервиса / ограниченный сервис, запрет роуминга, откат на 2G, приём SMS, перенастройка cell broadcast и AUTHENTICATE. По кнопке на сценарий; карта должна быть подключена.</p>
|
||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||
<li><strong>Холодная загрузка</strong> — инвалидация EPSNSC (KSI 07, ключ стирается) и фиктивные location-файлы.</li>
|
||
<li><strong>Подключение EPS / 2G</strong> — запись реального контекста EPS NAS (KSI, KASME, счётчики NAS, алгоритм) и реальных LOCI/PSLOCI/EPSLOCI (в 2G дополнительно реальные Kc/KcGPRS). Подключение считается успешным ручным выбором выбранного PLMN: если он есть в EF.FPLMN, его записи сначала очищаются (TS 23.122), поэтому подключение к запрещённой сети не проходит незаметно.</li>
|
||
<li><strong>Потеря сервиса / ограниченный сервис / запрет роуминга</strong> — событие Location status (только если карта на него подписана), инвалидация EPSNSC (по желанию с сохранением старого KASME), фиктивные location-файлы (LOCI/PSLOCI сохраняют PLMN, LAC <code class="font-mono text-sm">FFFE</code>, статус <code class="font-mono text-sm">01</code>; EPSLOCI стирается до <code class="font-mono text-sm">0B F6</code> + FF×13 + <code class="font-mono text-sm">FF FE 01</code>) и инвалидация Kc. <strong>Запрет роуминга</strong> эмулирует постоянный отказ «PLMN not allowed» (NAS cause #11): location-файлы получают статус <code class="font-mono text-sm">010</code> (EPSLOCI <code class="font-mono text-sm">0B F6</code> + FF×13 + <code class="font-mono text-sm">FF FE 02</code>), запрещённый VPLMN дописывается в <strong>EF.FPLMN</strong> по семантике сдвига из TS 31.102 §4.2.16 (домашняя сеть не записывается, дубликаты не создаются — уже имеющаяся запись пропускается), ключевой контекст стирается.</li>
|
||
<li><strong>Серия переподключений</strong> — реальная → невалидная запись EPSNSC подряд (число циклов и задержка настраиваются).</li>
|
||
<li><strong>Принято SMS</strong> — инкремент счётчика EF.SMSstatus (чтение-изменение-запись) и, по желанию, перезапись location-файлов.</li>
|
||
<li><strong>Перенастройка CB</strong> — запись списков CBMI/CBMIR или их очистка (все FF).</li>
|
||
<li><strong>AUTHENTICATE</strong> — команда AUTHENTICATE с заданными или случайными RAND/AUTN и показ ответа. Команда зависит от класса карты: UICC получает форму 3G/EPS/5G (<code class="font-mono text-sm">00 88 00 81 22</code>, ответ <code class="font-mono text-sm">DB</code> — успех или <code class="font-mono text-sm">DC</code> — ошибка синхронизации с AUTS), SIM — форму 2G (<code class="font-mono text-sm">A0 88 00 00 10</code>, только RAND, ответ SRES + Kc).</li>
|
||
</ul>
|
||
<p class="text-sm mb-3"><strong>Параметры</strong> (свёрнуты) задают оператора (поиск по мировому списку MCC/MNC с сервера плюс выбор случайного роуминг-оператора и кнопка <strong>«Домашняя сеть»</strong>, заполняющая HPLMN карты из первой записи EF.HPLMNwAcT с откатом на IMSI), LAC/Cell ID/TAC/RAC, необязательные идентификаторы (пусто = случайно: TMSI, GUTI, KSI, KASME, Kc, счётчики NAS, алгоритм, RAND/AUTN), переключатели сценария (включая <strong>«Отказ: записать FPLMN»</strong>) и число циклов/задержку. Журнал шагов показывает каждую запись, ENVELOPE и AUTHENTICATE с их SW. Отправляются только UPDATE BINARY/RECORD, ENVELOPE и AUTHENTICATE — FPLMN дописывается только сценарием постоянного отказа (TS 31.102 §4.2.16, без дубликатов), а подключение к сети из списка сначала очищает её запись (успешный ручной выбор, TS 23.122); 5GS location-файлы не записываются; записи меняют карту и видны в последующих сравнениях снимков.</p>
|
||
|
||
<h4 id="network-state" class="font-medium mb-1">Монитор сетевого состояния</h4>
|
||
<p class="text-sm mb-3">Рядом с кнопками симуляции компактная панель <strong>«Сетевое состояние»</strong> показывает, что сейчас хранит карта и что было сэмулировано последним. В заголовке — <strong>сэмулированное состояние сервиса</strong>: <em>Не определено</em>, пока его не задаст сценарий или событие Location status, затем <em>Обычный сервис</em> (зелёный), <em>Ограниченный сервис</em> (жёлтый) или <em>Нет сервиса</em> (красный), с красной пометкой <em>PLMN не разрешён</em>, если location-файлы или EF.FPLMN указывают на отказ регистрации — плюс текущее <strong>местоположение</strong>: PLMN, страна и оператор (из необязательного мирового списка MCC/MNC, если он загружен), LAI/RAI/TAI и <strong>класс роуминга</strong> (<em>Домашняя сеть</em>, если PLMN совпадает с HPLMN; <em>Эквивалентная домашней</em>, если он есть в EF.EHPLMN; иначе <em>Гостевая (роуминг)</em>). Ниже — по одной компактной строке на контролируемый файл (IMSI, EHPLMN, SPDI, HPLMNwAcT, LOCI, PSLOCI, EPSLOCI, EPSNSC, CBMI, CBMIR, SMSstatus, FPLMN) с декодированной сводкой и признаком последнего обновления (<code class="font-mono text-sm">init</code>, <code class="font-mono text-sm">write</code>, <code class="font-mono text-sm">read</code>, <code class="font-mono text-sm">refresh</code>); при наведении — все декодированные поля; длинные списки PLMN сокращаются (EF.HPLMNwAcT показывает только первую сеть и пометку <code class="font-mono text-sm">… +N</code>, а технологии доступа — в подсказке). Панель читает файлы один раз при подключении карты (только если ICCID читается), обновляет их на месте по записанным симулятором байтам, перечитывает EF.IMSI после каждого сценария и события Location status (мульти-IMSI апплеты) и никогда не опрашивает карту — кнопка <strong>«Обновить»</strong> перечитывает все файлы по требованию.</p>
|
||
|
||
<h3 id="esim" class="text-lg font-medium mb-2">8.8 eSIM / LPA (локальные операции)</h3>
|
||
<p class="text-sm mb-2">Для eUICC (SGP.22/SGP.32) подвкладка <strong>«eSIM»</strong> читает чип и управляет установленными профилями через локальный интерфейс ES10 (через pySim, без обращения к SM-DP+):</p>
|
||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||
<li><strong>Чип</strong> — EID, EUICCInfo1/2 со всеми декодированными полями (версия профиля, SVN, прошивка, расширенные ресурсы карты — число установленных приложений и свободная энергонезависимая/энергозависимая память —, битовые списки возможностей UICC и RSP, идентификаторы CI PKI, категория, запрещённые PPR, версия PP, номер аккредитации SS, данные сертификации), настроенные адреса SM-DP+ по умолчанию / корневого DS и <strong>таблица авторизации правил</strong> (ES10b GetRat: идентификаторы PPR, разрешённые операторы, флаг согласия). Неизвестные TLV сохраняются как сырой hex. Поля сгруппированы в блоки — EID, EUICCInfo1, адреса и таблица авторизации правил слева, более крупный EUICCInfo2 в правом блоке (на узких экранах — одна колонка); короткие поля в блоке EUICCInfo2 располагаются в две колонки, длинные значения занимают всю ширину.</li>
|
||
<li><strong>Профили</strong> — все профили с состоянием (включён/отключён), ником, оператором, именем, ICCID, ISD-P AID, классом, владельцем и типом значка; в заголовке карточки показываются оператор, а затем ник (или имя профиля). Сам значок показывается в натуральную величину рядом с метаданными, а строка <strong>Icon</strong> содержит его тип и размер данных в байтах. Кнопки <strong>«Включить»</strong>/<strong>«Отключить»</strong> переключают профиль; карта обычно сначала отправляет REFRESH (виден в журнале проактивных команд) — терминальный ответ завершает переключение, после чего сессия карты переинициализируется как при equip: ICCID, сетевое состояние и все кэшированные данные перечитываются, а запрошенное состояние проверяется по перечитанному списку профилей.</li>
|
||
<li><strong>Уведомления</strong> — список ожидающих уведомлений только для чтения (номер последовательности, операция, адрес, ICCID); ничего не обрабатывается и не удаляется.</li>
|
||
</ul>
|
||
<p class="text-sm mb-3">Никаких загрузок профилей, обработки уведомлений и взаимодействия с SM-DP+ — используются только локальные функции ES10a/b/c. Если карта не eUICC, подвкладка сообщает об этом.</p>
|
||
|
||
</section>
|
||
|
||
<section class="mb-10">
|
||
<h3 id="test-script" class="text-lg font-medium mb-2">8.9 Тест-скрипт</h3>
|
||
<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>
|
||
<p class="text-sm mb-2">У вкладки <strong>четыре представления</strong>: <strong>список наборов</strong> (по умолчанию; <em>Добавить набор</em> / <em>Редактировать</em> / <em>Запустить</em> / <em>Экспорт</em> / <em>Удалить</em>), <strong>редактор набора</strong> (скрипты набора в порядке выполнения — необязательный <em>setup</em> первым и <em>teardown</em> последним, с пометками ролей; у каждого скрипта <em>Запустить</em>/<em>Редактировать</em>/<em>Переместить</em>/<em>Скопировать</em>/<em>Удалить</em>, политика <em>при ошибке</em> <em>остановить</em> (по умолчанию) / <em>продолжить</em> и <em>Требуется ADM</em>), <strong>редактор скрипта</strong> (список шагов; кнопка <em>Старт</em> выполняет только этот скрипт и показывает результат под шагами — он не сохраняется) и <strong>отчёт набора</strong> (после запуска набора: статус каждого скрипта, таблица шагов с ожидаемым/фактическим, примечание об ошибке и выдержка из журнала запуска; сводка с успешно/предупреждения/ошибки/пропущено, время выполнения, счётчики SCP80 до → после по каждому keyset, пресет и предупреждение о смене сессии карты; экспорт в <em>JSON</em> или <em>Markdown</em>). <strong>Запуск набора</strong> выполняет его скрипты по порядку в <strong>одной сессии карты, без сбросов и без продолжения с места остановки</strong>; <em>при ошибке</em> решает, остановится ли набор на этом скрипте или запустится следующий, <strong>teardown выполняется всегда</strong> при остановке или ошибке (пока карта в ридере), чтобы следующий тест начался с чистого состояния, а сброс карты останавливает набор и отмечается в отчёте. <strong>Начать со сброса карты</strong> сбрасывает карту и выполняет полную переинициализацию перед запуском набора (скрипты затем работают со свежеинициализированной картой); пресет должен по-прежнему совпадать с ICCID карты, а требуемый ADM проверяется заново для новой сессии карты. Инициализация поглощает начальные proactive-команды карты, поэтому скрипт не поймает первую команду после сброса (они остаются в журнале proactive). <strong>Требуется ADM</strong> (у набора или скрипта) проверяет ключ ADM из подобранного пресета <strong>один раз</strong> перед запуском — ошибка отклоняет запуск (проверьте вручную через значок ADM; автоматических повторов нет). Скрипты хранятся в хранилище наборов (<code class="font-mono text-sm">~/.pysim-simple-server/test_suites.json</code>, <code class="font-mono text-sm">--test-suites</code>); каждый скрипт принадлежит ровно одному набору, и скрипт можно переместить или скопировать в другой набор (экспорт набора — это пакет с набором и его скриптами; старый экспорт только скриптов импортируется в автоматически созданный набор «Imported scripts»).</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> (семантические формы: <strong>та же форма, что и в диалоге отправки на вкладке «Телефон»</strong>, для всех смоделированных событий — четыре события, которые собирает сервер (Location status, Access technology change, Network rejection, Data connection status change), передаются полями, которые он проверяет и собирает во время запуска, остальные несут собранный формой hex данных события (показывается под формой, с проверкой одного ENVELOPE); источник device identities берётся из события (например, MT call → сеть) или из его поля источника), <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 опрашивает, пока карта не объявит команду) и <em>Очистка очереди проактивных команд</em> (опрос STATUS и поглощение всех объявленных команд — результат TERMINAL RESPONSE для каждой, опционально другой результат для первой; граница попыток/интервала; опциональная проверка <em>require</em> по поглощённому. Пустой опрос проходит, финальный STATUS должен быть idle, а оставшаяся команда передаётся следующему шагу — используйте в начале, середине или конце скрипта, чтобы убедиться, что карта перестала слать команды; она же поглощает команду, оставшуюся от предыдущего шага (ответившего <code class="font-mono text-sm">91XX</code>)). У каждого действия есть проверка ответа: ожидаемые 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 с <em>попытками</em> > 1 опрашивает, когда апплет выдаёт команду при опросе. Проверяются тип команды, квалификатор и содержимое: текст / пункт / 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 оставляйте пустым; отклонённый ENVELOPE (<code class="font-mono text-sm">62XX</code>/<code class="font-mono text-sm">63XX</code>) может вовсе не нести пакет ответа — для такого шага оставляйте проверку PoR «любой» или ожидайте «без PoR») и проверка <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> (продолжает); уровень применяется к любой ошибке шага, включая ожидание без объявленной команды и ошибку карты, возникшую на шаге (например, <code class="font-mono text-sm">6A82</code> отсутствующего необязательного файла); каждая проверка показывается с ожидаемым и фактическим значением.</li>
|
||
<li><strong>Шаблоны</strong> — Empty, <em>Обзор меню STK</em>, <em>Апплет через SCP80</em>; редактор шагов — формный (действие Event показывает форму события из симулятора), а набор экспортируется/импортируется пакетом JSON (набор и его скрипты).</li>
|
||
</ul>
|
||
<p class="text-sm mb-3">Каждый шаг пишет семантическую строку в журнал сервера под своим номером (<code class="font-mono text-sm">TEST-RUN step N: …</code>), запрос перед ответом: отправленный APDU/данные и полученный SW, для SCP80 — открытый C-APDU, собранный защищённый пакет и R-APDU из PoR, для ожидания — тройка FETCH / команда / TERMINAL RESPONSE, очистка очереди проактивных команд — каждый раунд STATUS/FETCH/команда/TR, а очистка в конце запуска — поглощённые команды (отвечаются <code class="font-mono text-sm">ok</code> — cancel отправляется только по явному запросу скрипта), а для выбора пункта меню — полный ENVELOPE с определённым пунктом. Запустите сервер с <code class="font-mono text-sm">--apdu-trace</code>, чтобы добавить и журнал сырых транспортных APDU.</p>
|
||
|
||
<h3 id="bip" class="text-lg font-medium mb-2">8.10 BIP-терминал (обычный TCP)</h3>
|
||
<p class="text-sm mb-2">Пилюля <strong>BIP</strong> запускает терминальную сторону Bearer Independent Protocol для карт, использующих TCP без HTTP OTA (SCP81): апплет или пуш-триггер может открыть канал и обменяться сырыми данными. Одновременно работает только одна BIP-сессия — запуск здесь останавливает слушатель SCP81, а запуск слушателя SCP81 останавливает эту сессию (в обоих случаях сообщается, что было заменено).</p>
|
||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||
<li><strong>Локальный приёмник (только журнал)</strong> (по умолчанию) — принимает каналы карты на локальном слушателе и только записывает принятое в журнал; ничего не отправляется обратно. Оставьте порт пустым для эфемерного порта (занятый адрес появится в статусе). Подходит для карт, которые открывают TCP-соединение только чтобы выгрузить данные.</li>
|
||
<li><strong>Адрес карты (OPEN CHANNEL)</strong> — каждый канал подключается к адресу, который карта запросила в OPEN CHANNEL (Other address + transport port, только TCP-клиент); Host и Port не используются, используется сеть сервера (только для лаборатории).</li>
|
||
<li><strong>Заданный адрес</strong> — каждый канал подключается к указанному Host:Port; запрошенный картой адрес только записывается в журнал.</li>
|
||
</ul>
|
||
<p class="text-sm mb-2">Строка статуса показывает активный режим, занятый адрес, владельца сессии и открытые каналы; блок <strong>Каналы</strong> перечисляет счётчики байт по каналам, а <strong>Журнал BIP</strong> записывает каждое событие open / send / receive / close с hex-превью (те же события, что показывает вкладка SCP81). CAT_TP через UDP не реализован.</p>
|
||
|
||
<h2 id="server" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">9. Установка сервера</h2>
|
||
<p class="mb-3">Для работы с картой (вкладка «Картридер», «Симулятор», доставка OTA) нужен локальный <a href="https://github.com/anttro/simple" class="text-blue-600 dark:text-blue-400 hover:underline">pysim-simple-server</a> — встроенный в SIMple HTTP-сервер, оборачивающий pySim, работающий с ридером через PC/SC или serial и раздающий сам PWA (откройте <code class="font-mono text-sm">http://127.0.0.1:8080</code>).</p>
|
||
|
||
<h3 id="prerequisites" class="text-lg font-medium mb-2">9.1 Требования</h3>
|
||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||
<li><strong>Python 3.8+</strong> с <code class="font-mono text-sm">pip</code></li>
|
||
<li><strong>Git</strong></li>
|
||
<li><strong>Смарт-картридер</strong> (PC/SC или serial/FTDI). Предпочтителен PC/SC; на Linux требуются <code class="font-mono text-sm">pcsc-lite</code> + <code class="font-mono text-sm">ccid</code></li>
|
||
<li><strong>Только Windows</strong> — используйте <strong>Python 3.10–3.13</strong> (рекомендуется 3.13): <code class="font-mono text-sm">pyscard</code> (обёртка драйвера PC/SC) поставляет готовые wheels для этих версий. На Python 3.9 / 3.14 pip собирает <code class="font-mono text-sm">pyscard</code> из исходников, для чего требуются Microsoft C++ Build Tools («Desktop development with C++»). Мост SMPP (<code class="font-mono text-sm">smpp.twisted3</code>) на Windows намеренно не устанавливается, поэтому для Python 3.10–3.13 C++ Build Tools не нужны.</li>
|
||
</ul>
|
||
|
||
<h3 id="quickstart-linux" class="text-lg font-medium mb-2">9.2 Быстрый старт — Linux / macOS</h3>
|
||
<pre class="font-mono text-xs bg-gray-100 dark:bg-slate-800 rounded p-3 mb-3">git clone https://github.com/anttro/simple.git
|
||
cd simple
|
||
chmod +x setup.sh start.sh
|
||
./setup.sh # создаёт .venv, устанавливает pysim + сервер (однократно)
|
||
./start.sh # запускает сервер (PWA + API, автоопределение ридера)</pre>
|
||
|
||
<h3 id="quickstart-windows" class="text-lg font-medium mb-2">9.3 Быстрый старт — Windows</h3>
|
||
<pre class="font-mono text-xs bg-gray-100 dark:bg-slate-800 rounded p-3 mb-3">git clone https://github.com/anttro/simple.git
|
||
cd simple
|
||
setup.bat # создаёт .venv, устанавливает pysim + сервер (однократно)
|
||
start.bat # запускает сервер (PWA + API)</pre>
|
||
|
||
<h3 id="helper-scripts" class="text-lg font-medium mb-2">9.4 Вспомогательные скрипты</h3>
|
||
<table class="w-full text-sm mb-3 border-collapse">
|
||
<thead><tr class="border-b border-gray-300 dark:border-slate-700"><th class="text-left py-1 px-2">Скрипт</th><th class="text-left py-1 px-2">Назначение</th></tr></thead>
|
||
<tbody>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">setup.sh / setup.bat</td><td class="py-1 px-2">Создаёт <code class="font-mono text-sm">.venv/</code>, устанавливает pySim и сервер. Запускается один раз после клонирования.</td></tr>
|
||
<tr><td class="py-1 px-2 font-mono">start.sh / start.bat</td><td class="py-1 px-2">Запускает сервер из venv (при отсутствии — из глобальной установки).</td></tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<h3 id="reader-autodetect" class="text-lg font-medium mb-2">9.5 Автоопределение ридера</h3>
|
||
<ul class="list-disc list-inside text-sm space-y-1 mb-3">
|
||
<li><strong>PC/SC (Linux)</strong> — <code class="font-mono text-sm">start.sh</code> передаёт <code class="font-mono text-sm">-p 0</code>, если запущен демон <code class="font-mono text-sm">pcscd</code></li>
|
||
<li><strong>PC/SC (Windows)</strong> — <code class="font-mono text-sm">start.bat</code> всегда использует <code class="font-mono text-sm">-p 0</code> (PC/SC встроен в Windows)</li>
|
||
<li><strong>Резерв сервера</strong> — при запуске без аргументов ридера сервер сам опрашивает PC/SC-ридер при старте (3 попытки с интервалом 2 с)</li>
|
||
<li><strong>Serial-ридеры</strong> — запустите сервер вручную с <code class="font-mono text-sm">-d /dev/ttyUSB0</code> (Linux)</li>
|
||
</ul>
|
||
<p class="text-sm mb-3">Если карта отсутствует, вкладка «Картридер» показывает «Карта не обнаружена. Вставьте карту и нажмите Подключить карту». Вставьте карту — сервер инициализирует её автоматически (auto-equip включён по умолчанию) — либо нажмите <strong>Equip card</strong>. Сам сервер запускается и с пустым картридером: отсутствие карты — нормальное состояние, а не ошибка. Дополнительные аргументы <code class="font-mono text-sm">start.sh</code>/<code class="font-mono text-sm">start.bat</code> передаются серверу (например, <code class="font-mono text-sm">./start.sh --gsmtap</code> — поток APDU в виде GSMTAP-SIM пакетов для Wireshark / SIMtrace Analyser).</p>
|
||
|
||
<h3 id="manual-install" class="text-lg font-medium mb-2">9.6 Ручная установка</h3>
|
||
<pre class="font-mono text-xs bg-gray-100 dark:bg-slate-800 rounded p-3 mb-3"># Создать и активировать venv
|
||
python3 -m venv .venv
|
||
source .venv/bin/activate # Linux/macOS
|
||
# .venv\Scripts\activate # Windows
|
||
|
||
# Установить pysim
|
||
pip install git+https://github.com/osmocom/pysim.git
|
||
|
||
# Установить pysim-simple-server (editable — раздаёт встроенный PWA)
|
||
pip install -e .
|
||
|
||
# Запустить сервер (PWA + API)
|
||
pysim-simple-server --http-port 8080</pre>
|
||
<p class="text-sm mb-3">Подключите PC/SC-ридер с SIM-картой и откройте <code class="font-mono text-sm">http://127.0.0.1:8080</code> — PWA и API на одном origin, поэтому CORS не требуется.</p>
|
||
<p class="text-sm mb-3">Если PWA раздаётся с публичного HTTPS-хоста (например, <code class="font-mono text-sm">https://simple.example.com</code>), для доступа к локальному серверу карт нужны два условия: (1) сервер отвечает на preflight заголовком <code class="font-mono text-sm">Access-Control-Allow-Private-Network: true</code> (pysim-simple-server ≥ 1.6.1 делает это автоматически), и (2) браузеру должно быть разрешено обращаться к локальной сети — в Chrome/Edge/Vivaldi: Настройки сайта → Доступ к локальной сети → разрешить сайт (или подтвердить запрос). Без разрешения браузера запрос к <code class="font-mono text-sm">127.0.0.1</code> блокируется ещё до отправки preflight.</p>
|
||
|
||
|
||
</section>
|
||
<section class="mb-10">
|
||
<h2 id="compatibility" class="text-xl font-semibold mb-3 border-b border-gray-300 dark:border-slate-700 pb-1">10. Совместимость версий</h2>
|
||
<table class="w-full text-sm mb-3 border-collapse">
|
||
<thead><tr class="border-b border-gray-300 dark:border-slate-700"><th class="text-left py-1 px-2">PWA (SIMple)</th><th class="text-left py-1 px-2">Сервер</th><th class="text-left py-1 px-2">Статус</th></tr></thead>
|
||
<tbody>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">любая</td><td class="py-1 px-2 font-mono">та же мажорная</td><td class="py-1 px-2">✅ Совместимы</td></tr>
|
||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2 font-mono">любая</td><td class="py-1 px-2 font-mono">старее мажорная</td><td class="py-1 px-2">❌ Устарел — обновите сервер</td></tr>
|
||
<tr><td class="py-1 px-2 font-mono">любая</td><td class="py-1 px-2 font-mono">новее мажорная</td><td class="py-1 px-2">⚠️ Сервер новее — обновите PWA</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<p class="text-sm">PWA проверяет версию сервера при подключении через <code class="font-mono text-sm">GET /api/version</code> и сравнивает мажорную версию (например, PWA 3.x с сервером 3.x; сервер 2.x помечается как устаревший).</p>
|
||
|
||
|
||
</section>
|
||
|
||
</main>
|
||
</div>
|
||
|
||
<script>
|
||
(function () {
|
||
if (localStorage.getItem('theme') === 'dark' ||
|
||
(!localStorage.getItem('theme') && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
|
||
document.documentElement.classList.add('dark');
|
||
}
|
||
var toc = document.getElementById('toc');
|
||
var main = document.querySelector('main');
|
||
if (!toc || !main) return;
|
||
var headings = Array.prototype.filter.call(main.querySelectorAll('h2, h3, h4'), function (h) {
|
||
return /^\d/.test(h.textContent.trim());
|
||
});
|
||
var stack = [document.createElement('ol')];
|
||
stack[0].className = 'space-y-1 list-none';
|
||
var lastLevel = 2;
|
||
headings.forEach(function (h) {
|
||
var level = parseInt(h.tagName.charAt(1), 10);
|
||
var li = document.createElement('li');
|
||
var a = document.createElement('a');
|
||
a.href = '#' + h.id;
|
||
a.textContent = h.textContent;
|
||
li.appendChild(a);
|
||
if (level > lastLevel) {
|
||
var ul = document.createElement('ul');
|
||
ul.className = 'pl-4 mt-1 space-y-1 list-none';
|
||
var parent = stack[stack.length - 1].lastElementChild;
|
||
parent.appendChild(ul);
|
||
stack.push(ul);
|
||
} else if (level < lastLevel) {
|
||
while (stack.length > 1 && level < lastLevel) { stack.pop(); lastLevel--; }
|
||
}
|
||
stack[stack.length - 1].appendChild(li);
|
||
lastLevel = level;
|
||
});
|
||
toc.appendChild(stack[0]);
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html>
|