├── .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 |
SmartCardReader.connect
14 |
15 |
MS Windows
16 |
17 |
PCSClite macOS
18 |
19 |
20 |
21 |
if a transaction is ongoing:
22 |
23 |
24 |
25 |
26 |
27 |
shared mode
28 |
29 |
blocks
30 |
31 |
32 |
33 |
34 |
35 |
exclusive mode
36 |
37 |
fails with SCARD_E_SHARING_VIOLATION
38 |
39 |
40 |
41 |
42 |
43 |
direct mode
44 |
45 |
fails with SCARD_E_SHARING_VIOLATION (behaves as exclusive)
46 |
47 |
works (behaves as shared)
48 |
49 |
50 |
51 |
if another connection has exclusive mode:
52 |
53 |
54 |
55 |
56 |
57 |
shared mode
58 |
59 |
SCARD_E_SHARING_VIOLATION
60 |
61 |
62 |
63 |
64 |
65 |
exclusive mode
66 |
67 |
SCARD_E_SHARING_VIOLATION
68 |
69 |
70 |
71 |
72 |
73 |
direct mode
74 |
75 |
SCARD_E_SHARING_VIOLATION
76 |
77 |
works, but there's a protocol mismatch on transmission
78 |
79 |
80 |
81 |
direct mode, without concurrent connections:
82 |
83 |
84 |
85 |
86 | preferredProtocols: T0|T1
87 |
88 |
89 |
activeProtocol T1
90 |
91 |
activeProtocol T0|T1 (ie, transmitting will fail)
92 |
93 |
94 |
95 |
96 | preferredProtocols undefined
97 |
98 |
99 |
activeProtocol T1
100 |
101 |
error "invalid value given"
102 |
103 |
104 |
105 |
106 | preferredProtocols raw
107 |
108 |
109 |
SCARD_E_NOT_READY
110 |
111 |
activeProtocol raw
112 |
113 |
114 |
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 |
Gemalto (card removed after connection established)
163 |
164 |
shared, T0|T1
165 |
166 |
SCARD_W_REMOVED_CARD
167 |
168 |
169 |
170 |
Gemalto (card removed after connection established and then reinserted)
171 |
172 |
shared, T0|T1
173 |
174 |
SCARD_W_REMOVED_CARD
175 |
176 |
SCARD_W_RESET_CARD
177 |
178 |
179 |
180 |
Gemalto (reader removed after connection established)
181 |
182 |
shared, T0|T1
183 |
184 |
SCARD_E_SERVICE_STOPPED
185 |
186 |
SCARD_E_READER_UNAVAILABLE
187 |
188 |
189 |
190 |
YubiKey
191 |
192 |
direct, undefined
193 |
194 |
absent | powered, undefined
195 |
196 |
Error: invalid value
197 |
198 |
199 |
200 |
Gemalto (with card)
201 |
202 |
direct, undefined
203 |
204 |
present, undefined
205 |
206 |
Error: invalid value
207 |
208 |
209 |
210 |
Gemalto (without card)
211 |
212 |
direct, undefined
213 |
214 |
absent, undefined
215 |
216 |
Error: invalid value
217 |
218 |
219 |
220 |
Gemalto (card inserted after connection established)
221 |
222 |
direct, undefined
223 |
224 |
absent | present, undefined
225 |
226 |
N.A.
227 |
228 |
229 |
230 |
Gemalto (card inserted after connection established)
231 |
232 |
direct, raw
233 |
234 |
N.A.
235 |
236 |
0x7fb7, raw
237 |
238 | then SCARD_W_RESET_CARD
239 |
240 |
241 |
242 |
YubiKey
243 |
244 |
direct, raw
245 |
246 |
SCARD_E_NOT_READY
247 |
248 |
present | powered | specific, raw
249 |
250 |
251 |
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 |
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 |
89 |
Let |promise:Promise| be [=a new promise=].
90 |
Run the following steps [=in parallel=]:
91 |
92 |
Let |resourceManager:RESOURCEMANAGER| be a new instance of the
93 | platform's [[PCSC5]] `RESOURCEMANAGER` class.
94 |
Invoke the `EstablishContext` method of |resourceManager| with
95 | a "system" `Scope` parameter.
96 |
If the returned `RESPONSECODE` is not `SCARD_S_SUCCESS`, perform
97 | the following steps:
98 |
99 |
Destroy |resourceManager|.
100 |
[=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=].
104 |
105 |
106 |
Otherwise, perform the following steps:
107 |
108 |
Let |context:SmartCardContext| be a [=new=]
109 | {{SmartCardContext}} whose
110 | {{SmartCardContext/[[resourceManager]]}} internal slot is set
111 | to |resourceManager|.
112 |
[=Queue a global task=] on the [=relevant global object=]
113 | of [=this=] using the [=smart card task source=] to
114 | [=resolve=] |promise| with |context|.
115 |
116 |
117 |
118 |
119 |
Return |promise|.
120 |
121 |
122 |
123 |
124 |
125 |
SmartCardContext interface
126 |
A context for communicating with the PC/SC resource manager.
Instances of {{SmartCardContext}} are created with the internal slots
143 | described in the following table:
144 |
145 |
146 |
Internal slot
147 |
Initial value
148 |
Description (non-normative)
149 |
150 |
151 |
[[\resourceManager]]
152 |
`null`
153 |
The platform's [[PCSC5]] `RESOURCEMANAGER` to be used.
154 |
155 |
156 |
[[\operationInProgress]]
157 |
`false`
158 |
Whether there is an ongoing PC/SC operation in this context.
159 |
160 |
161 |
[[\connections]]
162 |
An empty [=ordered set=]
163 |
The existing {{SmartCardConnection}}s created by this context.
164 |
165 |
166 |
[[\tracker]]
167 |
`null`
168 |
A [[PCSC5]] `SCARDTRACK` instance.
169 |
170 |
171 |
[[\signal]]
172 |
`null`
173 |
The {{AbortSignal}} of the outstanding
174 | {{SmartCardContext/getStatusChange()}} call, if any.
175 |
176 |
177 |
183 |
184 |
listReaders() method
185 |
The {{SmartCardContext/listReaders()}} method steps
186 | are:
187 |
188 |
Let |promise:Promise| be [=a new promise=].
189 |
If [=this=].{{SmartCardContext/[[operationInProgress]]}} is
190 | `true`, [=reject=] |promise| with a "{{InvalidStateError}}"
191 | {{DOMException}} and return |promise|.
192 |
Set [=this=].{{SmartCardContext/[[operationInProgress]]}} to
193 | `true`.
194 |
Run the following steps [=in parallel=]:
195 |
196 |
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.
200 |
201 |
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 |
207 |
Let |pcscReaders:array of STR| be an empty `STR[]`.
208 |
Invoke the `ListReaders` method of |resourceQuery| with
209 | |groups| as input and |pcscReaders| as output parameters.
210 |
Let |responseCode:RESPONSECODE| be the returned
211 | `RESPONSECODE`.
212 |
Destroy |resourceQuery|.
213 |
[=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 |
[=Clear the operationInProgress=] of [=this=].
218 |
If |responseCode| is not `SCARD_S_SUCCESS`:
219 |
220 |
If |responseCode| is `SCARD_E_NO_READERS_AVAILABLE`,
221 | [=resolve=] |promise| with an empty `sequence` of
222 | {{DOMString}}.
223 |
229 |
230 |
Otherwise, [=reject=] |promise| with an
231 | [=exception=] {{SmartCardError/corresponding}} to
232 | |responseCode|.
233 |
234 |
235 |
Otherwise, [=resolve=] |promise| with a `sequence` of
236 | {{DOMString}} equivalent to |pcscReaders|.
237 |
238 |
239 |
240 |
241 |
Return |promise|.
242 |
243 |
244 |
245 |
getStatusChange() method
246 |
The {{SmartCardContext/getStatusChange(readerStates, options)}} method steps
247 | are:
248 |
249 |
Let |promise:Promise| be [=a new promise=].
250 |
If [=this=].{{SmartCardContext/[[operationInProgress]]}} is
251 | `true`, [=reject=] |promise| with a "{{InvalidStateError}}"
252 | {{DOMException}} and return |promise|.
253 |
If
254 | |options:SmartCardGetStatusChangeOptions|["{{SmartCardGetStatusChangeOptions/signal}}"]
255 | [=map/exists=], run the following steps:
256 |
257 |
Let |signal:AbortSignal| be
258 | |options|["{{SmartCardGetStatusChangeOptions/signal}}"].
259 |
If |signal| is [=AbortSignal/aborted=], [=reject=] |promise|
260 | with |signal|'s [=AbortSignal/abort reason=] and return
261 | |promise|.
262 |
Set [=this=].{{SmartCardContext/[[signal]]}} to |signal|
263 |
[=AbortSignal/Add=] the {{SmartCardContext/Cancel the outstanding
264 | GetStatusChange}} algorithm to |signal|.
265 |
266 |
267 |
Let |pcscTimeout:DWORD| be a [[PCSC5]] `DWORD` set to [[PCSC5]]
268 | `INFINITE`.
269 |
If
270 | |options|["{{SmartCardGetStatusChangeOptions/timeout}}"]
271 | [=map/exists=], set |pcscTimeout| to
272 | |options|["{{SmartCardGetStatusChangeOptions/timeout}}"].
273 |
Let |pcscReaderStates:array of SCARD_READERSTATE| be a [[PCSC5]]
274 | `SCARD_READERSTATE[]` [=SmartCardReaderStateIn/corresponding=] to
275 | |readerStates:sequence<SmartCardReaderStateIn>|.
276 |
Set [=this=].{{SmartCardContext/[[operationInProgress]]}} to
277 | `true`.
278 |
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.
282 |
Run the following steps [=in parallel=]:
283 |
284 |
Call
285 | [=this=].{{SmartCardContext/[[tracker]]}}.`GetStatusChange()`
286 | with |pcscReaderStates| and |pcscTimeout| as input parameters.
287 |
Let |responseCode:RESPONSECODE| be the returned
288 | [[PCSC5]] `RESPONSECODE`.
289 |
[=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 |
Set [=this=].{{SmartCardContext/[[tracker]]}} to `null`.
294 |
[=Clear the operationInProgress=] of [=this=].
295 |
Let |abortReason| be {{undefined}}.
296 |
If [=this=].{{SmartCardContext/[[signal]]}} is not `null`,
297 | run the following steps:
298 |
299 |
If [=this=].{{SmartCardContext/[[signal]]}} is
300 | [=AbortSignal/aborted=] then set |abortReason| to
301 | [=this=].{{SmartCardContext/[[signal]]}}'s
302 | [=AbortSignal/abort reason=].
303 |
[=AbortSignal/Remove=] the {{SmartCardContext/cancel the
304 | outstanding GetStatusChange}} algorithm from
305 | [=this=].{{SmartCardContext/[[signal]]}}.
306 |
Set [=this=].{{SmartCardContext/[[signal]]}} to
307 | `null`.
308 |
309 |
310 |
If |responseCode| is not `SCARD_S_SUCCESS`, run the
311 | following steps:
312 |
313 |
If |responseCode| is `SCARD_E_CANCELLED` and
314 | |abortReason| is not {{undefined}} then [=reject=]
315 | |promise| with |abortReason|.
316 |
Otherwise, [=reject=] |promise| with an [=exception=]
317 | {{SmartCardError/corresponding}} to |responseCode|.
318 |
Return.
319 |
320 |
321 |
Let
322 | |readerStatesOut:sequence<SmartCardReaderStateOut>| be
323 | a sequence of {{SmartCardReaderStateOut}}
324 | [=SmartCardReaderStateOut/corresponding=] to
325 | |pcscReaderStates|.
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 |
Let |pcscReaderStates:array of SCARD_READERSTATE| be an empty
363 | `SCARD_READERSTATE[]`.
364 |
[=list/For each=] |stateIn:SmartCardReaderStateIn| in |readerStates|:
365 |
366 |
Let |pcscState:SCARD_READERSTATE| be a `SCARD_READERSTATE`.
367 |
Set |pcscState|.`Reader` to
368 | |stateIn|["{{SmartCardReaderStateIn/readerName}}"].
369 |
Set |pcscState|.`CurrentState` to the `DWORD`
370 | [=SmartCardReaderStateFlagsIn/corresponding=]
371 | to |stateIn|["{{SmartCardReaderStateIn/currentState}}"].
372 |
If |stateIn|["{{SmartCardReaderStateIn/currentCount}}"]
373 | [=map/exists=], [=SmartCardContext/set the high word=] of
374 | |pcscState|.`CurrentState` to
375 | |stateIn|["{{SmartCardReaderStateIn/currentCount}}"].
376 |
Set |pcscState|.`EventState` to zero.
377 |
[=list/Append=] |pcscState| to |pcscReaderStates|.
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 |
Let |flagsIn:SmartCardReaderStateFlagsIn| be the given
445 | {{SmartCardReaderStateFlagsIn}}.
446 |
Let |pcscFlags:DWORD| be a `DWORD` set to zero.
447 |
If |flagsIn|["{{SmartCardReaderStateFlagsIn/unaware}}"] is
448 | `true`, [=add a flag|add=] [[PCSC5]] `SCARD_STATE_UNAWARE` to
449 | |pcscFlags|.
450 |
If |flagsIn|["{{SmartCardReaderStateFlagsIn/ignore}}"] is
451 | `true`, [=add a flag|add=] [[PCSC5]] `SCARD_STATE_IGNORE` to
452 | |pcscFlags|.
453 |
If |flagsIn|["{{SmartCardReaderStateFlagsIn/unavailable}}"]
454 | is `true`, [=add a flag|add=] [[PCSC5]]
455 | `SCARD_STATE_UNAVAILABLE` to |pcscFlags|.
456 |
If |flagsIn|["{{SmartCardReaderStateFlagsIn/empty}}"] is
457 | `true`, [=add a flag|add=] [[PCSC5]] `SCARD_STATE_EMPTY` to
458 | |pcscFlags|.
459 |
If |flagsIn|["{{SmartCardReaderStateFlagsIn/present}}"] is
460 | `true`, [=add a flag|add=] [[PCSC5]] `SCARD_STATE_PRESENT` to
461 | |pcscFlags|.
462 |
If |flagsIn|["{{SmartCardReaderStateFlagsIn/exclusive}}"] is
463 | `true`, [=add a flag|add=] [[PCSC5]] `SCARD_STATE_EXCLUSIVE` to
464 | |pcscFlags|.
465 |
If |flagsIn|["{{SmartCardReaderStateFlagsIn/inuse}}"] is
466 | `true`, [=add a flag|add=] [[PCSC5]] `SCARD_STATE_INUSE` to
467 | |pcscFlags|.
468 |
If |flagsIn|["{{SmartCardReaderStateFlagsIn/mute}}"] is
469 | `true`, [=add a flag|add=] `SCARD_STATE_MUTE` to
470 | |pcscFlags|.
471 |
472 |
If |flagsIn|["{{SmartCardReaderStateFlagsIn/unpowered}}"] is
473 | `true`, [=add a flag|add=] `SCARD_STATE_UNPOWERED` to
474 | |pcscFlags|.
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 |
Let |readerStatesOut:sequence<SmartCardReaderStateOut>| be
519 | an empty sequence of {{SmartCardReaderStateOut}}.
Let |stateOut:SmartCardReaderStateOut| be a
524 | {{SmartCardReaderStateOut}}.
525 |
Set |stateOut|["{{SmartCardReaderStateOut/readerName}}"] to
526 | |pcscState|.`Reader`.
527 |
Set |stateOut|["{{SmartCardReaderStateOut/eventState}}"] to
528 | the {{SmartCardReaderStateFlagsOut}} dictionary
529 | [=SmartCardReaderStateFlagsOut/corresponding=]
530 | to |pcscState|.`EventState`.
531 |
Set |stateOut|["{{SmartCardReaderStateOut/eventCount}}"] to
532 | the [=SmartCardContext/high word=] of |pcscState|.`EventState`.
533 |
548 |
549 |
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.
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 |
Let |flagsOut:SmartCardReaderStateFlagsOut| be a
618 | {{SmartCardReaderStateFlagsOut}} dictionary with [=dictionary
619 | member/default value|default members=].
620 |
If |pcscFlags| [=has a flag|has=] [[PCSC5]]
621 | `SCARD_STATE_IGNORE`, set
622 | |flagsOut|["{{SmartCardReaderStateFlagsOut/ignore}}"] to
623 | `true`.
624 |
If |pcscFlags| [=has a flag|has=] [[PCSC5]]
625 | `SCARD_STATE_CHANGED`, set
626 | |flagsOut|["{{SmartCardReaderStateFlagsOut/changed}}"] to
627 | `true`.
628 |
If |pcscFlags| [=has a flag|has=] [[PCSC5]]
629 | `SCARD_STATE_UNAVAILABLE`, set
630 | |flagsOut|["{{SmartCardReaderStateFlagsOut/unavailable}}"] to
631 | `true`.
632 |
If |pcscFlags| [=has a flag|has=] [[PCSC5]]
633 | `SCARD_STATE_UNKNOWN`, set
634 | |flagsOut|["{{SmartCardReaderStateFlagsOut/unknown}}"] to
635 | `true`.
636 |
If |pcscFlags| [=has a flag|has=] [[PCSC5]]
637 | `SCARD_STATE_EMPTY`, set
638 | |flagsOut|["{{SmartCardReaderStateFlagsOut/empty}}"] to
639 | `true`.
640 |
If |pcscFlags| [=has a flag|has=] [[PCSC5]]
641 | `SCARD_STATE_PRESENT`, set
642 | |flagsOut|["{{SmartCardReaderStateFlagsOut/present}}"] to
643 | `true`.
644 |
If |pcscFlags| [=has a flag|has=] [[PCSC5]]
645 | `SCARD_STATE_EXCLUSIVE`, set
646 | |flagsOut|["{{SmartCardReaderStateFlagsOut/exclusive}}"] to
647 | `true`.
648 |
If |pcscFlags| [=has a flag|has=] [[PCSC5]]
649 | `SCARD_STATE_INUSE`, set
650 | |flagsOut|["{{SmartCardReaderStateFlagsOut/inuse}}"] to
651 | `true`.
652 |
If |pcscFlags| [=has a flag|has=] `SCARD_STATE_MUTE`, set
653 | |flagsOut|["{{SmartCardReaderStateFlagsOut/mute}}"] to
654 | `true`.
655 |
If |pcscFlags| [=has a flag|has=] `SCARD_STATE_UNPOWERED`, set
656 | |flagsOut|["{{SmartCardReaderStateFlagsOut/unpowered}}"] to
657 | `true`.
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 |
Let |promise:Promise| be [=a new promise=].
694 |
If [=this=].{{SmartCardContext/[[operationInProgress]]}} is
695 | `true`, [=reject=] |promise| with a "{{InvalidStateError}}"
696 | {{DOMException}} and return |promise|.
697 |
Set [=this=].{{SmartCardContext/[[operationInProgress]]}} to
698 | `true`.
699 |
Run the following steps [=in parallel=]:
700 |
701 |
Let |accessFlags:DWORD| be a [[PCSC5]] `DWORD`
702 | [=SmartCardAccessMode/corresponding=] to
703 | |accessMode:SmartCardAccessMode|.
704 |
Let |protocolFlags:DWORD| be a `DWORD` set to `0`.
705 |
If
706 | |options:SmartCardConnectOptions|["{{SmartCardConnectOptions/preferredProtocols}}"]
707 | [=map/exists=], set |protocolFlags| to its
708 | [=SmartCardProtocol/corresponding flags=].
709 |
Let |activeProtocol:DWORD| be a `DWORD` set to `0`.
710 |
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.
714 |
Call |comm|.`Connect()` with |readerName|, |accessFlags|
715 | and |protocolFlags| as input and |activeProtocol| as output parameters.
716 |
Let |responseCode:RESPONSECODE| be the returned
717 | `RESPONSECODE`.
718 |
[=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 |
[=Clear the operationInProgress=] of [=this=].
723 |
If |responseCode| is not `SCARD_S_SUCCESS`:
724 |
725 |
Destroy |comm|.
726 |
[=Reject=] |promise| with an [=exception=]
727 | {{SmartCardError/corresponding}} to |responseCode| and abort these steps.
728 |
729 |
730 |
Let |result:SmartCardConnectResult| be an empty
731 | {{SmartCardConnectResult}} dictionary.
732 |
Let |connection:SmartCardConnection| be a new
733 | {{SmartCardConnection}}.
734 |
[=set/Append=] |connection| to
735 | [=this=].{{SmartCardContext/[[connections]]}}.
736 |
Set |connection|.{{SmartCardConnection/[[comm]]}} to |comm|.
737 |
Set |connection|.{{SmartCardConnection/[[context]]}} to
738 | [=this=].
739 |
Set |connection|.{{SmartCardConnection/[[activeProtocol]]}} to
740 | |activeProtocol|.
741 |
Set |result|["{{SmartCardConnectResult/connection}}"] to
742 | |connection|.
743 |
If |activeProtocol| is a [=SmartCardProtocol/valid
744 | protocol value=], set
745 | |result|["{{SmartCardConnectResult/activeProtocol}}"] to the
746 | corresponding {{SmartCardProtocol}}.
"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 |
Let |flags:DWORD| be a `DWORD` set to `0`.
788 |
[=list/For each=] |protocol:SmartCardProtocol| in |protocols|,
789 | [=add a flag|add=] the corresponding `DWORD` of |protocol| to |flags|.
790 |
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 |
Let |dword:DWORD| be a `DWORD` set to `0`.
835 |
If |accessMode| is "{{SmartCardAccessMode/shared}}", set |dword| to [[PCSC5]]
836 | `SCARD_SHARE_SHARED`.
837 |
If |accessMode| is "{{SmartCardAccessMode/exclusive}}", set |dword| to [[PCSC5]]
838 | `SCARD_SHARE_EXCLUSIVE`.
839 |
If |accessMode| is "{{SmartCardAccessMode/direct}}", set |dword| to [[PCSC5]]
840 | `SCARD_SHARE_DIRECT`.
Instances of {{SmartCardConnection}} are created with the internal slots
939 | described in the following table:
940 |
941 |
942 |
Internal slot
943 |
Initial value
944 |
Description (non-normative)
945 |
946 |
947 |
[[\comm]]
948 |
`null`
949 |
The platform's [[PCSC5]] `SCARDCOMM` to be used.
950 |
951 |
952 |
[[\context]]
953 |
`null`
954 |
The {{SmartCardContext}} that created this instance.
955 |
956 |
957 |
[[\activeProtocol]]
958 |
0
959 |
The active protocol `DWORD`, as returned by the platform's
960 | [[PCSC5]] implementation.
961 |
962 |
963 |
[[\transactionState]]
964 |
`null`
965 |
Holds the [=transaction state|state=] of an ongoing transaction
966 | started with {{SmartCardConnection/startTransaction()}}, if
967 | any.
968 |
969 |
970 |
981 |
982 |
disconnect() method
983 |
The {{SmartCardConnection/disconnect(disposition)}} method steps
984 | are:
985 |
986 |
Let |promise:Promise| be [=a new promise=].
987 |
If
988 | [=this=].{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}}
989 | is `true`, [=reject=] |promise| with a "{{InvalidStateError}}"
990 | {{DOMException}} and return |promise|.
991 |
If [=this=].{{SmartCardConnection/[[comm]]}} is `null`, [=reject=]
992 | |promise| with a "{{InvalidStateError}}" {{DOMException}} and return
993 | |promise|.
994 |
Set
995 | [=this=].{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}}
996 | to `true`.
997 |
Run the following steps [=in parallel=]:
998 |
999 |
Call [=this=].{{SmartCardConnection/[[comm]]}}.`Disconnect()`
1000 | with a `DWORD` corresponding to
1001 | |disposition:SmartCardDisposition| as input parameter.
1002 |
Let |responseCode:RESPONSECODE| be the returned
1003 | `RESPONSECODE`.
1004 |
[=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 |
[=Clear the operationInProgress=] of
1009 | [=this=].{{SmartCardConnection/[[context]]}}.
1010 |
If |responseCode| is not `SCARD_S_SUCCESS`, [=reject=]
1011 | |promise| with an [=exception=]
1012 | {{SmartCardError/corresponding}} to |responseCode| and abort
1013 | these steps.
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 |
Let |promise:Promise| be [=a new promise=].
1056 |
If
1057 | [=this=].{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}}
1058 | is `true`, [=reject=] |promise| with a "{{InvalidStateError}}"
1059 | {{DOMException}} and return |promise|.
1060 |
If [=this=].{{SmartCardConnection/[[comm]]}} is `null`, [=reject=]
1061 | |promise| with a "{{InvalidStateError}}" {{DOMException}} and return
1062 | |promise|.
1063 |
Let |protocol:DWORD| be a [[PCSC5]] `DWORD` set to
1064 | [=this=].{{SmartCardConnection/[[activeProtocol]]}}.
1065 |
If
1066 | |options:SmartCardTransmitOptions|["{{SmartCardTransmitOptions/protocol}}"]
1067 | [=map/exists=], set |protocol| to the `DWORD` corresponding to
1068 | |options:SmartCardTransmitOptions|["{{SmartCardTransmitOptions/protocol}}"].
1069 |
If |protocol| is not a [=SmartCardProtocol/valid protocol value=],
1070 | [=reject=] |promise| with a "{{InvalidStateError}}" {{DOMException}}
1071 | and return |promise|.
1072 |
Set
1073 | [=this=].{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}}
1074 | to `true`.
1075 |
Let |sendPci:SCARD_IO_HEADER| be the platform's [[PCSC5]]
1076 | `SCARD_IO_HEADER` corresponding to
1077 | [=this=].{{SmartCardConnection/[[activeProtocol]]}}.
1078 |
Let |pcscSendBuffer:array of BYTE| be a [[PCSC5]] `BYTE[]`
1079 | containing |sendBuffer:BufferSource|.
1080 |
Let |recvPci:SCARD_IO_HEADER| be the platform's `SCARD_IO_HEADER`
1081 | equivalent of empty or null.
1082 |
Let |recvBuffer:array of BYTE| be a `BYTE[]` big enough to hold
1083 | the largest [[ISO7186-3]] extended response APDU (65538 bytes).
1084 |
Let |recvLength:DWORD| be a `DWORD` set to `0`.
1085 |
Run the following steps [=in parallel=]:
1086 |
1087 |
Call [=this=].{{SmartCardConnection/[[comm]]}}.`Transmit()`
1088 | with |sendPci|, |pcscSendBuffer|, |recvPci|, |recvBuffer| and
1089 | |recvLength| as arguments.
1090 |
Let |responseCode:RESPONSECODE| be the returned
1091 | `RESPONSECODE`.
1092 |
[=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 |
[=Clear the operationInProgress=] of
1097 | [=this=].{{SmartCardConnection/[[context]]}}.
1098 |
If |responseCode| is not `SCARD_S_SUCCESS`, [=reject=]
1099 | |promise| with an [=exception=]
1100 | {{SmartCardError/corresponding}} to |responseCode| and abort
1101 | these steps.
1102 |
[=Resolve=] |promise| with an {{ArrayBuffer}} containing
1103 | the first |recvLength| bytes of |recvBuffer|.
The {{SmartCardConnection/startTransaction(transaction, options)}}
1126 | method steps are:
1127 |
1128 |
Let |promise:Promise| be [=a new promise=].
1129 |
If
1130 | [=this=].{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}}
1131 | is `true`, [=reject=] |promise| with a "{{InvalidStateError}}"
1132 | {{DOMException}} and return |promise|.
1133 |
If [=this=].{{SmartCardConnection/[[comm]]}} is `null`, [=reject=]
1134 | |promise| with a "{{InvalidStateError}}" {{DOMException}} and return
1135 | |promise|.
1136 |
If [=this=].{{SmartCardConnection/[[transactionState]]}} is not
1137 | `null`, [=reject=] |promise| with a "{{InvalidStateError}}"
1138 | {{DOMException}} and return |promise|.
1139 |
Let |signal| be an {{AbortSignal}} set to `null`.
1140 |
If
1141 | |options:SmartCardTransactionOptions|["{{SmartCardTransactionOptions/signal}}"]
1142 | [=map/exists=], run the following steps:
1143 |
1144 |
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|.
1149 |
Set |signal| to
1150 | |options|["{{SmartCardTransactionOptions/signal}}"].
1151 |
[=AbortSignal/Add=] the {{SmartCardConnection/cancel}}
1152 | algorithm to |signal|.
1153 |
1154 |
1155 |
Set
1156 | [=this=].{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}}
1157 | to `true`.
1158 |
Run the following steps [=in parallel=]:
1159 |
1160 |
Let |responseCode:RESPONSECODE| be the returned [[PCSC5]]
1163 | `RESPONSECODE`.
1164 |
[=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 |
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 |
Item
1194 |
Description (non-normative)
1195 |
1196 |
pendingDisposition
1197 |
If set, it means once the ongoing PC/SC operation finishes
1198 | [[PCSC5]] `EndTransaction()` should be called with this value as the
1199 | {{SmartCardDisposition}} parameter.
1200 |
1201 |
1202 |
pendingException
1203 |
The exception to be used when rejecting
1204 | [=transaction state/promise=].
1205 |
1206 |
1207 |
promise
1208 |
The pending {{Promise}} returned by a
1209 | {{SmartCardConnection/startTransaction()}} call.
1210 |
1211 |
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 |
[=Clear the operationInProgress=] of
1220 | |connection|.{{SmartCardConnection/[[context]]}}.
1221 |
Let |abortReason| be {{undefined}}.
1222 |
If |signal| is not `null`:
1223 |
1224 |
[=AbortSignal/Remove=] the
1225 | {{SmartCardConnection/cancel}} algorithm from
1226 | |signal|.
1227 |
If |signal| is [=AbortSignal/aborted=] then set
1228 | |abortReason| to |signal|'s [=AbortSignal/abort
1229 | reason=].
1230 |
1231 |
1232 |
If |responseCode| is not `SCARD_S_SUCCESS`:
1233 |
1234 |
If |responseCode| is `SCARD_E_CANCELLED` and
1235 | |abortReason| is not {{undefined}} then [=reject=]
1236 | |promise| with |abortReason|.
1237 |
Otherwise, [=reject=] |promise| with an
1238 | [=exception=] {{SmartCardError/corresponding}} to
1239 | |responseCode|.
1240 |
Return.
1241 |
1242 |
1243 |
Let |transactionState:transaction state| be a new [=transaction
1244 | state=] with its [=transaction state/promise=] item set to
1245 | |promise|.
1246 |
Set |connection|.{{SmartCardConnection/[[transactionState]]}}
1247 | to |transactionState|.
1248 |
Let |callbackPromise:Promise| be the result of [=invoking=]
1249 | |transaction|.
1250 |
[=promise/React=] to |callbackPromise|:
1251 |
1252 |
If |callbackPromise| was fulfilled with value |v|
1253 | then:
1254 |
1255 |
Let |disposition:SmartCardDisposition| be
1256 | "{{SmartCardDisposition/reset}}".
1257 |
If |v| is not {{undefined}}, set |disposition| to
1258 | |v|.
1259 |
If
1260 | |connection|.{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}}
1261 | is `true`:
1262 |
1263 |
Set |transactionState|'s [=transaction
1264 | state/pendingException=] to a "{{InvalidStateError}}"
1265 | {{DOMException}}.
1266 |
Set
1267 | |transactionState|'s [=transaction state/pendingDisposition=]
1268 | to |disposition|.
1269 |
1270 |
1271 |
Otherwise, [=end the transaction=] of |connection| with
1272 | |disposition|.
1273 |
1274 |
1275 |
If |callbackPromise| was rejected with reason |r|, then:
1276 |
1277 |
Set |transactionState|'s [=transaction
1278 | state/pendingException=] to |r|.
1279 |
If
1280 | |connection|.{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}}
1281 | is `true`, set
1282 | |transactionState|'s [=transaction state/pendingDisposition=] to
1283 | "{{SmartCardDisposition/reset}}".
1284 |
Otherwise, [=end the transaction=] of |connection| with
1285 | "{{SmartCardDisposition/reset}}".
1286 |
1287 |
1288 |
1289 |
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 |
[=Assert=]:
1297 | |connection|.{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}}
1298 | is `false`.
1299 |
[=Assert=]:
1300 | |connection|.{{SmartCardConnection/[[transactionState]]}} is not
1301 | `null`.
1302 |
[=Assert=]: |connection|.{{SmartCardConnection/[[transactionState]]}}'s
1303 | [=transaction state/pendingDisposition=] is `null`.
1304 |
Let |transactionPromise:Promise| be
1305 | |connection|.{{SmartCardConnection/[[transactionState]]}}'s
1306 | [=transaction state/promise=].
1307 |
If |connection|.{{SmartCardConnection/[[comm]]}} is `null`:
1308 |
1309 |
[=Reject=] |transactionPromise| with a "{{InvalidStateError}}"
1310 | {{DOMException}}.
1311 |
Set
1312 | |connection|.{{SmartCardConnection/[[transactionState]]}} to
1313 | `null`.
1314 |
Return.
1315 |
1316 |
1317 |
Set
1318 | |connection|.{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}}
1319 | to `true`.
1320 |
Run the following steps [=in parallel=]:
1321 |
1322 |
Call
1323 | [=this=].{{SmartCardConnection/[[comm]]}}.`EndTransaction()` with
1324 | a `DWORD` corresponding to |disposition| as input parameter.
1325 |
Let |responseCode:RESPONSECODE| be the returned [[PCSC5]]
1326 | `RESPONSECODE`.
1327 |
[=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 |
[=Clear the operationInProgress=] of
1332 | |connection|.{{SmartCardConnection/[[context]]}}.
1333 |
Let |exception| be
1334 | |connection|.{{SmartCardConnection/[[transactionState]]}}'s
1335 | [=transaction state/pendingException=].
1336 |
If |exception| is `null`, perform the following steps:
1337 |
1338 |
If |responseCode| is `SCARD_S_SUCCESS`,
1339 | [=resolve=] |transactionPromise|.
1340 |
Otherwise, [=reject=] |transactionPromise| with an
1341 | [=exception=] {{SmartCardError/corresponding}} to
1342 | |responseCode|.
1343 |
1344 |
1345 |
Otherwise, [=reject=] |transactionPromise| with
1346 | |exception|.
1347 |
Set
1348 | |connection|.{{SmartCardConnection/[[transactionState]]}}
1349 | to `null`.
1350 |
1351 |
1352 |
1353 |
1354 |
1355 |
1356 |
To end any settled transaction of a
1357 | {{SmartCardConnection}} |connection:SmartCardConnection|, perform the
1358 | following steps:
1359 |
1360 |
If |connection|.{{SmartCardConnection/[[transactionState]]}} is
1361 | `null`, abort these steps.
1362 |
Let |disposition| be
1363 | |connection|.{{SmartCardConnection/[[transactionState]]}}'s
1364 | [=transaction state/pendingDisposition=].
1365 |
If |disposition| is `null`, abort these steps.
1366 |
Set |connection|.{{SmartCardConnection/[[transactionState]]}}'s
1367 | [=transaction state/pendingDisposition=] to `null`.
1368 |
[=End the transaction=] of |connection| with |disposition|.
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 |
Let |promise:Promise| be [=a new promise=].
1380 |
If
1381 | [=this=].{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}}
1382 | is `true`, [=reject=] |promise| with a "{{InvalidStateError}}"
1383 | {{DOMException}} and return |promise|.
1384 |
If [=this=].{{SmartCardConnection/[[comm]]}} is `null`, [=reject=]
1385 | |promise| with a "{{InvalidStateError}}" {{DOMException}} and return
1386 | |promise|.
1387 |
Set
1388 | [=this=].{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}}
1389 | to `true`.
1390 |
Run the following steps [=in parallel=]:
1391 |
1392 |
Let |pcscReader:array of STR| be an empty `STR[]`.
1393 |
Let |pcscState:DWORD| be a [[PCSC5]] `DWORD` set to `0`.
1394 |
Let |activeProtocol:DWORD| be a [[PCSC5]] `DWORD` set to `0`.
1395 |
Let |pcscAtr:array of BYTE| be a `BYTE[]` big enough to hold
1396 | any [[ISO7186-3]] Answer To Reset (ATR).
1397 |
Call [=this=].{{SmartCardConnection/[[comm]]}}.`Status()`
1398 | with |pcscReader|, |pcscState|, |activeProtocol| and |pcscAtr| as
1399 | output parameters.
1400 |
Let |responseCode:RESPONSECODE| be the returned
1401 | `RESPONSECODE`.
1402 |
[=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 |
[=Clear the operationInProgress=] of
1407 | [=this=].{{SmartCardConnection/[[context]]}}.
1408 |
If |responseCode| is not `SCARD_S_SUCCESS`, [=reject=]
1409 | |promise| with an [=exception=]
1410 | {{SmartCardError/corresponding}} to |responseCode| and abort
1411 | these steps.
1412 |
Let |state:SmartCardConnectionState| be a
1413 | {{SmartCardConnectionState}}
1414 | [=SmartCardConnectionState/corresponding=] to |pcscState|
1415 | and |activeProtocol|.
1416 |
If |state| is {{undefined}}, [=reject=] |promise| with an
1417 | "{{UnknownError}}" {{DOMException}} and abort these steps.
1418 |
Let |status:SmartCardConnectionStatus| be a new
1419 | {{SmartCardConnectionStatus}}.
1420 |
Set |status|["{{SmartCardConnectionStatus/readerName}}"]
1421 | to |pcscReader|.
1422 |
Set |status|["{{SmartCardConnectionStatus/state}}"]
1423 | to |state|.
1424 |
Set
1425 | |status|["{{SmartCardConnectionStatus/answerToReset}}"] to
1426 | an {{ArrayBuffer}} with the bytes that were written to
1427 | |pcscAtr|.
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 |
If |pcscState| is [[PCSC5]] `SCARD_ABSENT`, return
1498 | "{{SmartCardConnectionState/absent}}".
1499 |
If |pcscState| is [[PCSC5]] `SCARD_PRESENT`, return
1500 | "{{SmartCardConnectionState/present}}".
1501 |
If |pcscState| is [[PCSC5]] `SCARD_SWALLOWED`, return
1502 | "{{SmartCardConnectionState/swallowed}}".
1503 |
If |pcscState| is [[PCSC5]] `SCARD_POWERED`, return
1504 | "{{SmartCardConnectionState/powered}}".
1505 |
If |pcscState| is [[PCSC5]] `SCARD_NEGOTIABLE`, return
1506 | "{{SmartCardConnectionState/negotiable}}".
1507 |
If |pcscState| is [[PCSC5]] `SCARD_SPECIFIC`, perform the
1508 | following steps:
1509 |
1510 |
If |activeProtocol| is [[PCSC5]] `SCARD_PROTOCOL_T0`,
1511 | return "{{SmartCardConnectionState/t0}}".
1512 |
If |activeProtocol| is [[PCSC5]] `SCARD_PROTOCOL_T1`,
1513 | return "{{SmartCardConnectionState/t1}}".
1514 |
If |activeProtocol| is [[PCSC5]] `SCARD_PROTOCOL_RAW`,
1515 | return "{{SmartCardConnectionState/raw}}".
1516 |
1517 |
1518 |
Return {{undefined}}.
1519 |
1520 |
1521 |
1522 |
1523 |
1524 |
control() method
1525 |
The {{SmartCardConnection/control(controlCode, data)}} method steps are:
1526 |
1527 |
Let |promise:Promise| be [=a new promise=].
1528 |
If
1529 | [=this=].{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}}
1530 | is `true`, [=reject=] |promise| with a "{{InvalidStateError}}"
1531 | {{DOMException}} and return |promise|.
1532 |
If [=this=].{{SmartCardConnection/[[comm]]}} is `null`, [=reject=]
1533 | |promise| with a "{{InvalidStateError}}" {{DOMException}} and return
1534 | |promise|.
1535 |
Set
1536 | [=this=].{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}}
1537 | to `true`.
1538 |
Let |pcscControlCode:DWORD| be a [[PCSC5]] `DWORD` containing
1539 | |controlCode|.
1540 |
[=Get a copy of the buffer source=] |data:BufferSource| and save
1541 | the result in a [[PCSC5]] `BYTE[]` |inBuffer:array of BYTE|.
1542 |
Let |outBuffer:array of BYTE| be a [[PCSC5]] `BYTE[]` large enough
1543 | to hold any control command response.
1544 |
Let |outBufferLength:DWORD| be a `DWORD` set to `0`.
1545 |
Run the following steps [=in parallel=]:
1546 |
1547 |
Call [=this=].{{SmartCardConnection/[[comm]]}}.`Control()`
1548 | with |pcscControlCode|, |inBuffer|, |outBuffer| and
1549 | |outBufferLength| as arguments.
1550 |
Let |responseCode:RESPONSECODE| be the returned
1551 | `RESPONSECODE`.
1552 |
[=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 |
[=Clear the operationInProgress=] of
1557 | [=this=].{{SmartCardConnection/[[context]]}}.
1558 |
If |responseCode| is not `SCARD_S_SUCCESS`, [=reject=]
1559 | |promise| with an [=exception=]
1560 | {{SmartCardError/corresponding}} to |responseCode| and abort
1561 | these steps.
1562 |
Let |resultBytes:byte sequence| be the first
1563 | |outBufferLength| bytes of |outBuffer|.
1564 |
[=Resolve=] |promise| with the result of
1565 | [=ArrayBuffer/Create|creating=] an {{ArrayBuffer}} from
1566 | |resultBytes| in [=this=]'s [=relevant Realm=].
1567 |
1568 |
1569 |
1570 |
1571 |
Return |promise|.
1572 |
1573 |
1574 |
1575 |
getAttribute() method
1576 |
The {{SmartCardConnection/getAttribute(tag)}} method steps are:
1577 |
1578 |
Let |promise:Promise| be [=a new promise=].
1579 |
If
1580 | [=this=].{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}}
1581 | is `true`, [=reject=] |promise| with a "{{InvalidStateError}}"
1582 | {{DOMException}} and return |promise|.
1583 |
If [=this=].{{SmartCardConnection/[[comm]]}} is `null`, [=reject=]
1584 | |promise| with a "{{InvalidStateError}}" {{DOMException}} and return
1585 | |promise|.
1586 |
Set
1587 | [=this=].{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}}
1588 | to `true`.
1589 |
Run the following steps [=in parallel=]:
1590 |
1591 |
Let |pcscTag:DWORD| be a [[PCSC5]] `DWORD` containing |tag|.
1592 |
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.
1595 |
Call [=this=].{{SmartCardConnection/[[comm]]}}.`GetReaderCapabilities()`
1596 | with |pcscTag| and |buffer| as arguments.
1597 |
Let |responseCode:RESPONSECODE| be the returned
1598 | `RESPONSECODE`.
1599 |
[=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 |
[=Clear the operationInProgress=] of
1604 | [=this=].{{SmartCardConnection/[[context]]}}.
1605 |
If |responseCode| is not `SCARD_S_SUCCESS`, [=reject=]
1606 | |promise| with an [=exception=]
1607 | {{SmartCardError/corresponding}} to |responseCode| and abort
1608 | these steps.
1609 |
Let |resultBytes:byte sequence| be the bytes of |buffer|
1610 | containing the attribute read.
1611 |
[=Resolve=] |promise| with the result of
1612 | [=ArrayBuffer/Create|creating=] an {{ArrayBuffer}} from
1613 | |resultBytes| in [=this=]'s [=relevant Realm=].
1614 |
1615 |
1616 |
1617 |
1618 |
Return |promise|.
1619 |
1620 |
1625 |
1626 |
1627 |
setAttribute() method
1628 |
The {{SmartCardConnection/setAttribute(tag, value)}} method steps are:
1629 |
1630 |
Let |promise:Promise| be [=a new promise=].
1631 |
If
1632 | [=this=].{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}}
1633 | is `true`, [=reject=] |promise| with a "{{InvalidStateError}}"
1634 | {{DOMException}} and return |promise|.
1635 |
If [=this=].{{SmartCardConnection/[[comm]]}} is `null`, [=reject=]
1636 | |promise| with a "{{InvalidStateError}}" {{DOMException}} and return
1637 | |promise|.
1638 |
Set
1639 | [=this=].{{SmartCardConnection/[[context]]}}.{{SmartCardContext/[[operationInProgress]]}}
1640 | to `true`.
1641 |
Let |pcscTag:DWORD| be a [[PCSC5]] `DWORD` containing
1642 | |tag|.
1643 |
[=Get a copy of the buffer source=] |value:BufferSource| and save
1644 | the result in a [[PCSC5]] `BYTE[]` |buffer:array of BYTE|.
1645 |
Run the following steps [=in parallel=]:
1646 |
1647 |
Call
1648 | [=this=].{{SmartCardConnection/[[comm]]}}.`SetReaderCapabilities()`
1649 | with |pcscTag| and |buffer| as arguments.
1650 |
Let |responseCode:RESPONSECODE| be the returned
1651 | `RESPONSECODE`.
1652 |
[=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 |
[=Clear the operationInProgress=] of
1657 | [=this=].{{SmartCardConnection/[[context]]}}.
1658 |
If |responseCode| is not `SCARD_S_SUCCESS`, [=reject=]
1659 | |promise| with an [=exception=]
1660 | {{SmartCardError/corresponding}} to |responseCode| and abort
1661 | these steps.
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'`.