Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Using Smart cards with a Windows Store App

5.00/5 (4 votes)
10 Feb 2013CPOL8 min read 33.1K   1.7K  
This article describes a solution to access API and resources that are not available with WinRT.

Introduction 

Some time ago I tried to port my Smart card framework for .NET to WinRT components in C++. As I have some experience with both smart card technoogy and COM components, that was I thought an interesting exercise.

So I created a simple WinRT component project in C++/CX to give access to a Windows Store application to smart card features. In a C++ application, you include winscard.h and this gives you access to a PC/SC API to communicate with the card. Unfortunately if you do that in a Windows store project, all the smart card API definitions are disabled by Microsoft.

I got a confirmation from Microsoft of what I discovered in the source of the .h. For a reason I don't really understand there is simply no way to get access to a smart card in a Windows Store application or library using the standard PC/SC API.

However I'm kind of obstinate and I don't give up easily when I'm trying to do something. Windows 8 still can run legacy windows application in what they call Windows Desktop. I could perfectly run my .NET smart card framework application in the desktop mode of Windows 8, so I had the simple following idea. If I can run a WCF service in the Desktop mode and use this WCF service from a WinRT component, then I have a solution to build a smart card component for Windows Store apps ... So far Microsoft didn't disable WCF in WinRT, it is still highly necessary to access the cloud!

In a previous article I introduced a WCF wrapper for my Smart card framework for .NET. This exercice doesn't have a lot of interest with Windows 7 or XP as smart cards are supported by PC/SC, but it is currently the only way you can access a smart card from a Windows Store app.

Image 1

Fig. 1: Components interaction diagram

The WinRT component to connect with the WCF smart card service

A smart card is a relatively slow device, so the overhead introduced by the WCF service is unnoticeable, especially with one of the binary bindings like Net TCP or Named Pipe. The WCF smart card service is described in a previous article. It is hosted in a windows form application that needs to be started when the system starts-up. Windows 7 and Windows 8 have restriction for the smart card access when running in a Windows service, that's why it needs to be hosted in a windows application, that could be a console eventually.

The service has a MEX end point so it is easy to create the client component. For the WinRT component I chose the NetTcp binding because when importing the reference it creates everything and you just need to call a parameter-less constructor to instantiate the WCF client. If you want to use the NamedPipe binding you need to instantiate the WCF client with a binding and endpoint address. I tested both bindings in a console test application and I couldn't notice any performance difference between the 2 bindings.

The code of the WinRT wrapper is given below:  

/// <summary>
/// This is a simple component to manage a smartcard
/// 
/// Method are made synchronous because the service on the local machine and a smartcard
/// although not very fast is a quite responsive device..
/// </summary>
public sealed class Smartcard
{
    private SCardService.RemoteCardClient cardClient = null;
    private const int TIMEOUT = 10000;

    public Smartcard()
    {
	// Create an instance of the 
	cardClient = new SCardService.RemoteCardClient();
    }

    /// <summary>
    /// Gets the list of readers
    /// 
    /// REM: This method is not really at its place and should be in a seperate 
    /// component. Maybe later if I have some time
    /// </summary>
    /// <returns>A string array of the readers</returns>
    public string[] ListReaders()
    {
	Task<ObservableCollection<string>> readers = cardClient.ListReadersAsync();

	try
	{
	    return readers.Result.ToArray();
	}
	catch (AggregateException ax)
	{
	    throw new Exception(ProcessAggregateException(ax));
	}
    }

    /// <summary>
    /// Connects to a card. Establishes a card session
    /// </summary>
    /// <param name="Reader">Reader string</param>
    /// <param name="ShareMode">Session share mode</param>
    /// <param name="PreferredProtocols">Session preferred protocol</param>
    public void Connect(string reader, SHARE shareMode, PROTOCOL preferredProtocols)
    {
	try
	{
	    cardClient.ConnectAsync(reader, (SCardService.SHARE)shareMode, (SCardService.PROTOCOL)preferredProtocols).Wait(TIMEOUT);
	}
	catch (AggregateException ax)
	{
	    throw new Exception(ProcessAggregateException(ax));
	}
    }

    /// <summary> 
    /// Disconnect the current session
    /// </summary>
    /// <param name="Disposition">Action when disconnecting from the card</param>
    public void Disconnect(DISCONNECT disposition)
    {
	try
	{
	    cardClient.DisconnectAsync((SCardService.DISCONNECT)disposition).Wait(TIMEOUT);
	}
	catch (AggregateException ax)
	{
	    throw new Exception(ProcessAggregateException(ax));
	}
    }

    /// <summary>
    /// Transmit an APDU command to the card
    /// </summary>
    /// <param name="ApduCmd">APDU Command to send to the card</param>
    /// <returns>An APDU Response from the card</returns>
    public APDUResponse Transmit(APDUCommand apduCmd)
    {
	Task<SCardService.APDUResponse> task = cardClient.TransmitAsync(
	    new SCardService.APDUCommand()
	    {
	        Class = apduCmd.Class,
		Ins = apduCmd.Ins,
		P1 = apduCmd.P1,
		P2 = apduCmd.P2,
		Le = apduCmd.Le,
		Data = apduCmd.Data
	    });

	try
	{
	    SCardService.APDUResponse resp = task.Result;

	    return new APDUResponse()
	    {
		SW1 = resp.SW1,
		SW2 = resp.SW2,
		Data = resp.Data
	    };
	}
	catch (AggregateException ax)
	{
	    throw new Exception(ProcessAggregateException(ax));
	}
	}

    /// <summary>
    /// Begins a card transaction
    /// </summary>
    public void BeginTransaction()
    {
	try
	{
	    cardClient.BeginTransactionAsync().Wait(TIMEOUT);
	}
	catch (AggregateException ax)
	{
	    throw new Exception(ProcessAggregateException(ax));
	}
    }

    /// <summary>
    /// Ends a card transaction
    /// </summary>
    public void EndTransaction(DISCONNECT disposition)
    {
	try
	{
	    cardClient.EndTransactionAsync((SCardService.DISCONNECT)disposition).Wait(TIMEOUT);
	}
	catch (AggregateException ax)
	{
	    throw new Exception(ProcessAggregateException(ax));
	}
    }

    /// <summary>
    /// Gets the attributes of the card
    /// 
    /// This command can be used to get the Answer to reset
    /// </summary>
    /// <param name="AttribId">Identifier for the Attribute to get</param>
    /// <returns>Attribute content</returns>
    public byte[] GetAttribute(UInt32 attribId)
    {
	Task<byte[]> task = cardClient.GetAttributeAsync(attribId);

	try
	{
	    return task.Result;
	}
	catch (AggregateException ax)
	{
	    throw new Exception(ProcessAggregateException(ax));
	}
    }

    /// <summary>
    /// This method extract the error message carried by the WCF fault
    /// 
    /// Supports SmarcardFault and GeneralFault
    /// </summary>
    /// <param name="ax">AggregateException object</param>
    /// <returns>Extracted message</returns>
    private static string ProcessAggregateException(AggregateException ax)
    {
	string msg = "Unknown fault";
	FaultException<SCardService.SmartcardFault> scFault = ax.InnerException as FaultException<SCardService.SmartcardFault>;
	if (scFault != null)
	{
	    msg = scFault.Detail.Message;
	}
	else
	{
	    FaultException<SCardService.GeneralFault> exFault = ax.InnerException as FaultException<SCardService.GeneralFault>;
	    if (exFault != null)
	    {
		msg = exFault.Detail.Message;
	    }
	}

	return msg;
    }
}

The Smartcard class is a WinRT component written in C# that simply wraps the WCF smart card service client. To create the generated wrapper, I simply ran the WCF service on the windows desktop and because it exposes a MEX end-point I could let Visual Studio generate the proxy. I could have used the WCF service directly in the Windows Store application, but it is a much better construction to have a component that does the work as it can be reused by different applications.

When you import a WCF service in a WinRT component or a Windows Store app you only get an async version of the methods. In this first version I only provide synchronous methods as the service runs on the local machine and the smart card is a quite responsive device. However if I have some time and as an exercice I will implement some asynchronous version of the methods (which should be quite straightforward).

If you look at the Transmit method, which the most complex one, there are basically 2 actions:

  • Call the async method, TransmitAsync 
  • Call the Result method on the generated Task<> running the service method

As the method call is running in a separate thread if your service can throw a FaultException this exception cannot be caught simply with a catch(FaultException<SmartcardException> ex) for example. Fortunately WinRT provides an AggregateException that can be caught with a catch around the asynchronous call and that contains a reference to the exceptions that could have happened inside the thread.

So the code of an asynchronous call with exception handling looks like this:

public byte[] GetAttribute(UInt32 attribId)
{
    Task<byte[]> task = cardClient.GetAttributeAsync(attribId);

    try
    {
	return task.Result;
    }
    catch (AggregateException ax)
    {
	throw new Exception(ProcessAggregateException(ax));
    }
}

The AggregateException instance contains an InnerException member that contains the main exception that has interrupted the thread. In our case it should contains one of the FaultException that is supported by the service implementation. The method ProcessAggregateException extracts the expected FaultException and returns a message indicating what happens. This is a simplistic implementation, my objective being just to avoid a nasty app termination if an exception happens within a service call.

A real app should make the difference between a recoverable exception and an exception that terminated the communication with the WCF service and would need the app to reconnect to the WCF service.

The demo application: A Windows Store ExchangeAPDU app

In the Smart card framework for .NET article I published a simple ExchangeAPDU demo application to send low level command to a smart card. I chose to do a simple port of that application to Windows Store. However it is a simpler version as the WCF service doesn't support card events yet.

I used C# to write this application as there is no performance issue to worry with such a demonstration. Windows Store app in C# use a technology similar to WPF so my simple app UI has a model, the Smartcard component and its APDUCommand and APDUResponse components, a view which is the main page and a View model to manage the view. There is strictly no code behind for the view.

In order to support the commands I extracted few classes from a nice MVVM framework that can be obtained on Github.

Image 2

Fig. 2: ExchangeAPDU app, Select MF (3F00) on a SIM card 

Filter for the data byte TextBox 

The support of XAML in Windows Store app doesn't seem to be as complete as the latest version of WPF was. In order to add some character filtering to the different TextBox controls I couldn't use standard WPF features.

  • PreviewTextInput is not supported  
  • UpdateSourceTrigger is not supported 

Those are two issues to support filtering. Without UpdateSourceTrigger it is not possible to choose when the source data is updated when characters are entered in the TextBox control. Without PreviewTextInput it is not possible to get the text that was entered before it is displayed.  

The only event available that I could find is KeyDown, but it gets the value of the VirtualKey that was entered and the value that it returns is not exact for numbers. For example on a french keyboard if you press '6' without shift it is '-', but for both characters you get VirtualKey.Number6. As a result some unwanted characters are not filtered.

Without UpdateSourceTrigger it is not possible to change the way the source is updated, so by default it is updated when the control loses focus. As I want the data to be updated when text is entered I normally would have used UpdateSourceTrigger=PropertyChanged.

I searched on the forums and I found a solution to work around the lack of UpdateSourceTrigger. It is a custom behavior that can be applied to the TextBox to update the source when characters are entered.

public class TextBoxUpdateSourceBehaviour
{
    private static Dictionary<TextBox, PropertyInfo> _boundProperties = new Dictionary<TextBox, PropertyInfo>();

    public static readonly DependencyProperty BindingSourceProperty =
        DependencyProperty.RegisterAttached(
        "BindingSource",
        typeof(string),
        typeof(TextBoxUpdateSourceBehaviour),
        new PropertyMetadata(default(string), OnBindingChanged));

    public static void SetBindingSource(TextBox element, string value)
    {
        element.SetValue(BindingSourceProperty, value);
    }

    public static string GetBindingSource(TextBox element)
    {
        return (string)element.GetValue(BindingSourceProperty);
    }

    private static void OnBindingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var txtBox = d as TextBox;
        if (txtBox != null)
        {
            txtBox.Loaded += OnLoaded;
            txtBox.TextChanged += OnTextChanged;
        }
    }

    static void OnLoaded(object sender, RoutedEventArgs e)
    {
        var txtBox = sender as TextBox;
        if (txtBox != null)
        {

            // Reflect the datacontext of the textbox to find the field to bind to.
            if (txtBox.DataContext != null) // DataContext is null in the designer
            {
                var dataContextType = txtBox.DataContext.GetType();
                AddToBoundPropertyDictionary(txtBox, dataContextType.GetRuntimeProperty(GetBindingSource(txtBox)));
            }
        }
    }

    static void AddToBoundPropertyDictionary(TextBox txtBox, PropertyInfo boundProperty)
    {
        PropertyInfo propInfo;
        if (!_boundProperties.TryGetValue(txtBox, out propInfo))
        {
            _boundProperties.Add(txtBox, boundProperty);
        }
    }

    static void OnTextChanged(object sender, TextChangedEventArgs e)
    {
        var txtBox = sender as TextBox;
        if (txtBox != null)
        {
            _boundProperties[txtBox].SetValue(txtBox.DataContext, txtBox.Text);
        }
    }

} 

To use this behavior you need to set the namespace in the XAML that way xmlns:util="using:Core.Wpf", then in the TextBox XAML you must add the following property: util:TextBoxUpdateSourceBehaviour.BindingSource="Class" 

Getting the source

You can get the source code of those projects from the ZIP files attached to that article or you can follow those projects on github where they will be updated regularly as this is a public repository.

.NET Smartcard library: https://github.com/orouit/SmartcardFramework.git
 WinRT component and demo app: https://github.com/orouit/SmartcardWithWindowsStore.git

Points of Interest 

Like I mentioned in the previous article, a WCF service is the solution to access a smart card resource from a Windows Store app. This demo application proves it!

In fact this technique can be applied to any case where an API of windows is no longer available to a Windows Store application. However I would only suggest to use this technique in an enterprise context where your application is not distributed through the Windows store. I haven' checked with the App submission toolkit but I suspect that an application that would access a non supported feature of windows using a WCF service would not be accepted. 

History

  • 10/2/2013: UI updated with hexadecimal filtering. Code up to date on Github. 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)