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.
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:
public sealed class Smartcard
{
private SCardService.RemoteCardClient cardClient = null;
private const int TIMEOUT = 10000;
public Smartcard()
{
cardClient = new SCardService.RemoteCardClient();
}
public string[] ListReaders()
{
Task<ObservableCollection<string>> readers = cardClient.ListReadersAsync();
try
{
return readers.Result.ToArray();
}
catch (AggregateException ax)
{
throw new Exception(ProcessAggregateException(ax));
}
}
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));
}
}
public void Disconnect(DISCONNECT disposition)
{
try
{
cardClient.DisconnectAsync((SCardService.DISCONNECT)disposition).Wait(TIMEOUT);
}
catch (AggregateException ax)
{
throw new Exception(ProcessAggregateException(ax));
}
}
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));
}
}
public void BeginTransaction()
{
try
{
cardClient.BeginTransactionAsync().Wait(TIMEOUT);
}
catch (AggregateException ax)
{
throw new Exception(ProcessAggregateException(ax));
}
}
public void EndTransaction(DISCONNECT disposition)
{
try
{
cardClient.EndTransactionAsync((SCardService.DISCONNECT)disposition).Wait(TIMEOUT);
}
catch (AggregateException ax)
{
throw new Exception(ProcessAggregateException(ax));
}
}
public byte[] GetAttribute(UInt32 attribId)
{
Task<byte[]> task = cardClient.GetAttributeAsync(attribId);
try
{
return task.Result;
}
catch (AggregateException ax)
{
throw new Exception(ProcessAggregateException(ax));
}
}
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.
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)
{
if (txtBox.DataContext != null)
{
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.