CCID(4D) 4D CCID(4D)
NAME
ccid - chip card interface device USB client class driver
SYNOPSIS
#include <sys/usb/clients/ccid/uccid.h>INTERFACE LEVEL
Volatile The interfaces provided by this driver are private at this time and subject
to change. It should not be relied upon.
DESCRIPTION
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).
Supported Devices
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.
Device Model
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.
I/O Model 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 The device is ready to receive a command using
write(2).
POLLIN, POLLRDNORM
The device has completed a command the results may be retrieved
with
read(2).
POLLHUP The card has been removed from the slot.
POLLERR An hardware error has occurred, or the CCID reader has been
disconnected.
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:
+o USB CCID reader removed
+o ICC removed
+o A fatal error while communicating to the device
+o An administrator issued an ioctl to power off or reset the ICC
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.
Opening Devices, Exclusive Access, and Performing I/O 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).
Device Status and ATR
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.
IOCTLS
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:
uint32_t ucs_version Indicates the current version of the structure. This should
be set to UCCID_CURRENT_VERSION.
uint32_t ucs_status This value is ignored when issuing the command. On return,
it will be filled in with various flags that describe the
current status of the slot and the contents returned in the
uccid_cmd_status_t. The following flags are defined:
UCCID_STATUS_F_CARD_PRESENT
A card has been inserted into the slot of the
CCID class device.
UCCID_STATUS_F_CARD_ACTIVE
The inserted card has been successfully
activated. This will only be set if the
UCCID_STATUS_F_CARD_PRESENT flag is also set.
UCCID_STATUS_F_PRODUCT_VALID
The contents of
ucs_product are valid.
UCCID_STATUS_F_SERIAL_VALID
The contents of
ucs_serial are valid.
UCCID_STATUS_F_PARAMS_VALID
The parameters returned in
ucs_params are
valid.
int32_t ucs_instance The instance number of the CCID device.
uint32_t ucs_slot The slot number currently in use.
uint8_t ucs_atr[UCCID_ATR_MAX] The ATR (answer to reset) of the card.
uint8_t ucs_atrlen The actual length of the ATR data. A length of 0 indicates
that there is no ATR data.
int8_t ucs_product[256] The product string of the CCID device.
int8_t ucs_serial[256] The serial number of the CCID device.
ccid_class_descr_t ucs_class The CCID class descriptor of the CCID device.
uccid_prot_t ucs_prot The protocol in use by the ICC. This can be either
UCCID_PROT_T0 for the TPDU T=0 protocol or UCCID_PROT_T1 for
the TPDU T=1 protocol.
ccid_params_t ucs_params The CCID parameters available on the card.
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:
uint32_t ucs_version Indicates the current version of the structure. This should
be set to UCCID_CURRENT_VERSION.
uint32_t uct_flags Flags that impact the behavior of the command. The following
flags are defined:
UCCID_TXN_DONT_BLOCK
The command should not block for exclusive
access. If exclusive access is not available,
then the command will fail immediately.
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:
uint32_t uct_version Indicates the current version of the structure. This should
be set to UCCID_CURRENT_VERSION.
uint32_t uct_flags UCCID_TXN_END_RESET
The ICC should be reset at the end of the
transaction.
UCCID_TXN_END_RELEASE
The ICC should be released without being reset
at the end of the transaction.
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:
uint32_t uci_version Indicates the current version of the structure. This should
be set to UCCID_CURRENT_VERSION.
uint32_t uci_action The action to be taken on the ICC. The following actions are
defined:
UCCID_ICC_POWER_ON
Power on the ICC.
UCCID_ICC_POWER_OFF
Power off the ICC.
UCCID_ICC_WARM_RESET
Perform a warm reset of the ICC.
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.
SYSTEM CALLS
This section lists the different system calls that may be issued to a CCID
device.
open(2) 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.
close(2) 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.
ioctl(2) 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.
write(2) 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 The number of bytes to write is larger than the maximum APDU
length supported by
ccid, currently defined as 261 bytes.
EACCES The device is opened read-only, or no transaction is active.
EBUSY There is unread data from a previous call to
write(2).
ENOTSUP The reader and/or ICC is unsupported for I/O.
ENXIO The ICC is inactive and can't be used for I/O.
ENODEV The CCID reader has been disconnected.
read(2) 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:
EACCES No transaction is active.
EBUSY Another thread is already blocked in
read(2) waiting for
data.
EOVERFLOW The buffer size is too small to fit the reply.
ENODATA No
write(2) was issued before and consequently there is no
reply to be read.
ENODEV The CCID reader has been disconnected.
poll(2) 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:
EACCES No transaction is active.
ENODEV The CCID reader has been disconnected.
SEE ALSO
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.
OmniOS December 20, 2019 OmniOS