To continue the list of PC/SC wrappers initiated in 2010 with "PC/SC sample in different languages" I now present a new sample code in
Erlang.
I use the PC/SC wrapper for Erlang:
erlang-pcsc from Alex
Wilson. The project description is "libpcsc NIF binding for erlang". The
license is
BSD 2 clause.
This is the same wrapper I used in the previous blog article "PC/SC sample in Elixir".
The wrapper is available on Hex.pm (The package
manager for the Erlang ecosystem) at
https://hex.pm/packages/pcsc.
API documentation is available at
https://arekinath.github.io/erlang-pcsc/index.html
Create a new application
$ rebar3 new app blog
===> Writing blog/src/blog_app.erl
===> Writing blog/src/blog_sup.erl
===> Writing blog/src/blog.app.src
===> Writing blog/rebar.config
===> Writing blog/.gitignore
===> Writing blog/LICENSE
===> Writing blog/README.md
Install pcsc module
Edit the file rebar.config to use:
{deps, [pcsc]}.
{erl_opts, [{i, "_build/default/lib/pcsc/include/"}]}.
The erl_opts
option is needed because we will include one header
file from the pcsc module. Maybe it is possible to have a less ugly/hardcoded
path.
Upgrade the dependencies:
$ rebar3 upgrade --all
===> Verifying dependencies...
===> Fetching pcsc v1.3.1
===> Fetching rebar3_hex v7.0.1
===> Fetching hex_core v0.8.4
===> Fetching verl v1.1.1
===> Analyzing applications...
===> Compiling verl
===> Compiling hex_core
===> Compiling rebar3_hex
_build/default/plugins/rebar3_hex/src/rebar3_hex_organization.erl:391:5: Warning: public_key:ssh_encode/2 is deprecated and will be removed in OTP 26; use ssh_file:encode/2 instead
===> Fetching lager v3.9.2
===> Fetching goldrush v0.1.9
===> No upgrade needed for pcsc
===> No upgrade needed for lager
===> No upgrade needed for goldrush
Build the dependencies:
$ rebar3 compile
===> Verifying dependencies...
make : on entre dans le répertoire « /home/rousseau/Documents/blog/erlang/_build/default/lib/pcsc/c_src »
cc -Wall -g -O2 -Wextra -pipe -funsigned-char -fstrict-aliasing -Wchar-subscripts -Wundef -Wshadow -Wcast-align -Wwrite-strings -Wunused -Wuninitialized -Wpointer-arith -Wredundant-decls -Winline -Wformat -Wformat-security -Wswitch-enum -Winit-self -Wmissing-include-dirs -Wempty-body -fdiagnostics-color=auto -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Wbad-function-cast -Wnested-externs -Wmissing-declarations -fPIC -I /usr/lib/erlang/erts-12.3.1/include/ -I /usr/lib/erlang/lib/erl_interface-5.2.2/include -pthread -I/usr/include/PCSC -c -o /home/rousseau/Documents/blog/erlang/_build/default/lib/pcsc/c_src/pcsc_nif.o /home/rousseau/Documents/blog/erlang/_build/default/lib/pcsc/c_src/pcsc_nif.c
[...]
cc /home/rousseau/Documents/blog/erlang/_build/default/lib/pcsc/c_src/pcsc_nif.o -shared -L /usr/lib/erlang/lib/erl_interface-5.2.2/lib -lei -lpcsclite -o /home/rousseau/Documents/blog/erlang/_build/default/lib/pcsc/c_src/../priv/pcsc_nif.so
make : on quitte le répertoire « /home/rousseau/Documents/blog/erlang/_build/default/lib/pcsc/c_src »
===> Analyzing applications...
===> Compiling goldrush
===> Compiling lager
===> Compiling pcsc
===> Analyzing applications...
===> Compiling blog
Edit the file src/blog.app.src to declare the pcsc application.
It should look like:
[...]
{applications,
[kernel,
stdlib,
pcsc
]},
[...]
Sample code
Create the source code file src/blog.erl with the content:
-module(blog).
-export([main/0]).
-include("iso7816.hrl").
main() ->
% get all the available readers
{ok, Readers} = pcsc_card_db:list_readers(),
% use the first reader
[Reader | _] = Readers,
io:fwrite("Using: ~s~n", [Reader]),
% connect
{ok, Card} = pcsc_card:start_link(Reader, shared, [t1, t0]),
% select applet
Aid = << 160, 0, 0, 0, 98, 3, 1, 12, 6, 1 >>,
Select_apdu = #apdu_cmd{cla = iso, ins = select, p1 = 4, p2 = 0, data = Aid},
{ok, Select_replies} = pcsc_card:command(Card, Select_apdu),
io:write(Select_replies),
io:fwrite("~n"),
% command
Command_apdu = #apdu_cmd{ cla = iso, ins = 0, p1 = 0, p2 = 0 },
{ok, Command_replies} = pcsc_card:command(Card, Command_apdu),
io:write(Command_replies),
io:fwrite("~n"),
% extract the answer
[Reply | _] = Command_replies,
case Reply of
{apdu_reply, _, ok, Msg} ->
io:write(binary_to_atom(Msg)),
io:fwrite("~n");
{apdu_reply, _, error, _} ->
io:fwrite("Error~n")
end.
Output
Generating a standalone Erlang application looks complex. But you can test
your code using the interactive shell.
$ rebar3 shell
===> Verifying dependencies...
===> Analyzing applications...
===> Compiling blog
Erlang/OTP 24 [erts-12.3.1] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [jit]
Eshell V12.3.1 (abort with ^G)
===> Booted syntax_tools
===> Booted compiler
===> Booted goldrush
===> Booted lager
===> Booted pcsc
===> Booted blog
1> blog:main().
Using: Gemalto PC Twin Reader 00 00
[{apdu_reply,t1,ok,none}]
[{apdu_reply,t1,ok,<<72,101,108,108,111,32,119,111,114,108,100,33>>}]
'Hello world!'
ok
2>
Comments
ehecatl
An older github project also exist at
https://github.com/zgbjgg/ehecatl
Its description is "An erlang library for read/write nfc smart cards".
I filed 2 issues in 2020:
Missing <PCSC/winscard.h>?
and
More complete PC/SC wrapper?
but got no answer.
This project has not seen any commit since 2014.
So I guess this project is dead.
erlang-pcsc
The only problem I have with
erlang-pcsc is that, if
no smart card reader is connected, I get:
$ rebar3 shell
===> Verifying dependencies...
===> Analyzing applications...
===> Compiling blog
Erlang/OTP 24 [erts-12.3.1] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [jit]
Eshell V12.3.1 (abort with ^G)
1> ===> Booted syntax_tools
===> Booted compiler
===> Booted goldrush
===> Booted lager
===> Booted pcsc
===> Booted blog
23:31:49.563 [warning] got pcsc_reader_error: {error,{pcsc_error,-2146435026,no_readers,"Cannot find a smart card reader."}}; restarted ok
23:31:49.622 [warning] got pcsc_reader_error: {error,{pcsc_error,-2146435026,no_readers,"Cannot find a smart card reader."}}; restarted ok
23:31:49.677 [warning] got pcsc_reader_error: {error,{pcsc_error,-2146435026,no_readers,"Cannot find a smart card reader."}}; restarted ok
23:31:49.729 [warning] got pcsc_reader_error: {error,{pcsc_error,-2146435026,no_readers,"Cannot find a smart card reader."}}; restarted ok
23:31:49.782 [warning] got pcsc_reader_error: {error,{pcsc_error,-2146435026,no_readers,"Cannot find a smart card reader."}}; restarted ok
23:31:49.836 [warning] got pcsc_reader_error: {error,{pcsc_error,-2146435026,no_readers,"Cannot find a smart card reader."}}; restarted ok
23:31:49.889 [warning] got pcsc_reader_error: {error,{pcsc_error,-2146435026,no_readers,"Cannot find a smart card reader."}}; restarted ok
23:31:49.941 [warning] got pcsc_reader_error: {error,{pcsc_error,-2146435026,no_readers,"Cannot find a smart card reader."}}; restarted ok
23:31:49.992 [warning] got pcsc_reader_error: {error,{pcsc_error,-2146435026,no_readers,"Cannot find a smart card reader."}}; restarted ok
23:31:50.044 [warning] got pcsc_reader_error: {error,{pcsc_error,-2146435026,no_readers,"Cannot find a smart card reader."}}; restarted ok
etc...
The error -2146435026 is
SCARD_E_NO_READERS_AVAILABLE
and is not really an error for
SCardListReaders().
I filed a github issue
[warning] got pcsc_reader_error:
{error,{pcsc_error,-2146435026,no_readers,"Cannot find a smart card
reader."}}; restarted ok #4
but with no answer so far.
Conclusion
Thanks Alex for the Erlang PC/SC wrapper. And thanks tofferoma, from the
elixir forum, for your help in writing the Erlang sample code.
If you work on a Free Software PC/SC wrapper that is not yet in
my list please let me know.