Web 智能卡 API

非官方提案草案

此版本:
https://wicg.github.io/web-smart-card/
问题跟踪:
GitHub
编辑:
Google
Google

摘要

此 API 的目标是使智能卡(PC/SC)应用程序 能够迁移到 Web 平台。它使这些应用程序能够访问主机操作系统中 可用的 PC/SC 实现(及读卡器驱动程序)。

另有一份配套的解释文档

本文档状态

本规范由 Web 平台孵化器 社区组发布。 它既不是 W3C 标准,也不处于 W3C 标准化流程中。 请注意,根据 W3C 社区贡献者许可协议 (CLA), 退出权受到限制,并且还适用其他条件。 进一步了解 W3C 社区组和业务组

[Exposed=Window, SecureContext, IsolatedContext]
partial interface Navigator {
  [SameObject] readonly attribute SmartCardResourceManager smartCard;
};

获取时,smartCard 属性始终返回同一个 SmartCardResourceManager 对象实例。

2. WorkerNavigator 接口的扩展

[Exposed=(DedicatedWorker, SharedWorker), SecureContext, IsolatedContext]
partial interface WorkerNavigator {
  [SameObject] readonly attribute SmartCardResourceManager smartCard;
};

2.1. smartCard 属性

获取时,smartCard 属性始终返回同一个 SmartCardResourceManager 对象实例。

3. SmartCardResourceManager 接口

[Exposed=(DedicatedWorker, SharedWorker, Window), SecureContext, IsolatedContext]
interface SmartCardResourceManager {
  Promise<SmartCardContext> establishContext();
};

此接口上的方法以异步方式完成,并将 工作排入智能卡 任务源

3.1. establishContext() 方法

从平台的 PC/SC 栈请求一个 PC/SC 上下文。

establishContext() 方法的步骤如下:

  1. 如果 this相关全局对象关联 Document获准使用名为 “smart-card”的策略控制功能,则抛出一个 “SecurityErrorDOMException

  2. promise一个新的 promise

  3. 并行运行以下步骤:

    1. resourceManager 为平台 [PCSC5] RESOURCEMANAGER 类的一个新实例。

    2. 以一个值为“system”的 Scope 参数调用 resourceManagerEstablishContext 方法。

    3. 如果返回的 RESPONSECODE 不是 SCARD_S_SUCCESS,则执行 以下步骤:

      1. 销毁 resourceManager

      2. 使用智能卡 任务源,在 this相关全局对象排入一个全局任务,以使用一个对应的 异常拒绝 promise

    4. 否则,执行以下步骤:

      1. context 为一个新的 SmartCardContext, 其 [[resourceManager]] 内部 槽被设置为 resourceManager

      2. 使用智能卡 任务源,在 this相关全局对象排入一个全局任务,以使用 context 兑现 promise

  4. 返回 promise

4. SmartCardContext 接口

用于与 PC/SC 资源管理器通信的上下文。

[Exposed=(DedicatedWorker, SharedWorker, Window), SecureContext, IsolatedContext]
interface SmartCardContext {
  Promise<sequence<DOMString>> listReaders();

  Promise<sequence<SmartCardReaderStateOut>> getStatusChange(
      sequence<SmartCardReaderStateIn> readerStates,
      optional SmartCardGetStatusChangeOptions options = {});

  Promise<SmartCardConnectResult> connect(
      DOMString readerName,
      SmartCardAccessMode accessMode,
      optional SmartCardConnectOptions options = {});
};

SmartCardContext 实例使用下表所述的内部槽 创建:

内部槽 初始值 说明(非规范性)
[[resourceManager]] null 要使用的平台 [PCSC5] RESOURCEMANAGER
[[operationInProgress]] false 此上下文中是否存在正在进行的 PC/SC 操作。
[[activeReaderTransactions]] 一个空映射 一个从读卡器名称映射到 SmartCardConnection映射;后者在此 上下文中当前持有该读卡器上的活动事务(若有)。
[[connections]] 一个空有序集合 由此上下文创建的现有 SmartCardConnection 实例。
[[tracker]] null 一个 [PCSC5] SCARDTRACK 实例。
[[signal]] null 未完成的 getStatusChange() 调用的 AbortSignal(若有)。

4.1. listReaders() 方法

listReaders() 方法的步骤如下:

  1. promise一个新的 promise

  2. 如果 this.[[operationInProgress]]true,则使用一个“InvalidStateErrorDOMException 拒绝 promise,并返回 promise

  3. this.[[operationInProgress]] 设置为 true

  4. 并行运行以下步骤:

    1. resourceQuery 为平台 [PCSC5] RESOURCEQUERY 类的一个新实例,并将 this.[[resourceManager]] 作为其 构造函数输入参数。

    2. groups 为平台的 [PCSC5] STR[],其中包含 与该平台中“系统内所有读卡器”等效的组名列表。

    3. pcscReaders 为一个空的 STR[]

    4. 调用 resourceQueryListReaders 方法, 以 groups 作为输入参数,以 pcscReaders 作为输出参数。

    5. responseCode 为返回的 RESPONSECODE

    6. 销毁 resourceQuery

    7. 使用智能卡 任务源,在 this相关全局对象排入一个全局任务,该任务执行 以下步骤:

      1. 清除 operationInProgress(目标为 this)。

      2. 如果 responseCode 不是 SCARD_S_SUCCESS

        1. 如果 responseCodeSCARD_E_NO_READERS_AVAILABLE, 则使用一个空的 DOMString sequence 兑现 promise

        2. 否则,使用一个与 responseCode 对应异常拒绝 promise

      3. 否则,使用一个等效于 pcscReadersDOMString sequence 兑现 promise

  5. 返回 promise

4.2. getStatusChange() 方法

getStatusChange(readerStates, options) 方法的步骤如下:

  1. promise一个新的 promise

  2. 如果 this.[[operationInProgress]]true,则使用一个“InvalidStateErrorDOMException 拒绝 promise,并返回 promise

  3. 如果 options["signal"] 存在,则运行以下步骤:

    1. signaloptions["signal"]。

    2. 如果 signal中止,则使用 signal中止原因拒绝 promise,并返回 promise

    3. this.[[signal]] 设置为 signal

    4. 取消未完成的 GetStatusChange 算法添加signal

  4. pcscTimeout 为一个 [PCSC5] DWORD,其值设置为 [PCSC5] INFINITE

  5. 如果 options["timeout"] 存在,则将 pcscTimeout 设置为 options["timeout"]。

  6. pcscReaderStates 为一个与 readerStates 对应[PCSC5] SCARD_READERSTATE[]

  7. this.[[operationInProgress]] 设置为 true

  8. this.[[tracker]] 设置为平台 [PCSC5] SCARDTRACK 类的一个新实例,并将 this.[[resourceManager]] 作为其 构造函数输入参数。

  9. 并行运行以下步骤:

    1. 使用 pcscReaderStatespcscTimeout 作为输入参数,调用 this.[[tracker]].GetStatusChange()

    2. responseCode 为返回的 [PCSC5] RESPONSECODE

    3. 使用智能卡 任务源,在 this相关全局对象排入一个全局任务,该任务执行 以下步骤:

      1. this.[[tracker]] 设置为 null

      2. 清除 operationInProgress(目标为 this)。

      3. abortReasonundefined

      4. 如果 this.[[signal]] 不为 null, 则运行以下步骤:

        1. 如果 this.[[signal]]中止,则将 abortReason 设置为 this.[[signal]]中止原因

        2. this.[[signal]]移除取消未完成的 GetStatusChange 算法。

        3. this.[[signal]] 设置为 null

      5. 如果 responseCode 不是 SCARD_S_SUCCESS,则运行 以下步骤:

        1. 如果 responseCodeSCARD_E_CANCELLED,并且 abortReason 不是 undefined, 则使用 abortReason 拒绝 promise

        2. 否则,使用一个与 responseCode 对应异常 拒绝 promise

        3. 返回。

      6. readerStatesOut 为一个与 pcscReaderStates 对应SmartCardReaderStateOut 序列。

      7. 使用 readerStatesOut 兑现 promise

  10. 返回 promise

4.2.1. SmartCardReaderStateIn 字典

dictionary SmartCardReaderStateIn {
  required DOMString readerName;
  required SmartCardReaderStateFlagsIn currentState;
  unsigned long currentCount;
};
readerName

智能卡读卡器的名称。

currentState

应用程序所知的该智能卡读卡器当前状态。

currentCount

应用程序所知的此读卡器中卡片插入和移除事件的当前次数。

给定一个名为 readerStatesSmartCardReaderStateIn 序列,按以下步骤创建一个对应的 [PCSC5] SCARD_READERSTATE[]

  1. pcscReaderStates 为一个空的 SCARD_READERSTATE[]

  2. 对于 readerStates 中的每个类型为 SmartCardReaderStateInstateIn逐一执行:

    1. pcscState 为一个 SCARD_READERSTATE

    2. pcscState.Reader 设置为 stateIn["readerName"]。

    3. pcscState.CurrentState 设置为与 stateIn["currentState"] 对应的 DWORD

    4. 如果 stateIn["currentCount"] 存在,则将 pcscState.CurrentState高位字设置为 stateIn["currentCount"]。

    5. pcscState.EventState 设置为零。

    6. pcscState 追加pcscReaderStates

  3. 返回 pcscReaderStates

4.2.1.1. SmartCardReaderStateFlagsIn 字典
dictionary SmartCardReaderStateFlagsIn {
  boolean unaware = false;
  boolean ignore = false;
  boolean unavailable = false;
  boolean empty = false;
  boolean present = false;
  boolean exclusive = false;
  boolean inuse = false;
  boolean mute = false;
  boolean unpowered = false;
};
unaware

应用程序不知道当前状态,并希望获知该状态。

ignore

应用程序对此读卡器不感兴趣,在监视 操作期间不应考虑它。

unavailable

应用程序认为此读卡器不可供使用。

empty

应用程序认为读卡器中没有卡片。

present

应用程序认为读卡器中有卡片。

exclusive

应用程序认为读卡器中的卡片已分配给另一个 应用程序独占使用。

inuse

应用程序认为读卡器中的卡片正被一个或多个其他应用程序使用,但 仍可通过共享模式连接。

mute

应用程序认为读卡器中有一张无响应的卡片。

unpowered

应用程序认为读卡器中的卡片尚未通电。

与给定 SmartCardReaderStateFlagsIn 对应的 [PCSC5] DWORD 对应的 按以下步骤创建:

  1. flagsIn 为给定的 SmartCardReaderStateFlagsIn

  2. pcscFlags 为一个设置为零的 DWORD

  3. 如果 flagsIn["unaware"] 为 true,则将 [PCSC5] SCARD_STATE_UNAWARE 添加pcscFlags

  4. 如果 flagsIn["ignore"] 为 true,则将 [PCSC5] SCARD_STATE_IGNORE 添加pcscFlags

  5. 如果 flagsIn["unavailable"] 为 true,则将 [PCSC5] SCARD_STATE_UNAVAILABLE 添加pcscFlags

  6. 如果 flagsIn["empty"] 为 true,则将 [PCSC5] SCARD_STATE_EMPTY 添加pcscFlags

  7. 如果 flagsIn["present"] 为 true,则将 [PCSC5] SCARD_STATE_PRESENT 添加pcscFlags

  8. 如果 flagsIn["exclusive"] 为 true,则将 [PCSC5] SCARD_STATE_EXCLUSIVE 添加pcscFlags

  9. 如果 flagsIn["inuse"] 为 true,则将 [PCSC5] SCARD_STATE_INUSE 添加pcscFlags

  10. 如果 flagsIn["mute"] 为 true,则将 SCARD_STATE_MUTE 添加pcscFlags

  11. 如果 flagsIn["unpowered"] 为 true,则将 SCARD_STATE_UNPOWERED 添加pcscFlags

  12. 返回 pcscFlags

4.2.2. SmartCardReaderStateOut 字典

智能卡读卡器的实际状态。
dictionary SmartCardReaderStateOut {
  required DOMString readerName;
  required SmartCardReaderStateFlagsOut eventState;
  required unsigned long eventCount;
  ArrayBuffer answerToReset;
};
readerName

智能卡读卡器的名称。

eventState

该智能卡读卡器的实际状态。

eventCount

此读卡器中实际发生的卡片插入和移除事件次数。

answerToReset

已插入卡片的 [ISO7816-3] 复位应答(ATR)(若适用)。

给定一个名为 pcscReaderStates[PCSC5] SCARD_READERSTATE[],按以下步骤创建一个对应的 SmartCardReaderStateOut 序列:

  1. readerStatesOut 为一个空的 SmartCardReaderStateOut 序列。

  2. 对于 pcscReaderStates 中的每个类型为 SCARD_READERSTATEpcscState逐一执行:

    1. stateOut 为一个 SmartCardReaderStateOut

    2. stateOut["readerName"] 设置为 pcscState.Reader

    3. stateOut["eventState"] 设置为与 pcscState.EventState 对应的 SmartCardReaderStateFlagsOut 字典。

    4. stateOut["eventCount"] 设置为 pcscState.EventState高位字

    5. 如果平台的 SCARD_READERSTATE 结构有一个包含卡片 [ISO7816-3] 复位应答的成员,则将 stateOut["answerToReset"] 设置为该值。

    6. stateOut 追加readerStatesOut

  3. 返回 readerStatesOut

4.2.2.1. SmartCardReaderStateFlagsOut 字典
dictionary SmartCardReaderStateFlagsOut {
  boolean ignore = false;
  boolean changed = false;
  boolean unavailable = false;
  boolean unknown = false;
  boolean empty = false;
  boolean present = false;
  boolean exclusive = false;
  boolean inuse = false;
  boolean mute = false;
  boolean unpowered = false;
};
ignore

应用程序请求忽略此读卡器。

changed

调用应用程序输入的状态与实际状态之间存在差异。

unavailable

此读卡器不可供使用。

unknown

应用程序给出的读卡器名称未知。

empty

读卡器中没有卡片。

present

读卡器中有卡片。

exclusive

读卡器中的卡片已分配给另一个应用程序独占使用。

inuse

读卡器中的卡片正被一个或多个其他应用程序使用,但仍可通过共享 模式连接。

mute

读卡器中有一张无响应的卡片。

unpowered

读卡器中的卡片尚未通电。

给定一个名为 pcscFlags[PCSC5] DWORD,按以下步骤创建一个对应的 SmartCardReaderStateFlagsOut 字典:

  1. flagsOut 为一个具有默认成员SmartCardReaderStateFlagsOut 字典。

  2. 如果 pcscFlags 具有 [PCSC5] SCARD_STATE_IGNORE,则将 flagsOut["ignore"] 设置为 true

  3. 如果 pcscFlags 具有 [PCSC5] SCARD_STATE_CHANGED,则将 flagsOut["changed"] 设置为 true

  4. 如果 pcscFlags 具有 [PCSC5] SCARD_STATE_UNAVAILABLE,则将 flagsOut["unavailable"] 设置为 true

  5. 如果 pcscFlags 具有 [PCSC5] SCARD_STATE_UNKNOWN,则将 flagsOut["unknown"] 设置为 true

  6. 如果 pcscFlags 具有 [PCSC5] SCARD_STATE_EMPTY,则将 flagsOut["empty"] 设置为 true

  7. 如果 pcscFlags 具有 [PCSC5] SCARD_STATE_PRESENT,则将 flagsOut["present"] 设置为 true

  8. 如果 pcscFlags 具有 [PCSC5] SCARD_STATE_EXCLUSIVE,则将 flagsOut["exclusive"] 设置为 true

  9. 如果 pcscFlags 具有 [PCSC5] SCARD_STATE_INUSE,则将 flagsOut["inuse"] 设置为 true

  10. 如果 pcscFlags 具有 SCARD_STATE_MUTE,则将 flagsOut["mute"] 设置为 true

  11. 如果 pcscFlags 具有 SCARD_STATE_UNPOWERED,则将 flagsOut["unpowered"] 设置为 true

  12. 返回 flagsOut

4.2.3. SmartCardGetStatusChangeOptions 字典

dictionary SmartCardGetStatusChangeOptions {
  DOMHighResTimeStamp timeout;
  AbortSignal signal;
};
timeout

GetStatusChange() [PCSC5] 方法的超时参数。如果未指定,则使用值为 INFINITE 的超时 (其定义取决于系统)。

signal

触发时,调用平台的 [PCSC5] Cancel() 方法。

4.3. connect() 方法

connect(readerName, accessMode, options) 方法的步骤如下:

  1. promise一个新的 promise

  2. 如果 this.[[operationInProgress]]true,则使用一个“InvalidStateErrorDOMException 拒绝 promise,并返回 promise

  3. 如果 this.[[activeReaderTransactions]][readerName] 存在,则使用一个“InvalidStateErrorDOMException 拒绝 promise,并返回 promise

  4. this.[[operationInProgress]] 设置为 true

  5. 并行运行以下步骤:

    1. accessFlags 为一个与 accessMode 对应的 [PCSC5] DWORD

    2. protocolFlags 为一个设置为 0DWORD

    3. 如果 options["preferredProtocols"] 存在,则将 protocolFlags 设置为其对应标志

    4. activeProtocol 为一个设置为 0DWORD

    5. comm 为平台 [PCSC5] SCARDCOMM 类的一个新实例,并将 this.[[resourceManager]] 作为其 构造函数参数。

    6. 调用 comm.Connect(),以 readerNameaccessFlagsprotocolFlags 作为输入参数,以 activeProtocol 作为输出参数。

    7. responseCode 为返回的 RESPONSECODE

    8. 使用智能卡 任务源,在 this相关全局对象排入一个全局任务,该任务执行以下步骤:

      1. 清除 operationInProgress(目标为 this)。

      2. 如果 responseCode 不是 SCARD_S_SUCCESS

        1. 销毁 comm

        2. 使用一个与 responseCode 对应异常拒绝 promise,并中止这些步骤。

      3. result 为一个空的 SmartCardConnectResult 字典。

      4. connection 为一个新的 SmartCardConnection

      5. connection 追加this.[[connections]]

      6. connection.[[comm]] 设置为 comm

      7. connection.[[readerName]] 设置为 readerName

      8. connection.[[context]] 设置为 this

      9. connection.[[activeProtocol]] 设置为 activeProtocol

      10. result["connection"] 设置为 connection

      11. 如果 activeProtocol 是一个有效协议值, 则将 result["activeProtocol"] 设置为对应的 SmartCardProtocol

      12. 使用 result 兑现 promise

  6. 返回 promise

4.3.1. SmartCardProtocol 枚举

enum SmartCardProtocol {
  "raw",
  "t0",
  "t1"
};
"raw"

“原始”模式。可用于支持特殊用途需求所需的任意数据交换协议。 对应于 [PCSC5] SCARD_PROTOCOL_RAW DWORD

"t0"

[ISO7816-3] T=0。异步半双工字符传输协议。对应于 [PCSC5] SCARD_PROTOCOL_T0 DWORD

"t1"

[ISO7816-3] T=1。异步半双工块传输协议。对应于 [PCSC5] SCARD_PROTOCOL_T1 DWORD

如果一个 [PCSC5] DWORD[PCSC5] SCARD_PROTOCOL_T0[PCSC5] SCARD_PROTOCOL_T1[PCSC5] SCARD_PROTOCOL_RAW 之一,则它是一个 有效协议值

给定一个名为 protocolsSmartCardProtocol 序列,按以下步骤创建一个带有对应标志[PCSC5] DWORD

  1. flags 为一个设置为 0DWORD

  2. 对于 protocols 中的每个类型为 SmartCardProtocolprotocol,将 protocol 对应的 DWORD 添加flags

  3. 返回 flags

4.3.2. SmartCardConnectResult 字典

dictionary SmartCardConnectResult {
  required SmartCardConnection connection;
  SmartCardProtocol activeProtocol;
};
connection

用于访问所创建连接的接口。

activeProtocol

实际使用的协议。

4.3.3. SmartCardAccessMode 枚举

enum SmartCardAccessMode {
  "shared",
  "exclusive",
  "direct"
};
"shared"

应用程序愿意与其他应用程序共享对卡片的访问。

"exclusive"

应用程序需要独占访问卡片。

"direct"

无论是否存在卡片,应用程序都需要连接到读卡器。此模式意味着独占访问。

给定一个名为 accessModeSmartCardAccessMode 枚举,按以下步骤创建一个对应的 [PCSC5] DWORD

  1. dword 为一个设置为 0DWORD

  2. 如果 accessMode 是“shared”, 则将 dword 设置为 [PCSC5] SCARD_SHARE_SHARED

  3. 如果 accessMode 是“exclusive”, 则将 dword 设置为 [PCSC5] SCARD_SHARE_EXCLUSIVE

  4. 如果 accessMode 是“direct”, 则将 dword 设置为 [PCSC5] SCARD_SHARE_DIRECT

  5. 返回 dword

4.3.4. SmartCardConnectOptions 字典

dictionary SmartCardConnectOptions {
  sequence<SmartCardProtocol> preferredProtocols;
};
preferredProtocols

可使用的卡片通信协议。

4.4. 辅助算法和定义

清除 operationInProgress(目标为 SmartCardContext context),执行以下步骤:

  1. 断言context.[[operationInProgress]]true

  2. context.[[operationInProgress]] 设置为 false

  3. 对于 context.[[connections]] 中的每个类型为 SmartCardConnectionconnection逐一执行:

    1. 结束 connection 的任何已敲定事务

    2. 如果 context.[[operationInProgress]]true,则中止这些步骤。

取消未完成的 GetStatusChange 算法的步骤 如下:

  1. 调用 this.[[tracker]].Cancel()

一个 [PCSC5] DWORD高位字, 是对该 DWORD 执行无符号右移 16 位所得的结果。

要将名为 dword[PCSC5] DWORD高位字设置为 给定数字 n,执行以下步骤:

  1. dword 设置为 dword 按位与 0xFFFF

  2. shiftedN 为对 n 执行左移 16 位所得的结果。

  3. dword 设置为 dword 按位或 shiftedN

要向 [PCSC5] DWORD flags 添加标志 f,将 flags 设置为 flags 按位或 f

如果 flags 按位与 f 的结果为 f,则 [PCSC5] DWORD flags 具有标志 f

5. SmartCardConnection 接口

[Exposed=(DedicatedWorker, SharedWorker, Window), SecureContext, IsolatedContext]
interface SmartCardConnection {
  Promise<undefined> disconnect(optional SmartCardDisposition disposition = "leave");

  Promise<ArrayBuffer> transmit(BufferSource sendBuffer,
      optional SmartCardTransmitOptions options = {});

  Promise<undefined> startTransaction(SmartCardTransactionCallback transaction,
      optional SmartCardTransactionOptions options = {});

  Promise<SmartCardConnectionStatus> status();

  Promise<ArrayBuffer> control([EnforceRange] unsigned long controlCode,
      BufferSource data);

  Promise<ArrayBuffer> getAttribute([EnforceRange] unsigned long tag);
  Promise<undefined> setAttribute([EnforceRange] unsigned long tag, BufferSource value);
};

callback SmartCardTransactionCallback = Promise<SmartCardDisposition?> ();

SmartCardConnection 实例使用下表所述的内部槽 创建:

内部槽 初始值 说明(非规范性)
[[comm]] null 要使用的平台 [PCSC5] SCARDCOMM
[[readerName]] null 与此连接关联的读卡器名称。
[[context]] null 创建此实例的 SmartCardContext
[[activeProtocol]] 0 平台 [PCSC5] 实现返回的活动协议 DWORD
[[transactionState]] null 保存通过 startTransaction() 启动的正在进行的事务的状态(若有)。

5.1. disconnect() 方法

disconnect(disposition) 方法的步骤如下:

  1. promise一个新的 promise

  2. 如果 this.[[context]].[[operationInProgress]]true,则使用一个“InvalidStateErrorDOMException 拒绝 promise,并返回 promise

  3. 如果 this.[[context]].[[activeReaderTransactions]][this.[[readerName]]] 存在且不等于 this,则使用一个“InvalidStateErrorDOMException 拒绝 promise 并返回 promise

  4. 如果 this.[[comm]]null,则使用一个“InvalidStateErrorDOMException 拒绝 promise,并返回 promise

  5. this.[[context]].[[operationInProgress]] 设置为 true

  6. 并行运行以下步骤:

    1. 调用 this.[[comm]].Disconnect(), 并将与 disposition 对应的 DWORD 作为输入参数。

    2. responseCode 为返回的 RESPONSECODE

    3. 使用智能卡任务 源,在 this相关全局对象排入一个全局任务,该任务执行以下步骤:

      1. 清除 operationInProgress(目标为 this.[[context]])。

      2. 如果 responseCode 不是 SCARD_S_SUCCESS,则使用一个与 responseCode 对应异常拒绝 promise,并中止这些步骤。

      3. 销毁 this.[[comm]]

      4. this.[[comm]] 设置为 null

      5. 兑现 promise

  7. 返回 promise

5.1.1. SmartCardDisposition 枚举

enum SmartCardDisposition {
  "leave",
  "reset",
  "unpower",
  "eject"
};
"leave"

不改变卡片状态。对应于 [PCSC5] SCARD_LEAVE_CARD DWORD

"reset"

重置卡片。对应于 [PCSC5] SCARD_RESET_CARD DWORD

"unpower"

断开卡片电源并终止对卡片的访问。对应于 [PCSC5] SCARD_UNPOWER_CARD DWORD

"eject"

从读卡器中弹出卡片。对应于 [PCSC5] SCARD_EJECT_CARD DWORD

5.2. transmit() 方法

transmit(sendBuffer, options) 方法的步骤如下:

  1. promise一个新的 promise

  2. 如果 this.[[context]].[[operationInProgress]]true,则使用一个“InvalidStateErrorDOMException 拒绝 promise,并返回 promise

  3. 如果 this.[[context]].[[activeReaderTransactions]][this.[[readerName]]] 存在且不等于 this,则使用一个“InvalidStateErrorDOMException 拒绝 promise 并返回 promise

  4. 如果 this.[[comm]]null,则使用一个“InvalidStateErrorDOMException 拒绝 promise,并返回 promise

  5. protocol 为一个 [PCSC5] DWORD,其值设置为 this.[[activeProtocol]]

  6. 如果 options["protocol"] 存在,则将 protocol 设置为与 options["protocol"] 对应的 DWORD

  7. 如果 protocol 不是一个有效协议值,则使用一个“InvalidStateErrorDOMException 拒绝 promise,并返回 promise

  8. this.[[context]].[[operationInProgress]] 设置为 true

  9. sendPci 为平台中与 this.[[activeProtocol]] 对应的 [PCSC5] SCARD_IO_HEADER

  10. pcscSendBuffer 为一个包含 sendBuffer[PCSC5] BYTE[]

  11. recvPci 为平台中等效于空值或 null 的 SCARD_IO_HEADER

  12. recvBuffer 为一个足以容纳最大 [ISO7816-3] 扩展响应 APDU(65538 字节)的 BYTE[]

  13. recvLength 为一个设置为 0DWORD

  14. 并行运行以下步骤:

    1. 调用 this.[[comm]].Transmit(), 并将 sendPcipcscSendBufferrecvPcirecvBufferrecvLength 作为实参。

    2. responseCode 为返回的 RESPONSECODE

    3. 使用智能卡任务 源,在 this相关全局对象排入一个全局任务,该任务执行以下步骤:

      1. 清除 operationInProgress(目标为 this.[[context]])。

      2. 如果 responseCode 不是 SCARD_S_SUCCESS,则使用一个与 responseCode 对应异常拒绝 promise,并中止这些步骤。

      3. 使用一个包含 recvBufferrecvLength 个字节的 ArrayBuffer 兑现 promise

  15. 返回 promise

5.2.1. SmartCardTransmitOptions 字典

dictionary SmartCardTransmitOptions {
  SmartCardProtocol protocol;
};
protocol

传输中要使用的协议。

5.3. startTransaction() 方法

startTransaction(transaction, options) 方法的步骤如下:

  1. promise一个新的 promise

  2. 如果 this.[[context]].[[operationInProgress]]true,则使用一个“InvalidStateErrorDOMException 拒绝 promise,并返回 promise

  3. 如果 this.[[context]].[[activeReaderTransactions]][this.[[readerName]]] 存在,则使用一个“InvalidStateErrorDOMException 拒绝 promise,并返回 promise

  4. 如果 this.[[comm]]null,则使用一个“InvalidStateErrorDOMException 拒绝 promise,并返回 promise

  5. 如果 this.[[transactionState]] 不为 null,则使用一个“InvalidStateErrorDOMException 拒绝 promise,并返回 promise

  6. signal 为一个设置为 nullAbortSignal

  7. 如果 options["signal"] 存在,则运行以下步骤:

    1. 如果 options["signal"] 已中止,则使用 options["signal"] 的 中止原因拒绝 promise,并返回 promise

    2. signal 设置为 options["signal"]。

    3. 取消 算法添加signal

  8. this.[[context]].[[operationInProgress]] 设置为 true

  9. 并行运行以下步骤:

    1. 调用 this.[[comm]].BeginTransaction()

    2. responseCode 为返回的 [PCSC5] RESPONSECODE

    3. 使用智能卡任务 源,在 this相关全局对象排入一个全局任务,以使用 thisresponseCodesignaltransactionpromise 处理 BeginTransaction 的结果

  10. 返回 promise

5.3.1. SmartCardTransactionOptions 字典

dictionary SmartCardTransactionOptions {
  AbortSignal signal;
};
signal

触发时,调用平台的 [PCSC5] Cancel() 方法。

5.3.2. 辅助算法和定义

事务状态是一个 结构体,具有 以下

pendingDisposition

如果已设置,则表示正在进行的 PC/SC 操作完成后,应调用 [PCSC5] EndTransaction(),并将此值作为 SmartCardDisposition 参数。

pendingException

拒绝promise 时要使用的异常。

promise

startTransaction() 调用返回的未完成 Promise

要在给定 SmartCardConnection connection[PCSC5] RESPONSECODE responseCodeAbortSignal signalSmartCardTransactionCallback transactionPromise promise 的情况下,处理 BeginTransaction 的结果,执行以下步骤:

  1. 清除 operationInProgress(目标为 connection.[[context]])。

  2. abortReasonundefined

  3. 如果 signal 不为 null

    1. signal移除取消 算法。

    2. 如果 signal中止,则将 abortReason 设置为 signal中止原因

  4. 如果 responseCode 不是 SCARD_S_SUCCESS

    1. 如果 responseCodeSCARD_E_CANCELLED,并且 abortReason 不是 undefined, 则使用 abortReason 拒绝 promise

    2. 否则,使用一个与 responseCode 对应异常拒绝 promise

    3. 返回。

  5. transactionState 为一个新的事务状态,并将其promise 项设置 为 promise

  6. connection.[[transactionState]] 设置为 transactionState

  7. connection.[[context]].[[activeReaderTransactions]][connection.[[readerName]]] 设置为 connection

  8. callbackPromise调用 transaction 的结果。

  9. callbackPromise 作出反应

要以 SmartCardDisposition disposition 结束 SmartCardConnection connection 的事务,执行以下步骤:

  1. 断言connection.[[context]].[[operationInProgress]]false

  2. 断言connection.[[transactionState]] 不为 null

  3. 断言connection.[[transactionState]]pendingDispositionnull

  4. transactionPromiseconnection.[[transactionState]]promise

  5. 如果 connection.[[comm]]null

    1. 使用一个“InvalidStateErrorDOMException 拒绝 transactionPromise

    2. connection.[[transactionState]] 设置为 null

    3. 返回。

  6. connection.[[context]].[[operationInProgress]] 设置为 true

  7. 并行运行以下步骤:

    1. 调用 connection.[[comm]].EndTransaction(), 并将与 disposition 对应的 DWORD 作为输入参数。

    2. responseCode 为返回的 [PCSC5] RESPONSECODE

    3. 使用智能卡任务 源,在 this相关全局对象排入一个全局任务,该任务执行以下步骤:

      1. 清除 operationInProgress(目标为 connection.[[context]])。

      2. connection.[[context]].[[activeReaderTransactions]]移除 connection.[[readerName]]

      3. exceptionconnection.[[transactionState]]pendingException

      4. 如果 exceptionnull,则执行以下步骤:

        1. 如果 responseCodeSCARD_S_SUCCESS,则兑现 transactionPromise

        2. 否则,使用一个与 responseCode 对应异常拒绝 transactionPromise

      5. 否则,使用 exception 拒绝 transactionPromise

      6. connection.[[transactionState]] 设置为 null

结束任何已敲定事务(目标为 SmartCardConnection connection),执行以下步骤:

  1. 如果 connection.[[transactionState]]null,则中止这些步骤。

  2. dispositionconnection.[[transactionState]]pendingDisposition

  3. 如果 dispositionnull,则中止这些步骤。

  4. connection.[[transactionState]]pendingDisposition 设置为 null

  5. disposition 结束 connection 的事务

取消未完成的 [PCSC5] SCARDCOMM 操作,调用 this.[[comm]].Cancel()

5.4. status() 方法

status() 方法的步骤如下:

  1. promise一个新的 promise

  2. 如果 this.[[context]].[[operationInProgress]]true,则使用一个“InvalidStateErrorDOMException 拒绝 promise,并返回 promise

  3. 如果 this.[[context]].[[activeReaderTransactions]][this.[[readerName]]] 存在且不等于 this,则使用一个“InvalidStateErrorDOMException 拒绝 promise 并返回 promise

  4. 如果 this.[[comm]]null,则使用一个“InvalidStateErrorDOMException 拒绝 promise,并返回 promise

  5. this.[[context]].[[operationInProgress]] 设置为 true

  6. 并行运行以下步骤:

    1. pcscReader 为一个空的 STR[]

    2. pcscState 为一个设置为 0[PCSC5] DWORD

    3. activeProtocol 为一个设置为 0[PCSC5] DWORD

    4. pcscAtr 为一个足以容纳任何 [ISO7816-3] 复位应答(ATR)的 BYTE[]

    5. 调用 this.[[comm]].Status(), 并将 pcscReaderpcscStateactiveProtocolpcscAtr 作为输出参数。

    6. responseCode 为返回的 RESPONSECODE

    7. 使用智能卡任务 源,在 this相关全局对象排入一个全局任务,该任务执行以下步骤:

      1. 清除 operationInProgress(目标为 this.[[context]])。

      2. 如果 responseCode 不是 SCARD_S_SUCCESS,则使用一个与 responseCode 对应异常拒绝 promise,并中止这些步骤。

      3. state 为一个与 pcscStateactiveProtocol 对应SmartCardConnectionState

      4. 如果 stateundefined, 则使用一个“UnknownErrorDOMException 拒绝 promise,并中止这些步骤。

      5. status 为一个新的 SmartCardConnectionStatus

      6. status["readerName"] 设置为 pcscReader

      7. status["state"] 设置为 state

      8. status["answerToReset"] 设置为一个包含写入 pcscAtr 的字节的 ArrayBuffer

      9. 使用 status 兑现 promise

  7. 返回 promise

5.4.1. SmartCardConnectionStatus 字典

dictionary SmartCardConnectionStatus {
  required DOMString readerName;
  required SmartCardConnectionState state;
  ArrayBuffer answerToReset;
};
readerName

已连接读卡器的名称。

state

连接的当前状态。

answerToReset

卡片的复位应答(ATR)字符串(若适用)。

5.4.1.1. SmartCardConnectionState 枚举
enum SmartCardConnectionState {
  "absent",
  "present",
  "swallowed",
  "powered",
  "negotiable",
  "t0",
  "t1",
  "raw"
};
"absent"

读卡器中没有卡片。

"present"

读卡器中有卡片,但尚未移动到可供使用的位置。

"swallowed"

读卡器中的卡片已处于可供使用的位置。卡片尚未通电。

"powered"

卡片已通电,但读卡器驱动程序不知道卡片所处的模式。

"negotiable"

卡片已重置,正在等待 PTS(协议类型选择)协商。

"t0"

卡片处于 [ISO7816-3] T=0 协议模式,无法协商新协议。

"t1"

卡片处于 [ISO7816-3] T=1 协议模式,无法协商新协议。

"raw"

卡片处于原始协议模式,无法协商新协议。

给定一个 [PCSC5] DWORD pcscState 和一个 DWORD activeProtocol,按以下步骤 创建一个对应的 SmartCardConnectionState

  1. 如果 pcscState[PCSC5] SCARD_ABSENT,则返回“absent”。

  2. 如果 pcscState[PCSC5] SCARD_PRESENT,则返回“present”。

  3. 如果 pcscState[PCSC5] SCARD_SWALLOWED,则返回“swallowed”。

  4. 如果 pcscState[PCSC5] SCARD_POWERED,则返回“powered”。

  5. 如果 pcscState[PCSC5] SCARD_NEGOTIABLE,则返回“negotiable”。

  6. 如果 pcscState[PCSC5] SCARD_SPECIFIC,则执行以下步骤:

    1. 如果 activeProtocol[PCSC5] SCARD_PROTOCOL_T0,则返回“t0”。

    2. 如果 activeProtocol[PCSC5] SCARD_PROTOCOL_T1,则返回“t1”。

    3. 如果 activeProtocol[PCSC5] SCARD_PROTOCOL_RAW,则返回“raw”。

  7. 返回 undefined

5.5. control() 方法

control(controlCode, data) 方法的步骤如下:

  1. promise一个新的 promise

  2. 如果 this.[[context]].[[operationInProgress]]true,则使用一个“InvalidStateErrorDOMException 拒绝 promise,并返回 promise

  3. 如果 this.[[context]].[[activeReaderTransactions]][this.[[readerName]]] 存在且不等于 this,则使用一个“InvalidStateErrorDOMException 拒绝 promise 并返回 promise

  4. 如果 this.[[comm]]null,则使用一个“InvalidStateErrorDOMException 拒绝 promise,并返回 promise

  5. this.[[context]].[[operationInProgress]] 设置为 true

  6. pcscControlCode 为一个包含 controlCode[PCSC5] DWORD

  7. 获取缓冲源的副本 data, 并将结果保存到 [PCSC5] BYTE[] inBuffer 中。

  8. outBuffer 为一个足以容纳任何控制命令响应的 [PCSC5] BYTE[]

  9. outBufferLength 为一个设置为 0DWORD

  10. 并行运行以下步骤:

    1. 调用 this.[[comm]].Control(), 并将 pcscControlCodeinBufferoutBufferoutBufferLength 作为实参。

    2. responseCode 为返回的 RESPONSECODE

    3. 使用智能卡任务 源,在 this相关全局对象排入一个全局任务,该任务执行以下步骤:

      1. 清除 operationInProgress(目标为 this.[[context]])。

      2. 如果 responseCode 不是 SCARD_S_SUCCESS,则使用一个与 responseCode 对应异常拒绝 promise,并中止这些步骤。

      3. resultBytesoutBuffer 的前 outBufferLength 个字节。

      4. 使用在 this相关 Realm 中从 resultBytes 创建 ArrayBuffer 所得的结果兑现 promise

  11. 返回 promise

5.6. getAttribute() 方法

getAttribute(tag) 方法的步骤如下:

  1. promise一个新的 promise

  2. 如果 this.[[context]].[[operationInProgress]]true,则使用一个“InvalidStateErrorDOMException 拒绝 promise,并返回 promise

  3. 如果 this.[[context]].[[activeReaderTransactions]][this.[[readerName]]] 存在且不等于 this,则使用一个“InvalidStateErrorDOMException 拒绝 promise 并返回 promise

  4. 如果 this.[[comm]]null,则使用一个“InvalidStateErrorDOMException 拒绝 promise,并返回 promise

  5. this.[[context]].[[operationInProgress]] 设置为 true

  6. 并行运行以下步骤:

    1. pcscTag 为一个包含 tag[PCSC5] DWORD

    2. buffer 为一个足以容纳此读卡器属性的 [PCSC5] BYTE[],其大小由平台的 [PCSC5] 实现确定。

    3. 调用 this.[[comm]].GetReaderCapabilities(), 并将 pcscTagbuffer 作为实参。

    4. responseCode 为返回的 RESPONSECODE

    5. 使用智能卡任务 源,在 this相关全局对象排入一个全局任务,该任务执行以下步骤:

      1. 清除 operationInProgress(目标为 this.[[context]])。

      2. 如果 responseCode 不是 SCARD_S_SUCCESS,则使用一个与 responseCode 对应异常拒绝 promise,并中止这些步骤。

      3. resultBytesbuffer 中包含所读取属性的字节。

      4. 使用在 this相关 Realm 中从 resultBytes 创建 ArrayBuffer 所得的结果兑现 promise

  7. 返回 promise

5.7. setAttribute() 方法

setAttribute(tag, value) 方法的步骤如下:

  1. promise一个新的 promise

  2. 如果 this.[[context]].[[operationInProgress]]true,则使用一个“InvalidStateErrorDOMException 拒绝 promise,并返回 promise

  3. 如果 this.[[context]].[[activeReaderTransactions]][this.[[readerName]]] 存在且不等于 this,则使用一个“InvalidStateErrorDOMException 拒绝 promise 并返回 promise

  4. 如果 this.[[comm]]null,则使用一个“InvalidStateErrorDOMException 拒绝 promise,并返回 promise

  5. this.[[context]].[[operationInProgress]] 设置为 true

  6. pcscTag 为一个包含 tag[PCSC5] DWORD

  7. 获取缓冲源的副本 value, 并将结果保存到 [PCSC5] BYTE[] buffer 中。

  8. 并行运行以下步骤:

    1. 调用 this.[[comm]].SetReaderCapabilities(), 并将 pcscTagbuffer 作为实参。

    2. responseCode 为返回的 RESPONSECODE

    3. 使用智能卡任务 源,在 this相关全局对象排入一个全局任务,该任务执行以下步骤:

      1. 清除 operationInProgress (目标为 this.[[context]])。

      2. 如果 responseCode 不是 SCARD_S_SUCCESS,则使用一个与 responseCode 对应异常拒绝 promise,并中止这些步骤。

      3. 兑现 promise

  9. 返回 promise

6. SmartCardError 接口

[
  Exposed=(DedicatedWorker, SharedWorker, Window),
  SecureContext,
  IsolatedContext
] interface SmartCardError : DOMException {
  constructor(optional DOMString message = "", SmartCardErrorOptions options);
  readonly attribute SmartCardResponseCode responseCode;
};

responseCode 属性是相关 [PCSC5] 方法返回的错误或警告响应代码。

给定一个不同于 SCARD_S_SUCCESS[PCSC5] RESPONSECODE,按以下步骤创建一个 对应的异常

  1. pcscCode 为该 RESPONSECODE

  2. 如果 pcscCodeSCARD_E_NO_SERVICE,则返回一个新的 "no-service" SmartCardError

  3. 如果 pcscCodeSCARD_E_NO_SMARTCARD,则返回一个新的 "no-smartcard" SmartCardError

  4. 如果 pcscCodeSCARD_E_NOT_READY,则返回一个新的 "not-ready" SmartCardError

  5. 如果 pcscCodeSCARD_E_NOT_TRANSACTED,则返回一个新的 "not-transacted" SmartCardError

  6. 如果 pcscCodeSCARD_E_PROTO_MISMATCH,则返回一个新的 "proto-mismatch" SmartCardError

  7. 如果 pcscCodeSCARD_E_READER_UNAVAILABLE,则返回一个新的 "reader-unavailable" SmartCardError

  8. 如果 pcscCodeSCARD_W_REMOVED_CARD,则返回一个新的 "removed-card" SmartCardError

  9. 如果 pcscCodeSCARD_W_RESET_CARD,则返回一个新的 "reset-card" SmartCardError

  10. 如果 pcscCodeSCARD_E_SERVER_TOO_BUSY,则返回一个新的 "server-too-busy" SmartCardError

  11. 如果 pcscCodeSCARD_E_SHARING_VIOLATION,则返回一个新的 "sharing-violation" SmartCardError

  12. 如果 pcscCodeSCARD_E_SYSTEM_CANCELLED,则返回一个新的 "system-cancelled" SmartCardError

  13. 如果 pcscCodeSCARD_E_UNKNOWN_READER,则返回一个新的 "unknown-reader" SmartCardError

  14. 如果 pcscCodeSCARD_W_UNPOWERED_CARD,则返回一个新的 "unpowered-card" SmartCardError

  15. 如果 pcscCodeSCARD_W_UNRESPONSIVE_CARD,则返回一个新的 "unresponsive-card" SmartCardError

  16. 如果 pcscCodeSCARD_W_UNSUPPORTED_CARD,则返回一个新的 "unsupported-card" SmartCardError

  17. 如果 pcscCodeSCARD_E_UNSUPPORTED_FEATURE,则返回一个新的 "unsupported-feature" SmartCardError

  18. 如果 pcscCodeSCARD_E_INVALID_PARAMETER,则返回一个新的 TypeError

  19. 如果 pcscCodeSCARD_E_INVALID_HANDLE,则返回一个新的InvalidStateErrorDOMException

  20. 如果 pcscCodeSCARD_E_SERVICE_STOPPED,则返回一个新的InvalidStateErrorDOMException

  21. 如果 pcscCodeSCARD_P_SHUTDOWN,则返回一个新的AbortErrorDOMException

  22. 否则,返回一个新的UnknownErrorDOMException

6.1. SmartCardErrorOptions 字典

dictionary SmartCardErrorOptions {
  required SmartCardResponseCode responseCode;
};

responseCode 成员是 SmartCardErrorresponseCode 属性的值。

6.2. SmartCardResponseCode 枚举

enum SmartCardResponseCode {
  "no-service",
  "no-smartcard",
  "not-ready",
  "not-transacted",
  "proto-mismatch",
  "reader-unavailable",
  "removed-card",
  "reset-card",
  "server-too-busy",
  "sharing-violation",
  "system-cancelled",
  "unknown-reader",
  "unpowered-card",
  "unresponsive-card",
  "unsupported-card",
  "unsupported-feature"
};
"no-service"

[PCSC5] 规范中的 SCARD_E_NO_SERVICE。

"no-smartcard"

[PCSC5] 规范中的 SCARD_E_NO_SMARTCARD。

"not-ready"

[PCSC5] 规范中的 SCARD_E_NOT_READY。

"not-transacted"

[PCSC5] 规范中的 SCARD_E_NOT_TRANSACTED。

"proto-mismatch"

[PCSC5] 规范中的 SCARD_E_PROTO_MISMATCH。

"reader-unavailable"

[PCSC5] 规范中的 SCARD_E_READER_UNAVAILABLE。

"removed-card"

[PCSC5] 规范中的 SCARD_W_REMOVED_CARD。

"reset-card"

[PCSC5] 规范中的 SCARD_W_RESET_CARD。

"server-too-busy"

智能卡资源管理器过于繁忙,无法完成此操作。

"sharing-violation"

[PCSC5] 规范中的 SCARD_E_SHARING_VIOLATION。

"system-cancelled"

[PCSC5] 规范中的 SCARD_E_SYSTEM_CANCELLED。

"unknown-reader"

[PCSC5] 规范中的 SCARD_E_UNKNOWN_READER。

"unpowered-card"

[PCSC5] 规范中的 SCARD_W_UNPOWERED_CARD。

"unresponsive-card"

[PCSC5] 规范中的 SCARD_W_UNRESPONSIVE_CARD。

"unsupported-card"

[PCSC5] 规范中的 SCARD_W_UNSUPPORTED_CARD。

"unsupported-feature"

[PCSC5] 规范中的 SCARD_E_UNSUPPORTED_FEATURE。

7. 安全和隐私注意事项

此 API 使 Web 应用程序能够访问主机的 PC/SC 智能 卡子系统。这是一项强大功能,如果被滥用, 可能对用户的安全和 隐私造成重大负面影响。本节概述所考虑的威胁,以及 用户代理为缓解这些威胁必须遵守的规范性要求。

访问智能卡读卡器及其中存在的任何卡片是一项 强大功能。如果没有明确许可,用户代理不得 允许 Web 应用程序获得对 SmartCardConnection 对象的访问权限。

必须针对特定 获得用户同意。许可请求必须由对 connect() 方法的调用触发。用户代理必须显示许可提示, 该提示应明确指出哪个源正在请求访问,并向 用户提供足够的信息以便其作出知情决定(例如, 显示智能卡读卡器的名称)。

用户代理应同时提供 临时许可(例如“仅限此会话”)和持久许可选项。 为降低用户忘记自己已授予持久 访问权限的风险,临时许可应作为 默认且更为醒目的选项。

必须为用户提供一种机制,用于 查看和撤销此前为此 API 授予的任何许可。

7.2. 指纹识别

listReaders() 方法和 answerToReset 成员会公开可用于被动指纹识别的信息,其中后者属于 SmartCardReaderStateOut 字典。智能卡 读卡器是否存在及其型号可能泄露有关用户的信息,例如用户是否 处于企业环境中。复位应答(ATR)还可以进一步 识别智能卡的类型和发行者。

虽然本规范不要求在调用 listReaders() 前显示许可提示,但对整个 API 的访问由“smart-card策略控制功能控制。这使管理员或 用户能够 针对特定源禁用此 API,从而缓解指纹识别 风险。

7.3. 设备和数据完整性

control()setAttribute() 方法提供对智能卡读卡器硬件的直接、 低级访问。恶意站点 可能利用这些方法上传恶意固件、 使设备无法运行,或以其他方式干扰其正常 运行。

同样,已连接到智能卡的恶意站点可能 反复尝试 PIN 验证,以永久锁定卡片,或 访问或覆盖敏感且未受保护的数据。

针对这些威胁的主要缓解措施,是要求在创建 SmartCardConnection 对象之前获得明确许可, 因为这会限制对随后所有强大方法的访问。

7.4. 身份验证和欺骗

对于身份验证用例,开发者 应尽可能优先使用 Web Authentication API。

7.5. 跨源通信

具有可写内存的智能卡可用作侧信道,使 不同源能够交换数据,从而绕过其他同源 策略。对此的缓解措施是,仅向特定 授予明确许可。攻击需要用户向 多个可能恶意的源授予智能卡访问权限。

7.6. 隔离上下文

此 API 必须仅在隔离上下文中公开。

7.7. 文档生命周期

为防止文档在不受用户直接控制时仍持有与敏感硬件的连接, 当文档不再 完全活动时,用户代理必须处置所有活动的 SmartCardContext 对象及其关联的 SmartCardConnection 对象。这包括自动断开 任何活动连接,就像调用了 disconnect() 一样。

8. 集成

8.1. 权限策略

本规范定义了一项功能,用于控制是否可以使用 Navigator 对象上的 smartCard 属性所公开的方法。

此功能的功能名称为 “smart-card”。

此功能的默认允许列表'none'。对于特定源,用户代理可以将其覆盖 为 'self'(例如,根据用户决定)。

一致性

文档 约定

一致性要求通过描述性断言 与 RFC 2119 术语的组合来表达。 本文档规范性部分中的关键词“MUST”“MUST NOT”“REQUIRED”“SHALL”“SHALL NOT”“SHOULD”“SHOULD NOT”“RECOMMENDED” “MAY”和“OPTIONAL” 应按照 RFC 2119 中的说明进行解释。 但是,为提高可读性, 本规范中的这些词并非全部以大写字母显示。

本规范的所有文本均为规范性内容, 但明确标记为非规范性的章节、示例和注释除外。[RFC2119]

本规范中的示例以“例如”一词引入, 或使用 class="example" 与规范性文本分隔, 如下所示:

这是一个资料性示例。

资料性注释以“注”一词开头, 并使用 class="note" 与规范性文本分隔, 如下所示:

注:这是一条资料性注释。

索引

本规范定义的 术语

通过引用 定义的术语

参考文献

规范性参考文献

[DOM]
Anne van Kesteren。DOM 标准。现行标准。 URL:https://dom.spec.whatwg.org/
[HR-TIME-3]
Yoav Weiss。高精度时间。URL:https://w3c.github.io/hr-time/
[HTML]
Anne van Kesteren;等。HTML 标准。 现行标准。URL:https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren;Domenic Denicola。Infra 标准。现行标准。URL:https://infra.spec.whatwg.org/
[ISO7816-3]
识别卡——集成电路卡; 第 3 部分:带触点的卡——电气接口和传输协议。2006 年 11 月 1 日。已发布。URL:https://www.iso.org/standard/38770.html
[ISOLATED-CONTEXTS]
隔离 上下文。社区组报告草案。URL:https://wicg.github.io/isolated-web-apps/isolated-contexts.html
[PCSC5]
ICC 与个人计算机系统 互操作性规范;第 5 部分:ICC 资源管理器 定义。2005 年 9 月 30 日。已发布。URL:https://pcscworkgroup.com/Download/Specifications/pcsc5_v2.01.01.pdf
[PERMISSIONS]
Marcos Caceres;Mike Taylor。权限。URL: https://w3c.github.io/permissions/
[PERMISSIONS-POLICY-1]
Ian Clelland。权限 策略。URL:https://w3c.github.io/webappsec-permissions-policy/
[RFC2119]
S. Bradner。用于 RFC 中 指示要求级别的关键词。1997 年 3 月。最佳当前实践。URL:https://datatracker.ietf.org/doc/html/rfc2119
[WEBIDL]
Edgar Chen;Timothy Gu。Web IDL 标准。现行 标准。URL:https://webidl.spec.whatwg.org/

IDL 索引

[Exposed=Window, SecureContext, IsolatedContext]
partial interface Navigator {
  [SameObject] readonly attribute SmartCardResourceManager smartCard;
};

[Exposed=(DedicatedWorker, SharedWorker), SecureContext, IsolatedContext]
partial interface WorkerNavigator {
  [SameObject] readonly attribute SmartCardResourceManager smartCard;
};

[Exposed=(DedicatedWorker, SharedWorker, Window), SecureContext, IsolatedContext]
interface SmartCardResourceManager {
  Promise<SmartCardContext> establishContext();
};

[Exposed=(DedicatedWorker, SharedWorker, Window), SecureContext, IsolatedContext]
interface SmartCardContext {
  Promise<sequence<DOMString>> listReaders();

  Promise<sequence<SmartCardReaderStateOut>> getStatusChange(
      sequence<SmartCardReaderStateIn> readerStates,
      optional SmartCardGetStatusChangeOptions options = {});

  Promise<SmartCardConnectResult> connect(
      DOMString readerName,
      SmartCardAccessMode accessMode,
      optional SmartCardConnectOptions options = {});
};

dictionary SmartCardReaderStateIn {
  required DOMString readerName;
  required SmartCardReaderStateFlagsIn currentState;
  unsigned long currentCount;
};

dictionary SmartCardReaderStateFlagsIn {
  boolean unaware = false;
  boolean ignore = false;
  boolean unavailable = false;
  boolean empty = false;
  boolean present = false;
  boolean exclusive = false;
  boolean inuse = false;
  boolean mute = false;
  boolean unpowered = false;
};

dictionary SmartCardReaderStateOut {
  required DOMString readerName;
  required SmartCardReaderStateFlagsOut eventState;
  required unsigned long eventCount;
  ArrayBuffer answerToReset;
};

dictionary SmartCardReaderStateFlagsOut {
  boolean ignore = false;
  boolean changed = false;
  boolean unavailable = false;
  boolean unknown = false;
  boolean empty = false;
  boolean present = false;
  boolean exclusive = false;
  boolean inuse = false;
  boolean mute = false;
  boolean unpowered = false;
};

dictionary SmartCardGetStatusChangeOptions {
  DOMHighResTimeStamp timeout;
  AbortSignal signal;
};

enum SmartCardProtocol {
  "raw",
  "t0",
  "t1"
};

dictionary SmartCardConnectResult {
  required SmartCardConnection connection;
  SmartCardProtocol activeProtocol;
};

enum SmartCardAccessMode {
  "shared",
  "exclusive",
  "direct"
};

dictionary SmartCardConnectOptions {
  sequence<SmartCardProtocol> preferredProtocols;
};

[Exposed=(DedicatedWorker, SharedWorker, Window), SecureContext, IsolatedContext]
interface SmartCardConnection {
  Promise<undefined> disconnect(optional SmartCardDisposition disposition = "leave");

  Promise<ArrayBuffer> transmit(BufferSource sendBuffer,
      optional SmartCardTransmitOptions options = {});

  Promise<undefined> startTransaction(SmartCardTransactionCallback transaction,
      optional SmartCardTransactionOptions options = {});

  Promise<SmartCardConnectionStatus> status();

  Promise<ArrayBuffer> control([EnforceRange] unsigned long controlCode,
      BufferSource data);

  Promise<ArrayBuffer> getAttribute([EnforceRange] unsigned long tag);
  Promise<undefined> setAttribute([EnforceRange] unsigned long tag, BufferSource value);
};

callback SmartCardTransactionCallback = Promise<SmartCardDisposition?> ();

enum SmartCardDisposition {
  "leave",
  "reset",
  "unpower",
  "eject"
};

dictionary SmartCardTransmitOptions {
  SmartCardProtocol protocol;
};

dictionary SmartCardTransactionOptions {
  AbortSignal signal;
};

dictionary SmartCardConnectionStatus {
  required DOMString readerName;
  required SmartCardConnectionState state;
  ArrayBuffer answerToReset;
};

enum SmartCardConnectionState {
  "absent",
  "present",
  "swallowed",
  "powered",
  "negotiable",
  "t0",
  "t1",
  "raw"
};

[
  Exposed=(DedicatedWorker, SharedWorker, Window),
  SecureContext,
  IsolatedContext
] interface SmartCardError : DOMException {
  constructor(optional DOMString message = "", SmartCardErrorOptions options);
  readonly attribute SmartCardResponseCode responseCode;
};

dictionary SmartCardErrorOptions {
  required SmartCardResponseCode responseCode;
};

enum SmartCardResponseCode {
  "no-service",
  "no-smartcard",
  "not-ready",
  "not-transacted",
  "proto-mismatch",
  "reader-unavailable",
  "removed-card",
  "reset-card",
  "server-too-busy",
  "sharing-violation",
  "system-cancelled",
  "unknown-reader",
  "unpowered-card",
  "unresponsive-card",
  "unsupported-card",
  "unsupported-feature"
};