웹 스마트 카드 API

비공식 제안 초안,

이 버전:
https://wicg.github.io/web-smart-card/
이슈 추적:
GitHub
편집자:
(Google)
(Google)

초록

이 API의 목적은 스마트 카드(PC/SC) 애플리케이션을 웹 플랫폼으로 이전할 수 있도록 하는 것이다. 이 API는 호스트 OS에서 사용할 수 있는 PC/SC 구현(및 카드 판독기 드라이버)에 대한 접근을 제공한다.

함께 제공되는 설명 문서도 있다.

이 문서의 상태

이 명세는 웹 플랫폼 인큐베이터 커뮤니티 그룹에서 발행했다. 이 명세는 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"라는 이름의 정책 제어 기능사용하도록 허용되지 않은 경우, "SecurityError" DOMException발생시킨다.

  2. promise새 프로미스라고 하자.

  3. 다음 단계를 병렬로 실행한다:

    1. resourceManager를 플랫폼의 [PCSC5] RESOURCEMANAGER 클래스의 새 인스턴스라고 하자.

    2. resourceManagerEstablishContext 메서드를 "system" Scope 매개변수로 호출한다.

    3. 반환된 RESPONSECODESCARD_S_SUCCESS가 아니면 다음 단계를 수행한다:

      1. resourceManager를 파기한다.

      2. this관련 전역 객체에서 스마트 카드 태스크 소스를 사용하여 전역 태스크를 큐에 넣고, promise대응하는 예외거부한다.

    4. 그렇지 않으면 다음 단계를 수행한다:

      1. context SmartCardContext라고 하자. 이 객체의 [[resourceManager]] 내부 슬롯은 resourceManager로 설정된다.

      2. this관련 전역 객체에서 스마트 카드 태스크 소스를 사용하여 전역 태스크를 큐에 넣고, promisecontext이행한다.

  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새 프로미스라고 하자.

  2. this.[[operationInProgress]]true이면 promise를 "InvalidStateError" DOMException으로 거부하고 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. thisoperationInProgress를 지운다.

      2. responseCodeSCARD_S_SUCCESS가 아니면:

        1. responseCodeSCARD_E_NO_READERS_AVAILABLE이면 promise를 빈 DOMString sequence이행한다.

        2. 그렇지 않으면 promiseresponseCode대응하는 예외거부한다.

      3. 그렇지 않으면 promisepcscReaders와 동등한 DOMString sequence이행한다.

  5. promise를 반환한다.

4.2. getStatusChange() 메서드

getStatusChange(readerStates, options) 메서드 단계는 다음과 같다:

  1. promise새 프로미스라고 하자.

  2. this.[[operationInProgress]]true이면 promise를 "InvalidStateError" DOMException으로 거부하고 promise를 반환한다.

  3. options["signal"]이 존재하면 다음 단계를 실행한다:

    1. signaloptions["signal"]이라고 하자.

    2. signal중단된 경우, promisesignal중단 이유거부하고 promise를 반환한다.

    3. this.[[signal]]signal로 설정한다.

    4. 처리 중인 GetStatusChange를 취소하는 알고리즘을 signal추가한다.

  4. pcscTimeout[PCSC5] INFINITE로 설정된 [PCSC5] DWORD라고 하자.

  5. options["timeout"]이 존재하면, pcscTimeoutoptions["timeout"]으로 설정한다.

  6. pcscReaderStatesreaderStates대응하는 [PCSC5] SCARD_READERSTATE[]라고 하자.

  7. this.[[operationInProgress]]true로 설정한다.

  8. this.[[tracker]]를 플랫폼의 [PCSC5] SCARDTRACK 클래스의 새 인스턴스로 설정한다. 이때 생성자 입력 매개변수로 this.[[resourceManager]]를 사용한다.

  9. 다음 단계를 병렬로 실행한다:

    1. this.[[tracker]].GetStatusChange()pcscReaderStatespcscTimeout을 입력 매개변수로 사용하여 호출한다.

    2. responseCode를 반환된 [PCSC5] RESPONSECODE라고 하자.

    3. this관련 전역 객체에서 스마트 카드 태스크 소스를 사용하여 전역 태스크를 큐에 넣는다. 이 태스크는 다음 단계를 수행한다:

      1. this.[[tracker]]null로 설정한다.

      2. thisoperationInProgress를 지운다.

      3. abortReasonundefined라고 하자.

      4. this.[[signal]]null이 아니면 다음 단계를 실행한다:

        1. this.[[signal]]중단된 경우 abortReasonthis.[[signal]]중단 이유로 설정한다.

        2. 처리 중인 GetStatusChange를 취소하는 알고리즘을 this.[[signal]]에서 제거한다.

        3. this.[[signal]]null로 설정한다.

      5. responseCodeSCARD_S_SUCCESS가 아니면 다음 단계를 실행한다:

        1. responseCodeSCARD_E_CANCELLED이고 abortReasonundefined가 아니면 promiseabortReason으로 거부한다.

        2. 그렇지 않으면 promiseresponseCode대응하는 예외거부한다.

        3. 반환한다.

      6. readerStatesOutpcscReaderStates대응하는 SmartCardReaderStateOut 시퀀스라고 하자.

      7. promisereaderStatesOut으로 이행한다.

  10. promise를 반환한다.

4.2.1. SmartCardReaderStateIn 딕셔너리

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

스마트 카드 판독기의 이름.

currentState

애플리케이션이 알고 있는 해당 스마트 카드 판독기의 현재 상태.

currentCount

애플리케이션이 알고 있는 이 판독기의 현재 카드 삽입 및 제거 이벤트 수.

readerStates라는 이름의 SmartCardReaderStateIn 시퀀스가 주어지면, [PCSC5] SCARD_READERSTATE[]대응하는 값을 다음 단계로 생성한다:

  1. pcscReaderStates를 빈 SCARD_READERSTATE[]라고 하자.

  2. readerStates에 있는 SmartCardReaderStateIn 유형의 각 stateIn에 대해:

    1. pcscStateSCARD_READERSTATE라고 하자.

    2. pcscState.ReaderstateIn["readerName"]으로 설정한다.

    3. pcscState.CurrentStatestateIn["currentState"]에 대응하는 DWORD로 설정한다.

    4. stateIn["currentCount"]이 존재하면, pcscState.CurrentState상위 워드를 stateIn["currentCount"]으로 설정한다.

    5. pcscState.EventState를 0으로 설정한다.

    6. pcscStatepcscReaderStates추가한다.

  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를 0으로 설정된 DWORD라고 하자.

  3. flagsIn["unaware"]가 true이면, [PCSC5] SCARD_STATE_UNAWAREpcscFlags추가한다.

  4. flagsIn["ignore"]가 true이면, [PCSC5] SCARD_STATE_IGNOREpcscFlags추가한다.

  5. flagsIn["unavailable"]이 true이면, [PCSC5] SCARD_STATE_UNAVAILABLEpcscFlags추가한다.

  6. flagsIn["empty"]가 true이면, [PCSC5] SCARD_STATE_EMPTYpcscFlags추가한다.

  7. flagsIn["present"]가 true이면, [PCSC5] SCARD_STATE_PRESENTpcscFlags추가한다.

  8. flagsIn["exclusive"]가 true이면, [PCSC5] SCARD_STATE_EXCLUSIVEpcscFlags추가한다.

  9. flagsIn["inuse"]가 true이면, [PCSC5] SCARD_STATE_INUSEpcscFlags추가한다.

  10. flagsIn["mute"]가 true이면, SCARD_STATE_MUTEpcscFlags추가한다.

  11. flagsIn["unpowered"]가 true이면, SCARD_STATE_UNPOWEREDpcscFlags추가한다.

  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] Answer To Reset(ATR).

pcscReaderStates라는 이름의 [PCSC5] SCARD_READERSTATE[]가 주어지면, SmartCardReaderStateOut대응하는 시퀀스를 다음 단계로 생성한다:

  1. readerStatesOut을 빈 SmartCardReaderStateOut 시퀀스라고 하자.

  2. pcscReaderStates에 있는 SCARD_READERSTATE 유형의 각 pcscState에 대해:

    1. stateOutSmartCardReaderStateOut이라고 하자.

    2. stateOut["readerName"]을 pcscState.Reader로 설정한다.

    3. stateOut["eventState"]을 pcscState.EventState대응하는 SmartCardReaderStateFlagsOut 딕셔너리로 설정한다.

    4. stateOut["eventCount"]을 pcscState.EventState상위 워드로 설정한다.

    5. 플랫폼의 SCARD_READERSTATE 구조체에 카드의 [ISO7816-3] Answer To Reset을 포함하는 멤버가 있으면, stateOut["answerToReset"]을 해당 값으로 설정한다.

    6. stateOutreaderStatesOut추가한다.

  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. pcscFlagsSCARD_STATE_MUTE 플래그를 가지면, flagsOut["mute"]를 true로 설정한다.

  11. pcscFlagsSCARD_STATE_UNPOWERED 플래그를 가지면, flagsOut["unpowered"]를 true로 설정한다.

  12. flagsOut을 반환한다.

4.2.3. SmartCardGetStatusChangeOptions 딕셔너리

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

[PCSC5] GetStatusChange() 메서드의 시간 제한 매개변수. 지정하지 않으면 INFINITE(시스템에 따라 정의됨) 시간 제한 값을 사용한다.

signal

트리거되면 플랫폼의 [PCSC5] Cancel() 메서드를 호출한다.

4.3. connect() 메서드

connect(readerName, accessMode, options) 메서드 단계는 다음과 같다:

  1. promise새 프로미스라고 하자.

  2. this.[[operationInProgress]]true이면 promise를 "InvalidStateError" DOMException으로 거부하고 promise를 반환한다.

  3. this.[[activeReaderTransactions]][readerName]이 존재하면, promise를 "InvalidStateError" DOMException으로 거부하고 promise를 반환한다.

  4. this.[[operationInProgress]]true로 설정한다.

  5. 다음 단계를 병렬로 실행한다:

    1. accessFlagsaccessMode대응하는 [PCSC5] DWORD라고 하자.

    2. protocolFlags0으로 설정된 DWORD라고 하자.

    3. options["preferredProtocols"]이 존재하면, protocolFlags를 해당 값의 대응 플래그로 설정한다.

    4. activeProtocol0으로 설정된 DWORD라고 하자.

    5. comm을 플랫폼의 [PCSC5] SCARDCOMM 클래스의 새 인스턴스라고 하자. 생성자 매개변수로 this.[[resourceManager]]를 사용한다.

    6. comm.Connect()readerName, accessFlagsprotocolFlags를 입력 매개변수로, activeProtocol을 출력 매개변수로 사용하여 호출한다.

    7. responseCode를 반환된 RESPONSECODE라고 하자.

    8. this관련 전역 객체에서 스마트 카드 태스크 소스를 사용하여 전역 태스크를 큐에 넣는다. 이 태스크는 다음 단계를 수행한다:

      1. thisoperationInProgress를 지운다.

      2. responseCodeSCARD_S_SUCCESS가 아니면:

        1. comm을 파기한다.

        2. promiseresponseCode대응하는 예외거부하고 이 단계를 중단한다.

      3. result를 빈 SmartCardConnectResult 딕셔너리라고 하자.

      4. connection을 새 SmartCardConnection이라고 하자.

      5. connectionthis.[[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. promiseresult이행한다.

  6. promise를 반환한다.

4.3.1. SmartCardProtocol 열거형

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

"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 중 하나이면 유효한 프로토콜 값이다.

protocols라는 이름의 SmartCardProtocol 시퀀스가 주어지면, 대응하는 플래그를 갖는 [PCSC5] DWORD를 다음 단계로 생성한다:

  1. flags0으로 설정된 DWORD라고 하자.

  2. protocols에 있는 SmartCardProtocol 유형의 각 protocol에 대해, protocol에 대응하는 DWORDflags추가한다.

  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"

카드의 존재 여부와 관계없이 애플리케이션이 판독기 연결을 요구한다. 독점 접근을 의미한다.

accessMode라는 이름의 SmartCardAccessMode 열거형이 주어지면, 대응하는 [PCSC5] DWORD를 다음 단계로 생성한다:

  1. dword0으로 설정된 DWORD라고 하자.

  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. 보조 알고리즘 및 정의

SmartCardContext context operationInProgress를 지우려면 다음 단계를 수행한다:

  1. 단언: context.[[operationInProgress]]true이다.

  2. context.[[operationInProgress]]false로 설정한다.

  3. context.[[connections]]에 있는 SmartCardConnection 유형의 각 connection에 대해:

    1. connection완료된 모든 트랜잭션을 종료한다.

    2. context.[[operationInProgress]]true이면 이 단계를 중단한다.

처리 중인 GetStatusChange를 취소하는 알고리즘 단계는 다음과 같다:

  1. this.[[tracker]].Cancel()을 호출한다.

[PCSC5] DWORD상위 워드는 해당 DWORD를 16비트 부호 없는 오른쪽 시프트한 결과이다.

dword라는 이름의 [PCSC5] DWORD상위 워드를 설정하여 주어진 숫자 n으로 만들려면 다음 단계를 수행한다:

  1. dworddword0xFFFF의 비트 AND 결과로 설정한다.

  2. shiftedNn을 16비트 왼쪽 시프트한 결과라고 하자.

  3. dworddwordshiftedN의 비트 OR 결과로 설정한다.

[PCSC5] DWORD flags에 플래그 f추가하려면, flagsflagsf의 비트 OR 결과로 설정한다.

[PCSC5] DWORD flagsf의 비트 AND 결과가 f이면 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새 프로미스라고 하자.

  2. this.[[context]].[[operationInProgress]]true이면 promise를 "InvalidStateError" DOMException으로 거부하고 promise를 반환한다.

  3. this.[[context]].[[activeReaderTransactions]][this.[[readerName]]]이 존재하고 this와 같지 않으면, promise를 "InvalidStateError" DOMException으로 거부하고 promise를 반환한다.

  4. this.[[comm]]null이면, promise를 "InvalidStateError" DOMException으로 거부하고 promise를 반환한다.

  5. this.[[context]].[[operationInProgress]]true로 설정한다.

  6. 다음 단계를 병렬로 실행한다:

    1. this.[[comm]].Disconnect()disposition에 대응하는 DWORD를 입력 매개변수로 사용하여 호출한다.

    2. responseCode를 반환된 RESPONSECODE라고 하자.

    3. this관련 전역 객체에서 스마트 카드 태스크 소스를 사용하여 전역 태스크를 큐에 넣는다. 이 태스크는 다음 단계를 수행한다:

      1. this.[[context]]operationInProgress를 지운다.

      2. responseCodeSCARD_S_SUCCESS가 아니면, promiseresponseCode대응하는 예외거부하고 이 단계를 중단한다.

      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새 프로미스로 설정한다.

  2. this.[[context]].[[operationInProgress]]true이면, "InvalidStateError" DOMException으로 promise거부하고 promise를 반환한다.

  3. this.[[context]].[[activeReaderTransactions]][this.[[readerName]]]가 존재하고 this와 같지 않으면, "InvalidStateError" DOMException으로 promise거부하고 promise를 반환한다.

  4. this.[[comm]]null이면, "InvalidStateError" DOMException으로 promise거부하고 promise를 반환한다.

  5. protocolthis.[[activeProtocol]]로 설정된 [PCSC5] DWORD로 설정한다.

  6. options["protocol"]이 존재하면, protocoloptions["protocol"]에 해당하는 DWORD로 설정한다.

  7. protocol유효한 프로토콜 값이 아니면, "InvalidStateError" DOMException으로 promise거부하고 promise를 반환한다.

  8. this.[[context]].[[operationInProgress]]true로 설정한다.

  9. sendPcithis.[[activeProtocol]]에 해당하는 플랫폼의 [PCSC5] SCARD_IO_HEADER로 설정한다.

  10. pcscSendBuffersendBuffer를 포함하는 [PCSC5] BYTE[]로 설정한다.

  11. recvPci를 비어 있거나 null인 것과 동등한 플랫폼의 SCARD_IO_HEADER로 설정한다.

  12. recvBuffer를 가장 큰 [ISO7816-3] 확장 응답 APDU(65538바이트)를 담기에 충분히 큰 BYTE[]로 설정한다.

  13. recvLength0으로 설정된 DWORD로 설정한다.

  14. 다음 단계를 병렬로 실행한다.

    1. sendPci, pcscSendBuffer, recvPci, recvBufferrecvLength를 인수로 사용하여 this.[[comm]].Transmit()을 호출한다.

    2. responseCode를 반환된 RESPONSECODE로 설정한다.

    3. this관련 전역 객체에서 스마트 카드 태스크 소스를 사용하여 다음 단계를 수행하는 전역 태스크를 큐에 넣는다.

      1. this.[[context]]operationInProgress를 지운다.

      2. responseCodeSCARD_S_SUCCESS가 아니면, responseCode해당하는 예외promise거부하고 이 단계를 중단한다.

      3. recvBuffer의 처음 recvLength바이트를 포함하는 ArrayBufferpromise이행한다.

  15. promise를 반환한다.

5.2.1. SmartCardTransmitOptions 딕셔너리

dictionary SmartCardTransmitOptions {
  SmartCardProtocol protocol;
};
protocol

전송에 사용할 프로토콜이다.

5.3. startTransaction() 메서드

startTransaction(transaction, options) 메서드의 단계는 다음과 같다.

  1. promise새 프로미스로 설정한다.

  2. this.[[context]].[[operationInProgress]]true이면, "InvalidStateError" DOMException으로 promise거부하고 promise를 반환한다.

  3. this.[[context]].[[activeReaderTransactions]][this.[[readerName]]]가 존재하면, "InvalidStateError" DOMException으로 promise거부하고 promise를 반환한다.

  4. this.[[comm]]null이면, "InvalidStateError" DOMException으로 promise거부하고 promise를 반환한다.

  5. this.[[transactionState]]null이 아니면, "InvalidStateError" DOMException으로 promise거부하고 promise를 반환한다.

  6. signalnull로 설정된 AbortSignal로 설정한다.

  7. options["signal"]이 존재하면 다음 단계를 실행한다.

    1. options["signal"]이 중단된 상태이면, options["signal"]의 중단 사유promise거부하고 promise를 반환한다.

    2. signaloptions["signal"]로 설정한다.

    3. 취소 알고리즘을 signal추가한다.

  8. this.[[context]].[[operationInProgress]]true로 설정한다.

  9. 다음 단계를 병렬로 실행한다.

    1. this.[[comm]].BeginTransaction()을 호출한다.

    2. responseCode를 반환된 [PCSC5] RESPONSECODE로 설정한다.

    3. this관련 전역 객체에서 스마트 카드 태스크 소스를 사용하여 this, responseCode, signal, transactionpromise를 사용해 BeginTransaction의 결과를 처리하는 전역 태스크를 큐에 넣는다.

  10. promise를 반환한다.

5.3.1. SmartCardTransactionOptions 딕셔너리

dictionary SmartCardTransactionOptions {
  AbortSignal signal;
};
signal

트리거되면 플랫폼의 [PCSC5] Cancel() 메서드가 호출된다.

5.3.2. 보조 알고리즘 및 정의

트랜잭션 상태는 다음 항목을 포함하는 구조체이다.

pendingDisposition

설정되어 있으면 진행 중인 PC/SC 작업이 끝난 후 이 값을 SmartCardDisposition 매개변수로 사용하여 [PCSC5] EndTransaction()을 호출해야 함을 의미한다.

pendingException

promise를 거부할 때 사용할 예외이다.

promise

startTransaction() 호출이 반환한 대기 중인 Promise이다.

SmartCardConnection connection, [PCSC5] RESPONSECODE responseCode, AbortSignal signal, SmartCardTransactionCallback transactionPromise promise가 주어졌을 때 BeginTransaction의 결과를 처리하려면 다음 단계를 수행한다.

  1. connection.[[context]]operationInProgress를 지운다.

  2. abortReasonundefined로 설정한다.

  3. signalnull이 아니면 다음을 수행한다.

    1. signal에서 취소 알고리즘을 제거한다.

    2. signal중단된 상태이면 abortReasonsignal중단 사유로 설정한다.

  4. responseCodeSCARD_S_SUCCESS가 아니면 다음을 수행한다.

    1. responseCodeSCARD_E_CANCELLED이고 abortReasonundefined가 아니면 abortReason으로 promise거부한다.

    2. 그렇지 않으면 responseCode해당하는 예외promise거부한다.

    3. 반환한다.

  5. transactionState트랜잭션 상태의 새 인스턴스로 설정하고, 그 promise 항목을 promise로 설정한다.

  6. connection.[[transactionState]]transactionState로 설정한다.

  7. connection.[[context]].[[activeReaderTransactions]][connection.[[readerName]]]을 connection으로 설정한다.

  8. callbackPromisetransaction호출한 결과로 설정한다.

  9. callbackPromise반응한다.

SmartCardConnection connection트랜잭션을 종료하려면 SmartCardDisposition disposition을 사용하여 다음 단계를 수행한다.

  1. 단언: connection.[[context]].[[operationInProgress]]false이다.

  2. 단언: connection.[[transactionState]]null이 아니다.

  3. 단언: connection.[[transactionState]]pendingDispositionnull이다.

  4. transactionPromiseconnection.[[transactionState]]promise로 설정한다.

  5. connection.[[comm]]null이면 다음을 수행한다.

    1. "InvalidStateError" DOMException으로 transactionPromise거부한다.

    2. connection.[[transactionState]]null로 설정한다.

    3. 반환한다.

  6. connection.[[context]].[[operationInProgress]]true로 설정한다.

  7. 다음 단계를 병렬로 실행한다.

    1. disposition에 해당하는 DWORD를 입력 매개변수로 사용하여 connection.[[comm]].EndTransaction()을 호출한다.

    2. responseCode를 반환된 [PCSC5] RESPONSECODE로 설정한다.

    3. this관련 전역 객체에서 스마트 카드 태스크 소스를 사용하여 다음 단계를 수행하는 전역 태스크를 큐에 넣는다.

      1. connection.[[context]]operationInProgress를 지운다.

      2. connection.[[readerName]]connection.[[context]].[[activeReaderTransactions]]에서 제거한다.

      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]]pendingDispositionnull로 설정한다.

  5. disposition을 사용하여 connection트랜잭션을 종료한다.

대기 중인 [PCSC5] SCARDCOMM 작업을 취소하려면 this.[[comm]].Cancel()을 호출한다.

5.4. status() 메서드

status() 메서드의 단계는 다음과 같다.

  1. promise새 프로미스로 설정한다.

  2. this.[[context]].[[operationInProgress]]true이면, "InvalidStateError" DOMException으로 promise거부하고 promise를 반환한다.

  3. this.[[context]].[[activeReaderTransactions]][this.[[readerName]]]가 존재하고 this와 같지 않으면, "InvalidStateError" DOMException으로 promise거부하고 promise를 반환한다.

  4. this.[[comm]]null이면, "InvalidStateError" DOMException으로 promise거부하고 promise를 반환한다.

  5. this.[[context]].[[operationInProgress]]true로 설정한다.

  6. 다음 단계를 병렬로 실행한다.

    1. pcscReader를 빈 STR[]로 설정한다.

    2. pcscState0으로 설정된 [PCSC5] DWORD로 설정한다.

    3. activeProtocol0으로 설정된 [PCSC5] DWORD로 설정한다.

    4. pcscAtr을 모든 [ISO7816-3] 리셋 응답(ATR)을 담기에 충분히 큰 BYTE[]로 설정한다.

    5. pcscReader, pcscState, activeProtocolpcscAtr을 출력 매개변수로 사용하여 this.[[comm]].Status()를 호출한다.

    6. responseCode를 반환된 RESPONSECODE로 설정한다.

    7. this관련 전역 객체에서 스마트 카드 태스크 소스를 사용하여 다음 단계를 수행하는 전역 태스크를 큐에 넣는다.

      1. this.[[context]]operationInProgress를 지운다.

      2. responseCodeSCARD_S_SUCCESS가 아니면, responseCode해당하는 예외promise거부하고 이 단계를 중단한다.

      3. statepcscStateactiveProtocol해당하는 SmartCardConnectionState로 설정한다.

      4. stateundefined이면, "UnknownError" DOMException으로 promise거부하고 이 단계를 중단한다.

      5. status를 새 SmartCardConnectionStatus로 설정한다.

      6. status["readerName"]을 pcscReader로 설정한다.

      7. status["state"]를 state로 설정한다.

      8. status["answerToReset"]을 pcscAtr에 기록된 바이트를 포함하는 ArrayBuffer로 설정한다.

      9. statuspromise이행한다.

  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 pcscStateDWORD 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새 프로미스로 설정한다.

  2. this.[[context]].[[operationInProgress]]true이면, "InvalidStateError" DOMException으로 promise거부하고 promise를 반환한다.

  3. this.[[context]].[[activeReaderTransactions]][this.[[readerName]]]가 존재하고 this와 같지 않으면, "InvalidStateError" DOMException으로 promise거부하고 promise를 반환한다.

  4. this.[[comm]]null이면, "InvalidStateError" DOMException으로 promise거부하고 promise를 반환한다.

  5. this.[[context]].[[operationInProgress]]true로 설정한다.

  6. pcscControlCodecontrolCode를 포함하는 [PCSC5] DWORD로 설정한다.

  7. data버퍼 소스 복사본을 가져와 그 결과를 [PCSC5] BYTE[] inBuffer에 저장한다.

  8. outBuffer를 모든 제어 명령 응답을 담기에 충분히 큰 [PCSC5] BYTE[]로 설정한다.

  9. outBufferLength0으로 설정된 DWORD로 설정한다.

  10. 다음 단계를 병렬로 실행한다.

    1. pcscControlCode, inBuffer, outBufferoutBufferLength를 인수로 사용하여 this.[[comm]].Control()을 호출한다.

    2. responseCode를 반환된 RESPONSECODE로 설정한다.

    3. this관련 전역 객체에서 스마트 카드 태스크 소스를 사용하여 다음 단계를 수행하는 전역 태스크를 큐에 넣는다.

      1. this.[[context]]operationInProgress를 지운다.

      2. responseCodeSCARD_S_SUCCESS가 아니면, responseCode해당하는 예외promise거부하고 이 단계를 중단한다.

      3. resultBytesoutBuffer의 처음 outBufferLength바이트로 설정한다.

      4. this관련 Realm에서 resultBytes로부터 ArrayBuffer생성한 결과로 promise이행한다.

  11. promise를 반환한다.

5.6. getAttribute() 메서드

getAttribute(tag) 메서드의 단계는 다음과 같다.

  1. promise새 프로미스로 설정한다.

  2. this.[[context]].[[operationInProgress]]true이면, "InvalidStateError" DOMException으로 promise거부하고 promise를 반환한다.

  3. this.[[context]].[[activeReaderTransactions]][this.[[readerName]]]가 존재하고 this와 같지 않으면, "InvalidStateError" DOMException으로 promise거부하고 promise를 반환한다.

  4. this.[[comm]]null이면, "InvalidStateError" DOMException으로 promise거부하고 promise를 반환한다.

  5. this.[[context]].[[operationInProgress]]true로 설정한다.

  6. 다음 단계를 병렬로 실행한다.

    1. pcscTagtag를 포함하는 [PCSC5] DWORD로 설정한다.

    2. buffer를 플랫폼의 [PCSC5] 구현에서 결정한 이 판독기 속성을 담기에 충분히 큰 [PCSC5] BYTE[]로 설정한다.

    3. pcscTagbuffer를 인수로 사용하여 this.[[comm]].GetReaderCapabilities()를 호출한다.

    4. responseCode를 반환된 RESPONSECODE로 설정한다.

    5. this관련 전역 객체에서 스마트 카드 태스크 소스를 사용하여 다음 단계를 수행하는 전역 태스크를 큐에 넣는다.

      1. this.[[context]]operationInProgress를 지운다.

      2. responseCodeSCARD_S_SUCCESS가 아니면, responseCode해당하는 예외promise거부하고 이 단계를 중단한다.

      3. resultBytes를 읽은 속성이 들어 있는 buffer의 바이트로 설정한다.

      4. this관련 Realm에서 resultBytes로부터 ArrayBuffer생성한 결과로 promise이행한다.

  7. promise를 반환한다.

5.7. setAttribute() 메서드

setAttribute(tag, value) 메서드의 단계는 다음과 같다.

  1. promise새 프로미스로 설정한다.

  2. this.[[context]].[[operationInProgress]]true이면, "InvalidStateError" DOMException으로 promise거부하고 promise를 반환한다.

  3. this.[[context]].[[activeReaderTransactions]][this.[[readerName]]]가 존재하고 this와 같지 않으면, "InvalidStateError" DOMException으로 promise거부하고 promise를 반환한다.

  4. this.[[comm]]null이면, "InvalidStateError" DOMException으로 promise거부하고 promise를 반환한다.

  5. this.[[context]].[[operationInProgress]]true로 설정한다.

  6. pcscTagtag를 포함하는 [PCSC5] DWORD로 설정한다.

  7. value버퍼 소스 복사본을 가져와 그 결과를 [PCSC5] BYTE[] buffer에 저장한다.

  8. 다음 단계를 병렬로 실행한다.

    1. pcscTagbuffer를 인수로 사용하여 this.[[comm]].SetReaderCapabilities()를 호출한다.

    2. responseCode를 반환된 RESPONSECODE로 설정한다.

    3. this관련 전역 객체에서 스마트 카드 태스크 소스를 사용하여 다음 단계를 수행하는 전역 태스크를 큐에 넣는다.

      1. this.[[context]]operationInProgress를 지운다.

      2. responseCodeSCARD_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이면 새 "InvalidStateError" DOMException반환한다.

  20. pcscCodeSCARD_E_SERVICE_STOPPED이면 새 "InvalidStateError" DOMException반환한다.

  21. pcscCodeSCARD_P_SHUTDOWN이면 새 "AbortError" DOMException반환한다.

  22. 그렇지 않으면 새 "UnknownError" DOMException반환한다.

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는 웹 애플리케이션에 호스트의 PC/SC 스마트 카드 하위 시스템에 대한 접근을 제공한다. 이는 오용될 경우 사용자의 보안과 개인정보 보호에 중대한 부정적 영향을 미칠 수 있는 강력한 기능이다. 이 절에서는 고려된 위협과 이를 완화하기 위한 사용자 에이전트의 규범적 요구 사항을 설명한다.

스마트 카드 판독기와 그 안에 있는 카드에 대한 접근은 강력한 기능이다. 사용자 에이전트는 명시적 권한 없이 웹 애플리케이션이 SmartCardConnection 객체에 접근하도록 허용해서는 안 된다.

특정 출처에 대해 사용자 동의를 얻어야 한다. 동의 요청은 connect() 메서드 호출로 트리거되어야 한다. 사용자 에이전트는 어느 출처가 접근을 요청하는지 명확히 표시하고 사용자가 충분한 정보를 바탕으로 결정을 내릴 수 있도록 하는 권한 프롬프트를 표시해야 한다(예: 스마트 카드 판독기의 이름 표시).

사용자 에이전트는 일시적 권한(예: "이 세션에서만")과 영구적 권한을 모두 선택할 수 있도록 하는 것이 좋다. 사용자가 영구 접근 권한을 부여했다는 사실을 잊을 위험을 완화하려면 일시적 권한을 기본값이자 더 눈에 띄는 옵션으로 제공하는 것이 좋다.

사용자에게 이 API에 대해 이전에 부여된 모든 권한을 확인하고 취소할 수 있는 메커니즘을 제공해야 한다.

7.2. 핑거프린팅

listReaders() 메서드와 SmartCardReaderStateOut 딕셔너리의 answerToReset 멤버는 수동적 핑거프린팅에 사용할 수 있는 정보를 노출한다. 스마트 카드 판독기의 존재와 모델은 사용자가 기업 환경에 있는지 여부와 같은 정보를 드러낼 수 있다. 리셋 응답(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; et al. 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"
};