智能卡微型驱动器概述

卡特定的微型驱动程序是基础 CSP/KSP 中最低的逻辑接口层。 此微型驱动程序允许基础 CSP/KSP 和应用程序使用 SCRM 直接与特定类型的卡交互。

卡微型驱动程序是一个 DLL,用于导出此规范中定义的一组特定 API。 每次调用 卡 微型驱动程序都包含指向提供上下文信息的CARD_DATA结构的指针。 除了函数指针表之外,此上下文信息还提供一些状态信息,该表用于促进上层和卡微型驱动程序之间的通信。

有关此上下文结构的详细信息,请参阅 CardAcquireContext

Cardmod.h C 头文件提供了与此规范相关的其他信息。 此文件包含 Microsoft smart 卡 微型驱动程序 API 指定的函数原型和结构。 此 API 可通过 Microsoft 加密提供程序开发工具包 (CPDK) 获取。

常规设计指南

  • 卡微型驱动程序应作为 DLL 分发。

  • 每个特定于卡的操作都应实现单个原子事务,除非另有说明。

  • 应实现一组标准化的宏级操作。

  • 逻辑卡文件系统对象应映射到其物理位置。

  • 基于此新模型的卡应能够动态增长存储在卡上的任何文件。 对于只读且无法遵循此准则的卡,微型驱动程序应遵循本规范中详述的只读卡的特定准则。

  • 微型驱动程序从 CPDK 导入定义。 (Cardmod.h) 的微型驱动程序头文件包含用于此目的的 Bcrypt.h 。 实现必须通过 Microsoft Visual Studio 项目设置来解决此依赖项,以便编译微型驱动程序。

  • 插件或驱动程序的受保护进程要求

    • 若要使 LSA 插件或驱动程序作为受保护进程成功加载,它必须满足以下条件:

      • 签名验证

        o 保护模式要求加载到 LSA 中的任何插件都必须使用 Microsoft 签名进行数字签名。 因此,任何未签名的或第三方签名的插件将无法在 LSA 中加载。 此类插件的示例包括智能卡驱动程序、加密插件、密码筛选器等。

        o 需要对作为驱动程序 (LSA 插件(例如智能卡驱动程序) )进行数字签名。

        注意Windows 硬件兼容性计划为 Windows 的驱动程序提供数字签名的唯一方法。 因此,请务必参考网站获取此信息。

    • 遵循 Microsoft 安全开发生命周期 (SDL) 流程指南。

      • 所有插件还需要符合 Microsoft 安全开发生命周期 (SDL) - 流程指南 主题的适用部分。 例如,请参阅附录 G 中的 SDL 进程中所述的 无共享节

      • 即使插件使用 Microsoft 签名正确签名,不符合 SDL 流程也可能导致无法加载插件。

有关 SDL 的信息,请参阅 Microsoft 安全开发生命周期 (SDL) – 流程指南

有关开发人员指南的讨论,请参阅 开发人员指南

事务管理

  • 如果卡微型驱动程序使用 SCRM 访问卡,则应假定事务由调用方处理。
  • 卡微型驱动程序可以假定所有入口点(CardDeleteContext 除外)都通过保留卡事务来调用。 无法在 CardDeleteContext 中假定这一点,因为卡可能已被删除或正在作为清理过程的一部分调用。
  • 单个进程中可以存在多个上下文。 在一个进程中调用 CardDeleteContext 不应阻止另一个上下文正常运行。
  • 处理卡的身份验证状态也是调用方的责任,而不是卡微型驱动程序。

约定

字符串:UNICODE 和 ANSI

在应用程序级别,字符串通常作为用户界面的元素直接或间接遇到。 因此,它们通常必须本地化 (翻译成用户的语言) ,以便可以理解它们。 因此,大多数应用程序使用的字符串类型是双字节 (即 UNICODE) 以适应不同的字符集。

但是,智能卡使用最少的资源运行,并且对目录、文件、用户等进行命名的选项很少。 字符串的字符集是单字节 ANSI,它提供更紧凑的字符串数据表示形式。

因此,与微型驱动程序卡的字符串缓冲区应为单字节 ANSI,并且必须在卡微型驱动程序外部执行此字符类型所需的转换。

错误处理

为了确保卡微型驱动程序的错误处理、故障响应和行为一致,应遵循以下约定:

  • 所有 NULL 和无效参数(包括错误标志)都会返回SCARD_E_INVALID_PARAMETER。
  • 所有错误的 PIN 或密钥错误的尝试都会返回SCARD_W_WRONG_CHV。
  • 如果发生一般故障,API 将返回SCARD_E_UNEXPECTED。

此外,以下部分所述的函数返回的错误应来自 SCARD_* 类别 (winerror.h) 。 例如,建议使用 SCARD_E_INVALID_PARAMETER (0x80100004) 而不是ERROR_INVALID_PARAMETER (0x00000057) 。

注意如果由于 I/O 错误或某些与卡上该文件的实际存在无关的其他不可恢复数据问题而无法从卡读取文件,则 Microsoft 建议返回SCARD_E_COMM_DATA_LOST。

在这种情况下,以伞式错误代码的形式返回SCARD_E_FILE_NOT_FOUND会提供误导性的调试信息。

身份验证和授权

从版本 6 开始,微型驱动程序接口将 PIN 的概念扩展到传统字母数字字符串之外。 有关详细信息,请参阅本规范后面的“SECRET_TYPE (枚举) ”。

处理内存分配

此规范中通过调用 PFN_CSP_ALLOC 在内部分配内存缓冲区的所有 API 元素执行此操作。 因此,必须通过调用 PFN_CSP_FREE 释放任何此类内存缓冲区。

卡微型驱动程序执行的任何内存分配都应使用PFN_CSP_ALLOCPFN_CSP_REALLOC来完成。

缓存

基本 CSP/KSP 中的卡接口层实现数据缓存,以最大程度地减少必须写入或从卡读取的数据量。 数据缓存也可供卡微型驱动程序通过CARD_DATA结构中的函数指针使用,卡微型驱动程序应使用这些指针通过缓存存储在卡上的内部数据文件来提高性能。

数据缓存需要对卡的写入访问权限,才能将缓存新鲜度计数器保存到卡。 如果将数据写入卡不可行,微型驱动程序可以控制数据缓存。

有关如何控制数据缓存的详细信息,请参阅本规范后面的 CardGetProperty 中 CP_CARD_CACHE_MODE 属性的定义。

强制版本检查

所有卡微型驱动程序都必须实现版本检查。 CARD_DATA 结构的版本是调用方希望支持的版本与卡微型驱动程序实际可以支持的版本之间的协商。

CARD_DATA版本检查

将最低版本定义为卡微型驱动程序上下文结构的最低版本, (即CARD_DATA支持的结构) ,并将当前版本定义为此卡微型驱动程序的设计级别,并保证所有卡微型驱动程序集结构项在从 CardAcquireContext 成功返回时都有效。 当前版本必须大于或等于最低版本,小于或等于 cardmod.h 中定义的 CARD_DATA_CURRENT_VERSION。

当调用应用程序调用 CardAcquireContext 时,它会指定要加载的所需版本。 此请求的版本在 CARD_DATA 结构的 dwVersion 成员中设置。

如果请求的版本小于卡微型驱动程序支持的最低版本,则 CardAcquireContext 必须返回修订不匹配错误 (请参阅以下示例代码) 。

如果请求的版本至少与最低版本相同,则卡微型驱动程序应将 dwVersion 成员设置为它可以支持的最高版本,该版本小于或等于请求的版本。

以下示例代码显示了检查版本时预期的卡微型驱动程序行为。 假定这是在 CardAcquireContext 函数的正文中。 pCardData 是指向传递到此调用 的CARD_DATA 结构的指针。

#define MINIMUM_VERSION_SUPPORTED (4)
#define CURRENT_VERSION_SUPPORTED (7)

    // The lowest supported version is 4.
    If (pCardData->dwVersion < MINIMUM_VERSION_SUPPORTED)
    {
        dwError = (DWORD) ERROR_REVISION_MISMATCH;
        goto Ret;
    }

    // Set the version to what we support, but don’t exceed the
    // requested version
    pCardData->dwVersion =
       min(pCardData->dwVersion, CURRENT_VERSION_SUPPORTED);

注意如果卡微型驱动程序返回的版本不适合调用应用程序,则调用应用程序负责适当处理此情况。

对 CardAcquireContext 的调用中设置 dwVersion 后,假定调用方或卡微型驱动程序在同一上下文中时不会更改它。

其他结构版本检查

对于其他版本控制结构和其他卡微型驱动程序 API 方法,版本处理与CARD_DATA结构相同,但有一个例外。 如果使用包含设置为 0 的 dwVersion 成员的结构调用 API 方法,则必须将其视为 dwVersion 值 1。

CardRSADecryptCardSignData 函数对传入的数据结构的版本号具有特殊处理。