├── .github └── workflows │ └── auto-publish.yml ├── .gitignore ├── .pr-preview.json ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── background.md ├── behavioral-differences.md ├── index.html ├── tidyconfig.txt └── w3c.json /.github/workflows/auto-publish.yml: -------------------------------------------------------------------------------- 1 | name: deploy-spec 2 | on: 3 | pull_request: {} 4 | push: 5 | branches: [main] 6 | jobs: 7 | main: 8 | name: Build, Validate and Deploy Spec 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v3 12 | - uses: w3c/spec-prod@v2 13 | with: 14 | SOURCE: index.html 15 | TOOLCHAIN: respec 16 | GH_PAGES_BRANCH: gh-pages 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | package-lock.json 3 | package.json 4 | -------------------------------------------------------------------------------- /.pr-preview.json: -------------------------------------------------------------------------------- 1 | { 2 | "src_file": "index.html", 3 | "type": "respec" 4 | } 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Web Platform Incubator Community Group 2 | 3 | This repository is being used for work in the W3C Web Platform Incubator Community Group, governed by the [W3C Community License 4 | Agreement (CLA)](http://www.w3.org/community/about/agreements/cla/). To make substantive contributions, 5 | you must join the CG. 6 | 7 | If you are not the sole contributor to a contribution (pull request), please identify all 8 | contributors in the pull request comment. 9 | 10 | To add a contributor (other than yourself, that's automatic), mark them one per line as follows: 11 | 12 | ``` 13 | +@github_username 14 | ``` 15 | 16 | If you added a contributor by mistake, you can remove them in a comment with: 17 | 18 | ``` 19 | -@github_username 20 | ``` 21 | 22 | If you are making a pull request on behalf of someone else but you had no part in designing the 23 | feature, you can remove yourself with the above syntax. 24 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | All Reports in this Repository are licensed by Contributors 2 | under the 3 | [W3C Software and Document License](http://www.w3.org/Consortium/Legal/2015/copyright-software-and-document). 4 | 5 | Contributions to Specifications are made under the 6 | [W3C CLA](https://www.w3.org/community/about/agreements/cla/). 7 | 8 | Contributions to Test Suites are made under the 9 | [W3C 3-clause BSD License](https://www.w3.org/Consortium/Legal/2008/03-bsd-license.html) 10 | 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Web Smart Card Explainer 2 | 3 | ## Introduction 4 | 5 | The objective of this API is to enable [smart card](https://en.wikipedia.org/wiki/Smart_card) ([PC/SC](https://en.wikipedia.org/wiki/PC%2FSC)) applications to move to the Web platform. It gives them access to the PC/SC implementation (and card reader drivers) available in the host OS. 6 | 7 | See [background.md](background.md) for background information. 8 | 9 | There's also the [Unofficial draft of the Specification](https://wicg.github.io/web-smart-card/). 10 | 11 | ## Motivating Use Cases 12 | 13 | ### Identification and Authentication 14 | 15 | While there are other APIs that provide the right level of abstraction and security properties for identity on the Web, such as WebAuthn, there are domain-specific functions which can't be captured by such higher-level APIs. Take German ID cards for example: The [AusweisApp2](https://www.ausweisapp.bund.de/en/home) needs [native code](https://github.com/Governikus/AusweisApp2/tree/community/src/card/pcsc) to talk to the platform's PC/SC stack to access a USB smart card reader. It can issue control commands to the reader to establish and destroy [PACE](https://de.wikipedia.org/wiki/Password_Authenticated_Connection_Establishment) channels between the reader and the card (if the reader supports this feature). Websites from the German government then have to interact with the user's ID card via that native companion application. 16 | 17 | ### Remote Access Applications 18 | 19 | A remote access (aka "remote desktop") web app letting the remote machine access the host's card reader as if it were directly connected to it. Enabling PC/SC applications on that remote machine to work without modification, unaware that the card reader is not local. 20 | 21 | ### Badge reading kiosks 22 | 23 | A web-based kiosk could read even simple RFID badges via PC/SC and then display relevant information on a display. It's also not uncommon for such readers to need control commands to put them into the proper state for reading the particular type of card the application supports. 24 | 25 | ### Enable new and niche smart card use cases 26 | 27 | You can see smart cards as a platform to communicate with applications (also known as applets) running on small, resource-constricted, computers with tamper-proof memory. Thus, being an application-indepentent platform, there are in theory no restrictions to its possible use cases. 28 | 29 | While a higher level API is preferable, safer, more convenient or even necessary (think WebAuthN for FIDO2 applets), there's also a variety of both standardized and proprietary applets for which there's not enough "general usefulness" to justify a specific, higher-level, Web API for it. Or it's simply a new applet for a new use case. 30 | 31 | ## Non-goals 32 | 33 | * Provide an API that is at a higher level than PC/SC. 34 | * Solve all inconsistencies between the different native PC/SC stacks. 35 | 36 | ## Transmitting a command to a smart card present in a reader 37 | 38 | This shows all the steps necessary to transmit a command to a smart card. This includes the prerequisite steps of listing available readers and establishing a connection to the smart card present in a given reader. 39 | 40 | ```js 41 | try { 42 | let context = await navigator.smartCard.establishContext(); 43 | let readers = await context.listReaders(); 44 | 45 | // Assume there's at least one reader present. 46 | let reader = readers[0]; 47 | 48 | console.log("Connecting to the smart card inside " + reader); 49 | // A permission prompt might be displayed before the connection is established. 50 | let connectResult = await context.connect(reader, "shared", 51 | {preferredProtocols: ["t0", "t1"]}); 52 | 53 | console.log(`Connected with protocol ${connectResult.activeProtocol}`); 54 | 55 | let connection = connectResult.connection; 56 | 57 | // Send an APDU (application protocol data unit) and get the card's response 58 | let command = new Uint8Array([0x00, 0xA4, 0x04, 0x00, 0x0A, 0xA0, 0x00, 0x00, 59 | 0x00, 0x62, 0x03, 0x01, 0x0C, 0x06, 0x01]); 60 | 61 | let responseData = connection.transmit(command); 62 | console.log("Card responded with: " + responseData); 63 | 64 | await connection.disconnect(); 65 | } catch(ex) { 66 | console.warn("A Smart Card operation failed: " + ex); 67 | } 68 | ``` 69 | 70 | ## Transmissions in a transaction 71 | 72 | If a connection is established in `"shared"` access mode, to ensure consecutive transmissions are not disrupted by concurrent use from other applications, they must be done inside a transaction. 73 | 74 | ```js 75 | try { 76 | await connection.startTransaction(async () => { 77 | // A transaction has successfully started. 78 | let firstCommand = new Uint8Array([0x00, 0xA4, 0x04, 0x00, 0x0A, 0xA0, 0x00, 79 | 0x00, 0x00, 0x62, 0x03, 0x01, 0x0C, 0x06, 0x01]); 80 | let firstResponse = await connection.transmit(firstCommand); 81 | … 82 | await connection.transmit(someOtherCommand); 83 | … 84 | await connection.transmit(finalCommand); 85 | 86 | // Reset the card when ending the transaction. 87 | return "reset"; 88 | }); 89 | } catch (ex) { 90 | // Either the transaction failed to start, the callback 91 | // has thrown or the transaction failed to end. 92 | } 93 | ``` 94 | 95 | Upon calling `startTransaction()`, a transaction will be started with the card related to this connection. When successful, the given callback will be called. All interactions with the card done inside this callback will then be part of this transaction. The transaction is ended once the `Promise` returned by the callback settles. If the settled `Promise` is fulfilled, the transaction is ended with the card disposition it was fulfilled with. If that value is `undefined` or invalid, a `"leave"` card disposition is assumed. A rejected `Promise` also causes the transaction to be ended with a `"leave"` card disposition. 96 | 97 | ## Reacting to reader availability 98 | 99 | A common use case is reacting when a new card reader becomes available. On most platforms one can be notified of that using the special reader name `\\?PnP?\Notification`: 100 | 101 | ```js 102 | try { 103 | let context = await navigator.smartCard.establishContext(); 104 | 105 | let oldReaders = await context.listReaders(); 106 | 107 | let allReaders = await context.getStatusChange( 108 | [{readerName: "\\\\?PnP?\\Notification", currentState: {}}], 109 | {timeout: 10000}) 110 | .then( 111 | (statesOut) => { 112 | // A new reader was added. 113 | return context.listReaders(); 114 | } 115 | ); 116 | 117 | let newReaders = allReaders.filter(x => !oldReaders.includes(x)); 118 | console.log("Readers added: " + newReaders); 119 | } catch(ex) { 120 | console.warn("A Smart Card operation failed (or timed out): " + ex); 121 | } 122 | ``` 123 | 124 | ## Security and Privacy Considerations 125 | 126 | Smart cards offer tamper-resistant storage for private keys and other personal information as well as isolation for security-critical computations. Such devices can be used in identification and authentication applications. 127 | 128 | The security-sensitive nature of smart card applications and the fact that PC/SC is a rather low level API, which makes it powerful while at the same time hard (or impossible) to differentiate legitimate from malicious use, it is recommended that it is made available only to [Isolated Web Apps](https://github.com/reillyeon/isolated-web-apps/blob/main/README.md). Note that despite this recommendation, this API is described independently from it. 129 | 130 | ### Risks 131 | 132 | The scenarios described here refer to API access by websites in general and can be read as a justification for the recommendation of having it available only to Isolated Web Apps. 133 | 134 | #### Accessing sensitive information 135 | 136 | A malicious website might want to read information from the user's ID card (assuming it's inserted in a reader), to reveal their identity and obtain other private information. Such a card normally requires a PIN to proceed with this operation. Thus besides the user having to explicitly give permission for this website to establish connections with smart cards, that website will also have to lure the user into providing their card's PIN. Alternatively that website could simply try out guessed PINs against the inserted card, but that card would then go into a blocked state and would no longer be usable. 137 | 138 | There are cards however, or parts of a card, which are not PIN protected. But if it was decided not to protect them with a PIN one could assume that this information wasn't considered to be sensitive enough. 139 | 140 | #### Permanently disabling a smart card 141 | 142 | A malicious website either intentionally or by exhausting guess attempts could permanently disable a card after failing to verify its PIN consecutively. 143 | 144 | #### Misleading user into authenticating against a malicious website 145 | 146 | A malicious website could mislead the user into assuming they're using their smart card to authenticate against a legitimate service. This exposes the user to a man-in-the-middle attack, potentially granting the attacker access to the legitimate website the user thought they were accessing. 147 | WebAuthN is not susceptible to this attack. But with PC/SC being a lower-level API, the browser has no way to know this is happening since it cannot tell that the challenges being issued to the card don't actually come from that website. Strictly speaking, all the browser knows is that [APDU](https://en.wikipedia.org/wiki/Smart_card_application_protocol_data_unit)s are being transmitted to the card. 148 | 149 | #### Cross-origin communication 150 | 151 | Some smart cards have the ability to store arbitrary data without requiring PIN entry, thus different origins could share information by reading and writing data into the same card. But for this to be possible, the user would have to explicitly grant permission to both origins to access smart cards. 152 | 153 | #### Changing the state of a reader device 154 | 155 | The `SmartCardConnection.control` and `SmartCardConnection.setAttribute` methods are able to change the state and configuration of a card reader. 156 | Some readers have the ability of having their firmware updated via some vendor-specific control codes. An attacker could theoretically exploit this feature to upload a malicious firmware that intercepts or stores PINs contained in APDUs sent by legitimate PC/SC applications in order to later gain access to that card using those PINs. 157 | Alternatively, an attacker could aim to simply render the card reader unusable, either temporarily by setting an invalid mode that requires a reboot, or permanently by uploading a nonfunctional firmware. 158 | The user would have to explicitly grant permission for the malicious website to establish connections with card readers to make this possible. 159 | 160 | ### Fingerprinting 161 | 162 | The names of the available smart card readers provide an [active fingerprinting](https://www.w3.org/TR/fingerprinting-guidance/#dfn-active-fingerprinting) surface. This is made available via the `SmartCardContext.listReaders()` API call and does not require user consent. 163 | The name of a reader is also dependent on its driver, which is platform-specific. Ie, the same device when plugged on a Windows machine may show a different name than when plugged on a macOS, as the corresponding PC/SC stacks also come with their own different reader drivers and the reader name comes from its driver. 164 | 165 | The `SmartCardConnection.status()` and `SmartCardContext.getStatusChange()` methods extend that fingerprinting surface by providing `answerToReset` that allows one to also know the model and, in some cases, issuer of the smart card inserted in that reader. For example, the SIM card of a particular phone carrier is inserted in a particular card reader model. 166 | 167 | Some devices such as YubiKeys show up as both a smart card and its own card reader (ie, a card reader that has always the same card inserted). In this situation the ATR doesn't provide additional entropy as there is a one-to-one mapping between the reader name its constant ATR. 168 | 169 | #### Entropy 170 | 171 | Smart card readers are traditionally used in corporate or institutional machines, whereas their use in private computers by the general public is rare. Thus the mere presence of a smart card reader can already give out the category of its user (professional vs. private/leisure use). 172 | 173 | #### Persistence 174 | 175 | It persists as long as the same set of readers and inserted cards remains unchanged. 176 | 177 | #### Availability 178 | 179 | Only isolated web apps may access this fingerprinting surface. 180 | 181 | #### Scope 182 | 183 | The surface is consistent across origins. 184 | 185 | #### Mitigation 186 | 187 | A possible user-level mitigation is to simply remove readers (or cards) when not in active use (assuming they are not built in), which removes that fingerprinting surface. 188 | 189 | `navigator.smartCard.establishContext()`, which is an entrypoint to any of the API capabilities, is `Promise`-based and hence suitable for permission prompts and rejections. It is also guarded by the `"smart-card"` permission check. A browser may move to adding a permission prompt at this point - this however, along with the permission prompts before the actually powerful `connect()`, carries the threat of overwhelming the user with dialogues to the point where they are auto-accepting them. 190 | 191 | ## Considered alternatives 192 | 193 | ### Letting the user choose which card reader a website has access to 194 | 195 | Device APIs like WebUSB, Web Serial, Web Bluetooth and WebHID all implement a chooser model in which a website can only see and enumerate the devices that the user has explicitly allowed them to (via a device picker GUI). 196 | 197 | In the case of the Web Smart Card API, the privacy and security sensitive interface is essentially `SmartCardConnection`. Freely enumerating all smart card readers does open an active fingerprinting surface but nothing more than that. Therefore it was decided to have the permission prompting at the point a website tries to establish a connection with a card (and/or with the reader itself, as reader control commands and reader attributes can then be sent/read). This is the point where that powerful interface would be made available to the website. Ie, the [powerful feature](https://w3c.github.io/permissions/#dfn-powerful-feature) is `SmartCardConnection` and not the entire Web Smart Card API. 198 | 199 | Having said that, the asynchronous design of the `establishContext()` method does provide optionality for implementing a permission prompt before any reader information is provided to the page, but no implementation is currently pursuing this route. The potential reasoning behind not doing so is mentioned in the [Mitigation](#mitigation) section above. However, a browser setting allowing the user to manually remove the `"smart-card"` permission for the individual installed applications—or for all by default—would be a desirable feature. 200 | 201 | ### Access permissions based on card type 202 | 203 | The entity whose access needs permission is ultimately the smart card, as it contains sensitive data, and not the smart card reader. Thus the User Agent would grant/prompt/deny access based on the type of card that is inserted in a reader. Eg: one could end up with a card permissions configuration like the following (built by prompting for permission at different times): "Allow Web App Foo to access identification cards from maker X but deny it access to SIM cards from provider Y". 204 | 205 | But unlike USB devices, smart card type identification is very irregular. It's an array of up to 32 bytes (called ATR, standing for Answer to Reset) containing a varying combination of *optional* information about the card type, including data in proprietary format. Thus card type identification is essentially about [*fingerprinting* its ATR byte array](http://ludovic.rousseau.free.fr/softwares/pcsc-tools/smartcard_list.txt). This means that the User Agent cannot reliably display a human-readable string to the user when prompting for permission. All it can do is display something close to "Do you want to give permission for accessing the card type currently inserted on reader X?". Note that the ATR identifies the card type, not the individual card at hand (ie, it's not a unique identifier). 206 | 207 | Another limitation of the ATR fingerprinting is that the mapping between cards and their ATR strings is not well defined. Ie, cards that for all effects and purposes are of the same type may reply with different ATRs due to the manufacturer or the issuer/provider deciding to include different information. This would lead to an inconsistent user experience: it would be hard for the user to predict (or reason about) whether he would be prompted for permission when inserting a different card. One cannot expect the user to be aware of the peculiarities of ATR arrays that ultimately led to the User Agent decision. 208 | 209 | ### Access permissions based on card readers 210 | 211 | Unlike USB devices which have well defined vendor and product IDs, card readers cannot be reliably identified in PC/SC. Card readers are identified only by their names (even though they're actually USB devices as well). The name string is meant to be human readable and its only requirement is that it's unique among the currently attached readers. For a given reader device, the value of its PC/SC name string depends both on the PC/SC implementation and on the PC/SC reader driver at hand. This is particularly problematic when there are multiple readers of the same model connected to the host as their name strings will be prefixed or suffixed with an index to avoid collisions. Thus it's possible that the same reader, on the same host, will get a different name string when reattached to the host. 212 | 213 | It's possible to get the USB vendor and product IDs of a reader by sending a `GET_TLV_PROPERTIES` control command to that reader driver. But that doesn't solve our problem since a reader driver might not support this feature and even if it does, it requires establishing a direct connection to that reader and sending a control command through it. Those operations are exposed in the Web API and therefore it's up to the Web API user to request them (and handle its results and possible errors) and not the Web API implementation itself. 214 | 215 | ### SCardConnection.status as an attribute with a onstatuschange event handler 216 | 217 | The `SmartCardConnection.status()` method of this Web API exposes the information provided by the `SCARDCOMM::Status` method in the PC/SC spec (or `SmartCardStatus` function in winscard.h and PCSClite). There's no event-based procedure to get this information. Thus if `SmartCardConnection.status` was a changeable attribute in this Web API it would mean that its implementation would necessarily have to do polling of the aforementioned PC/SC function. 218 | 219 | ### Abstracting away the concept of a card reader 220 | 221 | Even though the purpose of this API is to enable websites to read smart cards, and thus the readers are merely enablers or channels for that, it's still useful to expose card readers in the API. One use case is that some readers need to have control commands sent to them to put them in a particular mode where they can read the types of cards that an application is interested in or supports. Ie, for configuring, initializing, or setting up a card reader. 222 | 223 | ## Acknowledgements 224 | * Reilly Grant <reillyg@google.com> 225 | * Domenic Denicola <domenic@google.com> 226 | * Maksim Ivanov <emaxx@google.com> 227 | -------------------------------------------------------------------------------- /background.md: -------------------------------------------------------------------------------- 1 | # Web Smart Card - Background 2 | 3 | The [PS/SC Workgroup specification](https://pcscworkgroup.com/) defines what a compliant API for smart card access must look like. The existing compliant implementations are [winscard](https://docs.microsoft.com/en-us/windows/win32/api/winscard/) on Windows (which is the de facto canonical implementation of PC/SC) and [PCSClite](https://pcsclite.apdu.fr/), a free-software implementation providing an API compatible with winscard.h. The [CCID project](https://ccid.apdu.fr/) provides PCSClite with free software smart card and card reader drivers. 4 | 5 | PC/SC support in platforms is as follows: 6 | * Microsoft Windows: ships with winscard (out of the box). 7 | * macOS: ships with a forked version of PCSClite (out of the box). 8 | * Linux: PCSClite can be installed. 9 | * ChromeOS: Available via the [Smart Card Connector](https://chrome.google.com/webstore/detail/smart-card-connector/khpfeaanjngmcnplbdlpegiifgpfgdco?hl=en) extension, which bundles PCSClite and CCID compiled to PNaCl/WebAssembly. 10 | 11 | Even though the existing PC/SC implementations share pretty much the same C API, meaning that a C application (when properly written) can be compiled against both winscard (on Windows) and PCSClite (on macOS and Linux) with little to no modifications, their actual behaviors differ significantly ([some examples](behavioral-differences.md)). Such differences cannot be ignored or be transparent to users of a Web API that is at the same abstraction level, providing the same concepts and features, as that C PC/SC API. 12 | -------------------------------------------------------------------------------- /behavioral-differences.md: -------------------------------------------------------------------------------- 1 | # Behavioral differences between PC/SC native implementations 2 | 3 | Tests made with a "Yubico YubiKey OTP+FIDO+CCID" (Vendor ID `1050`, Device ID `0407`) and a Gemalto IDBridge CT30 (Vendor ID `08e6`, Device ID `3437`). When not specified, it's implied that a YubiKey was used. 4 | 5 | Behavioral differences can be attributed to both different PC/SC implementations and to different smartcard reader drivers. 6 | 7 | 8 | ## SmartCardReader.connect() 9 | 10 | 11 | 12 | 13 | 15 | 17 | 19 | 20 | 21 | 23 | 24 | 25 | 27 | 29 | 31 | 32 | 33 | 35 | 37 | 39 | 40 | 41 | 43 | 45 | 47 | 49 | 50 | 51 | 53 | 54 | 55 | 57 | 59 | 61 | 62 | 63 | 65 | 67 | 69 | 70 | 71 | 73 | 75 | 77 | 79 | 80 | 81 | 83 | 84 | 85 | 89 | 91 | 93 | 94 | 95 | 99 | 101 | 103 | 104 | 105 | 109 | 111 | 113 | 114 |
SmartCardReader.connect 14 | MS Windows 16 | PCSClite macOS 18 |
if a transaction is ongoing: 22 |
26 | shared mode 28 | blocks 30 |
34 | exclusive mode 36 | fails with SCARD_E_SHARING_VIOLATION 38 |
42 | direct mode 44 | fails with SCARD_E_SHARING_VIOLATION (behaves as exclusive) 46 | works (behaves as shared) 48 |
if another connection has exclusive mode: 52 |
56 | shared mode 58 | SCARD_E_SHARING_VIOLATION 60 |
64 | exclusive mode 66 | SCARD_E_SHARING_VIOLATION 68 |
72 | direct mode 74 | SCARD_E_SHARING_VIOLATION 76 | works, but there's a protocol mismatch on transmission 78 |
direct mode, without concurrent connections: 82 |

86 | preferredProtocols: T0|T1

87 | 88 |
activeProtocol T1 90 | activeProtocol T0|T1 (ie, transmitting will fail) 92 |

96 | preferredProtocols undefined

97 | 98 |
activeProtocol T1 100 | error "invalid value given" 102 |

106 | preferredProtocols raw

107 | 108 |
SCARD_E_NOT_READY 110 | activeProtocol raw 112 |
115 | 116 | 117 | 118 | ## SmartCardConnection.startTransaction() 119 | 120 | On Microsoft Windows, winscard automatically resets the card if a transaction is kept idle (ie, without any commands being issued) for more than 5 seconds. PCSClite has no such behavior (an idle transaction can be kept indefinitely). 121 | 122 | 123 | ## SmartCardConnection.status() 124 | 125 | Note that the status in native PC/SC APIs by flags that can be combined and have overlapping meaning (specific ⊂ powered ⊂ present ), unlike in the Web API where status is an enumeration. 126 | 127 | This table shows the content of an SCardStatus call after a SCardConnect using the parameters specified in the leftmost column. 128 | 129 | 130 | 131 | 132 | 134 | 136 | 138 | 140 | 141 | 142 | 144 | 146 | 148 | 150 | 151 | 152 | 154 | 156 | 158 | 160 | 161 | 162 | 164 | 166 | 168 | 169 | 170 | 172 | 174 | 176 | 178 | 179 | 180 | 182 | 184 | 186 | 188 | 189 | 190 | 192 | 194 | 196 | 198 | 199 | 200 | 202 | 204 | 206 | 208 | 209 | 210 | 212 | 214 | 216 | 218 | 219 | 220 | 222 | 224 | 226 | 228 | 229 | 230 | 232 | 234 | 236 | 240 | 241 | 242 | 244 | 246 | 248 | 250 | 251 |
device 133 | connect() parameters: shared mode, preferred protocols 135 | MS Windows 137 | PCSClite macOS 139 |
YubiKey 143 | shared, T0|T1 145 | present | powered, T1 147 | present | powered | specific, T1 149 |
Gemalto (with card) 153 | shared, T0|T1 155 | present | powered, T1 157 | present | powered | specific, T1 159 |
Gemalto (card removed after connection established) 163 | shared, T0|T1 165 | SCARD_W_REMOVED_CARD 167 |
Gemalto (card removed after connection established and then reinserted) 171 | shared, T0|T1 173 | SCARD_W_REMOVED_CARD 175 | SCARD_W_RESET_CARD 177 |
Gemalto (reader removed after connection established) 181 | shared, T0|T1 183 | SCARD_E_SERVICE_STOPPED 185 | SCARD_E_READER_UNAVAILABLE 187 |
YubiKey 191 | direct, undefined 193 | absent | powered, undefined 195 | Error: invalid value 197 |
Gemalto (with card) 201 | direct, undefined 203 | present, undefined 205 | Error: invalid value 207 |
Gemalto (without card) 211 | direct, undefined 213 | absent, undefined 215 | Error: invalid value 217 |
Gemalto (card inserted after connection established) 221 | direct, undefined 223 | absent | present, undefined 225 | N.A. 227 |
Gemalto (card inserted after connection established) 231 | direct, raw 233 | N.A. 235 | 0x7fb7, raw 237 |

238 | then SCARD_W_RESET_CARD 239 |

YubiKey 243 | direct, raw 245 | SCARD_E_NOT_READY 247 | present | powered | specific, raw 249 |
252 | 253 | 254 | On Windows, when a reader device is removed after a connection is established not only the connection handle is invalidated but also the context handle (resource manager context) as well. Meaning that one has to establish a new resource manager context to continue operation, whereas in PCSClite the context remains unaffected by the reader removal. 255 | 256 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 23 | 24 | 25 |

Web Smart Card API

26 |
27 |

28 | The objective of this API is to enable smart card (PC/SC) applications 29 | to move to the Web Platform. It gives them access to the PC/SC 30 | implementation (and card reader drivers) available in the host OS. 31 | 32 | There is also a companion explainer document. 33 |

34 |

35 | 36 |
37 | 38 |
39 | 40 |
41 |

Extensions to the {{Navigator}} interface

42 |
  43 |         [Exposed=Window, SecureContext]
  44 |         partial interface Navigator {
  45 |           [SameObject] readonly attribute SmartCardResourceManager smartCard;
  46 |         };
  47 |       
48 | 49 |

smartCard attribute

50 |

When getting, the {{Navigator/smartCard}} attribute always returns the same 51 | instance of the {{SmartCardResourceManager}} object.

52 |
53 | 54 |
55 |

Extensions to the {{WorkerNavigator}} interface

56 |
  57 |         [Exposed=(DedicatedWorker, SharedWorker), SecureContext]
  58 |         partial interface WorkerNavigator {
  59 |           [SameObject] readonly attribute SmartCardResourceManager smartCard;
  60 |         };
  61 |       
62 | 63 |

smartCard attribute

64 |

When getting, the {{Navigator/smartCard}} attribute always returns the same 65 | instance of the {{SmartCardResourceManager}} object.

66 |
67 | 68 |
69 |

SmartCardResourceManager interface

70 |
  71 |         [Exposed=(DedicatedWorker, SharedWorker, Window), SecureContext]
  72 |         interface SmartCardResourceManager {
  73 |           Promise<SmartCardContext> establishContext();
  74 |         };
  75 |       
76 |

Methods on this interface complete asynchronously, queuing 77 | work on the smart card task source.

78 |
79 |

establishContext() method

80 |

Requests a PC/SC context from the platform's PC/SC stack.

81 | The {{SmartCardResourceManager/establishContext()}} method steps are: 82 |
    83 |
  1. 84 | If [=this=]'s [=relevant global object=]'s [=associated Document=] is 85 | not [=allowed to use=] the [=policy-controlled feature=] named 86 | "[=policy-controlled feature/smart-card=]", [=exception/throw=] a 87 | "{{SecurityError}}" {{DOMException}}. 88 |
  2. 89 |
  3. Let |promise:Promise| be [=a new promise=].
  4. 90 |
  5. Run the following steps [=in parallel=]: 91 |
      92 |
    1. Let |resourceManager:RESOURCEMANAGER| be a new instance of the 93 | platform's [[PCSC5]] `RESOURCEMANAGER` class.
    2. 94 |
    3. Invoke the `EstablishContext` method of |resourceManager| with 95 | a "system" `Scope` parameter.
    4. 96 |
    5. If the returned `RESPONSECODE` is not `SCARD_S_SUCCESS`, perform 97 | the following steps: 98 |
        99 |
      1. Destroy |resourceManager|.
      2. 100 |
      3. [=Queue a global task=] on the [=relevant global object=] of 101 | [=this=] using the [=smart card task source=] to [=reject=] 102 | |promise| with a {{SmartCardError/corresponding}} 103 | [=exception=].
      4. 104 |
      105 |
    6. 106 |
    7. Otherwise, perform the following steps: 107 |
        108 |
      1. Let |context:SmartCardContext| be a [=new=] 109 | {{SmartCardContext}} whose 110 | {{SmartCardContext/[[resourceManager]]}} internal slot is set 111 | to |resourceManager|.
      2. 112 |
      3. [=Queue a global task=] on the [=relevant global object=] 113 | of [=this=] using the [=smart card task source=] to 114 | [=resolve=] |promise| with |context|.
      4. 115 |
      116 |
    8. 117 |
    118 |
  6. 119 |
  7. Return |promise|.
  8. 120 |
121 |
122 |
123 | 124 |
125 |

SmartCardContext interface

126 |

A context for communicating with the PC/SC resource manager.

127 |
 128 |         [Exposed=(DedicatedWorker, SharedWorker, Window), SecureContext]
 129 |         interface SmartCardContext {
 130 |           Promise<sequence<DOMString>> listReaders();
 131 | 
 132 |           Promise<sequence<SmartCardReaderStateOut>> getStatusChange(
 133 |               sequence<SmartCardReaderStateIn> readerStates,
 134 |               optional SmartCardGetStatusChangeOptions options = {});
 135 | 
 136 |           Promise<SmartCardConnectResult> connect(
 137 |               DOMString readerName,
 138 |               SmartCardAccessMode accessMode,
 139 |               optional SmartCardConnectOptions options = {});
 140 |         };
 141 |       
142 |

Instances of {{SmartCardContext}} are created with the internal slots 143 | described in the following table:

144 | 145 | 146 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 175 | 176 |
Internal slot 147 | Initial value 148 | Description (non-normative) 149 |
[[\resourceManager]]`null`The platform's [[PCSC5]] `RESOURCEMANAGER` to be used.
[[\operationInProgress]]`false`Whether there is an ongoing PC/SC operation in this context.
[[\connections]]An empty [=ordered set=]The existing {{SmartCardConnection}}s created by this context.
[[\tracker]]`null`A [[PCSC5]] `SCARDTRACK` instance.
[[\signal]]`null`The {{AbortSignal}} of the outstanding 174 | {{SmartCardContext/getStatusChange()}} call, if any.
177 | 183 |
184 |

listReaders() method

185 |

The {{SmartCardContext/listReaders()}} method steps 186 | are:

187 |
    188 |
  1. Let |promise:Promise| be [=a new promise=].
  2. 189 |
  3. If [=this=].{{SmartCardContext/[[operationInProgress]]}} is 190 | `true`, [=reject=] |promise| with a "{{InvalidStateError}}" 191 | {{DOMException}} and return |promise|.
  4. 192 |
  5. Set [=this=].{{SmartCardContext/[[operationInProgress]]}} to 193 | `true`.
  6. 194 |
  7. Run the following steps [=in parallel=]: 195 |
      196 |
    1. Let |resourceQuery:RESOURCEQUERY| be a new instance of the 197 | platform's [[PCSC5]] `RESOURCEQUERY` class, with 198 | [=this=].{{SmartCardContext/[[resourceManager]]}} as its 199 | constructor input parameter.
    2. 200 | 201 |
    3. Let |groups:array of STR| be the platform's [[PCSC5]] `STR[]` 202 | containing the list of group names that is equivalent to "all 203 | readers in the system" in that platform. 204 | 206 |
    4. 207 |
    5. Let |pcscReaders:array of STR| be an empty `STR[]`. 208 |
    6. Invoke the `ListReaders` method of |resourceQuery| with 209 | |groups| as input and |pcscReaders| as output parameters.
    7. 210 |
    8. Let |responseCode:RESPONSECODE| be the returned 211 | `RESPONSECODE`.
    9. 212 |
    10. Destroy |resourceQuery|.
    11. 213 |
    12. [=Queue a global task=] on the [=relevant global object=] of 214 | [=this=] using the [=smart card task source=] which performs the 215 | following steps: 216 |
        217 |
      1. [=Clear the operationInProgress=] of [=this=].
      2. 218 |
      3. If |responseCode| is not `SCARD_S_SUCCESS`: 219 |
          220 |
        1. If |responseCode| is `SCARD_E_NO_READERS_AVAILABLE`, 221 | [=resolve=] |promise| with an empty `sequence` of 222 | {{DOMString}}. 223 | 229 |
        2. 230 |
        3. Otherwise, [=reject=] |promise| with an 231 | [=exception=] {{SmartCardError/corresponding}} to 232 | |responseCode|.
        4. 233 |
        234 |
      4. 235 |
      5. Otherwise, [=resolve=] |promise| with a `sequence` of 236 | {{DOMString}} equivalent to |pcscReaders|.
      6. 237 |
      238 |
    13. 239 |
    240 |
  8. 241 |
  9. Return |promise|.
  10. 242 |
243 |
244 |
245 |

getStatusChange() method

246 |

The {{SmartCardContext/getStatusChange(readerStates, options)}} method steps 247 | are:

248 |
    249 |
  1. Let |promise:Promise| be [=a new promise=].
  2. 250 |
  3. If [=this=].{{SmartCardContext/[[operationInProgress]]}} is 251 | `true`, [=reject=] |promise| with a "{{InvalidStateError}}" 252 | {{DOMException}} and return |promise|.
  4. 253 |
  5. If 254 | |options:SmartCardGetStatusChangeOptions|["{{SmartCardGetStatusChangeOptions/signal}}"] 255 | [=map/exists=], run the following steps: 256 |
      257 |
    1. Let |signal:AbortSignal| be 258 | |options|["{{SmartCardGetStatusChangeOptions/signal}}"].
    2. 259 |
    3. If |signal| is [=AbortSignal/aborted=], [=reject=] |promise| 260 | with |signal|'s [=AbortSignal/abort reason=] and return 261 | |promise|.
    4. 262 |
    5. Set [=this=].{{SmartCardContext/[[signal]]}} to |signal|
    6. 263 |
    7. [=AbortSignal/Add=] the {{SmartCardContext/Cancel the outstanding 264 | GetStatusChange}} algorithm to |signal|.
    8. 265 |
    266 |
  6. 267 |
  7. Let |pcscTimeout:DWORD| be a [[PCSC5]] `DWORD` set to [[PCSC5]] 268 | `INFINITE`.
  8. 269 |
  9. If 270 | |options|["{{SmartCardGetStatusChangeOptions/timeout}}"] 271 | [=map/exists=], set |pcscTimeout| to 272 | |options|["{{SmartCardGetStatusChangeOptions/timeout}}"].
  10. 273 |
  11. Let |pcscReaderStates:array of SCARD_READERSTATE| be a [[PCSC5]] 274 | `SCARD_READERSTATE[]` [=SmartCardReaderStateIn/corresponding=] to 275 | |readerStates:sequence<SmartCardReaderStateIn>|.
  12. 276 |
  13. Set [=this=].{{SmartCardContext/[[operationInProgress]]}} to 277 | `true`.
  14. 278 |
  15. Set [=this=].{{SmartCardContext/[[tracker]]}} to a new instance of the 279 | platform's [[PCSC5]] `SCARDTRACK` class, with 280 | [=this=].{{SmartCardContext/[[resourceManager]]}} as its 281 | constructor input parameter.
  16. 282 |
  17. Run the following steps [=in parallel=]: 283 |
      284 |
    1. Call 285 | [=this=].{{SmartCardContext/[[tracker]]}}.`GetStatusChange()` 286 | with |pcscReaderStates| and |pcscTimeout| as input parameters.
    2. 287 |
    3. Let |responseCode:RESPONSECODE| be the returned 288 | [[PCSC5]] `RESPONSECODE`.
    4. 289 |
    5. [=Queue a global task=] on the [=relevant global object=] of 290 | [=this=] using the [=smart card task source=] which performs the 291 | following steps: 292 |
        293 |
      1. Set [=this=].{{SmartCardContext/[[tracker]]}} to `null`.
      2. 294 |
      3. [=Clear the operationInProgress=] of [=this=].
      4. 295 |
      5. Let |abortReason| be {{undefined}}.
      6. 296 |
      7. If [=this=].{{SmartCardContext/[[signal]]}} is not `null`, 297 | run the following steps: 298 |
          299 |
        1. If [=this=].{{SmartCardContext/[[signal]]}} is 300 | [=AbortSignal/aborted=] then set |abortReason| to 301 | [=this=].{{SmartCardContext/[[signal]]}}'s 302 | [=AbortSignal/abort reason=].
        2. 303 |
        3. [=AbortSignal/Remove=] the {{SmartCardContext/cancel the 304 | outstanding GetStatusChange}} algorithm from 305 | [=this=].{{SmartCardContext/[[signal]]}}.
        4. 306 |
        5. Set [=this=].{{SmartCardContext/[[signal]]}} to 307 | `null`.
        6. 308 |
        309 |
      8. 310 |
      9. If |responseCode| is not `SCARD_S_SUCCESS`, run the 311 | following steps: 312 |
          313 |
        1. If |responseCode| is `SCARD_E_CANCELLED` and 314 | |abortReason| is not {{undefined}} then [=reject=] 315 | |promise| with |abortReason|.
        2. 316 |
        3. Otherwise, [=reject=] |promise| with an [=exception=] 317 | {{SmartCardError/corresponding}} to |responseCode|.
        4. 318 |
        5. Return.
        6. 319 |
        320 |
      10. 321 |
      11. Let 322 | |readerStatesOut:sequence<SmartCardReaderStateOut>| be 323 | a sequence of {{SmartCardReaderStateOut}} 324 | [=SmartCardReaderStateOut/corresponding=] to 325 | |pcscReaderStates|.
      12. 326 |
      13. [=Resolve=] |promise| with |readerStatesOut|.
      14. 327 |
      328 |
    6. 329 |
    330 |
  18. 331 |
  19. Return |promise|.
  20. 332 |
333 | 334 |
335 |

SmartCardReaderStateIn dictionary

336 |
 337 |             dictionary SmartCardReaderStateIn {
 338 |               required DOMString readerName;
 339 |               required SmartCardReaderStateFlagsIn currentState;
 340 |               unsigned long currentCount;
 341 |             };
 342 |           
343 | 344 |
345 |
readerName member
346 |
Name of the smart card reader.
347 | 348 |
currentState member
349 |
The current state of that smart card reader as known by the 350 | application.
351 | 352 |
currentCount member
353 |
The current number of card insertion and removal events in this 354 | reader, as known by the application.
355 |
356 |

Given a sequence of {{SmartCardReaderStateIn}} named 357 | |readerStates:sequence<SmartCardReaderStateIn>|, a 358 | corresponding 359 | [[PCSC5]] `SCARD_READERSTATE[]` is created with the following 360 | steps:

361 |
    362 |
  1. Let |pcscReaderStates:array of SCARD_READERSTATE| be an empty 363 | `SCARD_READERSTATE[]`.
  2. 364 |
  3. [=list/For each=] |stateIn:SmartCardReaderStateIn| in |readerStates|: 365 |
      366 |
    1. Let |pcscState:SCARD_READERSTATE| be a `SCARD_READERSTATE`.
    2. 367 |
    3. Set |pcscState|.`Reader` to 368 | |stateIn|["{{SmartCardReaderStateIn/readerName}}"].
    4. 369 |
    5. Set |pcscState|.`CurrentState` to the `DWORD` 370 | [=SmartCardReaderStateFlagsIn/corresponding=] 371 | to |stateIn|["{{SmartCardReaderStateIn/currentState}}"].
    6. 372 |
    7. If |stateIn|["{{SmartCardReaderStateIn/currentCount}}"] 373 | [=map/exists=], [=SmartCardContext/set the high word=] of 374 | |pcscState|.`CurrentState` to 375 | |stateIn|["{{SmartCardReaderStateIn/currentCount}}"].
    8. 376 |
    9. Set |pcscState|.`EventState` to zero.
    10. 377 |
    11. [=list/Append=] |pcscState| to |pcscReaderStates|.
    12. 378 |
    379 |
  4. 380 |
  5. Return |pcscReaderStates|.
  6. 381 |
382 | 383 |
384 |
SmartCardReaderStateFlagsIn dictionary
385 | 386 |
 387 |               dictionary SmartCardReaderStateFlagsIn {
 388 |                 boolean unaware = false;
 389 |                 boolean ignore = false;
 390 |                 boolean unavailable = false;
 391 |                 boolean empty = false;
 392 |                 boolean present = false;
 393 |                 boolean exclusive = false;
 394 |                 boolean inuse = false;
 395 |                 boolean mute = false;
 396 |                 boolean unpowered = false;
 397 |               };
 398 |             
399 | 400 |
401 |
unaware member
402 |
The application is unaware of the current state, and would like 403 | to know.
404 | 405 |
ignore member
406 |
The application is not interested in this reader, and it should 407 | not be considered during monitoring operations.
408 | 409 |
unavailable member
410 |
The application believes that this reader is not available for 411 | use.
412 | 413 |
empty member
414 |
The application believes that there is not a card in the 415 | reader.
416 | 417 |
present member
418 |
The application believes that there is a card in the 419 | reader.
420 | 421 |
exclusive member
422 |
The application believes that the card in the reader is 423 | allocated for exclusive use by another application.
424 | 425 |
inuse member
426 |
The application believes that the card in the reader is in use 427 | by one or more other applications, but may be connected to in 428 | shared mode.
429 | 430 |
mute member
431 |
The application believes that there is an unresponsive card in 432 | the reader.
433 | 434 |
unpowered member
435 |
The application believes that the card in the reader has not 436 | been powered up.
437 |
438 | 439 |

The [[PCSC5]] `DWORD` 440 | corresponding 441 | to a given {{SmartCardReaderStateFlagsIn}} is created with the 442 | following steps:

443 |
    444 |
  1. Let |flagsIn:SmartCardReaderStateFlagsIn| be the given 445 | {{SmartCardReaderStateFlagsIn}}.
  2. 446 |
  3. Let |pcscFlags:DWORD| be a `DWORD` set to zero.
  4. 447 |
  5. If |flagsIn|["{{SmartCardReaderStateFlagsIn/unaware}}"] is 448 | `true`, [=add a flag|add=] [[PCSC5]] `SCARD_STATE_UNAWARE` to 449 | |pcscFlags|.
  6. 450 |
  7. If |flagsIn|["{{SmartCardReaderStateFlagsIn/ignore}}"] is 451 | `true`, [=add a flag|add=] [[PCSC5]] `SCARD_STATE_IGNORE` to 452 | |pcscFlags|.
  8. 453 |
  9. If |flagsIn|["{{SmartCardReaderStateFlagsIn/unavailable}}"] 454 | is `true`, [=add a flag|add=] [[PCSC5]] 455 | `SCARD_STATE_UNAVAILABLE` to |pcscFlags|.
  10. 456 |
  11. If |flagsIn|["{{SmartCardReaderStateFlagsIn/empty}}"] is 457 | `true`, [=add a flag|add=] [[PCSC5]] `SCARD_STATE_EMPTY` to 458 | |pcscFlags|.
  12. 459 |
  13. If |flagsIn|["{{SmartCardReaderStateFlagsIn/present}}"] is 460 | `true`, [=add a flag|add=] [[PCSC5]] `SCARD_STATE_PRESENT` to 461 | |pcscFlags|.
  14. 462 |
  15. If |flagsIn|["{{SmartCardReaderStateFlagsIn/exclusive}}"] is 463 | `true`, [=add a flag|add=] [[PCSC5]] `SCARD_STATE_EXCLUSIVE` to 464 | |pcscFlags|.
  16. 465 |
  17. If |flagsIn|["{{SmartCardReaderStateFlagsIn/inuse}}"] is 466 | `true`, [=add a flag|add=] [[PCSC5]] `SCARD_STATE_INUSE` to 467 | |pcscFlags|.
  18. 468 |
  19. If |flagsIn|["{{SmartCardReaderStateFlagsIn/mute}}"] is 469 | `true`, [=add a flag|add=] `SCARD_STATE_MUTE` to 470 | |pcscFlags|. 471 |
  20. 472 |
  21. If |flagsIn|["{{SmartCardReaderStateFlagsIn/unpowered}}"] is 473 | `true`, [=add a flag|add=] `SCARD_STATE_UNPOWERED` to 474 | |pcscFlags|.
  22. 475 |
  23. Return |pcscFlags|.
  24. 476 |
477 | 482 |
483 |
484 |
485 |

SmartCardReaderStateOut dictionary

486 |

The actual state of a smart card reader.

487 | 488 |
 489 |             dictionary SmartCardReaderStateOut {
 490 |               required DOMString readerName;
 491 |               required SmartCardReaderStateFlagsOut eventState;
 492 |               required unsigned long eventCount;
 493 |               ArrayBuffer answerToReset;
 494 |             };
 495 |           
496 | 497 |
498 |
readerName member
499 |
Name of the smart card reader.
500 | 501 |
eventState member
502 |
The actual state of that smart card reader.
503 | 504 |
eventCount member
505 |
The actual number of card insertion and removal events in this 506 | reader.
507 | 508 |
answerToReset member
509 |
The inserted card's [[ISO7186-3]] Answer To Reset (ATR), if 510 | applicable.
511 |
512 | 513 |

Given a [[PCSC5]] `SCARD_READERSTATE[]` named 514 | |pcscReaderStates:array of SCARD_READERSTATE|, a corresponding sequence of 516 | {{SmartCardReaderStateOut}} is created with the following steps:

517 |
    518 |
  1. Let |readerStatesOut:sequence<SmartCardReaderStateOut>| be 519 | an empty sequence of {{SmartCardReaderStateOut}}.
  2. 520 |
  3. [=list/For each=] |pcscState:SCARD_READERSTATE| in 521 | |pcscReaderStates|: 522 |
      523 |
    1. Let |stateOut:SmartCardReaderStateOut| be a 524 | {{SmartCardReaderStateOut}}.
    2. 525 |
    3. Set |stateOut|["{{SmartCardReaderStateOut/readerName}}"] to 526 | |pcscState|.`Reader`.
    4. 527 |
    5. Set |stateOut|["{{SmartCardReaderStateOut/eventState}}"] to 528 | the {{SmartCardReaderStateFlagsOut}} dictionary 529 | [=SmartCardReaderStateFlagsOut/corresponding=] 530 | to |pcscState|.`EventState`.
    6. 531 |
    7. Set |stateOut|["{{SmartCardReaderStateOut/eventCount}}"] to 532 | the [=SmartCardContext/high word=] of |pcscState|.`EventState`. 533 | 548 |
    8. 549 |
    9. If the platform's `SCARD_READERSTATE` structure has a member 550 | containing the card's [[ISO7186-3]] Answer To Reset, set 551 | |stateOut|["{{SmartCardReaderStateOut/answerToReset}}"] to 552 | that value.
    10. 553 |
    11. [=list/Append=] |stateOut| to |readerStatesOut|.
    12. 554 |
    555 |
  4. 556 |
  5. Return |readerStatesOut|.
  6. 557 |
558 | 559 |
560 |
SmartCardReaderStateFlagsOut dictionary
561 | 562 |
 563 |               dictionary SmartCardReaderStateFlagsOut {
 564 |                 boolean ignore = false;
 565 |                 boolean changed = false;
 566 |                 boolean unavailable = false;
 567 |                 boolean unknown = false;
 568 |                 boolean empty = false;
 569 |                 boolean present = false;
 570 |                 boolean exclusive = false;
 571 |                 boolean inuse = false;
 572 |                 boolean mute = false;
 573 |                 boolean unpowered = false;
 574 |               };
 575 |             
576 | 577 |
578 |
ignore member
579 |
The application requested that this reader be ignored.
580 | 581 |
changed member
582 |
There is a difference between the state input by the calling 583 | application, and the actual state.
584 | 585 |
unavailable member
586 |
This reader is not available for use.
587 | 588 |
unknown member
589 |
The reader name given by the application is not known.
590 | 591 |
empty member
592 |
There is no card in the reader.
593 | 594 |
present member
595 |
There is a card in the reader.
596 | 597 |
exclusive member
598 |
The card in the reader is allocated for exclusive use by 599 | another application.
600 | 601 |
inuse member
602 |
The card in the reader is in use by one or more other 603 | applications, but may be connected to in shared mode.
604 | 605 |
mute member
606 |
There is an unresponsive card in the reader.
607 | 608 |
unpowered member
609 |
The card in the reader has not been powered up.
610 |
611 | 612 |

Given a [[PCSC5]] `DWORD` named |pcscFlags:DWORD|, a corresponding 614 | {{SmartCardReaderStateFlagsOut}} dictionary is created with the 615 | following steps:

616 |
    617 |
  1. Let |flagsOut:SmartCardReaderStateFlagsOut| be a 618 | {{SmartCardReaderStateFlagsOut}} dictionary with [=dictionary 619 | member/default value|default members=].
  2. 620 |
  3. If |pcscFlags| [=has a flag|has=] [[PCSC5]] 621 | `SCARD_STATE_IGNORE`, set 622 | |flagsOut|["{{SmartCardReaderStateFlagsOut/ignore}}"] to 623 | `true`.
  4. 624 |
  5. If |pcscFlags| [=has a flag|has=] [[PCSC5]] 625 | `SCARD_STATE_CHANGED`, set 626 | |flagsOut|["{{SmartCardReaderStateFlagsOut/changed}}"] to 627 | `true`.
  6. 628 |
  7. If |pcscFlags| [=has a flag|has=] [[PCSC5]] 629 | `SCARD_STATE_UNAVAILABLE`, set 630 | |flagsOut|["{{SmartCardReaderStateFlagsOut/unavailable}}"] to 631 | `true`.
  8. 632 |
  9. If |pcscFlags| [=has a flag|has=] [[PCSC5]] 633 | `SCARD_STATE_UNKNOWN`, set 634 | |flagsOut|["{{SmartCardReaderStateFlagsOut/unknown}}"] to 635 | `true`.
  10. 636 |
  11. If |pcscFlags| [=has a flag|has=] [[PCSC5]] 637 | `SCARD_STATE_EMPTY`, set 638 | |flagsOut|["{{SmartCardReaderStateFlagsOut/empty}}"] to 639 | `true`.
  12. 640 |
  13. If |pcscFlags| [=has a flag|has=] [[PCSC5]] 641 | `SCARD_STATE_PRESENT`, set 642 | |flagsOut|["{{SmartCardReaderStateFlagsOut/present}}"] to 643 | `true`.
  14. 644 |
  15. If |pcscFlags| [=has a flag|has=] [[PCSC5]] 645 | `SCARD_STATE_EXCLUSIVE`, set 646 | |flagsOut|["{{SmartCardReaderStateFlagsOut/exclusive}}"] to 647 | `true`.
  16. 648 |
  17. If |pcscFlags| [=has a flag|has=] [[PCSC5]] 649 | `SCARD_STATE_INUSE`, set 650 | |flagsOut|["{{SmartCardReaderStateFlagsOut/inuse}}"] to 651 | `true`.
  18. 652 |
  19. If |pcscFlags| [=has a flag|has=] `SCARD_STATE_MUTE`, set 653 | |flagsOut|["{{SmartCardReaderStateFlagsOut/mute}}"] to 654 | `true`.
  20. 655 |
  21. If |pcscFlags| [=has a flag|has=] `SCARD_STATE_UNPOWERED`, set 656 | |flagsOut|["{{SmartCardReaderStateFlagsOut/unpowered}}"] to 657 | `true`.
  22. 658 |
  23. Return |flagsOut|.
  24. 659 |
660 | 665 |
666 |
667 |
668 |

SmartCardGetStatusChangeOptions dictionary

669 |
 670 |             dictionary SmartCardGetStatusChangeOptions {
 671 |               DOMHighResTimeStamp timeout;
 672 |               AbortSignal signal;
 673 |             };
 674 |           
675 | 676 |
677 |
timeout member
678 |
Timeout parameter for the GetStatusChange() [[PCSC5]] method. If 679 | not specified, a timeout value of INFINITE (which is defined system 680 | dependent) will be used.
681 | 682 |
signal member
683 |
When triggered, the platform's [[PCSC5]] Cancel() method is 684 | called.
685 |
686 |
687 |
688 |
689 |

connect() method

690 |

The {{SmartCardContext/connect(readerName, accessMode, options)}} 691 | method steps are:

692 |
    693 |
  1. Let |promise:Promise| be [=a new promise=].
  2. 694 |
  3. If [=this=].{{SmartCardContext/[[operationInProgress]]}} is 695 | `true`, [=reject=] |promise| with a "{{InvalidStateError}}" 696 | {{DOMException}} and return |promise|.
  4. 697 |
  5. Set [=this=].{{SmartCardContext/[[operationInProgress]]}} to 698 | `true`.
  6. 699 |
  7. Run the following steps [=in parallel=]: 700 |
      701 |
    1. Let |accessFlags:DWORD| be a [[PCSC5]] `DWORD` 702 | [=SmartCardAccessMode/corresponding=] to 703 | |accessMode:SmartCardAccessMode|.
    2. 704 |
    3. Let |protocolFlags:DWORD| be a `DWORD` set to `0`.
    4. 705 |
    5. If 706 | |options:SmartCardConnectOptions|["{{SmartCardConnectOptions/preferredProtocols}}"] 707 | [=map/exists=], set |protocolFlags| to its 708 | [=SmartCardProtocol/corresponding flags=].
    6. 709 |
    7. Let |activeProtocol:DWORD| be a `DWORD` set to `0`.
    8. 710 |
    9. Let |comm:SCARDCOMM| be a new instance of the platform's 711 | [[PCSC5]] `SCARDCOMM` class, with 712 | [=this=].{{SmartCardContext/[[resourceManager]]}} as its 713 | constructor parameter.
    10. 714 |
    11. Call |comm|.`Connect()` with |readerName|, |accessFlags| 715 | and |protocolFlags| as input and |activeProtocol| as output parameters.
    12. 716 |
    13. Let |responseCode:RESPONSECODE| be the returned 717 | `RESPONSECODE`.
    14. 718 |
    15. [=Queue a global task=] on the [=relevant global object=] of 719 | [=this=] using the [=smart card task source=] which performs the 720 | following steps: 721 |
        722 |
      1. [=Clear the operationInProgress=] of [=this=].
      2. 723 |
      3. If |responseCode| is not `SCARD_S_SUCCESS`: 724 |
          725 |
        1. Destroy |comm|.
        2. 726 |
        3. [=Reject=] |promise| with an [=exception=] 727 | {{SmartCardError/corresponding}} to |responseCode| and abort these steps.
        4. 728 |
        729 |
      4. 730 |
      5. Let |result:SmartCardConnectResult| be an empty 731 | {{SmartCardConnectResult}} dictionary.
      6. 732 |
      7. Let |connection:SmartCardConnection| be a new 733 | {{SmartCardConnection}}.
      8. 734 |
      9. [=set/Append=] |connection| to 735 | [=this=].{{SmartCardContext/[[connections]]}}.
      10. 736 |
      11. Set |connection|.{{SmartCardConnection/[[comm]]}} to |comm|. 737 |
      12. Set |connection|.{{SmartCardConnection/[[context]]}} to 738 | [=this=]. 739 |
      13. Set |connection|.{{SmartCardConnection/[[activeProtocol]]}} to 740 | |activeProtocol|. 741 |
      14. Set |result|["{{SmartCardConnectResult/connection}}"] to 742 | |connection|.
      15. 743 |
      16. If |activeProtocol| is a [=SmartCardProtocol/valid 744 | protocol value=], set 745 | |result|["{{SmartCardConnectResult/activeProtocol}}"] to the 746 | corresponding {{SmartCardProtocol}}.
      17. 747 |
      18. [=Resolve=] |promise| with |result|.
      19. 748 |
      749 |
    16. 750 |
    751 |
  8. 752 |
  9. Return |promise|.
  10. 753 |
754 |
755 |

SmartCardProtocol enum

756 |
 757 |             enum SmartCardProtocol {
 758 |               "raw",
 759 |               "t0",
 760 |               "t1"
 761 |             };
 762 |           
763 |
764 |
raw
765 |
"Raw" mode. May be used to support arbitrary data exchange 766 | protocols for special-purpose requirements. Corresponds to a 767 | [[PCSC5]] `SCARD_PROTOCOL_RAW` `DWORD`.
768 | 769 |
t0
770 |
[[ISO7186-3]] T=0. Asynchronous half duplex character 771 | transmission protocol. Corresponds to a [[PCSC5]] 772 | `SCARD_PROTOCOL_T0` `DWORD`.
773 | 774 |
t1
775 |
[[ISO7186-3]] T=1. Asynchronous half duplex block transmission 776 | protocol. Corresponds to a [[PCSC5]] `SCARD_PROTOCOL_T1` 777 | `DWORD`.
778 |
779 |

A [[PCSC5]] `DWORD` is a valid protocol value if it is either 780 | [[PCSC5]] `SCARD_PROTOCOL_T0`, [[PCSC5]] `SCARD_PROTOCOL_T1` or 781 | [[PCSC5]] `SCARD_PROTOCOL_RAW`.

782 |

Given a sequence of {{SmartCardProtocol}} named 783 | |protocols:sequence<SmartCardProtocol>|, a [[PCSC5]] `DWORD` 784 | with the corresponding 785 | flags is created with the following steps:

786 |
    787 |
  1. Let |flags:DWORD| be a `DWORD` set to `0`.
  2. 788 |
  3. [=list/For each=] |protocol:SmartCardProtocol| in |protocols|, 789 | [=add a flag|add=] the corresponding `DWORD` of |protocol| to |flags|. 790 |
  4. 791 |
  5. Return |flags|.
  6. 792 |
793 |
794 |
795 |

SmartCardConnectResult dictionary

796 |
 797 |             dictionary SmartCardConnectResult {
 798 |               required SmartCardConnection connection;
 799 |               SmartCardProtocol activeProtocol;
 800 |             };
 801 |           
802 |
803 |
connection member
804 |
An interface to the connection created.
805 | 806 |
activeProtocol member
807 |
The protocol actually in use.
808 |
809 |
810 |
811 |

SmartCardAccessMode enum

812 |
 813 |             enum SmartCardAccessMode {
 814 |               "shared",
 815 |               "exclusive",
 816 |               "direct"
 817 |             };
 818 |           
819 |
820 |
shared
821 |
Application is willing to share access to card with other 822 | applications.
823 |
exclusive
824 |
Application requires exclusive access to the card.
825 |
direct
826 |
Application requires connection to reader whether or not card 827 | is present. Implies exclusive access.
828 |
829 |

Given a {{SmartCardAccessMode}} enum named 830 | |accessMode:SmartCardAccessMode|, a corresponding [[PCSC5]] 832 | `DWORD` is created with the following steps:

833 |
    834 |
  1. Let |dword:DWORD| be a `DWORD` set to `0`. 835 |
  2. If |accessMode| is "{{SmartCardAccessMode/shared}}", set |dword| to [[PCSC5]] 836 | `SCARD_SHARE_SHARED`.
  3. 837 |
  4. If |accessMode| is "{{SmartCardAccessMode/exclusive}}", set |dword| to [[PCSC5]] 838 | `SCARD_SHARE_EXCLUSIVE`.
  5. 839 |
  6. If |accessMode| is "{{SmartCardAccessMode/direct}}", set |dword| to [[PCSC5]] 840 | `SCARD_SHARE_DIRECT`.
  7. 841 |
  8. Return |dword|.
  9. 842 |
843 |
844 |
845 |

SmartCardConnectOptions dictionary

846 |
 847 |             dictionary SmartCardConnectOptions {
 848 |               sequence<SmartCardProtocol> preferredProtocols;
 849 |             };
 850 |           
851 |
852 |
preferredProtocols
853 |
Card communication protocols that may be used.
854 |
855 |
856 |
857 |
858 |

Auxiliary algorithms and definitions

859 | 860 |

To clear the operationInProgress of a 861 | {{SmartCardContext}} |context:SmartCardContext|, perform the following steps:

862 |
    863 |
  1. [=Assert=]: |context|.{{SmartCardContext/[[operationInProgress]]}} 864 | is `true`.
  2. 865 |
  3. Set |context|.{{SmartCardContext/[[operationInProgress]]}} to 866 | `false`.
  4. 867 |
  5. [=set/For each=] |connection:SmartCardConnection| of 868 | |context|.{{SmartCardContext/[[connections]]}}: 869 |
      870 |
    1. [=SmartCardConnection/End any settled transaction=] of 871 | |connection|.
    2. 872 |
    3. If |context|.{{SmartCardContext/[[operationInProgress]]}} is 873 | `true`, abort there steps.
    4. 874 |
    875 |
  6. 876 |
877 | 888 | 889 |

The cancel the outstanding GetStatusChange 890 | algorithm steps are:

891 |
    892 |
  1. Call [=this=].{{SmartCardContext/[[tracker]]}}.`Cancel()`.
  2. 893 |
894 | 895 |

The high word of a [[PCSC5]] `DWORD` is the result of an 896 | unsigned right shift of 16 bits on that `DWORD`.

897 | 898 |

To set the high word of a [[PCSC5]] `DWORD` named 899 | |dword:DWORD| to a given number |n|, perform the following steps.

900 |
    901 |
  1. Set |dword| to |dword| bitwise AND `0xFFFF`.
  2. 902 |
  3. Let |shiftedN| be the result of a left shift of 16 bits on |n|.
  4. 903 |
  5. Set |dword| to |dword| bitwise OR |shiftedN|.
  6. 904 |
905 | 906 |

To add a flag |f:DWORD| to a [[PCSC5]] `DWORD` 907 | |flags:DWORD|, set |flags| to |flags| bitwise OR |f|.

908 | 909 |

A [[PCSC5]] `DWORD` |flags:DWORD| has a flag |f:DWORD| 910 | if |flags| bitwise AND |f| is |f|.

911 |
912 |
913 | 914 |
915 |

SmartCardConnection interface

916 |
 917 |         [Exposed=(DedicatedWorker, SharedWorker, Window), SecureContext]
 918 |         interface SmartCardConnection {
 919 |           Promise<undefined> disconnect(optional SmartCardDisposition disposition = "leave");
 920 | 
 921 |           Promise<ArrayBuffer> transmit(BufferSource sendBuffer,
 922 |               optional SmartCardTransmitOptions options = {});
 923 | 
 924 |           Promise<undefined> startTransaction(SmartCardTransactionCallback transaction,
 925 |               optional SmartCardTransactionOptions options = {});
 926 | 
 927 |           Promise<SmartCardConnectionStatus> status();
 928 | 
 929 |           Promise<ArrayBuffer> control([EnforceRange] unsigned long controlCode,
 930 |               BufferSource data);
 931 | 
 932 |           Promise<ArrayBuffer> getAttribute([EnforceRange] unsigned long tag);
 933 |           Promise<undefined> setAttribute([EnforceRange] unsigned long tag, BufferSource value);
 934 |         };
 935 | 
 936 |         callback SmartCardTransactionCallback = Promise<SmartCardDisposition?> ();
 937 |       
938 |

Instances of {{SmartCardConnection}} are created with the internal slots 939 | described in the following table:

940 | 941 | 942 | 946 | 947 | 948 | 949 | 950 | 951 | 952 | 953 | 954 | 955 | 956 | 957 | 958 | 959 | 961 | 962 | 963 | 964 | 965 | 968 | 969 |
Internal slot 943 | Initial value 944 | Description (non-normative) 945 |
[[\comm]]`null`The platform's [[PCSC5]] `SCARDCOMM` to be used.
[[\context]]`null`The {{SmartCardContext}} that created this instance.
[[\activeProtocol]]0The active protocol `DWORD`, as returned by the platform's 960 | [[PCSC5]] implementation.
[[\transactionState]]`null`Holds the [=transaction state|state=] of an ongoing transaction 966 | started with {{SmartCardConnection/startTransaction()}}, if 967 | any.
970 | 981 |
982 |

disconnect() method

983 |

The {{SmartCardConnection/disconnect(disposition)}} method steps 984 | are:

985 |
    986 |
  1. Let |promise:Promise| be [=a new promise=].
  2. 987 |
  3. If 988 | [=this=].{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}} 989 | is `true`, [=reject=] |promise| with a "{{InvalidStateError}}" 990 | {{DOMException}} and return |promise|.
  4. 991 |
  5. If [=this=].{{SmartCardConnection/[[comm]]}} is `null`, [=reject=] 992 | |promise| with a "{{InvalidStateError}}" {{DOMException}} and return 993 | |promise|.
  6. 994 |
  7. Set 995 | [=this=].{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}} 996 | to `true`.
  8. 997 |
  9. Run the following steps [=in parallel=]: 998 |
      999 |
    1. Call [=this=].{{SmartCardConnection/[[comm]]}}.`Disconnect()` 1000 | with a `DWORD` corresponding to 1001 | |disposition:SmartCardDisposition| as input parameter.
    2. 1002 |
    3. Let |responseCode:RESPONSECODE| be the returned 1003 | `RESPONSECODE`.
    4. 1004 |
    5. [=Queue a global task=] on the [=relevant global object=] of 1005 | [=this=] using the [=smart card task source=] which performs the 1006 | following steps: 1007 |
        1008 |
      1. [=Clear the operationInProgress=] of 1009 | [=this=].{{SmartCardConnection/[[context]]}}.
      2. 1010 |
      3. If |responseCode| is not `SCARD_S_SUCCESS`, [=reject=] 1011 | |promise| with an [=exception=] 1012 | {{SmartCardError/corresponding}} to |responseCode| and abort 1013 | these steps.
      4. 1014 |
      5. Destroy [=this=].{{SmartCardConnection/[[comm]]}}.
      6. 1015 |
      7. Set [=this=].{{SmartCardConnection/[[comm]]}} to `null`.
      8. 1016 |
      9. [=Resolve=] |promise|.
      10. 1017 |
      1018 |
    6. 1019 |
    1020 |
  10. 1021 |
  11. Return |promise|.
  12. 1022 |
1023 | 1024 |
1025 |

SmartCardDisposition enum

1026 |
1027 |             enum SmartCardDisposition {
1028 |               "leave",
1029 |               "reset",
1030 |               "unpower",
1031 |               "eject"
1032 |             };
1033 |           
1034 |
1035 |
leave
1036 |
Don't alter card state. Corresponds to a [[PCSC5]] 1037 | `SCARD_LEAVE_CARD` `DWORD`.
1038 |
reset
1039 |
Reset the card. Corresponds to a [[PCSC5]] `SCARD_RESET_CARD` 1040 | `DWORD`.
1041 |
unpower
1042 |
Unpower and terminate access to the card. Corresponds to a 1043 | [[PCSC5]] `SCARD_UNPOWER_CARD` `DWORD`.
1044 |
eject
1045 |
Eject the card from the reader. Corresponds to a [[PCSC5]] 1046 | `SCARD_EJECT_CARD` `DWORD`.
1047 |
1048 |
1049 |
1050 |
1051 |

transmit() method

1052 |

The {{SmartCardConnection/transmit(sendBuffer, options)}} method steps 1053 | are:

1054 |
    1055 |
  1. Let |promise:Promise| be [=a new promise=].
  2. 1056 |
  3. If 1057 | [=this=].{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}} 1058 | is `true`, [=reject=] |promise| with a "{{InvalidStateError}}" 1059 | {{DOMException}} and return |promise|.
  4. 1060 |
  5. If [=this=].{{SmartCardConnection/[[comm]]}} is `null`, [=reject=] 1061 | |promise| with a "{{InvalidStateError}}" {{DOMException}} and return 1062 | |promise|.
  6. 1063 |
  7. Let |protocol:DWORD| be a [[PCSC5]] `DWORD` set to 1064 | [=this=].{{SmartCardConnection/[[activeProtocol]]}}. 1065 |
  8. If 1066 | |options:SmartCardTransmitOptions|["{{SmartCardTransmitOptions/protocol}}"] 1067 | [=map/exists=], set |protocol| to the `DWORD` corresponding to 1068 | |options:SmartCardTransmitOptions|["{{SmartCardTransmitOptions/protocol}}"]. 1069 |
  9. If |protocol| is not a [=SmartCardProtocol/valid protocol value=], 1070 | [=reject=] |promise| with a "{{InvalidStateError}}" {{DOMException}} 1071 | and return |promise|.
  10. 1072 |
  11. Set 1073 | [=this=].{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}} 1074 | to `true`.
  12. 1075 |
  13. Let |sendPci:SCARD_IO_HEADER| be the platform's [[PCSC5]] 1076 | `SCARD_IO_HEADER` corresponding to 1077 | [=this=].{{SmartCardConnection/[[activeProtocol]]}}.
  14. 1078 |
  15. Let |pcscSendBuffer:array of BYTE| be a [[PCSC5]] `BYTE[]` 1079 | containing |sendBuffer:BufferSource|.
  16. 1080 |
  17. Let |recvPci:SCARD_IO_HEADER| be the platform's `SCARD_IO_HEADER` 1081 | equivalent of empty or null.
  18. 1082 |
  19. Let |recvBuffer:array of BYTE| be a `BYTE[]` big enough to hold 1083 | the largest [[ISO7186-3]] extended response APDU (65538 bytes).
  20. 1084 |
  21. Let |recvLength:DWORD| be a `DWORD` set to `0`.
  22. 1085 |
  23. Run the following steps [=in parallel=]: 1086 |
      1087 |
    1. Call [=this=].{{SmartCardConnection/[[comm]]}}.`Transmit()` 1088 | with |sendPci|, |pcscSendBuffer|, |recvPci|, |recvBuffer| and 1089 | |recvLength| as arguments.
    2. 1090 |
    3. Let |responseCode:RESPONSECODE| be the returned 1091 | `RESPONSECODE`.
    4. 1092 |
    5. [=Queue a global task=] on the [=relevant global object=] of 1093 | [=this=] using the [=smart card task source=] which performs the 1094 | following steps: 1095 |
        1096 |
      1. [=Clear the operationInProgress=] of 1097 | [=this=].{{SmartCardConnection/[[context]]}}.
      2. 1098 |
      3. If |responseCode| is not `SCARD_S_SUCCESS`, [=reject=] 1099 | |promise| with an [=exception=] 1100 | {{SmartCardError/corresponding}} to |responseCode| and abort 1101 | these steps.
      4. 1102 |
      5. [=Resolve=] |promise| with an {{ArrayBuffer}} containing 1103 | the first |recvLength| bytes of |recvBuffer|.
      6. 1104 |
      1105 |
    6. 1106 |
    1107 |
  24. 1108 |
  25. Return |promise|.
  26. 1109 |
1110 |
1111 |

SmartCardTransmitOptions dictionary

1112 |
1113 |             dictionary SmartCardTransmitOptions {
1114 |               SmartCardProtocol protocol;
1115 |             };
1116 |           
1117 |
1118 |
protocol member
1119 |
The protocol to be used in the transmission.
1120 |
1121 |
1122 |
1123 |
1124 |

startTransaction() method

1125 |

The {{SmartCardConnection/startTransaction(transaction, options)}} 1126 | method steps are:

1127 |
    1128 |
  1. Let |promise:Promise| be [=a new promise=].
  2. 1129 |
  3. If 1130 | [=this=].{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}} 1131 | is `true`, [=reject=] |promise| with a "{{InvalidStateError}}" 1132 | {{DOMException}} and return |promise|.
  4. 1133 |
  5. If [=this=].{{SmartCardConnection/[[comm]]}} is `null`, [=reject=] 1134 | |promise| with a "{{InvalidStateError}}" {{DOMException}} and return 1135 | |promise|.
  6. 1136 |
  7. If [=this=].{{SmartCardConnection/[[transactionState]]}} is not 1137 | `null`, [=reject=] |promise| with a "{{InvalidStateError}}" 1138 | {{DOMException}} and return |promise|.
  8. 1139 |
  9. Let |signal| be an {{AbortSignal}} set to `null`.
  10. 1140 |
  11. If 1141 | |options:SmartCardTransactionOptions|["{{SmartCardTransactionOptions/signal}}"] 1142 | [=map/exists=], run the following steps: 1143 |
      1144 |
    1. If 1145 | |options:SmartCardTransactionOptions|["{{SmartCardTransactionOptions/signal}}"] 1146 | is [=AbortSignal/aborted=], [=reject=] |promise| with 1147 | |options:SmartCardTransactionOptions|["{{SmartCardTransactionOptions/signal}}"]'s 1148 | [=AbortSignal/abort reason=] and return |promise|.
    2. 1149 |
    3. Set |signal| to 1150 | |options|["{{SmartCardTransactionOptions/signal}}"].
    4. 1151 |
    5. [=AbortSignal/Add=] the {{SmartCardConnection/cancel}} 1152 | algorithm to |signal|.
    6. 1153 |
    1154 |
  12. 1155 |
  13. Set 1156 | [=this=].{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}} 1157 | to `true`.
  14. 1158 |
  15. Run the following steps [=in parallel=]: 1159 |
      1160 |
    1. Call 1161 | [=this=].{{SmartCardConnection/[[comm]]}}.`BeginTransaction()`.
    2. 1162 |
    3. Let |responseCode:RESPONSECODE| be the returned [[PCSC5]] 1163 | `RESPONSECODE`.
    4. 1164 |
    5. [=Queue a global task=] on the [=relevant global object=] of 1165 | [=this=] using the [=smart card task source=] to 1166 | [=process the result of a BeginTransaction=] with [=this=], 1167 | |responseCode|, |signal|, |transaction| and |promise|. 1168 |
    6. 1169 |
    1170 |
  16. 1171 |
  17. Return |promise|.
  18. 1172 |
1173 |
1174 |

SmartCardTransactionOptions dictionary

1175 |
1176 |             dictionary SmartCardTransactionOptions {
1177 |               AbortSignal signal;
1178 |             };
1179 |           
1180 | 1181 |
1182 |
signal member
1183 |
When triggered, the platform's [[PCSC5]] Cancel() method is 1184 | called.
1185 |
1186 |
1187 |
1188 |

Auxiliary algorithms and definitions

1189 |

A transaction state is a [=struct=] with the following 1190 | [=struct/items=]:

1191 | 1192 | 1193 | 1196 | 1197 | 1200 | 1201 | 1202 | 1203 | 1205 | 1206 | 1207 | 1208 | 1210 | 1211 |
Item 1194 | Description (non-normative) 1195 |
pendingDispositionIf set, it means once the ongoing PC/SC operation finishes 1198 | [[PCSC5]] `EndTransaction()` should be called with this value as the 1199 | {{SmartCardDisposition}} parameter.
pendingExceptionThe exception to be used when rejecting 1204 | [=transaction state/promise=].
promiseThe pending {{Promise}} returned by a 1209 | {{SmartCardConnection/startTransaction()}} call.
1212 |

To process the result of a BeginTransaction given a 1213 | {{SmartCardConnection}} |connection:SmartCardConnection|, a [[PCSC5]] 1214 | `RESPONSECODE` |responseCode:RESPONSECODE|, an {{AbortSignal}} 1215 | |signal:AbortSignal|, a {{SmartCardTransactionCallback}} 1216 | |transaction:SmartCardTransactionCallback| and a {{Promise}} 1217 | |promise:Promise|, perform the following steps:

1218 |
    1219 |
  1. [=Clear the operationInProgress=] of 1220 | |connection|.{{SmartCardConnection/[[context]]}}.
  2. 1221 |
  3. Let |abortReason| be {{undefined}}.
  4. 1222 |
  5. If |signal| is not `null`: 1223 |
      1224 |
    1. [=AbortSignal/Remove=] the 1225 | {{SmartCardConnection/cancel}} algorithm from 1226 | |signal|.
    2. 1227 |
    3. If |signal| is [=AbortSignal/aborted=] then set 1228 | |abortReason| to |signal|'s [=AbortSignal/abort 1229 | reason=].
    4. 1230 |
    1231 |
  6. 1232 |
  7. If |responseCode| is not `SCARD_S_SUCCESS`: 1233 |
      1234 |
    1. If |responseCode| is `SCARD_E_CANCELLED` and 1235 | |abortReason| is not {{undefined}} then [=reject=] 1236 | |promise| with |abortReason|.
    2. 1237 |
    3. Otherwise, [=reject=] |promise| with an 1238 | [=exception=] {{SmartCardError/corresponding}} to 1239 | |responseCode|.
    4. 1240 |
    5. Return.
    6. 1241 |
    1242 |
  8. 1243 |
  9. Let |transactionState:transaction state| be a new [=transaction 1244 | state=] with its [=transaction state/promise=] item set to 1245 | |promise|.
  10. 1246 |
  11. Set |connection|.{{SmartCardConnection/[[transactionState]]}} 1247 | to |transactionState|.
  12. 1248 |
  13. Let |callbackPromise:Promise| be the result of [=invoking=] 1249 | |transaction|.
  14. 1250 |
  15. [=promise/React=] to |callbackPromise|: 1251 |
      1252 |
    • If |callbackPromise| was fulfilled with value |v| 1253 | then: 1254 |
        1255 |
      1. Let |disposition:SmartCardDisposition| be 1256 | "{{SmartCardDisposition/reset}}". 1257 |
      2. If |v| is not {{undefined}}, set |disposition| to 1258 | |v|.
      3. 1259 |
      4. If 1260 | |connection|.{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}} 1261 | is `true`: 1262 |
          1263 |
        1. Set |transactionState|'s [=transaction 1264 | state/pendingException=] to a "{{InvalidStateError}}" 1265 | {{DOMException}}.
        2. 1266 |
        3. Set 1267 | |transactionState|'s [=transaction state/pendingDisposition=] 1268 | to |disposition|.
        4. 1269 |
        1270 |
      5. 1271 |
      6. Otherwise, [=end the transaction=] of |connection| with 1272 | |disposition|.
      7. 1273 |
      1274 |
    • 1275 |
    • If |callbackPromise| was rejected with reason |r|, then: 1276 |
        1277 |
      1. Set |transactionState|'s [=transaction 1278 | state/pendingException=] to |r|.
      2. 1279 |
      3. If 1280 | |connection|.{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}} 1281 | is `true`, set 1282 | |transactionState|'s [=transaction state/pendingDisposition=] to 1283 | "{{SmartCardDisposition/reset}}".
      4. 1284 |
      5. Otherwise, [=end the transaction=] of |connection| with 1285 | "{{SmartCardDisposition/reset}}".
      6. 1286 |
      1287 |
    • 1288 |
    1289 |
  16. 1290 |
1291 | 1292 |

To end the transaction of a {{SmartCardConnection}} 1293 | |connection:SmartCardConnection| with a {{SmartCardDisposition}} 1294 | |disposition:SmartCardDisposition|, perform the following steps:

1295 |
    1296 |
  1. [=Assert=]: 1297 | |connection|.{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}} 1298 | is `false`.
  2. 1299 |
  3. [=Assert=]: 1300 | |connection|.{{SmartCardConnection/[[transactionState]]}} is not 1301 | `null`.
  4. 1302 |
  5. [=Assert=]: |connection|.{{SmartCardConnection/[[transactionState]]}}'s 1303 | [=transaction state/pendingDisposition=] is `null`.
  6. 1304 |
  7. Let |transactionPromise:Promise| be 1305 | |connection|.{{SmartCardConnection/[[transactionState]]}}'s 1306 | [=transaction state/promise=].
  8. 1307 |
  9. If |connection|.{{SmartCardConnection/[[comm]]}} is `null`: 1308 |
      1309 |
    1. [=Reject=] |transactionPromise| with a "{{InvalidStateError}}" 1310 | {{DOMException}}.
    2. 1311 |
    3. Set 1312 | |connection|.{{SmartCardConnection/[[transactionState]]}} to 1313 | `null`.
    4. 1314 |
    5. Return.
    6. 1315 |
    1316 |
  10. 1317 |
  11. Set 1318 | |connection|.{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}} 1319 | to `true`.
  12. 1320 |
  13. Run the following steps [=in parallel=]: 1321 |
      1322 |
    1. Call 1323 | [=this=].{{SmartCardConnection/[[comm]]}}.`EndTransaction()` with 1324 | a `DWORD` corresponding to |disposition| as input parameter.
    2. 1325 |
    3. Let |responseCode:RESPONSECODE| be the returned [[PCSC5]] 1326 | `RESPONSECODE`.
    4. 1327 |
    5. [=Queue a global task=] on the [=relevant global object=] of 1328 | [=this=] using the [=smart card task source=] which performs 1329 | the following steps: 1330 |
        1331 |
      1. [=Clear the operationInProgress=] of 1332 | |connection|.{{SmartCardConnection/[[context]]}}.
      2. 1333 |
      3. Let |exception| be 1334 | |connection|.{{SmartCardConnection/[[transactionState]]}}'s 1335 | [=transaction state/pendingException=].
      4. 1336 |
      5. If |exception| is `null`, perform the following steps: 1337 |
          1338 |
        1. If |responseCode| is `SCARD_S_SUCCESS`, 1339 | [=resolve=] |transactionPromise|.
        2. 1340 |
        3. Otherwise, [=reject=] |transactionPromise| with an 1341 | [=exception=] {{SmartCardError/corresponding}} to 1342 | |responseCode|.
        4. 1343 |
        1344 |
      6. 1345 |
      7. Otherwise, [=reject=] |transactionPromise| with 1346 | |exception|.
      8. 1347 |
      9. Set 1348 | |connection|.{{SmartCardConnection/[[transactionState]]}} 1349 | to `null`.
      10. 1350 |
      1351 |
    6. 1352 |
    1353 |
  14. 1354 |
1355 | 1356 |

To end any settled transaction of a 1357 | {{SmartCardConnection}} |connection:SmartCardConnection|, perform the 1358 | following steps:

1359 |
    1360 |
  1. If |connection|.{{SmartCardConnection/[[transactionState]]}} is 1361 | `null`, abort these steps.
  2. 1362 |
  3. Let |disposition| be 1363 | |connection|.{{SmartCardConnection/[[transactionState]]}}'s 1364 | [=transaction state/pendingDisposition=].
  4. 1365 |
  5. If |disposition| is `null`, abort these steps.
  6. 1366 |
  7. Set |connection|.{{SmartCardConnection/[[transactionState]]}}'s 1367 | [=transaction state/pendingDisposition=] to `null`.
  8. 1368 |
  9. [=End the transaction=] of |connection| with |disposition|.
  10. 1369 |
1370 | 1371 |

To cancel outstanding [[PCSC5]] `SCARDCOMM` operations, 1372 | call [=this=].{{SmartCardConnection/[[comm]]}}.`Cancel()`.

1373 |
1374 |
1375 |
1376 |

status() method

1377 |

The {{SmartCardConnection/status()}} method steps are:

1378 |
    1379 |
  1. Let |promise:Promise| be [=a new promise=].
  2. 1380 |
  3. If 1381 | [=this=].{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}} 1382 | is `true`, [=reject=] |promise| with a "{{InvalidStateError}}" 1383 | {{DOMException}} and return |promise|.
  4. 1384 |
  5. If [=this=].{{SmartCardConnection/[[comm]]}} is `null`, [=reject=] 1385 | |promise| with a "{{InvalidStateError}}" {{DOMException}} and return 1386 | |promise|.
  6. 1387 |
  7. Set 1388 | [=this=].{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}} 1389 | to `true`.
  8. 1390 |
  9. Run the following steps [=in parallel=]: 1391 |
      1392 |
    1. Let |pcscReader:array of STR| be an empty `STR[]`.
    2. 1393 |
    3. Let |pcscState:DWORD| be a [[PCSC5]] `DWORD` set to `0`.
    4. 1394 |
    5. Let |activeProtocol:DWORD| be a [[PCSC5]] `DWORD` set to `0`.
    6. 1395 |
    7. Let |pcscAtr:array of BYTE| be a `BYTE[]` big enough to hold 1396 | any [[ISO7186-3]] Answer To Reset (ATR).
    8. 1397 |
    9. Call [=this=].{{SmartCardConnection/[[comm]]}}.`Status()` 1398 | with |pcscReader|, |pcscState|, |activeProtocol| and |pcscAtr| as 1399 | output parameters.
    10. 1400 |
    11. Let |responseCode:RESPONSECODE| be the returned 1401 | `RESPONSECODE`.
    12. 1402 |
    13. [=Queue a global task=] on the [=relevant global object=] of 1403 | [=this=] using the [=smart card task source=] which performs the 1404 | following steps: 1405 |
        1406 |
      1. [=Clear the operationInProgress=] of 1407 | [=this=].{{SmartCardConnection/[[context]]}}.
      2. 1408 |
      3. If |responseCode| is not `SCARD_S_SUCCESS`, [=reject=] 1409 | |promise| with an [=exception=] 1410 | {{SmartCardError/corresponding}} to |responseCode| and abort 1411 | these steps.
      4. 1412 |
      5. Let |state:SmartCardConnectionState| be a 1413 | {{SmartCardConnectionState}} 1414 | [=SmartCardConnectionState/corresponding=] to |pcscState| 1415 | and |activeProtocol|.
      6. 1416 |
      7. If |state| is {{undefined}}, [=reject=] |promise| with an 1417 | "{{UnknownError}}" {{DOMException}} and abort these steps.
      8. 1418 |
      9. Let |status:SmartCardConnectionStatus| be a new 1419 | {{SmartCardConnectionStatus}}.
      10. 1420 |
      11. Set |status|["{{SmartCardConnectionStatus/readerName}}"] 1421 | to |pcscReader|.
      12. 1422 |
      13. Set |status|["{{SmartCardConnectionStatus/state}}"] 1423 | to |state|.
      14. 1424 |
      15. Set 1425 | |status|["{{SmartCardConnectionStatus/answerToReset}}"] to 1426 | an {{ArrayBuffer}} with the bytes that were written to 1427 | |pcscAtr|.
      16. 1428 |
      17. [=Resolve=] |promise| with |status|.
      18. 1429 |
      1430 |
    14. 1431 |
    1432 |
  10. 1433 |
  11. Return |promise|.
  12. 1434 |
1435 |
1436 |

SmartCardConnectionStatus dictionary

1437 |
1438 |             dictionary SmartCardConnectionStatus {
1439 |               required DOMString readerName;
1440 |               required SmartCardConnectionState state;
1441 |               ArrayBuffer answerToReset;
1442 |             };
1443 |           
1444 |
1445 |
readerName member
1446 |
Name of the connected reader.
1447 |
state member
1448 |
Current state of the connection.
1449 |
answerToReset member
1450 |
The answer to reset (ATR) string from the card, if applicable.
1451 |
1452 |
1453 |
SmartCardConnectionState enum
1454 |
1455 |               enum SmartCardConnectionState {
1456 |                 "absent",
1457 |                 "present",
1458 |                 "swallowed",
1459 |                 "powered",
1460 |                 "negotiable",
1461 |                 "t0",
1462 |                 "t1",
1463 |                 "raw"
1464 |               };
1465 |             
1466 |
1467 |
absent
1468 |
There is no card in the reader.
1469 |
present
1470 |
There is a card in the reader, but it has not been moved into 1471 | position for use.
1472 |
swallowed
1473 |
There is a card in the reader in position for use. The card is 1474 | not powered.
1475 |
powered
1476 |
Power is being provided to the card, but the reader driver is 1477 | unaware of the mode of the card.
1478 |
negotiable
1479 |
The card has been reset and is awaiting PTS (protocol type 1480 | selection) negotiation.
1481 |
t0
1482 |
The card is in [[ISO7186-3]] T=0 protocol mode and a new protocol 1483 | may not be negotiated.
1484 |
t1
1485 |
The card is in [[ISO7186-3]] T=1 protocol mode and a new protocol 1486 | may not be negotiated.
1487 |
raw
1488 |
The card is in raw protocol mode and a new protocol may not be 1489 | negotiated.
1490 |
1491 | 1492 |

Given a [[PCSC5]] `DWORD` |pcscState:DWORD| and a `DWORD` 1493 | |activeProtocol:DWORD|, a 1494 | corresponding 1495 | {{SmartCardConnectionState}} is created with the following steps:

1496 |
    1497 |
  1. If |pcscState| is [[PCSC5]] `SCARD_ABSENT`, return 1498 | "{{SmartCardConnectionState/absent}}".
  2. 1499 |
  3. If |pcscState| is [[PCSC5]] `SCARD_PRESENT`, return 1500 | "{{SmartCardConnectionState/present}}".
  4. 1501 |
  5. If |pcscState| is [[PCSC5]] `SCARD_SWALLOWED`, return 1502 | "{{SmartCardConnectionState/swallowed}}".
  6. 1503 |
  7. If |pcscState| is [[PCSC5]] `SCARD_POWERED`, return 1504 | "{{SmartCardConnectionState/powered}}".
  8. 1505 |
  9. If |pcscState| is [[PCSC5]] `SCARD_NEGOTIABLE`, return 1506 | "{{SmartCardConnectionState/negotiable}}".
  10. 1507 |
  11. If |pcscState| is [[PCSC5]] `SCARD_SPECIFIC`, perform the 1508 | following steps: 1509 |
      1510 |
    1. If |activeProtocol| is [[PCSC5]] `SCARD_PROTOCOL_T0`, 1511 | return "{{SmartCardConnectionState/t0}}".
    2. 1512 |
    3. If |activeProtocol| is [[PCSC5]] `SCARD_PROTOCOL_T1`, 1513 | return "{{SmartCardConnectionState/t1}}".
    4. 1514 |
    5. If |activeProtocol| is [[PCSC5]] `SCARD_PROTOCOL_RAW`, 1515 | return "{{SmartCardConnectionState/raw}}".
    6. 1516 |
    1517 |
  12. 1518 |
  13. Return {{undefined}}.
  14. 1519 |
1520 |
1521 |
1522 |
1523 |
1524 |

control() method

1525 |

The {{SmartCardConnection/control(controlCode, data)}} method steps are:

1526 |
    1527 |
  1. Let |promise:Promise| be [=a new promise=].
  2. 1528 |
  3. If 1529 | [=this=].{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}} 1530 | is `true`, [=reject=] |promise| with a "{{InvalidStateError}}" 1531 | {{DOMException}} and return |promise|.
  4. 1532 |
  5. If [=this=].{{SmartCardConnection/[[comm]]}} is `null`, [=reject=] 1533 | |promise| with a "{{InvalidStateError}}" {{DOMException}} and return 1534 | |promise|.
  6. 1535 |
  7. Set 1536 | [=this=].{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}} 1537 | to `true`.
  8. 1538 |
  9. Let |pcscControlCode:DWORD| be a [[PCSC5]] `DWORD` containing 1539 | |controlCode|.
  10. 1540 |
  11. [=Get a copy of the buffer source=] |data:BufferSource| and save 1541 | the result in a [[PCSC5]] `BYTE[]` |inBuffer:array of BYTE|.
  12. 1542 |
  13. Let |outBuffer:array of BYTE| be a [[PCSC5]] `BYTE[]` large enough 1543 | to hold any control command response.
  14. 1544 |
  15. Let |outBufferLength:DWORD| be a `DWORD` set to `0`.
  16. 1545 |
  17. Run the following steps [=in parallel=]: 1546 |
      1547 |
    1. Call [=this=].{{SmartCardConnection/[[comm]]}}.`Control()` 1548 | with |pcscControlCode|, |inBuffer|, |outBuffer| and 1549 | |outBufferLength| as arguments.
    2. 1550 |
    3. Let |responseCode:RESPONSECODE| be the returned 1551 | `RESPONSECODE`.
    4. 1552 |
    5. [=Queue a global task=] on the [=relevant global object=] of 1553 | [=this=] using the [=smart card task source=] which performs the 1554 | following steps: 1555 |
        1556 |
      1. [=Clear the operationInProgress=] of 1557 | [=this=].{{SmartCardConnection/[[context]]}}.
      2. 1558 |
      3. If |responseCode| is not `SCARD_S_SUCCESS`, [=reject=] 1559 | |promise| with an [=exception=] 1560 | {{SmartCardError/corresponding}} to |responseCode| and abort 1561 | these steps.
      4. 1562 |
      5. Let |resultBytes:byte sequence| be the first 1563 | |outBufferLength| bytes of |outBuffer|.
      6. 1564 |
      7. [=Resolve=] |promise| with the result of 1565 | [=ArrayBuffer/Create|creating=] an {{ArrayBuffer}} from 1566 | |resultBytes| in [=this=]'s [=relevant Realm=].
      8. 1567 |
      1568 |
    6. 1569 |
    1570 |
  18. 1571 |
  19. Return |promise|.
  20. 1572 |
1573 |
1574 |
1575 |

getAttribute() method

1576 |

The {{SmartCardConnection/getAttribute(tag)}} method steps are:

1577 |
    1578 |
  1. Let |promise:Promise| be [=a new promise=].
  2. 1579 |
  3. If 1580 | [=this=].{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}} 1581 | is `true`, [=reject=] |promise| with a "{{InvalidStateError}}" 1582 | {{DOMException}} and return |promise|.
  4. 1583 |
  5. If [=this=].{{SmartCardConnection/[[comm]]}} is `null`, [=reject=] 1584 | |promise| with a "{{InvalidStateError}}" {{DOMException}} and return 1585 | |promise|.
  6. 1586 |
  7. Set 1587 | [=this=].{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}} 1588 | to `true`.
  8. 1589 |
  9. Run the following steps [=in parallel=]: 1590 |
      1591 |
    1. Let |pcscTag:DWORD| be a [[PCSC5]] `DWORD` containing |tag|.
    2. 1592 |
    3. Let |buffer:array of BYTE| be a [[PCSC5]] `BYTE[]` large 1593 | enough to hold this reader attribute, as determined by the 1594 | platform's [[PCSC5]] implementation.
    4. 1595 |
    5. Call [=this=].{{SmartCardConnection/[[comm]]}}.`GetReaderCapabilities()` 1596 | with |pcscTag| and |buffer| as arguments.
    6. 1597 |
    7. Let |responseCode:RESPONSECODE| be the returned 1598 | `RESPONSECODE`.
    8. 1599 |
    9. [=Queue a global task=] on the [=relevant global object=] of 1600 | [=this=] using the [=smart card task source=] which performs the 1601 | following steps: 1602 |
        1603 |
      1. [=Clear the operationInProgress=] of 1604 | [=this=].{{SmartCardConnection/[[context]]}}.
      2. 1605 |
      3. If |responseCode| is not `SCARD_S_SUCCESS`, [=reject=] 1606 | |promise| with an [=exception=] 1607 | {{SmartCardError/corresponding}} to |responseCode| and abort 1608 | these steps.
      4. 1609 |
      5. Let |resultBytes:byte sequence| be the bytes of |buffer| 1610 | containing the attribute read.
      6. 1611 |
      7. [=Resolve=] |promise| with the result of 1612 | [=ArrayBuffer/Create|creating=] an {{ArrayBuffer}} from 1613 | |resultBytes| in [=this=]'s [=relevant Realm=].
      8. 1614 |
      1615 |
    10. 1616 |
    1617 |
  10. 1618 |
  11. Return |promise|.
  12. 1619 |
1620 | 1625 |
1626 |
1627 |

setAttribute() method

1628 |

The {{SmartCardConnection/setAttribute(tag, value)}} method steps are:

1629 |
    1630 |
  1. Let |promise:Promise| be [=a new promise=].
  2. 1631 |
  3. If 1632 | [=this=].{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}} 1633 | is `true`, [=reject=] |promise| with a "{{InvalidStateError}}" 1634 | {{DOMException}} and return |promise|.
  4. 1635 |
  5. If [=this=].{{SmartCardConnection/[[comm]]}} is `null`, [=reject=] 1636 | |promise| with a "{{InvalidStateError}}" {{DOMException}} and return 1637 | |promise|.
  6. 1638 |
  7. Set 1639 | [=this=].{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}} 1640 | to `true`.
  8. 1641 |
  9. Let |pcscTag:DWORD| be a [[PCSC5]] `DWORD` containing 1642 | |tag|.
  10. 1643 |
  11. [=Get a copy of the buffer source=] |value:BufferSource| and save 1644 | the result in a [[PCSC5]] `BYTE[]` |buffer:array of BYTE|.
  12. 1645 |
  13. Run the following steps [=in parallel=]: 1646 |
      1647 |
    1. Call 1648 | [=this=].{{SmartCardConnection/[[comm]]}}.`SetReaderCapabilities()` 1649 | with |pcscTag| and |buffer| as arguments.
    2. 1650 |
    3. Let |responseCode:RESPONSECODE| be the returned 1651 | `RESPONSECODE`.
    4. 1652 |
    5. [=Queue a global task=] on the [=relevant global object=] of 1653 | [=this=] using the [=smart card task source=] which performs the 1654 | following steps: 1655 |
        1656 |
      1. [=Clear the operationInProgress=] of 1657 | [=this=].{{SmartCardConnection/[[context]]}}.
      2. 1658 |
      3. If |responseCode| is not `SCARD_S_SUCCESS`, [=reject=] 1659 | |promise| with an [=exception=] 1660 | {{SmartCardError/corresponding}} to |responseCode| and abort 1661 | these steps.
      4. 1662 |
      5. [=Resolve=] |promise|.
      6. 1663 |
      1664 |
    6. 1665 |
    1666 |
  14. 1667 |
  15. Return |promise|.
  16. 1668 |
1669 |
1670 |
1671 | 1672 |
1673 |

SmartCardError interface

1674 |
1675 |         [Exposed=(DedicatedWorker, SharedWorker, Window), Serializable]
1676 |         interface SmartCardError : DOMException {
1677 |           constructor(optional DOMString message = "", SmartCardErrorOptions options);
1678 |           readonly attribute SmartCardResponseCode responseCode;
1679 |         };
1680 |       
1681 |

The responseCode attribute is the error or warning response 1682 | code returned by the related [[PCSC5]] method.

1683 |

Given a [[PCSC5]] `RESPONSECODE` different from `SCARD_S_SUCCESS`, a 1684 | corresponding [=exception=] is 1685 | created with the following steps:

1686 | 1696 |
    1697 |
  1. Let |pcscCode:RESPONSECODE| be that `RESPONSECODE`.
  2. 1698 |
  3. If |pcscCode| is `SCARD_E_NO_SERVICE`, return a [=new=] 1699 | {{SmartCardResponseCode/"no-service"}} {{SmartCardError}}. 1700 | 1709 |
  4. 1710 |
  5. If |pcscCode| is `SCARD_E_NO_SMARTCARD`, return a [=new=] 1711 | {{SmartCardResponseCode/"no-smartcard"}} {{SmartCardError}}.
  6. 1712 |
  7. If |pcscCode| is `SCARD_E_NOT_READY`, return a [=new=] 1713 | {{SmartCardResponseCode/"not-ready"}} {{SmartCardError}}.
  8. 1714 |
  9. If |pcscCode| is `SCARD_E_NOT_TRANSACTED`, return a [=new=] 1715 | {{SmartCardResponseCode/"not-transacted"}} {{SmartCardError}}.
  10. 1716 |
  11. If |pcscCode| is `SCARD_E_PROTO_MISMATCH`, return a [=new=] 1717 | {{SmartCardResponseCode/"proto-mismatch"}} {{SmartCardError}}.
  12. 1718 |
  13. If |pcscCode| is `SCARD_E_READER_UNAVAILABLE`, return a [=new=] 1719 | {{SmartCardResponseCode/"reader-unavailable"}} 1720 | {{SmartCardError}}.
  14. 1721 |
  15. If |pcscCode| is `SCARD_W_REMOVED_CARD`, return a [=new=] 1722 | {{SmartCardResponseCode/"removed-card"}} {{SmartCardError}}.
  16. 1723 |
  17. If |pcscCode| is `SCARD_W_RESET_CARD`, return a [=new=] 1724 | {{SmartCardResponseCode/"reset-card"}} {{SmartCardError}}.
  18. 1725 |
  19. If |pcscCode| is `SCARD_E_SERVER_TOO_BUSY`, return a [=new=] 1726 | {{SmartCardResponseCode/"server-too-busy"}} {{SmartCardError}}.
  20. 1727 |
  21. If |pcscCode| is `SCARD_E_SHARING_VIOLATION`, return a [=new=] 1728 | {{SmartCardResponseCode/"sharing-violation"}} {{SmartCardError}}.
  22. 1729 |
  23. If |pcscCode| is `SCARD_E_SYSTEM_CANCELLED`, return a [=new=] 1730 | {{SmartCardResponseCode/"system-cancelled"}} {{SmartCardError}}.
  24. 1731 |
  25. If |pcscCode| is `SCARD_E_UNKNOWN_READER`, return a [=new=] 1732 | {{SmartCardResponseCode/"unknown-reader"}} {{SmartCardError}}.
  26. 1733 |
  27. If |pcscCode| is `SCARD_W_UNPOWERED_CARD`, return a [=new=] 1734 | {{SmartCardResponseCode/"unpowered-card"}} {{SmartCardError}}.
  28. 1735 |
  29. If |pcscCode| is `SCARD_W_UNRESPONSIVE_CARD`, return a [=new=] 1736 | {{SmartCardResponseCode/"unresponsive-card"}} {{SmartCardError}}.
  30. 1737 |
  31. If |pcscCode| is `SCARD_W_UNSUPPORTED_CARD`, return a [=new=] 1738 | {{SmartCardResponseCode/"unsupported-card"}} {{SmartCardError}}.
  32. 1739 |
  33. If |pcscCode| is `SCARD_E_UNSUPPORTED_FEATURE`, return a [=new=] 1740 | {{SmartCardResponseCode/"unsupported-feature"}} 1741 | {{SmartCardError}}.
  34. 1742 |
  35. If |pcscCode| is `SCARD_E_INVALID_PARAMETER`, return a [=new=] 1743 | {{TypeError}}.
  36. 1744 |
  37. If |pcscCode| is `SCARD_E_INVALID_HANDLE`, return a [=new=] 1745 | "{{InvalidStateError}}" {{DOMException}}.
  38. 1746 |
  39. If |pcscCode| is `SCARD_E_SERVICE_STOPPED`, return a [=new=] 1747 | "{{InvalidStateError}}" {{DOMException}}.
  40. 1748 |
  41. If |pcscCode| is `SCARD_P_SHUTDOWN`, return a [=new=] 1749 | "{{AbortError}}" {{DOMException}}.
  42. 1750 |
  43. Otherwise return a [=new=] "{{UnknownError}}" {{DOMException}}.
  44. 1751 |
1752 |
1753 |

SmartCardErrorOptions dictionary

1754 |
1755 |           dictionary SmartCardErrorOptions {
1756 |             required SmartCardResponseCode responseCode;
1757 |           };
1758 |         
1759 |

The responseCode member is the value for {{SmartCardError}}'s 1760 | {{SmartCardError/responseCode}} attribute.

1761 |
1762 |
1763 |

SmartCardResponseCode enum

1764 |
1765 |           enum SmartCardResponseCode {
1766 |             "no-service",
1767 |             "no-smartcard",
1768 |             "not-ready",
1769 |             "not-transacted",
1770 |             "proto-mismatch",
1771 |             "reader-unavailable",
1772 |             "removed-card",
1773 |             "reset-card",
1774 |             "server-too-busy",
1775 |             "sharing-violation",
1776 |             "system-cancelled",
1777 |             "unknown-reader",
1778 |             "unpowered-card",
1779 |             "unresponsive-card",
1780 |             "unsupported-card",
1781 |             "unsupported-feature"
1782 |           };
1783 |         
1784 |
1785 |
no-service
1786 |
SCARD_E_NO_SERVICE in the [[PCSC5]] spec.
1787 |
no-smartcard
1788 |
SCARD_E_NO_SMARTCARD in the [[PCSC5]] spec.
1789 |
not-ready
1790 |
SCARD_E_NOT_READY in the [[PCSC5]] spec.
1791 |
not-transacted
1792 |
SCARD_E_NOT_TRANSACTED in the [[PCSC5]] spec.
1793 |
proto-mismatch
1794 |
SCARD_E_PROTO_MISMATCH in the [[PCSC5]] spec.
1795 |
reader-unavailable
1796 |
SCARD_E_READER_UNAVAILABLE in the [[PCSC5]] spec.
1797 |
removed-card
1798 |
SCARD_W_REMOVED_CARD in the [[PCSC5]] spec.
1799 |
reset-card
1800 |
SCARD_W_RESET_CARD in the [[PCSC5]] spec.
1801 |
server-too-busy
1802 |
The smart card resource manager is too busy to complete this operation.
1803 |
sharing-violation
1804 |
SCARD_E_SHARING_VIOLATION in the [[PCSC5]] spec.
1805 |
system-cancelled
1806 |
SCARD_E_SYSTEM_CANCELLED in the [[PCSC5]] spec.
1807 |
unknown-reader
1808 |
SCARD_E_UNKNOWN_READER in the [[PCSC5]] spec.
1809 |
unpowered-card
1810 |
SCARD_W_UNPOWERED_CARD in the [[PCSC5]] spec.
1811 |
unresponsive-card
1812 |
SCARD_W_UNRESPONSIVE_CARD in the [[PCSC5]] spec.
1813 |
unsupported-card
1814 |
SCARD_W_UNSUPPORTED_CARD in the [[PCSC5]] spec.
1815 |
unsupported-feature
1816 |
SCARD_E_UNSUPPORTED_FEATURE in the [[PCSC5]] spec.
1817 |
1818 |
1819 |
1820 |
1821 |

Integrations

1822 | 1823 |
1824 |

Permissions Policy

1825 | 1826 |

This specification defines a feature that controls whether the 1827 | methods exposed by the {{Navigator/smartCard}} attribute on the 1828 | {{Navigator}} object may be used.

1829 | 1830 |

The feature name for this feature is 1831 | "smart-card".

1832 | 1833 |

The [=policy-controlled feature/default allowlist=] for this feature 1834 | is `'self'`.

1835 |
1836 |
1837 |
1838 | 1839 |
1840 | 1841 | 1842 | -------------------------------------------------------------------------------- /tidyconfig.txt: -------------------------------------------------------------------------------- 1 | char-encoding: utf8 2 | indent: yes 3 | indent-spaces: 2 4 | wrap: 80 5 | tidy-mark: no 6 | -------------------------------------------------------------------------------- /w3c.json: -------------------------------------------------------------------------------- 1 | { 2 | "group": [80485] 3 | , "contacts": ["cwilso"] 4 | , "repo-type": "cg-report" 5 | } 6 | --------------------------------------------------------------------------------