Всем привет!
Традиционное вступление в стиле "плач Ярославны": GlobalPlatform, ISO 7816, JavaCard и прочие смежные стандарты - боль. Тонна материала написанная сухим языком так и навивает мысль, что авторы всего этого не инженеры, а юристы. Для тех немногих счастливчиков, кому не приходится иметь с этим дело, в качестве примера скажу, что каждый стандарт ETSI начинается со смысловых определений и толкований глаголов "shall", "shall not", "should", "should not" и т.д. Нет, в канцелярском стиле ничего плохого нет. Плохо становится когда он плавно переходит в поросячью латынь - и это одно из самых терпимых определений. Это же додуматься надо "размазать" требования к несчастной SMS-ске между пятью стандартами (ETSI 102-223/-225/-226 и 131-111/-115).
Ну вот ты преодолел пучины стандартов, затем засел за написание JavaCard-апплета, с чем тоже успешно справился, ну а дальше начинается квест "найди тулзы". Инструментарий от Oracle для сборки .cap-файлов недоступен из России, благо есть один удобный в открытом доступе. Там же рядышком лежит тулза для установки/удаления апплетов (да и вообще управления жизненным циклом карты).
Итак, ты скомпилировал и загрузил апплет на карту. Классно! А дальше? А дальше поговорим в статье.
Что есть на рынке?
Вообще, инструментов для взаимодействия с картой крайне мало. Из известных мне это JCShell от NXP Semiconductors и PCOM от Oberthur. Судя по синтаксису можно заключить, что авторы, как бы помягче выразиться, как никто другой пострадали от чтения отраслевых стандартов.
Вот скрипт на JCShell:
DEFUN External_authenticate_session @includeJCipherPlugin /send "0084 0000 08" *9000 /set-var RAND_IC ${last.response.data} /echo ${RAND_IC} /set-var data $(enc -m DES3/CBC -k ${KENC} -p NOPAD ${RAND_IC}) ## send EXT AUTH /send "0082 00${KIDX} #(${data})" *9000 END
А вот на PCOM:
;; Prepare data for EXT AUTH .SET_DATA %RAND_IFD %RAND_IC %K_IFD .SET_KEY %KENC .SET_VECT_INI 0000000000000000 .DES3CBC L FF .DISPLAY L ;;Compute MAC .SET_DATA L .SET_KEY %KMAC .SET_VECT_INI 0000000000000000 .MAC3 J 80 /P .DISPLAY J
Всякий раз как сложность сценария выходит за рамки "Status Word" читаемость скриптов скатывается на уровень регулярных выражений. К тому же оба инструмента проприетарные и в открытом доступе их не найти.
Попытка упростить себе жизнь.
За последние годы я четко определил видение своего будущего - стать миллионером! На худой конец освою python. Штош, как человек далекий от питона с удивлением обнаружил, насколько он удобен: операции со списками, функциями, объектами и прочим-прочим - все максимально абстрагировано в угоду быстрой разработки и читаемости кода (тут главное не увлекаться). Самым любознательным советую сравнить исходники FunGP и GlobalPlatformPro в части, отвечающей за установление защищенного соединения.
В общем и целом, результат получился следующим:
isd.mutual_auth()
Это всё, что нужно написать тестеру, чтобы осуществить процедуру MUTUAL AUTHENTICATE. Ладно, шучу - не всё, просто привел в качестве примера на контрасте с предыдущими монстрами. Но вот скрипт, который считывает данные с карты:
from fun_gp import SmartCard from fun_gp.utils import lv known_readers = ['ACS ACR39U ICC Reader 0', 'ACS ACR39U ICC Reader 00 00'] isd_default_keys = ["404142434445464748494A4B4C4D4E4F", "404142434445464748494A4B4C4D4E4F", "404142434445464748494A4B4C4D4E4F"] isd = SmartCard(known_readers, isd_default_keys) isd.apdu_plain('00A4 0400' + lv('a000000151000000')) # isd.apdu_plain('80CA 2F00 02 5C00', name='GET DATA: list of applications') isd.apdu_plain('80CA 00E0 00', expected_sw=0x9000) isd.apdu_plain('80CA 0042 00', expected_sw=0x6A88, name='GET DATA: Issuer Identification Number')
Тут обращаем внимание на следующие элементы:
known_readers[] - узнать имя ридера можно разными путями, но самый простой - это запустить этот скрипт. Он рухнет, но перед этим выдаст список доступных ридеров, откуда и возьмете название своего:
Context established. Available PCSC readers: ACS ACR39U ICC Reader 0 >> 00A40400 08 A000000151000000 Traceback (most recent call last): --//--
isd_default_keys[] - святая-святых. Убедитесь, что они корректны.
SmartCard(known_readers, isd_default_keys)- обратит�� внимание, что переменная, хранящая указатель на экземпляр этого класса называется isd. На всякий случай уточню, что ISD (Issuer Security Domain) - это самый главный апплет на карте, который отвечает за установку/удаление других апплетов, а также обладает правом окирпичить вашу карту.
Банального общения с картой мне показалось недостаточным, потому-то проект перерос из тулзы для коммуникации по протоколу APDU в легковесный (пока) фреймворк, способный накатить апплет на карту:
from fun_gp import SmartCard from fun_gp.utils import lv known_readers = ['ACS ACR39U ICC Reader 0', 'ACS ACR39U ICC Reader 00 00'] isd_default_keys = ["404142434445464748494A4B4C4D4E4F", "404142434445464748494A4B4C4D4E4F", "404142434445464748494A4B4C4D4E4F"] applets = [ "../../resources/SimpleApplet.cap", # 'A000000082' ] isd = SmartCard(known_readers, isd_default_keys) isd.apdu_plain('00A4 0400' + lv('a000000151000000'), expected_sw=0x9000, name='SELECT: isd') isd.mutual_auth() for cap in applets: isd.install_app_scp02(cap)
Тулза GlobalPlatformPro (да и беспокойные JCShell с PCOM'ом) требует явного указания AID пакета и AID апплета. Я решил поручить эту грязную работенку методу install_app_scp02(), который извлекает эту инфу из .cap-файла. Важное уточнение - после вызова метода isd.mutual_auth() вся последующая коммуникация с картой через методы, оканчивающиеся на scp02(): apdu_scp02(), install_app_scp02() и т.д.
Удалить апплет можно так:
from fun_gp import SmartCard from fun_gp.utils import lv known_readers = ['ACS ACR39U ICC Reader 0', 'ACS ACR39U ICC Reader 00 00'] isd_default_keys = ["404142434445464748494A4B4C4D4E4F", "404142434445464748494A4B4C4D4E4F", "404142434445464748494A4B4C4D4E4F"] packages = [ 'A000000082', # 'SimpleApplet.cap' ] isd = SmartCard(known_readers, isd_default_keys) isd.apdu_plain('00A4 0400' + lv('a000000151000000'), expected_sw=0x9000, name='SELECT: isd') isd.mutual_auth() for aid in packages: isd.uninstall_app_scp02(package_aid=aid)
Надеюсь, те немногие, кто занят в области разработки под смарт-карты дадут обратную связь. Отдельное обращение к python-лордам и миледи: "не стреляйте в пианиста, он играет как умеет".
Всем пока!
