EMV-карты

Общие положения

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

Говоря об обслуживании держателей EMV-совместимых банковских карт, можно выделить три составляющих системы обслуживания:

  1. Централизованная система авторизации операций.

  2. Пользовательский интерфейс.

  3. Информационная безопасность.

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

Пользовательский интерфейс служит для указания реквизитов платежа. Безопасность пользовательских данных обеспечивается соблюдением регламентов платежных систем, которые включают требования к шифрованию ПИН-кода и использованию карточного приложения.

Для обеспечения возможности обслуживания чиповых банковских карт, совместимых со стандартом EMV, была создана библиотека MBK_AuthService, позволяющая реализовать терминальную логику, связанную с проведением операций по международным банковским картам.

Ключевым классом библиотеки является MBKService. Он представляет собой COM-объект для доступа к карточному приложению и включает в себя всю бизнес-логику компонента.

Можно представить компонент в виде совокупности двух взаимодействующих частей:

  1. Низкоуровневое EMV-ядро – обеспечивает физическое и информационное взаимодействие между банковской картой и платежным терминалом. Низкоуровневая реализация ядра позволяет минимизировать затраты при необходимости миграции кода на другую аппаратную платформу (например, при необходимости поддержки ARM-процессоров), или ОС(например, при миграции на Linux).

  2. Интеграционная составляющая EMV-ядра – компонент, удобный для использования прикладными программистами. Реализует следующие функции:

    • Подготовка EMV-ядра к работе, в частности, настройка для работы с различными типами карточных приложений. Так, например, можно управлять условиями эксплуатации: какие типы банковских карт ядро будет обслуживать (VISA, Masterсard и т. д.).

    • Упрощение доступа к низкоуровневому EMV-ядру с целью снижения сложности задачи встраивания ядра в прикладное ПО. Как отмечалось выше, низкоуровневое EMV-ядро написано в парадигме структурного программирования, обеспечивающего простоту процесса миграции кода на другие платформы. Замена парадигмы структурного программирования в пользу объектно-ориентированного позволяет значительно снизить риски возникновения ошибок при создании платежных приложений.

    • Унификация способа доступа к функциям EMV-ядра из прикладного ПО, работающего в среде Microsoft Windows. Низкоуровневый код EMV-ядра написан на языке Си, но для прикладных программистов предлагается использовать COM-интерфейс, что позволяет встраивать ядро как в web-приложение функционирующие в среде Microsoft Internet Explorer, так и, например, в Embarcadero C++ Builder, или в приложения, разработанные на Python.

Дополнительно с помощью библиотеки MBK_AuthService можно унифицировать работу с чиповыми картами и с картами, работающими по магнитной полосе.

В случае обслуживания карт с магнитной полосой типовой сценарий выглядит следующим образом:

  1. Клиент вставляет карту в считыватель карт.

  2. Производится считывание данных со второй дорожки магнитной полосы. Посредством FIT-таблиц данные проверяются на принадлежность известным финансовым системам. Если карта не является банковской, или не может быть обслужена подключенными платежными системами, она возвращается пользователю.

  3. Предлагается ввести ПИН-код карты.

  4. Плательщик осуществляет выбор банковской операции и указывает значения реквизитов (если это требуется).

  5. Номер карты, зашифрованный ПИН-код, сумма и реквизиты финансовой операции отправляются в банковский процессинг (чаще всего для этого используется финансовый протокол ISO8583 или управляющий – NDC).

  6. Если процессинг авторизует (разрешает) операцию, соответствующий ответ будет отправлен устройству самообслуживания. Если операция требует перечисления денежных средств, соответствующая сумма «замораживается» (hold) на счете клиента.

  7. Информация о результатах платежа передается плательщику – она може

В случае использования EMV-совместимой карты типовой сценарий расширяется за счет взаимодействия с приложением платежной системы, размещенной на банковской карте. Участие карточного приложения заключается в формировании криптограммы – зашифрованного набора реквизитов платежа, к которым относятся сумма (включая код валюты и экспоненту), наличие ПИН-кода в запросе, номер терминала, код операции, и т.д. В ответ на запрос хост присылает криптограмму эмитента для проверки карточным приложением. В ряде случаев (в частности, всегда при смене ПИН-кода) хост эмитента может отправить набор исполняемых скриптов, которые изменяют состояние приложения (изменение ПИН-кода, хранимого на карте, блокировка, разблокировка, изменение данных карты и пр.).

Таким образом, при помощи библиотеки MBK_AuthService разработчики могут создавать приложения для взаимодействия с любыми типами карт, используя один и тот же доступный инструментарий. Общая схема этапов обслуживания карт по магнитной полосе и с использованием приложения на банковской карте приведена на рисунке 1. На рисунке указано, на каких этапах сценария обслуживания может быть использован MBKService.

../_images/emv1.png

Рисунок 78. Общая схема этапов обслуживания карт

Описание библиотеки MBK_AuthService

Как было сказано выше, задача библиотеки MBK_AuthService – обеспечение терминальной логики, связанной с проведением операций по международным банковским картам, совместимых со стандартом EMV.

../_images/emv5.png

Рисунок 79. Диаграмма размещения MBK_AuthService среди компонентов ПроАТМ

MBK_AuthService представляет собой библиотеку классов COM, размещенных в библиотеке MBK_AuthService.dll.

../_images/emv6.png

Рисунок 80. Диаграмма классов в составе MBK_AuthService (нажмите на рисунок, чтобы увеличить схему)

Ключевым классом библиотеки является MBKService, инкапсулирующий в себя всю бизнес-логику компонента.

Примечание

C технической точки зрения, MBK Service является объектом типа singleton. Любая повторная инстанциация класса (например, ::CoCreateInstance() или new ActiveXObject() ) не приводит к порождению нового объекта, а возвращает указатель на интерфейс к уже существующему экземпляру.

ПроАТМ при старте обеспечивает создание одного экземпляра класса MBKService и его инициализацию, а при завершении – деинициализацию и освобождение. Тем самым обеспечивается возможность не заботиться о сохранности объекта MBKService при переходе между JavaScript-страницами.

Поскольку многие интерфейсные методы в ходе работы могут завершаться с результатом HRESULT, отличным от S_OK, их вызовы следует оборачивать в try/catch блоки. Такого рода исключительные ситуации возникают в случае некорректного использования библиотеки (нарушение последовательности вызовов, передача некорректных данных), трассируются в системе логирования и должны расцениваться как сбой при проведении транзакции.

Работу с классом MBKService можно разбить на следующие этапы:

  • Инициализация сервиса ( IMBKService::InitializeService(), обеспечивается средствами ПроАТМ);

  • Конфигурирование сервиса (выполняется один раз с момента запуска сервиса, допускается частичное конфигурирование силами ПроАТМ);

  • Подготовка к проведению операции по МБК;

  • Получение информации о карте;

  • Установка реквизитов операции;

  • Подготовка к онлайн авторизации, ввод ПИН-кода по требованию EMV-ядра;

  • Завершение операции;

  • Деинициализация сервиса (IMBKService::UninitializeService(), обеспечивается средствами ПроАТМ).

Примечание

Для получения исчерпывающих сведений об объектах, интерфейсах, свойствах и методах библиотеки MBK_AuthService.dll рекомендуется использовать средства просмотра библиотек COM, например «OLE/COM Object Viewer».

Этапы проведения транзакции

Конфигурирование сервиса

[id(0x00000001), helpstring("Сконфигурировать терминал. Допускается конфигурирование в несколько приемов, с передачей частично заполненной структуры TerminalConfigurationData")]
void ConfigureTerminal([in] ITerminalConfigurationData* pData);

Данный этап достаточно выполнить один раз: в момент запуска системы. Конфигурационная информация инкапсулируется классом TerminalConfigurationData и содержит нижеследующие настройки:

  • TerminalCountryCode – код страны терминала. Три цифры в соответствии с ISO 3166-1 (EMV тег 9F1A).

  • TerminalID – идентификатор терминала. Восемь цифр/букв (EMV тег 9F1C)

  • MerchantID – идентификатор продавца. Пятнадцать ASCII символов (EMV тег 9F16)

  • AcquirerID – идентификатор эквайера. От 6 до 11 десятичных цифр (EMV тег 9F01)

  • MerchantCategoryCode – категория продавца. Четыре десятичные цифры (EMV тег 9F15)

  • MerchantNameAndLocation – наименование и адрес продавца. До 248 ASCII-символов. (EMV тег 9F4E)

  • IfdSerialNo – серийный номер карт-ридера. Восемь цифр/букв (EMV тег 9F1E)

  • EmvPosEntryMode – первые две цифры значения поля ISO8583 POS ENTRY MODE, для EMV-транзакций. (EMV тег 9F39)

  • TranSeqCounterManagement – режим управления счетчиком транзакций. На выбор: ведение счетчика средствами MBKService, либо установка значения номера транзакции извне

  • DateTimeManagement – режим управления датой и временем транзакции. На выбор: либо используется дата/время, установленные на терминале, либо дата/время устанавливается извне

  • ExplicitOnlinePinEntry – (значение по умолчанию – FALSE). Если установлено значение TRUE, метод PrepareOnlineAuth() может завершиться с кодом OR_ONLINE_PIN_REQUESTED, означающим, что EMV-ядро запросило ввод онлайн ПИН-кода и ожидает передачи результата метода SetOnlinePinEntryResults().

    Примечание

    Допускается конфигурирование в несколько этапов, на каждом из которых сервису будет передаваться частичная конфигурация терминала (заполнены не все поля TerminalConfigurationData).

  • SupportedAIDs – коллекция идентификаторов EMV-приложений, поддерживаемых терминалом. Каждое поддерживаемое приложение описывается классом типа SupportedAID:

    • AID – идентификатор приложения EMV (5-16 байт). Кодируется в формате ASCII HEX. Пример ‘A0 00 00 00 03 20 10’;

    • AllowMultipleOccurrences – разрешить частичный выбор приложения;

    • ApplicationVersion – версия приложения (2 байта) Первый байт – старший, второй байт – младший;

    • DefaultTDOL – TDOL по умолчанию (см. EMV 4.2 Book 3, 9.2.2 Transaction Certificate Data);

    • TacDenial – Terminal Action Code DENIAL (см. EMV 4.2 Book 3, 10.7 Terminal Action Analysis);

    • OnlineChipDataTags – перечень EMV-тегов, на основе которых формируется BER-TLV пакет для отправки сообщений на хост (используется в рамках отработки IMBKService::ConstructOnlineChipData() ). Данный перечень формируется на основе требований платежных системам.

  • SingleAppAutoSelection – (по умолчанию TRUE). В случае единственного приложения на карте, не требующего явного подтверждения, происходит его автоматический выбор. Если установить значение FALSE, BeginNewTransaction / BeginAnotherTransaction не производят автоматический выбор, а после успешного старта транзакции потребуется явным образом перечислить приложения (даже если оно единственное) и сделать выбор с помощью метода SelectEmvApplication() / SelectEmvApplicationByAID().

    Внимание

    Если установлено значение FALSE, прикладное ПО само отрабатывает single app confirmation required.

В процессе запуска ПроАТМ предусматривается возможность частичного конфигурирования сервиса с помощью кастомизационного файла с настройками. XML-файл с именем mbk_auth_service_cfg.xml должен быть размещен в каталоге приложения (по умолчанию c:FS365Applications) и иметь ниже представленную структуру:

<?xml version="1.0" encoding="UTF-8"?>
<MBK_AuthServiceConfiguration>
        <!--
                Ниже закомментированные настройки индивидуальны для каждого терминала и будут устанавливаться отдельно

                <MerchantNameAndLocation><![CDATA[127001, Russia, Moscow, Federativny 15-4]]>
                </MerchantNameAndLocation>
                <TerminalID val="0001234Z"/>
                <MerchantID val="Merchant#123456"/>
        -->
        <TerminalCountryCode val="643"/>
        <AcquirerID val="12121212122"/>
        <MerchantCategoryCode val="604"/>
        <IfdSerialNo val="6234554Y" />
        <EmvPosEntryMode val="51" />
        <TranSeqCounterManagement val="EMM_EXTERNALLY_MANAGED" />
        <DateTimeManagement val="EMM_INTERNALLY_MANAGED" />

        <SupportedAids>

                <!-- Общая для всех AIDов настройка OnlineChipData -->
                <OnlineChipDataTagsGlobal>
                        <Tag id="9A" />
                        <Tag id="95" />
                        <Tag id="9B" />
                        <Tag id="57" />
                        <Tag id="9F10" />
                        <Tag id="9f26" />
                        <Tag id="9f27" />
                </OnlineChipDataTagsGlobal>

                <AID val="A0 00 00 00 03 10 10">
                        <AllowMultipleOccurrences val="true" />
                        <ApplicationVersion val="12 34" />
                        <DefaultTDOL val="95 05" />
                        <TacDenial val="00 01 00 00 40" />

            <!-- Индивидуальные настройки OnlineChipData -->
                        <OnlineChipDataTags>
                                <Tag id="9f26" />
                                <Tag id="9f27" />
                        </OnlineChipDataTags>
                </AID>

                <AID val="A0 00 00 00 04 10 10">
                        <AllowMultipleOccurrences val="false" />
                        <ApplicationVersion val="00 01" />
                        <DefaultTDOL val="95 05" />
                        <TacDenial val="00 00 00 00 00" />
                </AID>
        </SupportedAids>
</MBK_AuthServiceConfiguration>

Внимание

С технической точки зрения, данное конфигурирование выполняет подсистема ProATM::system.

Подготовка к проведению операции по МБК

Методы BeginNewTransaction() и BeginAnotherTransaction()

[id(0x00000002), helpstring("Шаг #1. Начать первую транзакцию в рамках текущей клиентской сессии.]
OperationResult BeginNewTransaction(
[in] VARIANT_BOOL bAllowFallback,
[in] VARIANT pVarTranPrereq,
[in] VARIANT pVarCardData);

pVarTranPrereq – объект, реализующий интерфейс ITransactionPrerequisites. pVarCardData – объект, реализующий интерфейс ICardDataBooster.

[id(0x00000003), helpstring("Шаг #1. Начать последующую транзакцию в рамках текущей клиентской сессии.]
OperationResult BeginAnotherTransaction(
[in] VARIANT_BOOL bAllowFallback,
[in] VARIANT pVarTranPrereq);

Данные методы необходимо выполнить по завершении следующих действий:

  • после вставки и считывания данных с карты – вызвав метод BeginNewTransaction();

  • после завершения/прерывания предыдущей транзакции в рамках единой клиентской сессии – вызвав метода BeginAnotherTransaction().

BeginNewTransaction() отличается от BeginAnotherTransaction() тем, что во втором случае пропускается фаза считывания магнитных дорожек с карты.

Примечание

Не запрещается использовать BeginNewTransaction() во всех случаях.

Методы BeginNewTransaction() и BeginAnotherTransaction() содержат следующие аргументы:

  • bAllowFallback – флаг разрешения запасной технологии. Используется, если сервисный код TRACK #2 содержит в первом разряде «2» или «6» (карта EMV), а чип не активируется.

    Примечание

    В настоящее время, fallback запрещается платежными системами.

  • pVarTranPrereq – предварительные реквизиты транзакциии. Указатель на объект, приводимый к интерфейсу ITransactionPrerequisites. Содержит номер транзакции и (или) ее дату/время, либо не передается вообще (зависит от настроек TranSeqCounterManagement и DateTimeManagement).

  • pVarCardData – кэш данных, прочитанных с карты в момент ее вставки. Указатель на объект, приводимый к интерфейсу ICardDataBooster. Несмотря на то, что данный аргумент является опциональным, рекомендуется его использовать. Перечитывание магнитных дорожек и активация чипа занимает от одной до трех секунд времени, а также усиливает механический износ карты и карт-ридера).

Результаты при выполнении методов BeginNewTransaction() и BeginAnotherTransaction():

  • OR_SUCCESS – подготовка успешно завершена.

  • OR_TERMINAL_IS_NOT_CONFIGURED – пропущен этап конфигурирования сервиса.

  • OR_INVALID_CARD – карта не читается либо не является МБК (подробнее можно выяснить с помощью методов MBKService::GetCardType() ).

  • OR_EMV_TERMINATED – карта EMV, транзакция терминирована на этапе чтения данных с чипа.

После успешного выполнения метода BeginNew(Another)Transaction() можно узнать тип карты с помощью метода MBKService::GetCardType().

Если это EMV-карта и на ней записано несколько приложений (или одно, но требующее явного подтверждения выбора держателем карты), то необходимо обеспечить шаг выбора приложения, выполнив интерфейсные методы IMBKService.

Метод GetEmvApplicationsCount()

[id(6), helpstring("Получение количества EMV-приложений кандидатов, подлежащих выбору со стороны держателя карты [VT_I4]. Если 0 - приложение уже выбрано. Автоматический выбор управляется флагом ITerminalConfigurationData::SingleAppAutoSelection")]
HRESULT GetEmvApplicationsCount( [out,retval] VARIANT* pVal );
[id(7), helpstring("Получение имени i-го [0..N-1] кандидата, пригодного для отображения на экране и подлежащего выбору")]
HRESULT GetEmvApplicationName( [in] VARIANT varIndex, [out,retval] BSTR* pVal );
[id(8), helpstring("Получение подробных сведений об i-м [0..N-1] кандидате (функция доступна только в ходе APPLICATION SELECTION)")]
HRESULT GetEmvApplicationDetailedInfo( [in] VARIANT varIndex, [out,retval] IEmvAppDetails** pVal );
[id(9), helpstring("Шаг #2 (опц.) Выбрать EMV-приложение с указанным индексом [0..N-1]. Внимание! Не забыть отработать код ошибки OR_RESELECT_APP_ONCE_AGAIN!")]
HRESULT SelectEmvApplication( [in] VARIANT varAppSelectedIdx, [out,retval] OperationResult* pResult );
[id(10), helpstring("Шаг #2 (опц.) Альтернативный способ выбрать EMV-приложение: по AID кандидата. Внимание! Не забыть отработать код ошибки OR_RESELECT_APP_ONCE_AGAIN!")]
HRESULT SelectEmvApplicationByAID( [in] BSTR bstrAID, [out,retval] OperationResult* pResult );

Результаты при выполнении метода GetEmvApplicationsCount():

  • 0 – не EMV-карта или на карте всего одно EMV-приложение и оно автоматически (такой сценарий – для большинства банковских карт) выбрано.

  • 1 – на карте одно EMV приложение, которое необходимо отобразить держателю карты и запросить подтверждение выбора.

  • 2 и более – на карте несколько EMV-приложений. Необходимо сформировать список и вывести держателю карты для выбора.

Примечание

В случае значения SingleAppAutoSelection FALSE, о необходимости подтверждения выбора единственного приложения говорит флаг bCardholderConfirmationRequired.

В двух последних случаях для получения имен приложений используется метод GetEmvApplicationName().

Метод GetEmvApplicationDetailedInfo()

Метод GetEmvApplicationDetailedInfo(), возвращающий объект с интерфейсом IEmvAppDetails, вызывается для получения детальной информации по каждому кандидату.

Листинг 19. Интерфейс метода GetEmvApplicationDetailedInfo()
  __interface IEmvAppDetails : IDispatch
  {
         [propget, id(1), helpstring("Наименование приложения для отображения картхолдеру, сформированное в соответствии с правилами EMV (наличие/отсутствие preferred name, поддержка кодировки терминалом, фильтрация неотображаемых символов и т.п.)")]
         HRESULT Name( [out, retval] BSTR* pVal );

         [propput, id(1), helpstring("Наименование приложения для отображения картхолдеру, сформированное в соответствии с правилами EMV (наличие/отсутствие preferred name, поддержка кодировки терминалом, фильтрация неотображаемых символов и т.п.)")]
         HRESULT Name( [in] BSTR newVal );

         [propget, id(2), helpstring("Идентификатор приложения, Tag 4F (например, 'A0000000032010' - VISA ELECTRON)")]
         HRESULT AID( [out, retval] BSTR* pVal );

         [propput, id(2), helpstring("Идентификатор приложения, Tag 4F (например, 'A0000000032010' - VISA ELECTRON)")]
         HRESULT AID( [in] BSTR newVal );

         [propget, id(3), helpstring("Название приложения, Tag 50 (например, 'PLUS')")]
         HRESULT ApplicationLabel( [out, retval] BSTR* pVal );

         [propput, id(3), helpstring("Название приложения, Tag 50 (например, 'PLUS')")]
         HRESULT ApplicationLabel( [in] BSTR newVal );

         [propget, id(4), helpstring("Предпочтительное название, Tag 9F12 (например, 'Виса кредит'). Значение транслировано из IssuerCodeTable в Unicode; если тег отсутствует или таблица кодирования не поддерживается ядром - записывается пустое значение")]
         HRESULT ApplicationPreferredName( [out, retval] BSTR* pVal );

         [propput, id(4), helpstring("Предпочтительное название, Tag 9F12 (например, 'Виса кредит'). Значение транслировано из IssuerCodeTable в Unicode; если тег отсутствует или таблица кодирования не поддерживается ядром - записывается пустое значение")]
         HRESULT ApplicationPreferredName( [in] BSTR newVal );

         [propget, id(5), helpstring("Предпочитаемые языки, Tag 5F2D. Строка, содержащая буквенные пары, каждая из которых предсталяет предпочитаемые языки картхолдера (ISO 639) в порядке убывания (например, 'ruen')")]
         HRESULT LanguagePreference( [out, retval] BSTR* pVal );

         [propput, id(5), helpstring("Предпочитаемые языки, Tag 5F2D. Строка, содержащая буквенные пары, каждая из которых предсталяет предпочитаемые языки картхолдера (ISO 639) в порядке убывания (например, 'ruen')")]
         HRESULT LanguagePreference( [in] BSTR newVal );

         [propget, id(6), helpstring("Флаг обязательного подтверждения выбора приложения, Tag 87 bit 8")]
         HRESULT ConfirmationRequired( [out, retval] VARIANT_BOOL* pVal );

         [propput, id(6), helpstring("Флаг обязательного подтверждения выбора приложения, Tag 87 bit 8")]
         HRESULT ConfirmationRequired( [in] VARIANT_BOOL newVal );

         [propget, id(7), helpstring("Application Priority Index [VT_UI1], Tag 87 без учета старшего бита (переносится в самостоятельный флаг ConfirmationRequired)")]
         HRESULT ApplicationPriorityIndex( [out, retval] VARIANT* pVal );

         [propput, id(7), helpstring("Application Priority Index [VT_UI1], Tag 87 без учета старшего бита (переносится в самостоятельный флаг ConfirmationRequired)")]
         HRESULT ApplicationPriorityIndex( [in] VARIANT newVal );

         [propget, id(8), helpstring("Issuer Code Table Index [VT_UI1], Tag 9F11")]
         HRESULT IssuerCodeTableIndex( [out, retval] VARIANT* pVal );

         [propput, id(8), helpstring("Issuer Code Table Index [VT_UI1], Tag 9F11")]
         HRESULT IssuerCodeTableIndex( [in] VARIANT newVal );
  };

Методы SelectEmvApplication() и SelectEmvApplicationByAID()

После успешного выбора приложения/подтверждения держателем карты, необходимо сообщить сервису о результате, вызвав метод SelectEmvApplication() с указанием индекса выбранного /подтвержденного приложения, либо воспользоваться альтернативным методом SelectEmvApplicationByAID().

Результаты:

  • OR_SUCCESS – выбор приложения выполнен успешно. Перейти к следующему шагу.

  • OR_RESELECT_APP_ONCE_AGAIN выбор приложения не выполнен, однако кандидат-лист содержит другие приложения. Необходимо обновить перечень приложений EMV (методы GetEmvApplicationsCount()/GetEmvApplicationName() ), сообщить держателю карты о неработоспособности выбранного им приложения и предоставить на выбор обновленный список. После выбора приложения снова вызвать SelectEmvApplication()/SelectEmvApplicationByAID().

    Примечание

    Код ошибки OR_RESELECT_APP_ONCE_AGAIN может возникнуть несколько раз подряд за одну операцию.

  • OR_EMV_TERMINATED – приложение не выбрано. Завершить транзакцию.

Получение информации о карте

После успешной подготовки к проведению транзакции можно получить детальную информацию о клиентской карте.

Тип карты:

  • CT_EMV – EMV-карта.

  • CT_MAG_STRIPE – карта с магнитной полосой.

  • CT_MAG_STRIPE_FALLBACK:

    Внимание

    EMV–карта, выполнен переход на запасную технологию Это необходимо отразить в транзакционном сообщении в поле POS_ENTRY_MODE.

  • CT_NON_MBK – карта содержит данные, но не является международной банковской (бонусные, социальные, loyalty, карты локальных платежных систем и пр. карты стандартов ISO-7810 и ISO-7816).

  • CT_HAS_NO_DATA – карта не содержит данных и, возможно, была вставлена неправильной стороной.

Примечание

По последним двум кодам можно выбрать тип экрана возврата карты: например, «ДАННЫЙ ТИП КАРТ НЕ ОБСЛУЖИВАЕТСЯ» или «ПОЖАЛУЙСТА, ВСТАВЬТЕ КАРТУ ПРАВИЛЬНОЙ СТОРОНОЙ».

Информация по карте:

  • PAN – выделяется из TRACK #2 в случае CT_MAG_STRIPE/CT_MAG_STRIPE_FALLBACK, либо считывается с чипа.

    Внимание

    В случае считывания с чипа PAN может отличаться от значения, взятого с магнитной полосы: именно этот PAN должен использоваться при формировании транзакционных сообщений.

  • PAN_SeqNo – порядковый номер PAN. В случае отсутствия данного элемента на карте, возвращается VT_EMPTY.

  • Track2 – выделяется с магнитной полосы, либо замещается данными, считанными с чипа. Для карты типа CT_EMV необходимо использовать именно это значение. Оно может отличаться от значения, записанного на магнитную полосу.

  • EmvAID – идентификатор приложения EMV (например, «A0000000032010»). Доступно если клиентский чек содержит AID приложения

  • EmvApplicationName – наименование приложения EMV для отображения на экране, в журнале, в чеке и т.п. (например, «VISA CREDIT»).

  • TransactionSeqNo – номер текущей транзакции. Доступно если счетчик транзакции ведется внутри сервиса.

  • TransactionDateTime – дата и время транзакции.

Примечание

Если тип карты отличен от EMV, последующие шаги не несут никакой функциональной нагрузки, и их можно опустить и использовать сервисом подписания транзакционных сообщений IMBKService::SignMessage().

Установка реквизитов операции

После подготовки к проведению транзакции, системе предлагается осуществить набор и установку реквизитов транзакции:

[id(0x0000000c), helpstring("Шаг #3. Установка реквизитов транзакции, pVarTranReq – объект, реализующий интерфейс ITransactionRequisites")]
void SetTransactionRequisites([in] VARIANT pVarTranReq);

Класс TransactionRequisites предусматривает следующие свойства:

  • IsoTransactionType – тип операции, определяемый первыми двумя цифрами поля PROCESSING_CODE, в соответствии с ISO 8583:1987.

  • EmvTransactionType – тип операции, в соответствии с классификацией EMV:

    • TT_CASH – выдача наличных;

    • TT_GOODS – покупка товаров;

    • TT_SERVICES – оплата услуг;

    • TT_CASHBACK – возврат;

    • TT_INQUIRY – запрос информации (баланс, история, выписка, и пр.);

    • TT_TRANSFER – перевод со счета на счет;

    • TT_PAYMENT – безналичная оплата;

    • TT_CASHDEPOSIT – внесение наличных.

  • Currency – транзакции в соответствии с ISO-4217 (Num).

  • CurrencyExponent – экспонента валюты (0..9). Для большинства валют, это число равно двум.

  • AmountAuthorized – сумма транзакции в копейках выбранной валюты.

Подготовка к онлайн авторизации

После того, как система сформировала реквизиты транзакции, необходимо осуществить подготовку к онлайн авторизации.

Внимание

MBKService не отвечает за процесс ввода ПИН-кода (данная функция выполняется компонентом AxPinManager), однако на данном этапе предполагается, что ПИН-блок либо уже известен, либо будет сформирован непосредственно перед выходом в онлайн.

Методы SetOnlinePinEntryResults() и PrepareOnlineAuth()

[id(18), helpstring("Шаг #4. Подготовка к онлайн-авторизации. Уже на данном этапе может сформироваться DECLINED(Z1)")]
OperationResult PrepareOnlineAuth();
[id(19), helpstring("Шаг #4.5 Сообщить о результатах ввода ПИН-кода [pinEntryResults - приводится к OnlinePinEntryResults]")]
HRESULT SetOnlinePinEntryResults( [in] VARIANT pinEntryResults, [out, retval] OperationResult* pResult );

Результаты выполнения:

  • OR_SUCCESS – подготовка выполнена успешно.

  • OR_ONLINE_PIN_REQUESTED – активен режим ITerminalConfigurationData::ExplicitOnlinePinEntry=TRUE, требуется ввод онлайн ПИН-кода c последующей передачей результата через SetOnlinePinEntryResults(). Результат исполнения SetOnlinePinEntryResults() проанализировать аналогично PrepareOnlineAuth().

  • OR_DECLINED_Z1 транзакция была отклонена на этапе EMV terminal/card action analysis.

  • OR_EMV_TERMINATED транзакция завершена на одном из этапов обработки EMV.

В случае успешного завершения операции, можно сформировать EMV-данные для передачи на хост эмитента:

[id(0x0000000e), helpstring("Cобрать EMV-данные для отправки на хост. pVarChipData - контейнер, приводимый к интерфейсу IBerTlvContainer. Используется после PrepareOnlineAuth() либо после Completion()")]
void ConstructOnlineChipData([in] VARIANT pVarChipData);

Метод наполняет контейнер EMV-данными, в соответствии с настройкой OnlineChipDataTags для текущего AID.

Подписание транзакционных сообщений

Метод SignMessage():

Подписание транзакционных сообщений выполняется методом SignMessage():

[id(0x0000000f), helpstring("Расчет подписи транзакционного сообщения (MAC). Формат данных – ASCII HEX")]
BSTR SignMessage(
                [in] BSTR bstrMessage,
                [in] BSTR bstrKeyName,
                [in] VARIANT_BOOL bInsertSpaces);

Аргументы метода:

  • bstrMessage – сообщение, закодированное в ASCII HEX (например, «31F520324A6B..» и пр.; допускается наличие символов-разделителей между байтами);

  • bstrKeyName – наименование криптографического ключа;

  • bInsertSpaces – флаг, указывающий на необходимость вставки пробелов между байтами в результате.

Завершение операции

Метод Complete()

После проведения онлайн авторизации, необходимо сообщить сервису ее результаты. Код ответа процессинга «00» в случае EMV-операции, не означает, что транзакция одобрена:

[id(0x00000010), helpstring("Шаг #5. Завершение транзакции. pVarHostData – EMV-данные, полученные с хоста (IBerTlvContainer); pVarScriptResults  контейнер для записи результатов исполнения скриптов эмитента (IEmvScriptResults);")]
OperationResult Complete(
                [in] VARIANT pVarHostData,
                [in] VARIANT pVarScriptResults);

Аргументы метода:

  • pVarHostData – контейнер, содержащий ответные EMV-данные от хоста эмитента карты, среди которые могут включать в себя:

    • Authorisation Response Code (тег 8A) – код ответа 00-99. Обязательное поле. В случае отсутствия или некорректных данных транзакция будет отклонена с кодом DECLINE Z3;

    • Authorisation Code (тег 89) – 6-тизначный код авторизации, присылаемый в случае одобрения транзакции со стороны хоста;

    • Issuer Authentication Data (тег 91) – опциональное поле, хост эмитента может прислать ответную криптограмму для аутентификации хоста картой;

    • Issuer Scripts (шаблоны 71 и 72) – опциональное поле, хост может прислать скрипты, которые будут исполнены картой.

  • pVarScriptResults – контейнер, в который будут записаны результаты исполнения скриптов (см. EMV 4.2 Book 4, A5 Issuer Script Results).

Результаты выполнения:

  • OR_SUCCESS – транзакция одобрена;

  • OR_DECLINED_Z1 – транзакция отклонена картой (например, в результате неуспешной аутентификации эмитента);

  • OR_DECLINED_Z3 – транзакция отклонена (нет связи с онлайн-хостом, либо ответ содержит некорректные данные);

  • OR_ONLINE_DECLINED – транзакция отклонена хостом (код ответа отличен от «00»);

  • OR_EMV_TERMINATED – в ходе завершения произошло завершение EMV-транзакции.

По результатам, система может отправить на хост подтверждение (CONFIRMATION MESSAGE) либо откат транзакции (REVERSAL MESSAGE). Для построения EMV-данных, можно вызывать метод IMBKService::ConstructOnlineChipData().

Пример html-страницы «Работа с МБК-сервисом»

 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
 <html>
 <head>
        <meta http-equiv='Pragma' content='no-cache'>
        <meta http-equiv='Content-Type' content='text/html; charset=UTF-8' />

        <script type='text/javascript' src='./../../../Applications/Ogre/_javascript_/jquery.js'></script>

        <script type='text/javascript'>

                // Определяем константы:

                // EntityManagementMode
                var EMM_INTERNALLY_MANAGED = 1;
                var EMM_EXTERNALLY_MANAGED = 2;

                // OperationResult
                var OR_SUCCESS = 1;
                var OR_TERMINAL_IS_NOT_CONFIGURED = 2;
                var OR_GENERIC_FAILURE = 3;
                var OR_INVALID_ARGUMENTS = 4;
                var OR_INVALID_CARD = 5;
                var OR_EMV_TERMINATED = 6;
                var OR_WRONG_EXECUTION_ORDER = 7;
                var OR_METHOD_CALL_NOT_SUITABLE = 8;
                var OR_DECLINED_Z1 = 9;
                var OR_DECLINED_Z3 = 10;
                var OR_ONLINE_DECLINED = 11;
                var OR_RESELECT_APP_ONCE_AGAIN = 12;
                var OR_ONLINE_PIN_REQUESTED = 13;

                // CardType
                var CT_EMV = 1;
                var CT_MAG_STRIPE = 2;
                var CT_MAG_STRIPE_FALLBACK = 3;
                var CT_NON_MBK = 4;
                var CT_HAS_NO_DATA = 5;

                // TransactionType
                var TT_CASH = 1;
                var TT_GOODS = 2;
                var TT_SERVICES = 3;
                var TT_CASHBACK = 4;
                var TT_INQUIRY = 5;
                var TT_TRANSFER = 6;
                var TT_PAYMENT = 7;
                var TT_ADMINISTRATIVE = 8;
                var TT_CASHDEPOSIT = 9;
                var TT_CANCEL = 10;

             // OnlinePinEntryResults
                var OPE_SUCCESS = 1;
                var OPE_USER_CANCELLED = 2;
                var OPE_NO_EPP = 3;

                // Some head scripts
                $(window).load( function() {
                        $('#chk_SingleAppAutoSelection').prop('checked', true);
                        $('#chk_ExplicitPinEntry').prop('checked', false);
                        $('#radio_ok').prop('checked', true);
                } );

                $(document).ready( function() {

                        // Обработчики кнопок
                        $('#btnInitialize')[0].onclick = function() {
                                mbkService.InitializeService();
                                PrintMsg( 'mbkService.VersionNo = ' + mbkService.VersionNo );
                        }

                        $('#btnUninitialize')[0].onclick = function() {
                             mbkService.UninitializeService();
                        }
                        $('#btnConfigureTerminal')[0].onclick = function() {

                                try {

                                        // 1. Конфигурация терминала
                                        var termCfg = new ActiveXObject( 'MBK_AuthService.TerminalConfiguration' );
                                        termCfg.TerminalCountryCode = 643;                           // Россия
                                        termCfg.TerminalID = '0001234Z';
                                        termCfg.MerchantID = 'Merchant#123456';
                                        termCfg.AcquirerID = '12121212122';
                                        termCfg.MerchantCategoryCode = 604;
                                        termCfg.MerchantNameAndLocation = '127001, Russia, Moscow, Federativny 15-4';
                                        termCfg.IfdSerialNo = '62345549';
                                        termCfg.EmvPosEntryMode = 51;

                                        // Предположим: и счетчик транзакций, и дата/время, управляются из скрипта:
                                        termCfg.TranSeqCounterManagement = EMM_EXTERNALLY_MANAGED;
                                        termCfg.DateTimeManagement = EMM_EXTERNALLY_MANAGED;
                                        // Добавляем поддержку EVM-приложений
                                        var AID = new ActiveXObject( 'MBK_AuthService.SupportedAID' );


                                        /* Commented block:  settings suitable for VISA ADVT

                                        // Для простоты: у всех AID'ов одиноковые настройки:
                                        AID.AllowMultipleOccurrences = true;
                                        AID.ApplicationVersion = 0x1234;
                                        AID.DefaultTDOL = '';
                                        AID.TacDenial = '00 01 00 00 40';
                                       {
                                               var onlineTags = new ActiveXObject( 'MBK_AuthService.TagIdCollection' );
                                               onlineTags.Add( 0x9f27 );
                                               onlineTags.Add( 0x9A );
                                               onlineTags.Add( 0x95 );               // TVR
                                               onlineTags.Add( 0x9B );               // TSI
                                               onlineTags.Add( 0x57 );
                                               onlineTags.Add( 0x9F10 );
                                               onlineTags.Add( 0x9F26 );     // Application Cryptogram (ARQC/TC/AAC)
                                               onlineTags.Add( 0x9F27 );     // Cryptogram information data (CID)
                                               onlineTags.Add( 0x5A );
                                               onlineTags.Add( 0x8A );               // ARC
                                               onlineTags.Add( 0x89 );               // AuthCode
                                               onlineTags.Add( 0x82 );
                                               onlineTags.Add( 0x9F03 );
                                               onlineTags.Add( 0x9F50 );     // Preauthorized Offline Limit
                                               AID.OnlineChipDataTags = onlineTags;
                                       }
                                        // Регистрируем 'VISA ELECTRON'
                                        AID.AID = 'A0 00 00 00 03 20 10';
                                        termCfg.AddSupportedAid( AID );

                                        // Регистрируем 'VISA'
                                        AID.AID = 'A0 00 00 00 03 10 10';
                                        termCfg.AddSupportedAid( AID );

                                        // Visa PLUS
                                        AID.AID = 'A0 00 00 00 03 80 10';
                                        termCfg.AddSupportedAid( AID );

                                        // Регистрируем 'PRO100'
                                        AID.AID = 'A0 00 00 04 32 00 01';
                                        termCfg.AddSupportedAid( AID );

                                        */
                                        // ICC Solutions
                                        {
                                                AID.ApplicationVersion = 0x008C;
                                                AID.DefaultTDOL = '81 04 9F 03 06';
                                                AID.TacDenial = '00 00 00 00 00';
                                                {
                                                        var onlineTags = new ActiveXObject( 'MBK_AuthService.TagIdCollection' );
                                                        onlineTags.Add( 0x9f27 );
                                                        onlineTags.Add( 0x9A );
                                                        onlineTags.Add( 0x95 );              // TVR
                                                        onlineTags.Add( 0x9B );              // TSI
                                                        onlineTags.Add( 0x57 );
                                                        onlineTags.Add( 0x9F10 );
                                                        onlineTags.Add( 0x9F26 );    // Application Cryptogram (ARQC/TC/AAC)
                                                        onlineTags.Add( 0x9F27 );    // Cryptogram information data (CID)
                                                        onlineTags.Add( 0x5A );
                                                        onlineTags.Add( 0x8A );              // ARC
                                                        onlineTags.Add( 0x89 );              // AuthCode
                                                        onlineTags.Add( 0x82 );
                                                        onlineTags.Add( 0x9F03 );
                                                        onlineTags.Add( 0x9F50 );    // Preauthorized Offline Limit
                                                        AID.OnlineChipDataTags = onlineTags;
                                                }
                                                // Visa AID
                                                AID.AID = 'A0000000031010';
                                                AID.AllowMultipleOccurrences = true;
                                                termCfg.AddSupportedAid( AID );

                                                // Non-EMV AID
                                                AID.AID = 'A0000000999090';
                                                AID.AllowMultipleOccurrences = true;
                                                termCfg.AddSupportedAid( AID );

                                                // Test
                                                AID.AID = 'A00000999901';
                                                AID.AllowMultipleOccurrences = true;
                                                termCfg.AddSupportedAid( AID );

                                                // ANO3
                                                AID.AID = 'A000000003101003';
                                                AID.AllowMultipleOccurrences = true;
                                                termCfg.AddSupportedAid( AID );

                                                // ANO4
                                                AID.AID = 'A000000003101004';
                                                AID.AllowMultipleOccurrences = true;
                                                termCfg.AddSupportedAid( AID );

                                                // ANO5
                                                AID.AID = 'A000000003101005';
                                                AID.AllowMultipleOccurrences = true;
                                                termCfg.AddSupportedAid( AID );

                                                // ANO6
                                                AID.AID = 'A000000003101006';
                                                AID.AllowMultipleOccurrences = true;
                                                termCfg.AddSupportedAid( AID );

                                                // ANO7
                                                AID.AID = 'A000000003101007';
                                                AID.AllowMultipleOccurrences = false;
                                                termCfg.AddSupportedAid( AID );

                                                // Mastercard AID
                                                AID.AID = 'A0000000041010';
                                                AID.AllowMultipleOccurrences = true;
                                                termCfg.AddSupportedAid( AID );

                                                // JCB AID
                                                AID.AID = 'A0000000651010';
                                                AID.AllowMultipleOccurrences = true;
                                                termCfg.AddSupportedAid( AID );

                                                // AMEX AID
                                                AID.AID = 'A000000025010501';
                                                AID.AllowMultipleOccurrences = true;
                                                termCfg.AddSupportedAid( AID );
                                        }

                                        // Автоматический выбор единственного приложения
                                        termCfg.SingleAppAutoSelection = $('#chk_SingleAppAutoSelection').is(':checked');

                                        // Эксплицитный ввод ПИНа
                                        termCfg.ExplicitOnlinePinEntry = $('#chk_ExplicitPinEntry').is(':checked');

                                        // Выполняем конфигурирование (+ здесь же: демонстрируем свойство singleton)
                                        mbkService2.ConfigureTerminal( termCfg );
                                }
                                catch( Exception ) {
                                        PrintMsg( Exception );
                                }

                                PrintMsg( 'ConfigureTerminal done.' );
                        }

                        $('#btnTransaction')[0].onclick = function() {
                                try {

                                        // Поскольку содержимое карты было прочитано при ее вставке,
                                        // сообщаем МБК сервису эти данные, избегая повторного перечитывания:
                                        var cardData = new ActiveXObject( 'MBK_AuthService.CardDataBooster' );
                                        cardData.Track1 = 'B676280389083828108^TEST/CARD6836 ^03011010000000000000';
                                        cardData.Track2 = '676280389083828110=10121010070100000';
                                        cardData.ChipATR = '3B 65 00 00 44 04 01 08 03';

                                        // Предварительные реквизиты транзакции
                                        // Примечание: выше, в настройках, мы упомянули, что счетчиком и временем управляет скрипт
                                        var tranPre = new ActiveXObject( 'MBK_AuthService.TranPrerequisites' );
                                        tranPre.TransactionDateTime = '2010.11.25 8:01:54';
                                        tranPre.TransactionSeqNo = 15;

                                        PrintMsg( 'BeginNewTransaction() = ' + mbkService.BeginNewTransaction( false, tranPre, null ) );

                                        // TODO: анализ результата!

                                        // Выявляем, есть ли приложения на выбор/подтверждение
                                        var nApps = mbkService2.GetEmvApplicationsCount();

                                        PrintMsg( 'GetEmvApplicationsCount() = ' + nApps );


                                        if( nApps > 0 ) {

                                                // Важно! nApps = 1 в случае termCfg.SingleAppAutoSelection = false требует детального рассмотрения:
                                                // если индикатор ConfirmationRequired = true, данное приложение следует отобразить
                                                // катрхолдеру на подтверждение. В противном случае, его необходимо выбрать автоматом.

                                                PrintMsg( 'Candidates: ' );
                                                for( var k = 0; k < nApps; k++ ) {

                                                        PrintMsg( ' ------------------------------' );

                                                        // Если требуется только название, можно воспользоваться методом:
                                                        // PrintMsg( mbkService.GetEmvApplicationName( k ) );

                                                        // Детальная информация по приложению
                                                        var candidateDetailedInfo = mbkService.GetEmvApplicationDetailedInfo( k );
                                                        PrintMsg( ' - Name: ' + candidateDetailedInfo.Name );
                                                        PrintMsg( ' - AID: ' + candidateDetailedInfo.AID );
                                                        PrintMsg( ' - ApplicationLabel: ' + candidateDetailedInfo.ApplicationLabel );
                                                        PrintMsg( ' - ApplicationPreferredName: ' + candidateDetailedInfo.ApplicationPreferredName );
                                                        PrintMsg( ' - LanguagePreference: ' + candidateDetailedInfo.LanguagePreference );
                                                        PrintMsg( ' - ConfirmationRequired: ' + candidateDetailedInfo.ConfirmationRequired );
                                                        PrintMsg( ' - ApplicationPriorityIndex: ' + candidateDetailedInfo.ApplicationPriorityIndex );
                                                        PrintMsg( ' - IssuerCodeTableIndex: ' + candidateDetailedInfo.IssuerCodeTableIndex );
                                                }
                                                PrintMsg( ' ------------------------------' );
                                        }

                                        if( nApps > 0 ) {

                                                // TODO: запросить выбор
                                                var selectionResult = mbkService.SelectEmvApplication( $('#edit_chosenAppNo').prop('value') );
                                                for( ; ; ) {

                                                        if( OR_SUCCESS == selectionResult ) {

                                                                PrintMsg( 'mbkService.SelectEmvApplication() = OR_SUCCESS' );
                                                                break;
                                                        }
                                                        if( OR_RESELECT_APP_ONCE_AGAIN == selectionResult ) {

                                                                PrintMsg( 'mbkService.SelectEmvApplication() = OR_RESELECT_APP_ONCE_AGAIN.' );

                                                                nApps = mbkService.GetEmvApplicationsCount();
                                                                for( var k = 0; k < nApps; k++ ) {
                                                                        PrintMsg( mbkService.GetEmvApplicationName( k ) );
                                                                }

                                                                // TODO: вывести новый список приложений на экран, запросить выбор
                                                                selectionResult = mbkService.SelectEmvApplication( 0 );
                                                                continue;
                                                        }

                                                        // Прочая ошибка
                                                        PrintMsg( 'mbkService.SelectEmvApplication() = ' +  selectionResult );

                                                        // TODO: Терминируем транзакцию
                                                        break;
                                                }
                                        }

                                        // Отображаем информацию о карте
                                        PrintMsg( 'PAN = ' + mbkService.PAN );
                                        if( mbkService.PAN_SeqNo === undefined ) {
                                                PrintMsg( 'PAN Seq No is not available' );
                                        } else {
                                                PrintMsg( 'PAN Seq No: ' + mbkService.PAN_SeqNo );
                                        }
                                        PrintMsg( 'Track2 = ' + mbkService.Track2 );
                                        if( CT_EMV == mbkService.GetCardType() ) {
                                            PrintMsg( 'EmvAID = ' + mbkService.EmvAID );
                                                PrintMsg( 'EmvApplicationName = ' + mbkService.EmvApplicationName );
                                        }

                                        // Собираем и устанавливаем реквизиты транзакции
                                        var tranReq = new ActiveXObject( 'MBK_AuthService.TranRequisites' );
                                        tranReq.IsoTransactionType = 51;
                                        tranReq.EmvTransactionType = TT_PAYMENT;                     // Безналичная оплата
                                        tranReq.Currency = 643;                                                              // RUB
                                        tranReq.CurrencyExponent = 2;
                                        tranReq.AmountAuthorized = 10000;                                    // 100.00 RUB

                                        mbkService2.SetTransactionRequisites( tranReq );

                                        // Подготовка к онлайн-авторизации
                                        {
                                                var prepareOnlineResult = mbkService.PrepareOnlineAuth();
                                                PrintMsg( 'mbkService.PrepareOnlineAuth() = ' + prepareOnlineResult );

                                                if( prepareOnlineResult == OR_ONLINE_PIN_REQUESTED ) {

                                                        // Ядро сконфигурировано на эксплицитный режим ввода ПИН-кода + в процессе Cardholder Verification был выбран метод Online PIN.
                                                        // От нас явным образом требуют ввести ПИН-код и сообщить ядру о результатах

                                                    // TODO: за ввод ПИН-кода МБК-сервис не отвечает.

                                                        // Имеем результат ввода ПИН-кода:
                                                        var pinEntryResult = OPE_SUCCESS;
                                                        {
                                                                if( $('#radio_ok').is(':checked') ) {
                                                                        pinEntryResult = OPE_SUCCESS;
                                                                } else if( $('#radio_cancelled').is(':checked') ) {
                                                                        pinEntryResult = OPE_USER_CANCELLED;
                                                                } else if( $('#radio_no_pinpad').is(':checked') ) {
                                                                        pinEntryResult = OPE_NO_EPP;
                                                                }
                                                        }

                                                        PrintMsg( 'mbkService.SetOnlinePinEntryResults( ' + pinEntryResult + ' ) = ' + mbkService.SetOnlinePinEntryResults( pinEntryResult ) );
                                                }

                                                // TODO: анализ результата. Уже здесь, мы можем получить DECLINED(Z1)!
                                        }

                                        var onlineChipData = new ActiveXObject( 'MBK_AuthService.BerTlvContainer' );
                                        mbkService.ConstructOnlineChipData( onlineChipData );
                                        PrintMsg( 'onlineChipData = ' + onlineChipData.FormatAsciiHex( true ) );

                                        // Имитация ответа хоста
                                        var onlineHostData = new ActiveXObject( 'MBK_AuthService.BerTlvContainer' );
                                        onlineHostData.ParseAsciiHex(
                                                  '8A 02 30 30 '                                                     // ARC = "00"
                                                + '89 06 31 32 33 34 35 36'                                  // AuthCode = "123456"
                                                + '91 0A 12 12 12 12 12 12 12 12 12 12'              // Невалидный Issuer AuthenticationData

                                                // Скрипты эмитента 71 и 72:
                                                + '71 28 9F 18 04 FE DC BA 97 86 09 84 24 00 00 04 AA BB CC DD 86 09 84 1E 00 00 04 AA BB CC DD 86 09 84 16 00 00 04 AA BB CC DD'
                                                + '71 28 9F 18 04 FE DC BA 98 86 09 84 24 00 00 04 AA BB CC DD 86 09 84 1E 00 00 04 AA BB CC DD 86 09 84 16 00 00 04 AA BB CC DD'
                                                + '72 28 9F 18 04 44 33 22 11 86 09 84 24 00 00 04 AA BB CC DD 86 09 84 1E 00 00 04 AA BB CC DD 86 09 84 16 00 00 04 AA BB CC DD'
                                                + '72 28 9F 18 04 44 33 22 10 86 09 84 24 00 00 04 AA BB CC DD 86 09 84 1E 00 00 04 AA BB CC DD 86 09 84 16 00 00 04 AA BB CC DD'
                                         );

                                        // Завершение транзакции
                                        //           - передаем ответ хоста
                                        //           - получаем результат исполнения скриптов эмитента
                                        //           - получаем финальный вердикт
                                        var issScrResults = new ActiveXObject( 'MBK_AuthService.EmvScriptResults' );
                                        PrintMsg( 'mbkService.Complete() = ' + mbkService2.Complete( onlineHostData, issScrResults ) );

                                        // TODO: анализ результата!

                                        // Результат исполнения скриптов может выглядеть так:
                                        PrintMsg( 'issuerScriptResults = ' + issScrResults.GetRawResult( true ) );

                                        // Или так:
                                        if( issScrResults.Count > 0 )
                                        {
                                                var firstResult = new ActiveXObject( 'MBK_AuthService.ScriptResultInfo' );
                                                issScrResults.GetResult( 0, firstResult );
                                            PrintMsg( 'Iss scr results count = ' + issScrResults.Count + '; First result: ScriptId = ' + firstResult.ScriptIdAsciiHex + '; ResultCode = ' + firstResult.ResultCode.toString(16) + "; FailedScriptSeqNo = " + firstResult.FailedCmdSeqNo );
                                                PrintMsg( 'Iss scr results count = ' + issScrResults.Count + '; First result: ScriptId = ' + firstResult.ScriptId.toString(16) + '; ResultCode = ' + firstResult.ResultCode.toString(16) + "; FailedScriptSeqNo = " + firstResult.FailedCmdSeqNo );
                                        }

                                        // Для отправки CONFIRMATION / REVERSAL MESSAGE на хост, вновь собираем EMV-данные
                                        mbkService.ConstructOnlineChipData( onlineChipData );
                                        PrintMsg( 'onlineChipData = ' + onlineChipData.FormatAsciiHex( true ) );
                                }
                                catch( Exception ) {
                                        PrintMsg( Exception );
                                }
                        }
                } );


                function PrintMsg( msg )
                {
                        $( '#divEvents' )[0].innerHTML += msg + '<br />';
                }

        </script>

</head>
<body>
        <button id='btnInitialize' >Ininitialize</button>
        <button id='btnConfigureTerminal' >ConfigureTerminal</button>
        <button id='btnTransaction' >Transaction</button>
        <button id='btnUninitialize' >Unininitialize</button>

        <div>
                SingleAppAutoSelection
                <input type="checkbox" id="chk_SingleAppAutoSelection" value="1" />
        </div>
        <div>
                ExplicitPinEntry
                <input type="checkbox" id="chk_ExplicitPinEntry" value="1" />
        </div>

        <div>
                Select app:
                <input type="text" id="edit_chosenAppNo" value="0">
        </div>
        <div id='explicitPinEntryResult'>
                explicitPinEntryResult:
                <input type='radio' id='radio_ok' name='pinentry' value='1' />ok
                <input type='radio' id='radio_cancelled' name='pinentry' value='2' />cancelled
                <input type='radio' id='radio_no_pinpad' name='pinentry' value='3' />no pinpad
        </div>
        <div id='divEvents' style='width: 800px;' >Messages:<br /></div>

</body>
<!-- COM objects to be placed outside the html/body -->
<OBJECT ID='mbkService' CLASSID='CLSID:DA30A7CF-A8F0-4949-8BD0-970308CDE5A7' width='0' height='0'></OBJECT>
<!-- Демонстрируем свойство 'singleton' класса MBKService -->
<OBJECT ID='mbkService2' CLASSID='CLSID:DA30A7CF-A8F0-4949-8BD0-970308CDE5A7' width='0' height='0'></OBJECT>

</html>