Вы находитесь на странице: 1из 1

КАК СТАТЬ АВТОРОМ Мегапосты: 60 лет лазеру Подкаст для разрабов ИТ-менеджмент в банке

Все потоки Разработка Администрирование Дизайн Менеджмент Маркетинг Научпоп Войти Регистрация

brake 10 января 2018 в 19:13

Работаем со смарт-картами, используя Python


(часть 1)
Python, API, Разработка систем связи

Сначала, на момент задумки, в 2014 году, данная


статья планировалась как единая публикация, но,
проработав материал (лень вынудила растянуть
этот процесс), я понял, что необходимо её
разделить на две части:

1. Знакомство с библиотекой и написание/разбор


кода специального командного процессора,
который ее использует.

2. Использование командного процессора из ч.1


для чтения содержимого файла с симки, которую
я, однажды, подобрал на улице (никаких
персональных данных раскрыто не будет). Узнаем,
как отучить Windows встревать в наше
взаимодействие с картой, а также, возможно,
затронем тему выбора (активации) системного приложения на карте (если моя экспериментальная
карта окажется UICC).
Реклама

Думаю, для профи-карточников первая часть будет представлять бо́льший интерес, а вторая часть будет
интересна, прежде всего, новичкам в этой теме (и будет иметь метку Tutorial). ЧИТАЮТ СЕЙЧАС

Среди множества Python-библиотек, обзоры которых есть на Хабре, я не обнаружил pyscard —


«Особенность» Вконтакте
библиотеки для взаимодействия со смарт-картами.
В этой статье я постараюсь дать краткое описание основных фич pyscard, а на сладкое напишем 30,2k 78

простенький командный процессор, работающий с картой посредством APDU.


Прошу учесть, что для понимания того, как использовать эту библиотеку, и окружающей терминологии Вышел Linux Mint 20 «Ulyana» (Ульяна)
требуется знакомство со стандартом ISO 7816-4 или, хотя бы, GSM 11.11. К GSM-стандарту проще 8,2k 12
получить официальный доступ, скачав его с сайта ETSI, впрочем и ISO 7816-4 (pdf, старенькая версия)
гуглится, несмотря на то, что за него на оф. сайте хотят денег). Путешествие по России в режиме
«Ночь в поезде, день в городе»
Pyscard существует с 2007 года и является кроссплатформенной (win/mac/linux) надстройкой над PC/SC 2,9k 50
API.
Comcast стал первым провайдером
мой опыт использования на платформах, если интересно... DNS-over-HTTPS для Firefox в США.
Пользователи недовольны
Мое рабочее окружение, где я использую pyscard — Windows7 2,1k 2
Материал данной статьи я тестировал, в основном, на mac OS, но на Windows7 тоже погонял, в
виртуалке. Должен отметить, что, в отличие от XP, «семерка» и, вероятно, «десятка», с настройками CP/M: взлет и падение Гэри Килдалла
по умолчанию, «ставит палки в колеса» при работе с картой в ридере:
9k 24

1. При помещении каждой карты в ридер эта карта считается устройством Plug&Play, для нее Как заработать на веб-скрапинге
системой «ищутся драйверы».
11,7k 22

2. Если мы дождались окончания п. 1, то система начинает искать на карте сертификаты, при этом
общаясь с ней своими APDU, эти APDU смешиваются с нашими и возникают коллизии,
Лазер: разрушительное оружие или
полезный инструмент?
приводящие к сбоям в наших программах.
Мегапост

Эти факторы доставили мне много боли при переходе с XP, пока я их не победил. Как это сделать,
расскажу во второй части.

Редакторский дайджест
Разработка начата под эгидой одного из ведущих (и на момент создания, и сейчас) игроков карточного Присылаем лучшие статьи раз в месяц
рынка.
Поддерживаются обе ветки Python (2 и 3). Электропочта

мой опыт использования с версиями Python…

В рабочем окружении я использую связку pyscard + Python 2.7, но, для статьи, мне показалось
правильным задействовать актуальную на сегодня ветку Python (3.6)

На мой взгляд библиотека pyscard спроектирована не особо pythonic и больше напоминает порт
какого-то Java фреймворка, однако полезности её это не уменьшает, по крайней мере для меня, хотя
имена модулей выглядят странно, конечно.

Точкой входа в библиотеку является пакет smartcard.

Отдельно стоит упомянуть пакет smartcard.scard, который отвечает за связь с карточным API
операционной системы. Если не нужны все абстракции библиотеки, а только голый PC/SC, то вам сюда.
Мы же на нём подробно останавливаться не будем.

Установка pyscard возможна следующими способами:

с PyPi (pip install pyscard) — подходит для систем, настроенных на сборку артефактов из
исходников, используется swig (ок для mac и, возможно, linux)

Из бинарного дистрибутива, который можно забрать c appveyor или c sourceforge (великолепно


прокатывает в Windows)

Pyscard имеет информативное руководство пользователя, которое доступно на официальном сайте,


pydoc и примеры, поэтому не вижу смысла дублировать все это здесь. Вместо этого мы:

1. Посмотрим на типовую структуру/шаблон программы;

2. Бросим взгляд на, по моему мнению, важнейшие объекты библиотеки, что должно убедить
пользоваться не низкоуровневым smartcard.scard, а именно smartcard;

3. Проиллюстрируем применение библиотеки на реальном примере — напишем командный


процессор (шелл) на Python 3.6, где командами будут прямо «APDU в хексе» и ответ с карты будет
выводиться в консоль. Также будут поддерживаться текстовые команды exit и atr.

Типовой шаблон программы


Пора уже сделать вброс порции кода, а то всё скучные вступительные «бубубу»...

from smartcard.CardRequest import CardRequest


cardrequest = CardRequest()
# метод waitforcard(), в нашем случае ждем любую карту
cardservice = cardrequest.waitforcard() # здесь выполнение будет приостановлено до помещения ка
рты в ридер

APDU = [0xA0, 0xA4, 0, 0, 2] # Это команда SELECT из GSM 11.11


# smartcard.CardConnection.CardConnection является контекст-менеджером
with cardservice.connection as connection:
connection.connect()
#далее - обмен данными с картой
data, sw1, sw2 = connection.transmit(APDU)

Какие задачи решает (практически любая) программа, работающая со смарт-картами в ридере? А вот
эти:

1. Выбор ридера, с которым мы будем взаимодействовать

2. Определение момента, когда карта окажется в этом ридере

3. Установка канала связи с картой

4. Проверка карты на соответствие нашим критериям (мы можем захотеть работать не с каждой
картой, которую пользователь нам подсунет)

5. Обмен данными с картой посредством APDU

6. Закрытие канала связи с картой

7. Определение момента, когда карта будет извлечена из ридера

Замечу, что перечисленные задачи решает, например, прошивка мобильного телефона.

Важнейшие объекты пакета smartcard


В этом разделе все имена указаны относительно пакета smartcard.

Подклассы CardType
Позволяют нам указать точный тип карт, с которыми наше приложение собирается работать. Можно
сделать так, чтобы наше приложение даже не реагировало на помещение в ридер карты, которая нам
не подходит.

Примеры:
CardType.ATRCardType (существует в библиотеке) — фильтрация карт по значению ATR. Наше
приложение будет реагировать только на карты с определенным значением ATR.

USIMCardType (я нафантазировал, можно реализовать) — допустимыми картами являются


только USIM, внутри проверяем возможность выбора USIM-приложения.

CardRequest и его подклассы


Позволяют свести воедино все требования нашего приложения, касающиеся установления связи с
картой:

строго задать тип карты (см. выше)

ограничить список допустимых ридеров (из уже установленных в системе)

изменить таймаут ожидания карты в ридере

По умолчанию никаких ограничений в CardRequest не ставится.

CardConnection
Канал коммуникации нашего приложения с картой, позволяет отправлять на карту APDU и получать
ответ, ключевой метод здесь — transmit(). Именно с его помощью происходит непосредственное
взаимодействие нашего приложения с картой. Необходимо отметить, что метод transmit() всегда
возвращает триплет (кортеж), состоящий из:

Ответных данных (содержит реальные данные или None, в зависимости от типа APDU, не все APDU
возвращают данные)

Первого байта статуса (StatusWord) SW1

Второго байта статуса (StatusWord) SW2

CardConnection является контекст-менеджером, что добавляет удобства при его использовании.

CardConnectionDecorator
Слово «декоратор» используется здесь в том же контексте, что и в Java, а не в том, к которому привыкли
Python-разработчики.
Позволяет придать особые свойства объекту CardConnection. Библиотека предоставляет рабочие
декораторы с говорящими названиями: ExclusiveConnectCardConnection и
ExclusiveTransmitCardConnection. Лично я не ощутил эффекта от использования этих декораторов —
если система (Windows) уж решила вклиниться со своими APDU в нашу сессию, то ни один из этих
декораторов не спасет, но, возможно, я что-то не так делал.

Функция System.readers()
Позволяет получить список подключенных к системе кардридеров и установить связь с картой в
определенном ридере.

sw.ErrorChecker, sw.ErrorCheckingChain
По умолчанию, в ходе обмена данными между картой и нашего приложением, никакие ошибочные
значения StatusWord (SW1, SW2) не возбуждают исключений. Это можно изменить, задействовав
потомков ErrorChecker, которые:

объединяются в последовательности sw.ErrorCheckingChain

привязываются к CardConnection и проверяют на отсутствие ошибок результат каждого вызова


метода transmit().
Встроенные в библиотеку «чекеры» позволяют получить в исключении подробную информацию о
проблеме без необходимости залезать в спеки и искать необходимые значения SW1, SW2.

Потомки CardConnectionObserver
Присоединяются к экземпляру CardConnection и получают информацию обо всех командных APDU и
ответах карты, которые проходят через наблюдаемое соединение. Пример применения — ведение лога
команд и ответов от карты.

Вооруженные таким знанием, мы вполне можем замахнуться на написание командного процессора,


использующего описываемую библиотеку.

Командный процессор с APDU (CLI)


Не буду подробно останавливаться на модуле cmd, который любезно предоставляет нам стандартная
библиотека, о нем уже писали здесь, перейду к реализации.

Весь исходный код процессора находится на гитхабе.


Пройдемся по главным моментам, не размениваясь на мелочи.

Функция select_reader()
Возвращает первый ридер, подключенный к компьютеру или None, если подключенных ридеров нет.

Код

Класс APDUShell
Данный класс, помимо наследования от cmd.Cmd, реализует интерфейс обладает поведением
наблюдателя smartcard.CardMonitoring.CardObserver

Данные экземпляра нашей оболочки


reader — устройство чтения, с которым будем работать.
card — объект карта, потребуется нам, чтобы определить момент смены карты в ридере.
connection — канал передачи APDU на карту и получения результата обработки.
sel_obj — строка, содержащая ID текущего объекта (файла или папки) выбранного командой SELECT. Эта
строка меняется всякий раз, когда команда SELECT выполняется.
atr — здесь мы запоминаем ATR текущей карты, чтобы можно было вывести его на экран, не
запрашивая карту каждый раз (такой запрос сбрасывает состояние выбора файла в карте).
card_connection_observer — наблюдатель, который привязывается к каждому connection, подробности
ниже.

В конструкторе
Код конструктора

Мы, помимо инициализации данных, добавляем себя в наблюдатели


smartcard.CardMonitoring.CardMonitor — объекта, который реагирует на события взаимодействия ридера
и карты (карта помещена в ридер, карта извлечена из ридера) и оповещает об этих событиях
smartcard.CardMonitoring.CardObserver, т.е. нас. Данный вид оповещения настраивается только один раз
за время жизни нашей оболочки. CardMonitor является синглтоном, поэтому мы не заботимся о времени
жизни его экземпляра.
Также обращаю внимание на экземпляр
smartcard.CardConnectionObserver.ConsoleCardConnectionObserver — это готовый библиотечный объект-
наблюдатель, отслеживающий состояние канала общения с картой и печатающий это состояние в
консоль. Мы его будем навешивать на каждое новое соединение с картой.

update()
Код

Это, собственно, поведение smartcard.CardMonitoring.CardObserver. Если наша текущая карта находится в


списке removedcards, то мы очищаем состояние оболочки для текущей карты.
Если в нашем выбранном ридере (и в списке addedcards, заодно) появилась новая карта, то мы
инициализируем новое состояние оболочки для этой карты.

default()
Код

Здесь все введенные пользователем шестнадцатиричные APDU превращаются в списки байтов и


отправляются на карту. Замечу, что единственное, что мы делаем с результатом здесь, это определяем,
не является ли отправленная команда успешным SELECT-ом. Если да, то мы обновляем ID последнего
выбранного объекта для печати в приглашении пользователю.
Всю остальную рутинную работу по интерпретации и отображению результата команды для
пользователя выполняет наш ConsoleCardConnectionObserver.

Небольшое попутное отступление


лично мне не очень нравится, как ConsoleCardConnectionObserver отображает результат исполнения
APDU — он не отделяет SW от результирующих данных так, как мне этого хотелось бы. Я
использовал его только, чтобы не захламлять код примера маловажными деталями. Однако, если
кому-то интересно, код метода update() моего наблюдателя есть в этом коммите.

_set_up_connection()
Код

Трудяга, который помогает нам каждый раз, когда карта в ридере меняется. Он создает соединение с
картой, навешивает на него ConsoleCardConnectionObserver, и запоминает ATR карты (чтобы команда atr
могла вывести его на экран).

_clear_connection()
Код

Антипод _set_up_connection(), «проводит зачистку», когда карта извлечена из ридера.

Заключение
На данном этапе мы можем запустить нашу командную оболочку и, в зависимости от наличия кард-
ридера, получить просто сообщение об ошибке (ридера нет) или увидеть шелл в работе (счастливчики с
ридером). При наличии ридера ничто не мешает вставить в него любую смарт-карту и выполнить
команду atr — должно сработать, однако, прошу не забывать, что на своих рабочих SIM и банковских
картах вы экспериментируете на свой страх и риск.

Скриншот работы нашего командного процессора

До встречи во второй части, предполагаю, что там Python-а не будет (почти или совсем), но будут APDU
и SW.

При подготовке статьи мне попалась пара проектов, которые используют данную библиотеку:
https://bitbucket.org/benallard/webscard/src
https://github.com/mitshell/card
Может реальные примеры кода окажутся полезными.

Теги: python, smart cards

Хабы: Python, API, Разработка систем связи

+11 82 11,4k 15 Поделиться

@ brake
Пользователь

ПОХОЖИЕ ПУБЛИКАЦИИ

20 июня 2020 в 10:35

Настраиваем окружение Python с помощью pyenv, virtualenvwrapper, tox и pip-compile


+11 6,4k 79 17

13 ноября 2019 в 10:24

Как написать смарт-контракт на Python в сети Ontology. Часть 2: Storage API


+5 994 31 9

6 июля 2015 в 12:57

Центр сертификации AD + Smart Card = Авторизация пользователя в домене


+3 35,9k 93 10

ЗАКАЗЫ

PHP symfony портал логистики. разработка и рефакторинг имеющего портал


600 ₽ за час • 3 отклика • 16 просмотров

Доработать ajax пагинацию на Wordpress


1 000 ₽ за проект • 3 отклика • 33 просмотра

Создания мобильного приложения на Flutter


80 000 ₽ за проект • 1 отклик • 33 просмотра

Разработка части приложения на ANDROID


1 000 ₽ за час • 6 откликов • 49 просмотров

Разработка части приложения на IOS


1 000 ₽ за час • 5 откликов • 27 просмотров

Больше заказов на Хабр Фрилансе

0+ ₽

Удобный браузер
Браузер, который умеет сохранять их
и синхронизировать пароли между устройствами.

ПОДРОБНЕЕ YANDEX.RU

Реклама

Комментарии 15 ЧТО ОБСУЖДАЮТ

fapsi 11 января 2018 в 00:36 0 Сейчас Вчера Неделя


Список APDU команд будет во второй части?
Для знакомства с тем, что происходит "по ту сторону", — Жикун Чен "Технология Java Card для смарт-карт. Путешествие по России в режиме
Архитектура и руководство программиста". «Ночь в поезде, день в городе»
2,6k 43

brake 11 января 2018 в 00:42 0 «Особенность» Вконтакте


Во второй части будут только несколько разных APDU. Остальное есть в указанных в начале стандартах. 29,9k 78

Как я закрыл трехлетний issue в


TypeScript
НЛО прилетело и опубликовало эту надпись здесь
11,7k 9

fapsi 11 января 2018 в 21:39 0


В Burger King использовали баг
Да со списком команд проблем нет, терминальная программа и карт-ридер в наличии. автопилота Tesla для рекламы.
Электрокары путают знаки сети со
«Стоп»
brake 11 января 2018 в 00:38 0 11,8k 22

Del
Подкаст: Build 2020 глазами инсайдера
— ИИ, суперкомпьютеры, нейросети и
Linux на Windows
mihmig 11 января 2018 в 08:46 0
Мегапост
Есть карт-ридер и несколько банковских карт с истёкшим сроком действия (пин-коды известны)
Возможно ли «заиспользовать» их в своём DIY-проекте?
Или в банковских картах используются нестандартные команды?

brake 11 января 2018 в 09:40 0

С банковскими картами я незнаком, но предполагаю, что часть команд ISO 7816-4 должна поддерживаться
(хотя бы SELECT, GET RESPONSE, READ BINARY, READ RECORD). Команды, думаю, стандартные, но стандарты
там свои.
Схема там, судя по интернетам, обычная для UICC — выбираем приложение по AID и вперед.
AID для Visa и MC известны.

fapsi 11 января 2018 в 11:07 0

Без ключей шифрования ничего не сделаете. Да и доступ к файловому менеджеру карты тоже закрыт.

brake 11 января 2018 в 11:19 0

В смысле, там каждый APDU шифруется и/или подписывается? Понятно, что финансовых операций не
совершим, но выбрать/прочитать какие-то файлы можно (если знать об их существовании)? Или там
общение происходит "инвелопами", типа как OTA в телекоме?

fapsi 11 января 2018 в 11:57 0

Ключи шифрования — они для транзакций. Да, они тут ни при чём, промахнулся.
Есть такой механизм защиты — брандмауэр аплетов, разграничивающий права доступа к общей и
защищённой областям памяти (к полям и методам аплета). Файл приложения тоже вряд ли
прочитаете.

Rudmz 11 января 2018 в 13:05 +1

Да, возможно. Пин-коды правда можно выкинуть, но считать данные с чипа карты (напр. её номер) и
воспользоваться ими ничего не мешает. См. Book 3 – Application Specification. Как шпаргалку можно
использовать этот туториал (на javascript).

fapsi 11 января 2018 в 13:20 0

Ну да, те данные, что выдавлены на карте.

Rudmz 11 января 2018 в 13:42 0

Приложение на банковской карте не блокируется по истечению срока действия. Хотя команда для
блокировки приложения есть, банками она как правило не используется в этом случае. Читаются все
файлы и теги платёжного приложения.

2mihmig: Для домашнего использования будет вполне достаточно воспользоваться оффлайн


аутентификацией. Разве что при реализации придётся игнорировать срок действия сертификатов на
карте.

НЛО прилетело и опубликовало эту надпись здесь

mihmig 11 января 2018 в 09:01 0

Можно ли использовать смарт-карту для входа в систему Windows без использования AD?
Может есть какой сторонний софт?

Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

САМОЕ ЧИТАЕМОЕ ПАРТНЕРСКИЕ МАТЕРИАЛЫ Разместить

Сутки Неделя Месяц

«Особенность» Вконтакте
+90 29,9k 46 78
Мегапост

Блокировка карт Payoneer Prepaid Mastercard® Card за пределами США Как российские и зарубежные города
+17 17,3k 12 74 внедряют интернет вещей

Как клеить по 13 девушек в час, используя машинное обучение и Tinder


+106 50,9k 190 85

Как заработать на веб-скрапинге


Промо
+37 11,5k 98 20

Разговор за завтраком: все о


Agile для банка: кейс о том, как выстроить ИТ-подразделение
корпоративной мобильности
Мегапост

Ваш аккаунт Разделы Информация Услуги

Войти Публикации Устройство сайта Реклама

Регистрация Новости Для авторов Тарифы

Хабы Для компаний Контент

Компании Документы Семинары

Пользователи Соглашение Мегапроекты

Песочница Конфиденциальность

Если нашли опечатку в посте, выделите ее и нажмите Ctrl+Enter, чтобы сообщить автору.

© 2006 – 2020 «TM» Настройка языка О сайте Служба поддержки Мобильная версия