kofi-q/pcsc-z
Zig PC/SC API bindings for smart card access on Linux / MacOS / Win32
› Zig PC/SC API bindings for smart card access on Linux / MacOS / Win32
Docs ↗ | | Prerequisites | | Installation | | Usage
Required packages:
ccid
pcsc-lite
pcsc-lite-libs
doas apk add ccid pcsc-lite pcsc-lite-libs
To run the server daemon:
doas rc-service pcscd start
Required packages:
libpcsclite1
pcscd
sudo apt install libpcsclite1 pcscd
To run the server daemon:
sudo systemctl start pcscd
N/A
:: MacOS and Windows come pre-installed with smart card support. No additional installation needed.
zig fetch --save=pcsc "git+https://github.com/kofi-q/pcsc-z.git"
const std = @import("std");
const pcsc = @import("pcsc");
pub fn main() !void {
const client = try pcsc.Client.init(.SYSTEM);
defer client.deinit() catch |err| std.debug.print(
"Unable to release client: {}",
.{err},
);
// Detect connected card readers:
var readers = [_]pcsc.Reader{.empty};
while (true) {
var reader_names = try client.readerNames();
if (reader_names.next()) |name| {
std.debug.print("Reader detected: {s}\n", .{name});
readers[0].name_ptr = name.ptr;
break;
}
std.debug.print("Connect a reader to continue...\n", .{});
try client.waitForUpdates(&[_]pcsc.Reader{.pnp_query}, .infinite);
}
// Detect inserted cards:
while (true) {
try client.waitForUpdates(&readers, .infinite);
readers[0].status = readers[0].status_new;
if (readers[0].status.flags.IN_USE) {
std.debug.print("Card in use. Waiting...\n", .{});
continue;
}
if (readers[0].status.flags.MUTE) {
std.debug.print("Card not readable. Check orientation...\n", .{});
continue;
}
if (readers[0].status.flags.PRESENT) break;
std.debug.print("Insert a card to continue...\n", .{});
}
std.debug.print("Connecting to card...\n", .{});
// Connect to an inserted card:
const card = try client.connect(readers[0].name_ptr, .SHARED, .ANY);
defer card.disconnect(.RESET) catch |err| std.debug.print(
"Unable to disconnect card: {}\n",
.{err},
);
std.debug.print("Card connected with protocol {}\n", .{card.protocol});
const command = [_]u8{ 0xca, 0xfe, 0xf0, 0x0d };
std.debug.print("Transmitting APDU: {x:0>2}\n", .{command});
// Transmit/receive data to/from a card:
var buf_response: [pcsc.max_buffer_len]u8 = undefined;
const response = try card.transmit(&command, &buf_response);
std.debug.print("Received response: {x:0>2}\n", .{response});
}
$ zig build example:hello
Connect a reader to continue...
Reader detected: Gemalto USB SmartCard Reader
Insert a card to continue...
Connecting to card...
Card connected with protocol T=1
Transmitting APDU: { ca, fe, f0, 0d }
Received response: { 68, 81 }
[!TIP]
See the E2E test application for more involved usage.
v0.14.1 required - see .zigversion
for latest compatible version.
See Linux section above for a list of runtime prerequisites.
Other relevant development libraries (e.g. libpcsclite-dev
on Debian-based distros) are included in this repo to ease cross-compilation. No additional installation needed.
N/A
:: Required MacOS Framework .tbd
s are included here. No additional installation needed.
NOTE: To update the .tbd
s, however, an XCode installation is needed.
N/A
:: Required DLLs are shipped with the Zig compiler. No additional installation needed.