1. Extensions to the Navigator interface
[Exposed =Window ,SecureContext ,IsolatedContext ]partial interface Navigator { [SameObject ]readonly attribute SmartCardResourceManager ; };smartCard
1.1. smartCard attribute
When getting, the smartCard attribute always returns the same
instance of the SmartCardResourceManager object.
2. Extensions to the WorkerNavigator interface
[Exposed =(DedicatedWorker ,SharedWorker ),SecureContext ,IsolatedContext ]partial interface WorkerNavigator { [SameObject ]readonly attribute SmartCardResourceManager ; };smartCard
2.1. smartCard attribute
When getting, the smartCard attribute always returns the same
instance of the SmartCardResourceManager object.
3. SmartCardResourceManager interface
[Exposed =(DedicatedWorker ,SharedWorker ,Window ),SecureContext ,IsolatedContext ]interface {SmartCardResourceManager Promise <SmartCardContext >(); };establishContext
Methods on this interface complete asynchronously, queuing work on the smart card task source.
3.1. establishContext() method
Requests a PC/SC context from the platform’s PC/SC stack.
The establishContext() method steps are:
-
If this’s relevant global object’s associated Document is not allowed to use the policy-controlled feature named "smart-card", throw a "
SecurityError"DOMException. -
Let promise be a new promise.
-
Run the following steps in parallel:
-
Let resourceManager be a new instance of the platform’s [PCSC5]
RESOURCEMANAGERclass. -
Invoke the
EstablishContextmethod of resourceManager with a "system"Scopeparameter. -
If the returned
RESPONSECODEis notSCARD_S_SUCCESS, perform the following steps:-
Destroy resourceManager.
-
Queue a global task on the relevant global object of this using the smart card task source to reject promise with a corresponding exception.
-
-
Otherwise, perform the following steps:
-
Let context be a new
SmartCardContextwhose [[resourceManager]] internal slot is set to resourceManager. -
Queue a global task on the relevant global object of this using the smart card task source to resolve promise with context.
-
-
-
Return promise.
4. SmartCardContext interface
A context for communicating with the PC/SC resource manager.
[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
Instances of SmartCardContext are created with the internal slots
described in the following table:
| Internal slot | Initial value | Description (non-normative) |
|---|---|---|
| [[resourceManager]] | null
| The platform’s [PCSC5] RESOURCEMANAGER to be used.
|
| [[operationInProgress]] | false
| Whether there is an ongoing PC/SC operation in this context. |
| [[activeReaderTransactions]] | An empty map | A map of reader names to the SmartCardConnection that
currently holds an active transaction on that reader in this
context, if any.
|
| [[connections]] | An empty ordered set | The existing SmartCardConnections created by this context.
|
| [[tracker]] | null
| A [PCSC5] SCARDTRACK instance.
|
| [[signal]] | null
| The AbortSignal of the outstanding
getStatusChange() call, if any.
|
4.1. listReaders() method
The listReaders() method steps are:
-
Let promise be a new promise.
-
If this.[[operationInProgress]] is
true, reject promise with a "InvalidStateError"DOMExceptionand return promise. -
Set this.[[operationInProgress]] to
true. -
Run the following steps in parallel:
-
Let resourceQuery be a new instance of the platform’s [PCSC5]
RESOURCEQUERYclass, with this.[[resourceManager]] as its constructor input parameter. -
Let groups be the platform’s [PCSC5]
STR[]containing the list of group names that is equivalent to "all readers in the system" in that platform. -
Let pcscReaders be an empty
STR[]. -
Invoke the
ListReadersmethod of resourceQuery with groups as input and pcscReaders as output parameters. -
Let responseCode be the returned
RESPONSECODE. -
Destroy resourceQuery.
-
Queue a global task on the relevant global object of this using the smart card task source which performs the following steps:
-
-
Return promise.
4.2. getStatusChange() method
The getStatusChange(readerStates, options) method steps are:
-
Let promise be a new promise.
-
If this.[[operationInProgress]] is
true, reject promise with a "InvalidStateError"DOMExceptionand return promise. -
If
options["signal"] exists, run the following steps:-
If signal is aborted, reject promise with signal’s abort reason and return promise.
-
Set this.[[signal]] to signal.
-
Add the cancel the outstanding GetStatusChange algorithm to signal.
-
If
options["timeout"] exists, set pcscTimeout tooptions["timeout"]. -
Let pcscReaderStates be a [PCSC5]
SCARD_READERSTATE[]corresponding toreaderStates. -
Set this.[[operationInProgress]] to
true. -
Set this.[[tracker]] to a new instance of the platform’s [PCSC5]
SCARDTRACKclass, with this.[[resourceManager]] as its constructor input parameter. -
Run the following steps in parallel:
-
Call this.[[tracker]].
GetStatusChange()with pcscReaderStates and pcscTimeout as input parameters. -
Let responseCode be the returned [PCSC5]
RESPONSECODE. -
Queue a global task on the relevant global object of this using the smart card task source which performs the following steps:
-
Set this.[[tracker]] to
null. -
Let abortReason be
undefined. -
If this.[[signal]] is not
null, run the following steps:-
If this.[[signal]] is aborted then set abortReason to this.[[signal]]’s abort reason.
-
Remove the cancel the outstanding GetStatusChange algorithm from this.[[signal]].
-
Set this.[[signal]] to
null.
-
-
If responseCode is not
SCARD_S_SUCCESS, run the following steps:-
If responseCode is
SCARD_E_CANCELLEDand abortReason is notundefinedthen reject promise with abortReason. -
Otherwise, reject promise with an exception corresponding to responseCode.
-
Return.
-
-
Let readerStatesOut be a sequence of
SmartCardReaderStateOutcorresponding to pcscReaderStates. -
Resolve promise with readerStatesOut.
-
-
-
Return promise.
4.2.1. SmartCardReaderStateIn dictionary
dictionary {SmartCardReaderStateIn required DOMString ;readerName required SmartCardReaderStateFlagsIn ;currentState unsigned long ; };currentCount
readerName-
Name of the smart card reader.
currentState-
The current state of that smart card reader as known by the application.
currentCount-
The current number of card insertion and removal events in this reader, as known by the application.
Given a sequence of SmartCardReaderStateIn named readerStates, a corresponding [PCSC5] SCARD_READERSTATE[] is created with the following steps:
-
Let pcscReaderStates be an empty
SCARD_READERSTATE[]. -
For each stateIn of type
SmartCardReaderStateInin readerStates:-
Let pcscState be a
SCARD_READERSTATE. -
Set pcscState.
Readerto stateIn["readerName"]. -
Set pcscState.
CurrentStateto theDWORDcorresponding to stateIn["currentState"]. -
If stateIn["
currentCount"] exists, set the high word of pcscState.CurrentStateto stateIn["currentCount"]. -
Set pcscState.
EventStateto zero. -
Append pcscState to pcscReaderStates.
-
-
Return pcscReaderStates.
4.2.1.1. SmartCardReaderStateFlagsIn dictionary
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-
The application is unaware of the current state, and would like to know.
ignore-
The application is not interested in this reader, and it should not be considered during monitoring operations.
unavailable-
The application believes that this reader is not available for use.
empty-
The application believes that there is not a card in the reader.
present-
The application believes that there is a card in the reader.
exclusive-
The application believes that the card in the reader is allocated for exclusive use by another application.
inuse-
The application believes that the card in the reader is in use by one or more other applications, but may be connected to in shared mode.
mute-
The application believes that there is an unresponsive card in the reader.
unpowered-
The application believes that the card in the reader has not been powered up.
The [PCSC5] DWORD corresponding to a given SmartCardReaderStateFlagsIn is created with the following steps:
-
Let flagsIn be the given
SmartCardReaderStateFlagsIn. -
Let pcscFlags be a
DWORDset to zero. -
If flagsIn["
unaware"] istrue, add [PCSC5]SCARD_STATE_UNAWAREto pcscFlags. -
If flagsIn["
ignore"] istrue, add [PCSC5]SCARD_STATE_IGNOREto pcscFlags. -
If flagsIn["
unavailable"] istrue, add [PCSC5]SCARD_STATE_UNAVAILABLEto pcscFlags. -
If flagsIn["
empty"] istrue, add [PCSC5]SCARD_STATE_EMPTYto pcscFlags. -
If flagsIn["
present"] istrue, add [PCSC5]SCARD_STATE_PRESENTto pcscFlags. -
If flagsIn["
exclusive"] istrue, add [PCSC5]SCARD_STATE_EXCLUSIVEto pcscFlags. -
If flagsIn["
inuse"] istrue, add [PCSC5]SCARD_STATE_INUSEto pcscFlags. -
If flagsIn["
mute"] istrue, addSCARD_STATE_MUTEto pcscFlags. -
If flagsIn["
unpowered"] istrue, addSCARD_STATE_UNPOWEREDto pcscFlags. -
Return pcscFlags.
4.2.2. SmartCardReaderStateOut dictionary
The actual state of a smart card reader.
dictionary {SmartCardReaderStateOut required DOMString ;readerName required SmartCardReaderStateFlagsOut ;eventState required unsigned long ;eventCount ArrayBuffer ; };answerToReset
readerName-
Name of the smart card reader.
eventState-
The actual state of that smart card reader.
eventCount-
The actual number of card insertion and removal events in this reader.
answerToReset-
The inserted card’s [ISO7816-3] Answer To Reset (ATR), if applicable.
Given a [PCSC5] SCARD_READERSTATE[] named pcscReaderStates, a corresponding sequence of SmartCardReaderStateOut is created with the following steps:
-
Let readerStatesOut be an empty sequence of
SmartCardReaderStateOut. -
For each pcscState of type
SCARD_READERSTATEin pcscReaderStates:-
Let stateOut be a
SmartCardReaderStateOut. -
Set stateOut["
readerName"] to pcscState.Reader. -
Set stateOut["
eventState"] to theSmartCardReaderStateFlagsOutdictionary corresponding to pcscState.EventState. -
Set stateOut["
eventCount"] to the high word of pcscState.EventState. -
If the platform’s
SCARD_READERSTATEstructure has a member containing the card’s [ISO7816-3] Answer To Reset, set stateOut["answerToReset"] to that value. -
Append stateOut to readerStatesOut.
-
-
Return readerStatesOut.
4.2.2.1. SmartCardReaderStateFlagsOut dictionary
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-
The application requested that this reader be ignored.
changed-
There is a difference between the state input by the calling application, and the actual state.
unavailable-
This reader is not available for use.
unknown-
The reader name given by the application is not known.
empty-
There is no card in the reader.
present-
There is a card in the reader.
exclusive-
The card in the reader is allocated for exclusive use by another application.
inuse-
The card in the reader is in use by one or more other applications, but may be connected to in shared mode.
mute-
There is an unresponsive card in the reader.
unpowered-
The card in the reader has not been powered up.
Given a [PCSC5] DWORD named pcscFlags, a corresponding SmartCardReaderStateFlagsOut dictionary is created with the following steps:
-
Let flagsOut be a
SmartCardReaderStateFlagsOutdictionary with default members. -
If pcscFlags has [PCSC5]
SCARD_STATE_IGNORE, set flagsOut["ignore"] totrue. -
If pcscFlags has [PCSC5]
SCARD_STATE_CHANGED, set flagsOut["changed"] totrue. -
If pcscFlags has [PCSC5]
SCARD_STATE_UNAVAILABLE, set flagsOut["unavailable"] totrue. -
If pcscFlags has [PCSC5]
SCARD_STATE_UNKNOWN, set flagsOut["unknown"] totrue. -
If pcscFlags has [PCSC5]
SCARD_STATE_EMPTY, set flagsOut["empty"] totrue. -
If pcscFlags has [PCSC5]
SCARD_STATE_PRESENT, set flagsOut["present"] totrue. -
If pcscFlags has [PCSC5]
SCARD_STATE_EXCLUSIVE, set flagsOut["exclusive"] totrue. -
If pcscFlags has [PCSC5]
SCARD_STATE_INUSE, set flagsOut["inuse"] totrue. -
If pcscFlags has
SCARD_STATE_MUTE, set flagsOut["mute"] totrue. -
If pcscFlags has
SCARD_STATE_UNPOWERED, set flagsOut["unpowered"] totrue. -
Return flagsOut.
4.2.3. SmartCardGetStatusChangeOptions dictionary
dictionary {SmartCardGetStatusChangeOptions DOMHighResTimeStamp ;timeout AbortSignal ; };signal
timeout-
Timeout parameter for the GetStatusChange() [PCSC5] method. If not specified, a timeout value of INFINITE (which is defined system dependent) will be used.
signal-
When triggered, the platform’s [PCSC5] Cancel() method is called.
4.3. connect() method
The connect(readerName, accessMode, options) method steps are:
-
Let promise be a new promise.
-
If this.[[operationInProgress]] is
true, reject promise with a "InvalidStateError"DOMExceptionand return promise. -
If this.[[activeReaderTransactions]][
readerName] exists, reject promise with a "InvalidStateError"DOMExceptionand return promise. -
Set this.[[operationInProgress]] to
true. -
Run the following steps in parallel:
-
Let accessFlags be a [PCSC5]
DWORDcorresponding toaccessMode. -
Let protocolFlags be a
DWORDset to0. -
If
options["preferredProtocols"] exists, set protocolFlags to its corresponding flags. -
Let activeProtocol be a
DWORDset to0. -
Let comm be a new instance of the platform’s [PCSC5]
SCARDCOMMclass, with this.[[resourceManager]] as its constructor parameter. -
Call comm.
Connect()withreaderName, accessFlags and protocolFlags as input and activeProtocol as output parameters. -
Let responseCode be the returned
RESPONSECODE. -
Queue a global task on the relevant global object of this using the smart card task source which performs the following steps:
-
If responseCode is not
SCARD_S_SUCCESS:-
Destroy comm.
-
Reject promise with an exception corresponding to responseCode and abort these steps.
-
-
Let result be an empty
SmartCardConnectResultdictionary. -
Let connection be a new
SmartCardConnection. -
Append connection to this.[[connections]].
-
Set connection.[[comm]] to comm.
-
Set connection.[[readerName]] to
readerName. -
Set connection.[[context]] to this.
-
Set connection.[[activeProtocol]] to activeProtocol.
-
Set result["
connection"] to connection. -
If activeProtocol is a valid protocol value, set result["
activeProtocol"] to the correspondingSmartCardProtocol. -
Resolve promise with result.
-
-
Return promise.
4.3.1. SmartCardProtocol enum
enum {SmartCardProtocol ,"raw" ,"t0" };"t1"
"raw"-
"Raw" mode. May be used to support arbitrary data exchange protocols for special-purpose requirements. Corresponds to a [PCSC5]
SCARD_PROTOCOL_RAWDWORD. "t0"-
[ISO7816-3] T=0. Asynchronous half duplex character transmission protocol. Corresponds to a [PCSC5]
SCARD_PROTOCOL_T0DWORD. "t1"-
[ISO7816-3] T=1. Asynchronous half duplex block transmission protocol. Corresponds to a [PCSC5]
SCARD_PROTOCOL_T1DWORD.
A [PCSC5] DWORD is a valid protocol value if it is either [PCSC5] SCARD_PROTOCOL_T0, [PCSC5] SCARD_PROTOCOL_T1 or [PCSC5] SCARD_PROTOCOL_RAW.
Given a sequence of SmartCardProtocol named protocols, a [PCSC5] DWORD with the corresponding flags is created with the following steps:
-
Let flags be a
DWORDset to0. -
For each protocol of type
SmartCardProtocolin protocols, add the correspondingDWORDof protocol to flags. -
Return flags.
4.3.2. SmartCardConnectResult dictionary
dictionary {SmartCardConnectResult required SmartCardConnection ;connection SmartCardProtocol ; };activeProtocol
connection-
An interface to the connection created.
activeProtocol-
The protocol actually in use.
4.3.3. SmartCardAccessMode enum
enum {SmartCardAccessMode ,"shared" ,"exclusive" };"direct"
"shared"-
Application is willing to share access to card with other applications.
"exclusive"-
Application requires exclusive access to the card.
"direct"-
Application requires connection to reader whether or not card is present. Implies exclusive access.
Given a SmartCardAccessMode enum named accessMode, a corresponding [PCSC5] DWORD is created with the following steps:
-
Let dword be a
DWORDset to0. -
If accessMode is "
shared", set dword to [PCSC5]SCARD_SHARE_SHARED. -
If accessMode is "
exclusive", set dword to [PCSC5]SCARD_SHARE_EXCLUSIVE. -
If accessMode is "
direct", set dword to [PCSC5]SCARD_SHARE_DIRECT. -
Return dword.
4.3.4. SmartCardConnectOptions dictionary
dictionary {SmartCardConnectOptions sequence <SmartCardProtocol >; };preferredProtocols
preferredProtocols-
Card communication protocols that may be used.
4.4. Auxiliary algorithms and definitions
To clear the operationInProgress of a SmartCardContext context, perform the following steps:
-
Assert: context.[[operationInProgress]] is
true. -
Set context.[[operationInProgress]] to
false. -
For each connection of type
SmartCardConnectionof context.[[connections]]:-
end any settled transaction of connection.
-
If context.[[operationInProgress]] is
true, abort there steps.
-
The cancel the outstanding GetStatusChange algorithm steps are:
-
Call this.[[tracker]].
Cancel().
The high word of a [PCSC5] DWORD is the result of an unsigned right shift of 16 bits on that DWORD.
To set the high word of a [PCSC5] DWORD named dword to a given number n, perform the following steps:
-
Set dword to dword bitwise AND
0xFFFF. -
Let shiftedN be the result of a left shift of 16 bits on n.
-
Set dword to dword bitwise OR shiftedN.
To add a flag f to a [PCSC5] DWORD flags, set flags to flags bitwise OR f.
A [PCSC5] DWORD flags has a flag f if flags bitwise AND f is f.
5. SmartCardConnection interface
[Exposed =(DedicatedWorker ,SharedWorker ,Window ),SecureContext ,IsolatedContext ]interface {SmartCardConnection Promise <undefined >(disconnect optional SmartCardDisposition = "leave");disposition 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 ?> ();
Instances of SmartCardConnection are created with the internal slots
described in the following table:
| Internal slot | Initial value | Description (non-normative) |
|---|---|---|
| [[comm]] | null
| The platform’s [PCSC5] SCARDCOMM to be used.
|
| [[readerName]] | null
| The name of the reader this connection is associated with. |
| [[context]] | null
| The SmartCardContext that created this instance.
|
| [[activeProtocol]] | 0 | The active protocol DWORD, as returned by the platform’s
[PCSC5] implementation.
|
| [[transactionState]] | null
| Holds the state of an ongoing transaction
started with startTransaction(), if any.
|
5.1. disconnect() method
The disconnect(disposition) method steps are:
-
Let promise be a new promise.
-
If this.[[context]].[[operationInProgress]] is
true, reject promise with a "InvalidStateError"DOMExceptionand return promise. -
If this.[[context]].[[activeReaderTransactions]][this.[[readerName]]] exists and is not equal to this, reject promise with a "
InvalidStateError"DOMExceptionand return promise. -
If this.[[comm]] is
null, reject promise with a "InvalidStateError"DOMExceptionand return promise. -
Set this.[[context]].[[operationInProgress]] to
true. -
Run the following steps in parallel:
-
Call this.[[comm]].
Disconnect()with aDWORDcorresponding todispositionas input parameter. -
Let responseCode be the returned
RESPONSECODE. -
Queue a global task on the relevant global object of this using the smart card task source which performs the following steps:
-
If responseCode is not
SCARD_S_SUCCESS, reject promise with an exception corresponding to responseCode and abort these steps. -
Resolve promise.
-
-
Return promise.
5.1.1. SmartCardDisposition enum
enum {SmartCardDisposition ,"leave" ,"reset" ,"unpower" };"eject"
"leave"-
Don’t alter card state. Corresponds to a [PCSC5]
SCARD_LEAVE_CARDDWORD. "reset"-
Reset the card. Corresponds to a [PCSC5]
SCARD_RESET_CARDDWORD. "unpower"-
Unpower and terminate access to the card. Corresponds to a [PCSC5]
SCARD_UNPOWER_CARDDWORD. "eject"-
Eject the card from the reader. Corresponds to a [PCSC5]
SCARD_EJECT_CARDDWORD.
5.2. transmit() method
The transmit(sendBuffer, options) method steps are:
-
Let promise be a new promise.
-
If this.[[context]].[[operationInProgress]] is
true, reject promise with a "InvalidStateError"DOMExceptionand return promise. -
If this.[[context]].[[activeReaderTransactions]][this.[[readerName]]] exists and is not equal to this, reject promise with a "
InvalidStateError"DOMExceptionand return promise. -
If this.[[comm]] is
null, reject promise with a "InvalidStateError"DOMExceptionand return promise. -
Let protocol be a [PCSC5]
DWORDset to this.[[activeProtocol]]. -
If
options["protocol"] exists, set protocol to theDWORDcorresponding tooptions["protocol"]. -
If protocol is not a valid protocol value, reject promise with a "
InvalidStateError"DOMExceptionand return promise. -
Set this.[[context]].[[operationInProgress]] to
true. -
Let sendPci be the platform’s [PCSC5]
SCARD_IO_HEADERcorresponding to this.[[activeProtocol]]. -
Let pcscSendBuffer be a [PCSC5]
BYTE[]containingsendBuffer. -
Let recvPci be the platform’s
SCARD_IO_HEADERequivalent of empty or null. -
Let recvBuffer be a
BYTE[]big enough to hold the largest [ISO7816-3] extended response APDU (65538 bytes). -
Let recvLength be a
DWORDset to0. -
Run the following steps in parallel:
-
Call this.[[comm]].
Transmit()with sendPci, pcscSendBuffer, recvPci, recvBuffer and recvLength as arguments. -
Let responseCode be the returned
RESPONSECODE. -
Queue a global task on the relevant global object of this using the smart card task source which performs the following steps:
-
If responseCode is not
SCARD_S_SUCCESS, reject promise with an exception corresponding to responseCode and abort these steps. -
Resolve promise with an
ArrayBuffercontaining the first recvLength bytes of recvBuffer.
-
-
Return promise.
5.2.1. SmartCardTransmitOptions dictionary
dictionary {SmartCardTransmitOptions SmartCardProtocol ; };protocol
protocol-
The protocol to be used in the transmission.
5.3. startTransaction() method
The startTransaction(transaction, options) method steps are:
-
Let promise be a new promise.
-
If this.[[context]].[[operationInProgress]] is
true, reject promise with a "InvalidStateError"DOMExceptionand return promise. -
If this.[[context]].[[activeReaderTransactions]][this.[[readerName]]] exists, reject promise with a "
InvalidStateError"DOMExceptionand return promise. -
If this.[[comm]] is
null, reject promise with a "InvalidStateError"DOMExceptionand return promise. -
If this.[[transactionState]] is not
null, reject promise with a "InvalidStateError"DOMExceptionand return promise. -
Let signal be an
AbortSignalset tonull. -
Set this.[[context]].[[operationInProgress]] to
true. -
Run the following steps in parallel:
-
Let responseCode be the returned [PCSC5]
RESPONSECODE. -
Queue a global task on the relevant global object of this using the smart card task source to process the result of a BeginTransaction with this, responseCode, signal,
transactionand promise.
-
Return promise.
5.3.1. SmartCardTransactionOptions dictionary
dictionary {SmartCardTransactionOptions AbortSignal ; };signal
signal-
When triggered, the platform’s [PCSC5] Cancel() method is called.
5.3.2. Auxiliary algorithms and definitions
A transaction state is a struct with the following items:
- pendingDisposition
-
If set, it means once the ongoing PC/SC operation finishes [PCSC5]
EndTransaction()should be called with this value as theSmartCardDispositionparameter. - pendingException
-
The exception to be used when rejecting promise.
- promise
-
The pending
Promisereturned by astartTransaction()call.
To process the result of a BeginTransaction given a SmartCardConnection connection, a [PCSC5] RESPONSECODE responseCode, an AbortSignal signal, a SmartCardTransactionCallback transaction and a Promise promise, perform the following steps:
-
Clear the operationInProgress of connection.[[context]].
-
Let abortReason be
undefined. -
If signal is not
null:-
If signal is aborted then set abortReason to signal’s abort reason.
-
If responseCode is not
SCARD_S_SUCCESS:-
If responseCode is
SCARD_E_CANCELLEDand abortReason is notundefinedthen reject promise with abortReason. -
Otherwise, reject promise with an exception corresponding to responseCode.
-
Return.
-
-
Let transactionState be a new transaction state with its promise item set to promise.
-
Set connection.[[transactionState]] to transactionState.
-
Set connection.[[context]].[[activeReaderTransactions]][connection.[[readerName]]] to connection.
-
Let callbackPromise be the result of invoking transaction.
-
React to callbackPromise:
-
If callbackPromise was fulfilled with value v then:
-
Let disposition be "
reset". -
If v is not
undefined, set disposition to v. -
If connection.[[context]].[[operationInProgress]] is
true:-
Set transactionState’s pendingException to a "
InvalidStateError"DOMException. -
Set transactionState’s pendingDisposition to disposition.
-
-
Otherwise, end the transaction of connection with disposition.
-
-
If callbackPromise was rejected with reason r, then:
-
Set transactionState’s pendingException to r.
-
If connection.[[context]].[[operationInProgress]] is
true, set transactionState’s pendingDisposition to "reset". -
Otherwise, end the transaction of connection with "
reset".
-
-
To end the transaction of a SmartCardConnection connection with a SmartCardDisposition disposition, perform the following steps:
-
Assert: connection.[[context]].[[operationInProgress]] is
false. -
Assert: connection.[[transactionState]] is not
null. -
Assert: connection.[[transactionState]]’s pendingDisposition is
null. -
Let transactionPromise be connection.[[transactionState]]’s promise.
-
If connection.[[comm]] is
null:-
Reject transactionPromise with a "
InvalidStateError"DOMException. -
Set connection.[[transactionState]] to
null. -
Return.
-
-
Set connection.[[context]].[[operationInProgress]] to
true. -
Run the following steps in parallel:
-
Call connection.[[comm]].
EndTransaction()with aDWORDcorresponding to disposition as input parameter. -
Let responseCode be the returned [PCSC5]
RESPONSECODE. -
Queue a global task on the relevant global object of this using the smart card task source which performs the following steps:
-
Clear the operationInProgress of connection.[[context]].
-
Remove connection.[[readerName]] from connection.[[context]].[[activeReaderTransactions]].
-
Let exception be connection.[[transactionState]]’s pendingException.
-
If exception is
null, perform the following steps:-
If responseCode is
SCARD_S_SUCCESS, resolve transactionPromise. -
Otherwise, reject transactionPromise with an exception corresponding to responseCode.
-
-
Otherwise, reject transactionPromise with exception.
-
Set connection.[[transactionState]] to
null.
-
-
To end any settled transaction of a SmartCardConnection connection, perform the following steps:
-
If connection.[[transactionState]] is
null, abort these steps. -
Let disposition be connection.[[transactionState]]’s pendingDisposition.
-
If disposition is
null, abort these steps. -
Set connection.[[transactionState]]’s pendingDisposition to
null. -
End the transaction of connection with disposition.
To cancel outstanding [PCSC5] SCARDCOMM operations, call this.[[comm]].Cancel().
5.4. status() method
The status() method steps are:
-
Let promise be a new promise.
-
If this.[[context]].[[operationInProgress]] is
true, reject promise with a "InvalidStateError"DOMExceptionand return promise. -
If this.[[context]].[[activeReaderTransactions]][this.[[readerName]]] exists and is not equal to this, reject promise with a "
InvalidStateError"DOMExceptionand return promise. -
If this.[[comm]] is
null, reject promise with a "InvalidStateError"DOMExceptionand return promise. -
Set this.[[context]].[[operationInProgress]] to
true. -
Run the following steps in parallel:
-
Let pcscReader be an empty
STR[]. -
Let pcscState be a [PCSC5]
DWORDset to0. -
Let activeProtocol be a [PCSC5]
DWORDset to0. -
Let pcscAtr be a
BYTE[]big enough to hold any [ISO7816-3] Answer To Reset (ATR). -
Call this.[[comm]].
Status()with pcscReader, pcscState, activeProtocol and pcscAtr as output parameters. -
Let responseCode be the returned
RESPONSECODE. -
Queue a global task on the relevant global object of this using the smart card task source which performs the following steps:
-
If responseCode is not
SCARD_S_SUCCESS, reject promise with an exception corresponding to responseCode and abort these steps. -
Let state be a
SmartCardConnectionStatecorresponding to pcscState and activeProtocol. -
If state is
undefined, reject promise with an "UnknownError"DOMExceptionand abort these steps. -
Let status be a new
SmartCardConnectionStatus. -
Set status["
readerName"] to pcscReader. -
Set status["
state"] to state. -
Set status["
answerToReset"] to anArrayBufferwith the bytes that were written to pcscAtr. -
Resolve promise with status.
-
-
Return promise.
5.4.1. SmartCardConnectionStatus dictionary
dictionary {SmartCardConnectionStatus required DOMString ;readerName required SmartCardConnectionState ;state ArrayBuffer ; };answerToReset
readerName-
Name of the connected reader.
state-
Current state of the connection.
answerToReset-
The answer to reset (ATR) string from the card, if applicable.
5.4.1.1. SmartCardConnectionState enum
enum {SmartCardConnectionState ,"absent" ,"present" ,"swallowed" ,"powered" ,"negotiable" ,"t0" ,"t1" };"raw"
"absent"-
There is no card in the reader.
"present"-
There is a card in the reader, but it has not been moved into position for use.
"swallowed"-
There is a card in the reader in position for use. The card is not powered.
"powered"-
Power is being provided to the card, but the reader driver is unaware of the mode of the card.
"negotiable"-
The card has been reset and is awaiting PTS (protocol type selection) negotiation.
"t0"-
The card is in [ISO7816-3] T=0 protocol mode and a new protocol may not be negotiated.
"t1"-
The card is in [ISO7816-3] T=1 protocol mode and a new protocol may not be negotiated.
"raw"-
The card is in raw protocol mode and a new protocol may not be negotiated.
Given a [PCSC5] DWORD pcscState and a DWORD activeProtocol, a corresponding SmartCardConnectionState is created with the following steps:
-
If pcscState is [PCSC5]
SCARD_SWALLOWED, return "swallowed". -
If pcscState is [PCSC5]
SCARD_NEGOTIABLE, return "negotiable". -
If pcscState is [PCSC5]
SCARD_SPECIFIC, perform the following steps: -
Return
undefined.
5.5. control() method
The control(controlCode, data) method steps are:
-
Let promise be a new promise.
-
If this.[[context]].[[operationInProgress]] is
true, reject promise with a "InvalidStateError"DOMExceptionand return promise. -
If this.[[context]].[[activeReaderTransactions]][this.[[readerName]]] exists and is not equal to this, reject promise with a "
InvalidStateError"DOMExceptionand return promise. -
If this.[[comm]] is
null, reject promise with a "InvalidStateError"DOMExceptionand return promise. -
Set this.[[context]].[[operationInProgress]] to
true. -
Let pcscControlCode be a [PCSC5]
DWORDcontainingcontrolCode. -
Get a copy of the buffer source
dataand save the result in a [PCSC5]BYTE[]inBuffer. -
Let outBuffer be a [PCSC5]
BYTE[]large enough to hold any control command response. -
Let outBufferLength be a
DWORDset to0. -
Run the following steps in parallel:
-
Call this.[[comm]].
Control()with pcscControlCode, inBuffer, outBuffer and outBufferLength as arguments. -
Let responseCode be the returned
RESPONSECODE. -
Queue a global task on the relevant global object of this using the smart card task source which performs the following steps:
-
If responseCode is not
SCARD_S_SUCCESS, reject promise with an exception corresponding to responseCode and abort these steps. -
Let resultBytes be the first outBufferLength bytes of outBuffer.
-
Resolve promise with the result of creating an
ArrayBufferfrom resultBytes in this’s relevant Realm.
-
-
Return promise.
5.6. getAttribute() method
The getAttribute(tag) method steps are:
-
Let promise be a new promise.
-
If this.[[context]].[[operationInProgress]] is
true, reject promise with a "InvalidStateError"DOMExceptionand return promise. -
If this.[[context]].[[activeReaderTransactions]][this.[[readerName]]] exists and is not equal to this, reject promise with a "
InvalidStateError"DOMExceptionand return promise. -
If this.[[comm]] is
null, reject promise with a "InvalidStateError"DOMExceptionand return promise. -
Set this.[[context]].[[operationInProgress]] to
true. -
Run the following steps in parallel:
-
Let buffer be a [PCSC5]
BYTE[]large enough to hold this reader attribute, as determined by the platform’s [PCSC5] implementation. -
Call this.[[comm]].
GetReaderCapabilities()with pcscTag and buffer as arguments. -
Let responseCode be the returned
RESPONSECODE. -
Queue a global task on the relevant global object of this using the smart card task source which performs the following steps:
-
If responseCode is not
SCARD_S_SUCCESS, reject promise with an exception corresponding to responseCode and abort these steps. -
Let resultBytes be the bytes of buffer containing the attribute read.
-
Resolve promise with the result of creating an
ArrayBufferfrom resultBytes in this’s relevant Realm.
-
Return promise.
5.7. setAttribute() method
The setAttribute(tag, value) method steps are:
-
Let promise be a new promise.
-
If this.[[context]].[[operationInProgress]] is
true, reject promise with a "InvalidStateError"DOMExceptionand return promise. -
If this.[[context]].[[activeReaderTransactions]][this.[[readerName]]] exists and is not equal to this, reject promise with a "
InvalidStateError"DOMExceptionand return promise. -
If this.[[comm]] is
null, reject promise with a "InvalidStateError"DOMExceptionand return promise. -
Set this.[[context]].[[operationInProgress]] to
true. -
Get a copy of the buffer source
valueand save the result in a [PCSC5]BYTE[]buffer. -
Run the following steps in parallel:
-
Call this.[[comm]].
SetReaderCapabilities()with pcscTag and buffer as arguments. -
Let responseCode be the returned
RESPONSECODE. -
Queue a global task on the relevant global object of this using the smart card task source which performs the following steps:
-
If responseCode is not
SCARD_S_SUCCESS, reject promise with an exception corresponding to responseCode and abort these steps. -
Resolve promise.
-
-
Return promise.
6. SmartCardError interface
[Exposed =(DedicatedWorker ,SharedWorker ,Window ),SecureContext ,IsolatedContext ]interface :SmartCardError DOMException {(constructor optional DOMString = "",message SmartCardErrorOptions );options readonly attribute SmartCardResponseCode ; };responseCode
The responseCode attribute is the error or warning response
code returned by the related [PCSC5] method.
Given a [PCSC5] RESPONSECODE different from SCARD_S_SUCCESS, a
corresponding exception is
created with the following steps:
-
Let pcscCode be that
RESPONSECODE. -
If pcscCode is
SCARD_E_NO_SERVICE, return a new"no-service"SmartCardError. -
If pcscCode is
SCARD_E_NO_SMARTCARD, return a new"no-smartcard"SmartCardError. -
If pcscCode is
SCARD_E_NOT_READY, return a new"not-ready"SmartCardError. -
If pcscCode is
SCARD_E_NOT_TRANSACTED, return a new"not-transacted"SmartCardError. -
If pcscCode is
SCARD_E_PROTO_MISMATCH, return a new"proto-mismatch"SmartCardError. -
If pcscCode is
SCARD_E_READER_UNAVAILABLE, return a new"reader-unavailable"SmartCardError. -
If pcscCode is
SCARD_W_REMOVED_CARD, return a new"removed-card"SmartCardError. -
If pcscCode is
SCARD_W_RESET_CARD, return a new"reset-card"SmartCardError. -
If pcscCode is
SCARD_E_SERVER_TOO_BUSY, return a new"server-too-busy"SmartCardError. -
If pcscCode is
SCARD_E_SHARING_VIOLATION, return a new"sharing-violation"SmartCardError. -
If pcscCode is
SCARD_E_SYSTEM_CANCELLED, return a new"system-cancelled"SmartCardError. -
If pcscCode is
SCARD_E_UNKNOWN_READER, return a new"unknown-reader"SmartCardError. -
If pcscCode is
SCARD_W_UNPOWERED_CARD, return a new"unpowered-card"SmartCardError. -
If pcscCode is
SCARD_W_UNRESPONSIVE_CARD, return a new"unresponsive-card"SmartCardError. -
If pcscCode is
SCARD_W_UNSUPPORTED_CARD, return a new"unsupported-card"SmartCardError. -
If pcscCode is
SCARD_E_UNSUPPORTED_FEATURE, return a new"unsupported-feature"SmartCardError. -
If pcscCode is
SCARD_E_INVALID_PARAMETER, return a newTypeError. -
If pcscCode is
SCARD_E_INVALID_HANDLE, return a new "InvalidStateError"DOMException. -
If pcscCode is
SCARD_E_SERVICE_STOPPED, return a new "InvalidStateError"DOMException. -
If pcscCode is
SCARD_P_SHUTDOWN, return a new "AbortError"DOMException. -
Otherwise return a new "
UnknownError"DOMException.
6.1. SmartCardErrorOptions dictionary
dictionary {SmartCardErrorOptions required SmartCardResponseCode ; };responseCode
The responseCode member is the value for SmartCardError’s responseCode attribute.
6.2. SmartCardResponseCode enum
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"-
SCARD_E_NO_SERVICE in the [PCSC5] spec.
"no-smartcard"-
SCARD_E_NO_SMARTCARD in the [PCSC5] spec.
"not-ready"-
SCARD_E_NOT_READY in the [PCSC5] spec.
"not-transacted"-
SCARD_E_NOT_TRANSACTED in the [PCSC5] spec.
"proto-mismatch"-
SCARD_E_PROTO_MISMATCH in the [PCSC5] spec.
"reader-unavailable"-
SCARD_E_READER_UNAVAILABLE in the [PCSC5] spec.
"removed-card"-
SCARD_W_REMOVED_CARD in the [PCSC5] spec.
"reset-card"-
SCARD_W_RESET_CARD in the [PCSC5] spec.
"server-too-busy"-
The smart card resource manager is too busy to complete this operation.
"sharing-violation"-
SCARD_E_SHARING_VIOLATION in the [PCSC5] spec.
"system-cancelled"-
SCARD_E_SYSTEM_CANCELLED in the [PCSC5] spec.
"unknown-reader"-
SCARD_E_UNKNOWN_READER in the [PCSC5] spec.
"unpowered-card"-
SCARD_W_UNPOWERED_CARD in the [PCSC5] spec.
"unresponsive-card"-
SCARD_W_UNRESPONSIVE_CARD in the [PCSC5] spec.
"unsupported-card"-
SCARD_W_UNSUPPORTED_CARD in the [PCSC5] spec.
"unsupported-feature"-
SCARD_E_UNSUPPORTED_FEATURE in the [PCSC5] spec.
7. Security and Privacy Considerations
This API provides web applications with access to the host’s PC/SC smart card subsystem. This is a powerful feature that, if misused, could have significant negative impacts on a user’s security and privacy. This section outlines the threats considered and the normative requirements for user agents to mitigate them.
7.1. User Consent
Access to a smart card reader and any card present within it is a
powerful feature. A user agent MUST NOT
allow a web application to gain access to a SmartCardConnection
object without express permission.
User consent MUST be obtained for a specific
origin. The request for consent MUST be
triggered by a call to the connect() method. The
user agent MUST display a permission prompt
that clearly indicates which origin is requesting access and provides
the user with enough information to make an informed decision (for
example, by displaying the name of the smart card reader).
User agents SHOULD provide options for both transient (e.g., "for this session only") and persistent permission. To mitigate the risk of users forgetting they have granted persistent access, transient permission SHOULD be the default and more prominent option.
Users MUST be provided with a mechanism to view and revoke any previously granted permissions for this API.
7.2. Fingerprinting
The listReaders() method and the
answerToReset member of the
SmartCardReaderStateOut dictionary expose information that can be
used for passive fingerprinting. The presence and model of smart card
readers can reveal information about the user, such as whether they
are in a corporate environment. The Answer to Reset (ATR) can further
identify the type and issuer of a smart card.
While this specification does not require a permission prompt before
calling listReaders(), access to the entire API
is controlled by the "smart-card"
policy-controlled feature. This allows administrators or users to
disable the API for specific origins, mitigating the fingerprinting
risk.
7.3. Device and Data Integrity
The control() and
setAttribute() methods provide direct,
low-level access to the smart card reader hardware. A malicious site
could potentially use these methods to upload malicious firmware,
render the device inoperable, or otherwise interfere with its normal
operation.
Similarly, a malicious site with a connection to a smart card could repeatedly attempt PIN verification to permanently block the card, or access or overwrite sensitive, unprotected data.
The primary mitigation for these threats is the requirement for
express permission before a SmartCardConnection object is created,
as this gates access to all subsequent powerful methods.
7.4. Authentication and Spoofing
For authentication use cases, developers SHOULD prefer using the Web Authentication API wherever possible.
7.5. Cross-Origin Communication
A smart card with writable memory could be used as a side-channel for different origins to exchange data, bypassing other same-origin policies. The mitigation for this is that express permission is granted to a specific origin. An attack would require the user to grant smart card access to multiple, potentially malicious, origins.
7.6. Isolated Context
This API MUST only be exposed in an isolated context.
7.7. Document Lifecycle
To prevent documents from holding connections to sensitive hardware
while not in the user’s direct control, a user agent
MUST dispose of all active
SmartCardContext objects and their associated
SmartCardConnections when a document is no longer
fully active. This includes automatically disconnecting
any active connections as if disconnect() were
called.
8. Integrations
8.1. Permissions Policy
This specification defines a feature that controls whether the
methods exposed by the smartCard attribute on the
Navigator object may be used.
The feature name for this feature is "smart-card".
The default allowlist for this feature
is 'none'. User agents MAY override this
to 'self' for particular origins (for example based on user decision).