Introduction
Working with smart cards and PKI stuff is an interesting field. You can see the state-of-art of computer security and how it can be used in real environment from real users. But, sometimes, debugging and testing applications that work with smart cards is a real pain, especially when you have to deal with negative test cases and, as it often happens, you don't have many test smart cards to play with. What if you accidentally block a PIN? Or your CSP issues a wrong command, leaving the card in an inconsistent state? These and many other issues are quite common in this field, so one of the first things I realized when I started to work in this field was that I needed an emulator: something to play with without the risk of doing any damage. In this article I will not speak about smart card OS emulation (perhaps it will be covered in the future...), but about a driver for a virtual smart card reader.
Searching the internet for virtual drivers leads you to find many interesting resources, but not the “guide for dummies” that I was hoping to find. I’m not an expert in driver developing; this is not by any means an article on “how to write drivers”. I’m just explaining my approach to a new subject, hoping that it will be useful for someone.
An alternative approach to the driver is just writing your own version on winscard.dll, and put it in the folder of the application you wish to debug. That's easier, in some cases, but has some drawbacks:
- To fully emulate the behavior of Windows Smart Card Resource Manager you must implement lots of functions
- It could be a pain to implement functions like SCardGetStatusChange, specially if you should mix real and simulated readers
- You can't replace system's real winscard.dll, since it's subject to system file protection, so it could by tricky to override it in some applications
Having tried both approaches, I think that the developing a driver is better, having learned some base lessons on how to do it (or having this article as a guide :) ).
Background
It needed just a few clicks on google to realize that, to keep things easy, I had to use UMDF (User Mode Driver Framework) as a basis for the development of the driver. From my point of view, and my understanding of the subject, the main reasons are:
If you make a mistake, you don't get an ugly blue screen - so, easy developing
You can debug your code with your old good user mode debugger - eg. VS2008 - no need for kernel mode debugging - so, easy debugging
In my case performance is not critical, and the little overhead introduced by the framework is not a problem
These are the reasons that led me to use UMDF. Considering the little effort and the satisfaction with the result, I think it was a good choice.
The code is base on the UMDFSkeleton sample of WDK 7.1. I will first comment the important points of the code, then I will explain the installation procedure.
As an addiction, the virtual card reader will communicate with a desktop application to provide the virtual smart card behavior; so, we'll see some IPC between a UMDF driver and a user process.
A look at an UMDF driver structure
As I said, UMDF simplifies a lot the development of a driver. You just need to write some COM (actually, COM-like) objects implementing some core interfaces and that's it. Let's take a look on how it all works.
A user mode driver is like a COM object. So, like a COM object, we are building a dll that exposes a DllGetClassObject function, that will be called by the UMDF framework to obtain a ClassFactory to create the actual driver object.
With ATL is very easy to create COM objects, so we'll use it to further simplify our job. The only function exposed by the dll is
STDAPI DllGetClassObject(__in REFCLSID rclsid, __in REFIID riid, __deref_out LPVOID* ppv)
{
return _AtlModule.DllGetClassObject(rclsid, riid, ppv);
}
Nothing strange here. The object we are creating (CMyDriver) must implement the IDriverEntry interface, that defines the main entry points of our driver. We can use the OnInitialize method to do all initialization stuff before the actual job begins, but it is not needed in our case.
The OnDeviceAdd method is called by the framework whenever a device is connected to the system that is managed by our driver. In our case we create a CMyDriver object (through CMyDevice::CreateInstance method), that will hold a reference to a IWDFDevice object, created by the CreateDevice function. This is the initialization of CMyDriver:
Read more: Codeproject
Working with smart cards and PKI stuff is an interesting field. You can see the state-of-art of computer security and how it can be used in real environment from real users. But, sometimes, debugging and testing applications that work with smart cards is a real pain, especially when you have to deal with negative test cases and, as it often happens, you don't have many test smart cards to play with. What if you accidentally block a PIN? Or your CSP issues a wrong command, leaving the card in an inconsistent state? These and many other issues are quite common in this field, so one of the first things I realized when I started to work in this field was that I needed an emulator: something to play with without the risk of doing any damage. In this article I will not speak about smart card OS emulation (perhaps it will be covered in the future...), but about a driver for a virtual smart card reader.
Searching the internet for virtual drivers leads you to find many interesting resources, but not the “guide for dummies” that I was hoping to find. I’m not an expert in driver developing; this is not by any means an article on “how to write drivers”. I’m just explaining my approach to a new subject, hoping that it will be useful for someone.
An alternative approach to the driver is just writing your own version on winscard.dll, and put it in the folder of the application you wish to debug. That's easier, in some cases, but has some drawbacks:
- To fully emulate the behavior of Windows Smart Card Resource Manager you must implement lots of functions
- It could be a pain to implement functions like SCardGetStatusChange, specially if you should mix real and simulated readers
- You can't replace system's real winscard.dll, since it's subject to system file protection, so it could by tricky to override it in some applications
Having tried both approaches, I think that the developing a driver is better, having learned some base lessons on how to do it (or having this article as a guide :) ).
Background
It needed just a few clicks on google to realize that, to keep things easy, I had to use UMDF (User Mode Driver Framework) as a basis for the development of the driver. From my point of view, and my understanding of the subject, the main reasons are:
If you make a mistake, you don't get an ugly blue screen - so, easy developing
You can debug your code with your old good user mode debugger - eg. VS2008 - no need for kernel mode debugging - so, easy debugging
In my case performance is not critical, and the little overhead introduced by the framework is not a problem
These are the reasons that led me to use UMDF. Considering the little effort and the satisfaction with the result, I think it was a good choice.
The code is base on the UMDFSkeleton sample of WDK 7.1. I will first comment the important points of the code, then I will explain the installation procedure.
As an addiction, the virtual card reader will communicate with a desktop application to provide the virtual smart card behavior; so, we'll see some IPC between a UMDF driver and a user process.
A look at an UMDF driver structure
As I said, UMDF simplifies a lot the development of a driver. You just need to write some COM (actually, COM-like) objects implementing some core interfaces and that's it. Let's take a look on how it all works.
A user mode driver is like a COM object. So, like a COM object, we are building a dll that exposes a DllGetClassObject function, that will be called by the UMDF framework to obtain a ClassFactory to create the actual driver object.
With ATL is very easy to create COM objects, so we'll use it to further simplify our job. The only function exposed by the dll is
STDAPI DllGetClassObject(__in REFCLSID rclsid, __in REFIID riid, __deref_out LPVOID* ppv)
{
return _AtlModule.DllGetClassObject(rclsid, riid, ppv);
}
Nothing strange here. The object we are creating (CMyDriver) must implement the IDriverEntry interface, that defines the main entry points of our driver. We can use the OnInitialize method to do all initialization stuff before the actual job begins, but it is not needed in our case.
The OnDeviceAdd method is called by the framework whenever a device is connected to the system that is managed by our driver. In our case we create a CMyDriver object (through CMyDevice::CreateInstance method), that will hold a reference to a IWDFDevice object, created by the CreateDevice function. This is the initialization of CMyDriver:
Read more: Codeproject