While the original CSP model made it possible to support smart cards, it was neither efficient or scalable. It put a significant burden on both upstream consumers and authors of each CSP. Applications had to know which CSP to load in advance– which is a tall order for smart cards, since they can be introduced at any point. In reality most applications were written on the assumption that a single CSP could service all their requirements, because the model did not permit easily mixing and matching. That meant even dedicated CSPs had to effectively duplicate all of the functionality in the default CSP, including features that have nothing to do with smart cards. These limitations motivated MSFT to introduce a different model with the ill-fated Vista OS, eventually reaching its full potential with Windows 7.
The new model takes advantage of the fact that there is a significant amount of logic shared across smart-card CSPs– such as prompting for a PIN– can be refactored into a platform component. The new architecture could be depicted in simplified form as follows:
Some observations about this architecture:
- CSP layer is still intact, but third-party CSPs are largely deprecated. While existing ones will continue to work, MSFT can at some point discourage publication of new ones due to another legacy of the crypto wars: every CSP must be signed by MSFT itself. In the logic of export restrictions, this would have prevented the bad guys from writing stronger cryptography implementations than they were entitled to according to the framework. Again the original motivation is long gone, but the restriction survived in the architecture. (Tangent: it is trivial for users to override this, with administrative privileges. First approach is to configure the machine for kernel debugging, which permits loading unsigned CSP by design. Another approach, adopted by this blogger for a past project, involves modifying the function in advapi32 responsible for loading new providers. Reverse engineering reveals the location where return value from signature verification is used in a conditional branch. Hot patching that code in memory to with NOOPs allows ignoring failed signature checks. This is best automated with a DLL injected into all processes, using the app-init DLL mechanism for example, such that existing apps can transparently load the unsigned CSP without modification.)
- There is a single CSP responsible for all smart cards. One more layer of indirection has been added under that CSP, branching out to individual mini-drivers responsible for a particular card edge. Vendors introducing a proprietary card edge– as opposed to simply shipping new hardware that conforms to an existing standard– are now tasked with writing smart card mini-drivers hooking into the generic smart card CSP instead of writing wholesale CSPs specific to one model of cards.
- To complicate the picture– Vista also introduced a new cryptographic API called Crypto Next Generation (CNG) with its own abstraction called Key Storage Providers, or KSP for short. Smart cards can also be accessed via this path using the unified smart-card KSP. One convenient property is that drivers can operate as part of either stack, depending on whether the calling application uses CAPI or CNG.
- Drivers are assumed to communicate via the PC/SC interface to the card itself, and they are invoked only after a connection to the card is established at PC/SC layer. A corollary is that cryptographic hardware that does not appear as a CCID device, such as networked HSMs or USB tokens communicating via home-brew HID interface, either have to stick with writing legacy CSP or create the appearance of a fake smart-card, complete with an associated fake smart-card reader to appease PC/SC, as in the case of virtual smart cards built on top of the TPM.
- The adjective “mini” is relative. Counting by sheer number of APIs, card drivers have a significantly more complex interface than the corresponding CSP they replaced.
- Two card edges are built into the OS out of the box: PIV and GIDS. Logically these appear as different card types but in reality they are implemented by a single driver, msclmd.dll. For coping with the terra incognito of card models beyond that, there exists a fairly elaborate discovery mechanisms to map a given smart card to a driver, as well as install new drivers via plug-and-play mechanism when confronted with an unfamiliar “card” such as an Android phone with embedded secure element. This will be the subject of the last post in the series.