How to write an NFC Host Card Emulation (HCE) app with Windows 10 for Mobile

 

Introduction 

This document details how HCE works on Windows Phone 10 devices and how to develop a card emulation app using this technology.
Windows Phone 8.1 supports NFC card emulation apps using a SIM-based secure element, but that model requires secure payments apps to be tightly coupled with mobile-network operators (MNOs) since SIM cards are owned by MNOs, which limits the variety of possible payment solutions by 3rd parties not aligned with MNOs.
In Windows Phone 10, we have introduced a new card emulation technology called host card emulation (HCE), which allows your application to directly communicate with an NFC reader. Windows Phone 10 continues to fully supports SIM-based card emulation, and SIM-based apps can co-exist with HCE apps.
This document outlines the design specifics of HCE on Windows Phone 10 platform and provides guidelines to implement an HCE card emulation app using WinRT.

What you need to develop an HCE app

To develop a HCE-based card emulation app for Windows Phone, you need:
• Windows Phone 10 SDK with Microsoft Visual Studio® 2015 (Windows Phone 10 Emulator is included and has NFC emulation support)
Optionally, to test with a real device (instead of just the emulator) you will also need:
• Windows Phone 10 with NFC HCE support (730/830/640/640XL …)
• Reader terminal (supporting protocols ISO/IEC 14443-4 and ISO/IEC 7816-4)

HCE Architecture

Windows 10 implements an HCE service that provides the following functionalities:
- Applications can register the applet identifiers (AIDs) for the cards they would like to implement
- Conflict resolution and routing of the Application Protocol Data Unit (APDU) command/response pairs to one of the registered apps based on the external reader card selection and user preference set on the mobile device.
- Handling of events/notifications to the apps as a result of user actions
Windows supports emulation of smart cards that are based on ISO-DEP (ISO-IEC 14443-4) and communicates using Application Protocol Data Units (APDUs) as defined in the ISO-IEC 7816-4 specification. Windows supports ISO/IEC 14443-4 Type A technology for Host Card Emulation applications. Type B, type F, and non-ISO-DEP (eg MIFARE) technologies are routed to the SIM by default.
The architecture for HCE and SIM based card emulation support is shown in the diagram below. In Windows 10, only mobile SKUs are enabled with the card emulation feature. SIM based and HCE based card emulation is not available on desktop SKU (such as tablets/PCs).

 

Application selection and AID routing

The user can install multiple different card emulation applications and each can register multiple HCE and/or SIM-based cards. Legacy Windows Phone 8.1-era SIM-based applications will continue to work in Windows 10 so long as the user chooses the “SIM Card” option (which is the default when booted with Windows 10 the first time) as their default payment card in the NFC control panel.
When a the user taps to a terminal the platform needs the know which application to route traffic to, this routing is based on the applet IDs (AIDs) which are 5-16 bytes identifiers. During a tap, the external terminal will transmit a SELECT command APDU to specify the AID it would like all subsequent command APDUs to be routed to (except subsequent SELECT commands, which will change the routing). Based on the AIDs registered by applications, and user preferences, the OS will route the APDU traffic for a specific application to respond. Be aware that a terminal may want to talk with multiple different applications during the same tap, so you must ensure your background task exits as quickly as possible when you are deactivated to make room for another application’s background task to respond.
Applications that implement card emulation shall register with the OS to declare the AIDs (via AID groups) they can handle in order to receive matching traffic. An AID group is conceptually equivalent to an individual physical card, so a particular credit card would be one AID group whereas a different credit card from a different bank for example would be a different AID group (even though both of them may have the same AIDs such as PPSE).

Conflict resolution for payment AID groups

When an application registers AID groups (cards), it can declare the AID group category as either “Payment” or “Other”. While there can be multiple payment AID groups registered at any given time (even by the same application), only one of these payment AID groups may be enabled at a time and the choice of which AID group to be enabled is controlled by the user. For AID groups registered as “Other” there can be multiple AID groups of that category enabled at the same time, and no user interaction is needed to enable them. The reason for this difference is that user expects be in control of consciously choosing a single particular payment/credit/debit card to use, whereas for other types of cards like loyalty/coupons/transit the user expect them to simply be always available whenever they tap.
All the AID groups that are registered as “Payment” appear in the list  of cards in the NFC Settings page, where the user can select their default payment card. When a default payment card is selected, the application that registered this payment AID group becomes the default payment app which allows it to change the enabled/disabled state of any of it’s payment AID groups without user interaction. This means that although an application which requests to enable a payment AID group will cause the OS to prompt the user to confirm their choice, if that application is already the default payment app ,then subsequent request by that application to change which AID group is enabled/disabled will not cause UI prompts. If the user declines a prompt, then previous default payment application (if any) continues to  remain as default.

 

In the example above, if the user changes his default payment card to another card that is not registered by the “HCE Application 1”, system creates a confirmation prompt for the user’s consent. However if the user changes his default payment card to another card that is registered by the “HCE Application 1”, system does not create a confirmation prompt for the user, since “HCE Application1” is already the default payment app.

Conflict resolution for non-payment AID groups

Non-payment cards categorized as “Other” do not appear in the NFC settings page currently, however this could change in future releases.
Your app can create, register and enable non-payment AID groups in the same manner as payment AID groups. The main difference is that for non-payment AID groups the emulation category is set to “Other” as opposed to “Payment”. After registering the AID group with the system, you need to enable the AID group to receive NFC traffic, as with payment AID groups. When you try to enable a non-payment AID group  to receive traffic, the user is not prompted for a confirmation unless there is a conflict with one of the AIDs registered in the system (by a different application). If there is a conflict, user will be prompted with information about which card/application(s) will be disabled if the user chooses to enable the newly registered AID group.
Coexistence with SIM based NFC applications
Windows 10 continues to support SIM-based card emulation along with HCE-based card emulation. Please refer to the “UICC based NFC emulation for Windows Phone 8.1” guide for how to develop an SIM-based card emulation application.
In Windows 10, the OS sets up the NFC controller routing table that is used to make routing decisions at the controller layer. The table contains routing information for:
- Individual AID routes
- Protocol based route (ISO-DEP)
- Technology based routing (NFC-A/B/F)
When an external reader sends a “SELECT AID” command, NFC controller first checks AID routes within the routing table for a match. If there is no match, it will use the protocol based route as the default route for ISO-DEP (14443-4-A) traffic. For any other non-ISO-DEP traffic it will use the technology based routing.
Windows 10 provides a menu option “SIM Card” in the NFC Settings page to continue to use legacy Windows Phone 8.1 SIM-based applications which do not register their AIDs with the OS. If the user selects “SIM card” as their default payment card, then the ISO-DEP route is set to UICC, for all other selections in the dropdown menu the ISO-DEP route is to the host.
The ISO-DEP route is set to “SIM Card” for devices that have an SE enabled SIM card when the device is booted for the first time with Windows 10. When the user installs an HCE enabled app and that app enables any HCE AID group registrations, the ISO-DEP route will be pointed to the host. New SIM-based applications need to register the AIDs in the SIM  in order for the specific AID routes to be populated in the controller routing table.

Implementing an HCE based app

You need to implement your HCE application in 2 parts:
- Foreground app
- Background task
Due to the extremely tight performance requirements of loading your background task in response to an NFC tap, we recommend that your entire background task be implementing in C++/CX native code (including any dependencies/references/libraries you depend on) rather than C# or managed code. While generally C# and managed code is very performant, there is overhead involved in loading the .NET CLR etc when your background task is activated that can be avoided by writing it in C++/CX.


Create and register a background task

You need to create a background task in your card emulation application. Your background task is responsible for processing and responding to Application Protocol Data Units (APDUs) routed to it by the OS. During first time launch of the application your foreground app registers an HCE background task that implements a “IBackgroundTaskRegistration” interface as follows:

var taskBuilder = new BackgroundTaskBuilder();
taskBuilder.Name = bgTaskName;
taskBuilder.TaskEntryPoint = taskEntryPoint;
taskBuilder.SetTrigger(new SmartCardTrigger(SmartCardTriggerType.EmulatorHostApplicationActivated));
bgTask = taskBuilder.Register();

Notice that the task trigger is set to “SmartCardTriggerType. EmulatorHostApplicationActivated”. It means that whenever a SELECT AID command APDU is received by the OS resolving to your app, your background task will be launched.


Receive and respond to APDUs

When there is an APDU targeted for your app, the OS will launch your background task. Your background task receives the APDU passed through the “SmartCardEmulatorApduReceivedEventArgs” object’s “CommandApdu” property and responds to the APDU using the “TryRespondAsync” method of the same object.
Consider keeping your background task for light operations for performance reasons, respond to the APDUs immediately and exit your background task when all processing is complete. Due to the nature of NFC transactions, users tend to hold their device against the reader for only a very short amount of time.
Your background task will continue to receive traffic from the reader until your connection is deactivated, in which case you will receive “SmartCardEmulatorConnectionDeactivatedEventArgs” object. Your connection can be deactivated due to one of the 2 following reasons:

- If the connection is deactivated due to “ConnectionLost”, it means that the user pulled her device away from the reader. If your application needs the user to tap to the terminal longer, you might consider prompting them with feedback. You should terminate your background task quickly (by completing your deferral) to ensure if they tap again it won’t be delayed waiting for the previous background task to exit.
-  If the connection is deactivated due to “ConnectionRedirected”, it means that the terminal sends a new SELECT AID command APDU directed to a different AID. In this case, your application should exit the background task immediately (by completing your deferral) to allow another background task to run.
The background task should also register for the “Cancelled” event on IBackgroundTaskInstance, and likewise quickly exit the background task (by completing your deferral) as this event is fired by the OS when it is finished with your background task.

void BgTask::Run(
    IBackgroundTaskInstance^ taskInstance)
{
    m_triggerDetails = static_cast<SmartCardTriggerDetails^>(taskInstance->TriggerDetails);
    if (m_triggerDetails == nullptr)
    {
        // May be not a smart card event that triggered us
        return;
    }

    m_emulator = m_triggerDetails->Emulator;
    m_taskInstance = taskInstance;

    switch (m_triggerDetails->TriggerType)
    {
    case SmartCardTriggerType::EmulatorHostApplicationActivated:
        HandleHceActivation();
        break;

    case SmartCardTriggerType::EmulatorAppletIdGroupRegistrationChanged:
        HandleRegistrationChange();
        break;

    default:
        break;
    }
}

void BgTask::HandleHceActivation()
{
 try
 {
        auto lock = m_srwLock.LockShared();
        // Take a deferral to keep this background task alive even after this "Run" method returns
        // You must complete this deferal immediately after you have done processing the current transaction
        m_deferral = m_taskInstance->GetDeferral();

        DebugLog(L"*** HCE Activation Background Task Started ***");

        // Set up a handler for if the background task is cancelled, we must immediately complete our deferral
        m_taskInstance->Canceled += ref new Windows::ApplicationModel::Background::BackgroundTaskCanceledEventHandler(
            [this](
            IBackgroundTaskInstance^ sender,
            BackgroundTaskCancellationReason reason)
        {
            DebugLog(L"Cancelled");
            DebugLog(reason.ToString()->Data());
            EndTask();
        });

        if (Windows::Phone::System::SystemProtection::ScreenLocked)
        {
            auto denyIfLocked = Windows::Storage::ApplicationData::Current->RoamingSettings->Values->Lookup("DenyIfPhoneLocked");
            if (denyIfLocked != nullptr && (bool)denyIfLocked == true)
            {
                // The phone is locked, and our current user setting is to deny transactions while locked so let the user know
                // Denied
                DoLaunch(Denied, L"Phone was locked at the time of tap");

                // We still need to respond to APDUs in a timely manner, even though we will just return failure
                m_fDenyTransactions = true;
            }
        }
        else
        {
            m_fDenyTransactions = false;
        }

        m_emulator->ApduReceived += ref new TypedEventHandler<SmartCardEmulator^, SmartCardEmulatorApduReceivedEventArgs^>(
            this, &BgTask::ApduReceived);

        m_emulator->ConnectionDeactivated += ref new TypedEventHandler<SmartCardEmulator^, SmartCardEmulatorConnectionDeactivatedEventArgs^>(
                [this](
                SmartCardEmulator^ emulator,
                SmartCardEmulatorConnectionDeactivatedEventArgs^ eventArgs)
            {
                DebugLog(L"Connection deactivated");
                EndTask();
            });

  m_emulator->Start();
        DebugLog(L"Emulator started");
 }
 catch (Exception^ e)
 {
        DebugLog(("Exception in Run: " + e->ToString())->Data());
        EndTask();
 }
}


Create and register AID groups

During the first launch of your application when the card is being provisioned, you will create and register AID groups with the OS. The OS determines the application that an external reader would like to talk to and route APDUs accordingly based on the registered AIDs and user preference.
Today most of the payment cards register for the same AID (which is PPSE AID) along with additional payment network card specific AIDs. Each AID group represents a card and when the user enables the card, all AIDs in the group are enabled. Similarly, when the user deactivates the card, all AIDs in the group are disabled.
To register an AID group, you need to create a SmartCardAppletIdGroup object and set its properties to reflect that this is an HCE based payment card. Your display name should be descriptive to the user since it will show up in the NFC settings menu as well as user prompts. For HCE payment cards, the emulation category should be set to “Payment” and emulation type should be set to “Host”.

public static byte[] AID_PPSE =
        {
            // File name "2PAY.SYS.DDF01" (14 bytes)
            (byte)'2', (byte)'P', (byte)'A', (byte)'Y',
            (byte)'.', (byte)'S', (byte)'Y', (byte)'S',
            (byte)'.', (byte)'D', (byte)'D', (byte)'F', (byte)'0', (byte)'1'
        };

var appletIdGroup = new SmartCardAppletIdGroup(
                        “Example DisplayName”,
                                new List<IBuffer> {AID_PPSE.AsBuffer()},
                                SmartCardEmulationCategory.Payment,
                                SmartCardEmulationType.Host);

For non-payment HCE cards, the emulation category should be set to “Other” and emulation type should be set to “Host”.

public static byte[] AID_OTHER =
        {
            (byte)'1', (byte)'2', (byte)'3', (byte)'4',
            (byte)'5', (byte)'6', (byte)'7', (byte)'8',
            (byte)'O', (byte)'T', (byte)'H', (byte)'E', (byte)'R’
        };

var appletIdGroup = new SmartCardAppletIdGroup(
                        “Example DisplayName”,
                                new List<IBuffer> {AID_OTHER.AsBuffer()},
                                SmartCardEmulationCategory.Other,
                                SmartCardEmulationType.Host);

You can include up to 9 AIDs (of length 5-16 bytes each) in each AID group.
Use the RegisterAppletIdGroupAsync method to register your AID group with the OS which will return an SmartCardAppletIdGroupRegistration object. By default the ActivationProperty of the registration object is set to “Disabled”, meaning that although your AIDs are registered with the system, they are not enabled yet and won’t receive traffic.

reg = await SmartCardEmulator.RegisterAppletIdGroupAsync(appletIdGroup);

You can enable your registered AID groups (cards) by using the RequestActivationPolicyChangeAsync method of the registration object as shown below. Since only a single payment card can be enabled at a time on the system, setting the “ActivationPolicy” of a payment AID group to “Enabled” is the same as setting the default payment card. The user will be prompted to allow this card as a default payment card, regardless of if there is a default payment card already selected or not (unless your application is already the default payment application, and is merely changing between it’s own AID groups) You can register up to 10 AID groups per application.

reg.RequestActivationPolicyChangeAsync(AppletIdGroupActivationPolicy.Enabled);

You can query your app’s registered AID groups with the OS and check their activation policy using the SmartCardEmulator.GetAppliedIdGroupRegistrationsAsync method.
Users will be prompted when you change the activation policy of a payment card from “Disabled” to “Enabled”, if your app is not already the default payment app. Users will only be prompted when you change the activation policy of a non-payment card from “Disabled” to “Enabled” if there is an AID conflict.

var registrations = await SmartCardEmulator.GetAppletIdGroupRegistrationsAsync();
    foreach (var registration in registrations)
    {
registration.RequestActivationPolicyChangeAsync (AppletIdGroupActivationPolicy.Enabled);
    }

Event notification when activation policy change
In your background task, you can register to receive events for when activation policy of one of your AID group registrations changes outside of your app. One example would be the user changing the default payment application through the NFC settings menu from one of your cards to another card hosted by another app. If your app needs to know about this change for internal setup such as updating live tiles, you can receive event notifications for this change and take action within your app accordingly.

var taskBuilder = new BackgroundTaskBuilder();
taskBuilder.Name = bgTaskName;
taskBuilder.TaskEntryPoint = taskEntryPoint;
taskBuilder.SetTrigger(new SmartCardTrigger(SmartCardTriggerType.EmulatorAppletIdGroupRegistrationChanged));
bgTask = taskBuilder.Register();

Foreground override behavior

You can change the activation policy of any of your AID group registrations (cards) to “ForegroundOverride” while your app is in the foreground without prompting to the user. When the user taps to a payment  terminal while your app is in the foreground, the traffic is routed to your application even if none of your payment cards were chosen by the user as their default payment card. When you change a card’s activation policy to “ForegroundOverride”, this change is only temporary (until your application leaves the foreground) and it will not change the previous selection of default payment card by the user. You can change the activation policy of your payment or non-payment cards from your foreground app as follows (please note that this API can only be called from a foreground app and cannot be called from a background task):

reg.RequestActivationPolicyChangeAsync(AppletIdGroupActivationPolicy.ForegroundOverride);

Also, you can register an AID group consisting of a single 0-length AID to which the OS will route all traffic regardless of AID and including any command APDUs sent before a SELECT AID command is received. However, such an AID group only works while your app is in the foreground as it can only be set to “ForegroundOverride” and cannot be permanently enabled. Also, this mechanism works both for “Host” and “UICC” to either route all traffic to your HCE background task, or to the SIM card.

public static byte[] AID_Foreground =
        {};

var appletIdGroup = new SmartCardAppletIdGroup(
                        “Example DisplayName”,
                                new List<IBuffer> {AID_Foreground.AsBuffer()},
                                SmartCardEmulationCategory.Other,
                                SmartCardEmulationType.Host);
reg = await SmartCardEmulator.RegisterAppletIdGroupAsync(appletIdGroup);
reg.RequestActivationPolicyChangeAsync(AppletIdGroupActivationPolicy.ForegroundOverride);

Check for NFC and HCE support

Your application should check whether a device has NFC hardware, supports card emulation feature, and supports host card emulation prior to offering such features to the user.
In Windows 10, NFC smart card emulation feature is only enabled in Mobile SKU, so trying to use smart card emulator APIs in desktop SKU will result in error. You can check for smart card API support as follows:

Windows.Foundation.Metadata.ApiInformation.IsTypePresent("Windows.Devices.SmartCards.SmartCardEmulator"

Additionally, in your application you can check to see if the device has NFC hardware capable of some form of card emulation by checking if SmartCardEmulator.GetDefaultAsync() returns null, if it does then no NFC card emulation is supported by the device.

var smartcardemulator = await SmartCardEmulator.GetDefaultAsync();

Support for HCE and AID-based UICC routing is only available on specific recently launched devices (such as the Lumia 730/830/640/640XL etc). Any new NFC capable device launching with Win10 and after will support HCE.  Your application can check for HCE support as follows:

Smartcardemulator.IsHostCardEmulationSupported();

Lock screen and screen off behavior

Windows has device level card emulation settings, which can be set by the mobile operator or the manufacturer of the device. By default, “tap to pay” toggle is disabled and the “enablement policy at device level” is set to “Always”, unless MO/OEM overwrites these values.
Your application can query the value of the “enablement policy” at device level and take action for each case depending on the desired behavior of your application  in each state:

SmartCardEmulator emulator = await SmartCardEmulator.GetDefaultAsync();

switch (emulator.EnablementPolicy)
{
case Never:
// you can take the user to the NFC settings to turn “tap and pay” on
await Windows.System.Launcher.LaunchUriAsync(new Uri("ms-settings-nfctransactions:"));
break;
 
 case Always:
return “Card emulation always on”;

 case ScreenOn:
 return “Card emulation on only when screen is on”;

 case ScreenUnlocked:
 return “Card emulation on only when screen unlocked”;
}

Your application’s background task will be launched even if the phone is locked and/or screen is off, if the external reader selects an AID that resolves to your application. You can respond to the commands from the reader in your background task, but if you need any input from the user or if you want to show a message to the user, you can launch your foreground app with some arguments. Your background task can launch your foreground app:
- under the device lock screen (the user will see your foreground app only after she unlocks the device)
- above the device lock screen (after the user dismisses your app, the device is still in locked state)

        if (Windows::Phone::System::SystemProtection::ScreenLocked)
        {
            // Launch above the lock with some arguments
            var result = await eventDetails.TryLaunchSelfAsync(“app-specific arguments”, SmartCardLaunchBehavior.AboveLock);
        } 

AID registration and other updates for SIM based apps

Card emulation apps that using the SIM as the secure element can register with the Windows service to declare the AIDs supported on the SIM. This registration is very similar to an HCE-based app registration. The only difference is the SmartCardEmulationType, which should be set to Uicc for SIM-based apps.
As the result of the payment card registration, the display name of the card will also be populated in the NFC setting menu.

var appletIdGroup = new SmartCardAppletIdGroup(
                        “Example DisplayName”,
                                new List<IBuffer> {AID_PPSE.AsBuffer()},
                                SmartCardEmulationCategory.Payment,
                                SmartCardEmulationType.Uicc);

Also note that the legacy binary SMS intercept support in Windows Phone 8.1 has been removed, and replaced with new broader SMS support in Windows 10 but any legacy Windows Phone 8.1 applications relying on that must update to use the new Windows 10 SMS APIs.


Resources

MSDN SmartCards Namespace:
https://msdn.microsoft.com/en-us/library/windows/apps/windows.devices.smartcards.aspx
MSDN Emulator support for NFC:
https://go.microsoft.com/fwlink/?LinkID=525770&clcid=0x409
NFC Team Blog:
https://blogs.msdn.com/b/nfc/
Sample Code:
https://go.microsoft.com/fwlink/?LinkID=534866&clcid=0x409  
Build Talk:
https://channel9.msdn.com/Events/Build/2015/3-773