CCID(4D) | Devices | CCID(4D) |
ccid
— chip card
interface device USB client class driver
#include
<sys/usb/clients/ccid/uccid.h>
The interfaces provided by this driver are private at this time and subject to change. It should not be relied upon.
The ccid
driver is a USB CCID (chip card
interface device) class device driver.
The driver exposes interfaces that allow consumers to send and receive APDUs (application protocol data unit) to a given smart card that is plugged into a reader. The driver also provides interfaces to obtain status information, the ATR (answer to reset), and obtain exclusive access to the device. In addition, the system exposes control of CCID devices through cfgadm(8).
The CCID specification allows for readers to come in different flavors. These different flavors support different communication protocols and have different levels of automation for determining the protocol and transfers that are required.
At this time, only the short APDU protocol is supported, which also works with readers using the extended APDU protocol. TPDU and character level readers are not supported by the driver. Readers in this category will still attach; however, I/O cannot be performed to them.
In addition, at this time the driver does not support devices which require manually setting the clock and data rates to support an ICC.
Each CCID class device provides a number of slots. Each slot may have an independent ICC (integrated circuit card or Smart Card) inserted into it. Each device, or reader, has its own directory under /dev/ccid based on its device number. Inside of each directory is a character device for each slot. A slot exists regardless of whether or not an ICC is inserted into it. As long as a CCID device is present in the system, its device nodes will be present.
Slots are enumerated using this pattern: /dev/ccid/ccid%instance/slot%slot.
For example, all the slots that belong to CCID instance 5 will be enumerated under the directory /dev/ccid/ccid5. Slots are numbered starting at zero for each reader and increment from there. For example, the second physical slot would be numbered as slot one. If this were on CCID instance zero, then we would find a character device at: /dev/ccid/ccid0/slot1.
To enumerate all of the ccid devices present on the system, one could read all of the directories under /dev/ccid. To enumerate all of the slots on a device, one could read all of the device nodes under a particular CCID device, such as: /dev/ccid/ccid0. The number of slots is also obtainable through various ioctls that will be discussed later on. It's important to note that while slot numbering will always be consistent for a given device, the CCID numbering is based on the driver instance. Therefore, it is possible for a device to change device numbers. To deal with this, symlinks based on other properties will be provided (for example, the USB serial number).
All of the CCID devices in the system can also be listed by using the ccidadm(8) command.
To send and receive responses to commands, a program must open up the corresponding slot's device node. In many of the commands that use an ICC, there is a logical notion of state associated with the ICC that is mutated by performing commands on it. For example, a command might be issued that uses a PIN to unlock a slot or that selects a particular PIV applet for use. Because of this, all I/O to a given device must be performed inside the context of a transaction. When a program begins a transaction, it is guaranteed that no one else may send commands to the ICC. When a program is finished, it must explicitly end the transaction, which may have the side effect of resetting the ICC. If a program with an open transaction crashes or closes the file descriptor without taking other actions, then the transaction will be automatically closed and the ICC will be reset. Without a transaction open, it will still be possible to issue ioctls that obtain the status of the slot and the reader.
While in an active transaction, a program may send commands to a card. Sending a command and reading a response are done through the traditional read(2) and write(2) family of system calls. To submit a command, the program would issue a write(2) family system call that contained the payload to send to the ICC. Once submitted, the call would return and the program would be able to issue a read(2) system call to obtain the results. Once a command has been submitted, it is illegal to submit another one. The next command cannot be submitted until the response has been fully consumed. Similarly, if a command has not been submitted, one cannot issue a read(2) system call to obtain results. Only a single thread may be blocked waiting to submit a command or read a response.
To facilitate non-blocking operation, the underlying file
descriptor may be opened with O_NONBLOCK
.
While a transaction is active,
poll(2) may be used to receive status
information about the slot. The following events are used by
ccid
:
POLLOUT
POLLIN,
POLLRDNORM
POLLHUP
POLLERR
One important note is that readers with multiple slots often still only allow I/O a single command to be outstanding across all of the slots in the system. Because transactions are on a per-slot basis, it is still possible for a command submission to block even though one has a transaction open.
While a transaction is open, various events can occur that cause a fatal error on the transaction. These include:
Once such a fatal error has occurred, all new I/O will fail though it will still be possible to read any successfully completed commands. To clear the error state the program will need to end the transaction and begin a new one or close the file descriptor if the device has been removed.
To perform I/O to a particular card, one must first open the slot
of interest. Opening the slot requires that the process be in the global
zone and that it have the privilege
PRIV_SYS_DEVICES.
The device node can be opened through the
open(2) or
openat(2) system calls. For programs
that just want to query the slot status using the
UCCID_CMD_STATUS
command, opening the device node
read-only is sufficient. All other uses require that the device be opened
both for reading and writing (O_RDWR
).
Once the device has been opened, the program may issue ioctls to get status information.
To perform general I/O to the card, a program must be in the
context of a transaction as discussed in the
I/O Model section. To open a
transaction, a program must issue the
UCCID_CMD_TXN_BEGIN
command through the
ioctl(2) system call.
When a program is done, it must issue the
UCCID_CMD_TXN_END
command to release the
transaction. As part of issuing the command, the program must determine a
disposition of what it would like done with the card when it has completed.
These options include leaving the ICC alone and resetting the ICC. For many
use cases, such as those where a pin is entered or the ICC's state is
mutated, a reset is the recommended option. If the program crashes or closes
the file descriptor without issuing a transaction end, then the ICC will be
reset.
Please see the ioctl listing in the IOCTLS section for more information on the command structure.
If a multi-threaded application opens a slot once and shares it
among multiple threads performing I/O to that slot, there can still only be
one transaction active or waiting on the slot shared by all threads.
Acquiring another transaction on the same slot minor while another thread is
already blocked waiting for one will return
EINPROGRESS
. If another transaction is already
active, EINVAL
will be returned. Consequently, all
threads in a multi-threaded application share the transaction state and may
issue writes, and read the results. The same applies to any other method of
sharing an open file descriptor of a slot minor, be it by sharing the fd
over a socket, a child process inheriting it from its parent during
fork(2), even across calls to
exec(2).
Once a slot has been opened, any caller may issue commands to get the status of the slot. This can also be used to obtain the ATR (answer to reset) of an ICC that is present on the slot, if it is known.
While exclusive access is not required to issue these commands, there is no guarantee that they will not have changed between the time that the program issued the command and it obtains a transaction.
To obtain information about the reader, slot, and the ATR, one
should issue the UCCID_CMD_STATUS
command. Please
see the ioctl listing in the IOCTLS section
for more information.
This section lists the different commands that may be issued to a CCID device through the ioctl(2) system call.
UCCID_CMD_STATUS
This command is used to obtain the status of the slot. It may be used regardless of whether or not the caller has exclusive access.
The UCCID_CMD_STATUS
command uses the
structure uccid_cmd_status_t, the fields of which have
the following meanings:
UCCID_CURRENT_VERSION
.UCCID_STATUS_F_CARD_PRESENT
UCCID_STATUS_F_CARD_ACTIVE
UCCID_STATUS_F_CARD_PRESENT
flag is
also set.UCCID_STATUS_F_PRODUCT_VALID
UCCID_STATUS_F_SERIAL_VALID
UCCID_STATUS_F_PARAMS_VALID
UCCID_PROT_T0
for the TPDU T=0 protocol or
UCCID_PROT_T1
for the TPDU T=1 protocol.UCCID_CMD_TXN_BEGIN
This command is used to begin a transaction. The command will
block until exclusive access is available to the caller. If the caller does
not wish to block, it should set the
UCCID_TXN_DONT_BLOCK
flag.
The command uses the structure uccid_cmd_txn_begin_t with the following members:
UCCID_CURRENT_VERSION
.UCCID_TXN_DONT_BLOCK
If an unknown flag is specified, an error will be returned.
UCCID_CMD_TXN_END
The UCCID_CMD_TXN_END
command is used to
end a transaction and relinquish exclusive access to the ICC.
The command uses the structure uccid_cmd_txn_end_t with the following members:
UCCID_CURRENT_VERSION
.UCCID_TXN_END_RESET
UCCID_TXN_END_RELEASE
Exactly one of these two flags must be specified. It is an error if neither flag or both flags are specified at the same time. If the device is closed without ending a transaction first, then the ICC will be reset.
UCCID_CMD_ICC_MODIFY
This command can be used to change the state of an ICC, if present.
The command uses the structure uccid_cmd_icc_modify_t with the following members:
UCCID_CURRENT_VERSION
.UCCID_ICC_POWER_ON
UCCID_ICC_POWER_OFF
UCCID_ICC_WARM_RESET
FIONREAD
This command returns the size in bytes of a command response available for reading with read(2). The size is returned in an int pointed to by the argument.
This section lists the different system calls that may be issued to a CCID device.
ccid
slot device nodes can be opened using
open(2). Non-blocking operation can be
selected by using the O_NONBLOCK
flag when opening
the device node. A device node opened for read-only operations will not
allow creating transactions or doing I/O, but it will allow the ICC/reader
status to be queried.
When no longer needed by a program, a device node can be closed with close(2). If a transaction is still active when a device node is closed, the transaction will be ended automatically and the ICC will be reset. Any unread data is discarded.
The ioctl(2) system call can be used to start or end a transaction, query the reply size for read(2), query the ICC and CCID reader status, or change the state of an ICC in a reader. See section IOCTLS for details.
Within an active transaction the write(2) system call can be used to transfer an APDU (application protocol data unit) to an ICC, one single complete APDU at a time. Partial writes or writing more than one APDU at a time are not supported. The data returned by the ICC must be consumed by a subsequent read(2) call before write(2) can be called again within the same transaction.
The following errors for
write(2) have specific meaning in
ccid
:
E2BIG
ccid
, currently defined as 261
bytes.EACCES
EBUSY
ENOTSUP
ENXIO
ENODEV
Within an active transaction the
read(2) system call is used to read the
reply from an ICC following sending an APDU with
write(2). The whole reply needs to be
read with a single call to read(2). The
size of the reply can be queried before reading by issuing the
FIONREAD
ioctl. See section
IOCTLS for details.
The following errors for
read(2) have specific meaning in
ccid
:
Within an active transaction the poll(2) system call is used to wait for status changes on a device node. See section I/O model for details.
The following errors for
poll(2) have specific meaning in
ccid
:
close(2), ioctl(2), open(2), poll(2), read(2), write(2), ccidadm(8), cfgadm(8)
Universal Serial Bus Device Class: Smart Card CCID, April 22, 2005, Revision 1.1.
Identification Cards - Integrated Circuits, Part 3: Cards with contacts — Electrical interface and transmission protocols, ISO/IEC, 2006, ISO/IEC 7616-3:2006.
December 20, 2019 | OmniOS |