Lab - Smartcards and the PTeID
In this guide you will develop Python programs using the Python PKCS11 module1 that interacts with PKCS#11 tokens to produce and validate digital signatures.
For that, you need to have installed the following software:
-
pcscd:
sudo apt install pcscd
-
Python3 PIP:
sudo apt install python3-pip
-
Swig:
sudo apt instlal swig
-
PyKCS11:
pip3 install --user pykcs11
-
PTEID Software: available at https://www.autenticacao.gov.pt/cc-aplicacao and pre-installed in the Virtual Machine Image.
-
(Optional) Opensc:
sudo apt install opensc-pkcs11
You can verify the correct operation of the software by executing
eidguiV2
and pkcs11-tool -L
.
PKCS#11 Standard
The PKCS#11 standard (Cryptographic Token Interface Standard) is produced by RSA Security and defines native programming interfaces to cryptographic tokens, such as hardware cryptographic accelerators and smartcards, as is the case of Portuguese Citizen Card.
Python PyKCS11 includes a provider that, in contrast to most other providers, does not implement cryptographic algorithms itself. Instead, it exposes functions that are executed in the hardware tokens, and allows to obtain the objects stored in a smart card. When using the Python Cryptography module, this is the role of the Backends (providing access to hardware tokens). Unfortunately, no public (and stable) backend supports PKCS#11, making it required to use a standalone module (PyKCS#11).
Loading the card interface module
Interating with the Portuguese Citizen Card requires the use of a module
that translated PKCS#11 calls into some internal format adequate to the
smart card hardware. This is independent of the programming language
used, and it is why we need to install the Portuguese Citizen Card
software: besides a visualization tool, it also contains libraries that
allow accessing the Portuguese Citizen Card (libpteidpkcs11.so
)
Using the PyKCS11 module, the following snippet will try to list all slots, and present information about the tokens contained:
import PyKCS11
import binascii
lib = '/usr/local/lib/libpteidpkcs11.so'
pkcs11 = PyKCS11.PyKCS11Lib()
pkcs11.load(lib)
slots = pkcs11.getSlotList()
for slot in slots:
print(pkcs11.getTokenInfo(slot))
If you obtain an error with this version, please use the library
available at (/usr/lib/x86_64-linux-gnu/opensc-pkcs11.so
) or, in
alternative, the SDK v1.6 available in the Elearning web page.
Task: List all tokens and print the detais of each token (revision, manufacturer, model, serial, etc...)
Contents of the Portuguese Citizen Card
After the token is available, it is possible to list the objects it contains. Some objects have public visibility and are accessed through a public session, while others are private, and the user must explicitelly create a private session. The different between sessions lies in the existence of omission of a pin code when opening the session.
You can list the contents of the Portuguese Citizen Card (i.e., its PKCS#11 objects), with code based on the following snippet:
all_attr = list(PyKCS11.CKA.keys())
#Filter attributes
all_attr = [e for e in all_attr if isinstance(e, int)]
session = pkcs11.openSession(slot)
for obj in session.findObjects():
# Get object attributes
attr = session.getAttributeValue(obj, all_attr)
# Create dictionary with attributes
attr = dict(zip(map(PyKCS11.CKA.get, all_attr), attr))
print('Label: ', attr['CKA_LABEL'])
The information you get in the CKA_LABEL
attribute is the
identification of the object included in the Portuguese Citizen Card.
Through these identifiers we can select which certificate, or private
key, we intend to use for each cryptographic operation. The attribute
CKA_CLASS
identifies the class of the object and the attribute
CKA_CERTIFICATE_TYPE
can identify the type of a certificate.
You can individually inspect all attributes of the objects. If you
require access to the certificate content, convert the tuple contained
in the CKA_VALUE
to bytes (bytes(attributes['CKA_VALUE'])
) and load
it as a DER
certificate (x509.load_der_x509_certificate
).
Task: Print the label of all objects, as well as the issuer and subject of all certificates.
Hint: Once loaded as a X509 certificate, you can reuse the code from the last class to print the issuer and subject.
Digital signature
Task: Create a program capable of generating a digital signature of a document, using the Portuguese Citizen Card, and storing it on a given file. Furthermore, complement it for writing on a file the public key certificate corresponding to the private key used for signing the document.
For this purpose consider the CITIZEN AUTHENTICATION CERTIFICATE
and
the corresponding CITIZEN AUTHENTICATION KEY
(the private key), as
many citizens to not have the CITIZEN SIGNATURE CERTIFICATE
activated.
Because the private key is not extractable, you cannot load this key as
a RSA key. Instead, use the session
object to sign the text:
private_key = session.findObjects([
(PyKCS11.CKA_CLASS, PyKCS11.CKO_PRIVATE_KEY),
(PyKCS11.CKA_LABEL, 'CITIZEN AUTHENTICATION KEY')
])[0]
mechanism = PyKCS11.Mechanism(PyKCS11.CKM_SHA1_RSA_PKCS, None)
text = b'text to sign'
signature = bytes(session.sign(private_key, text, mechanism))
Signature validation
Task: Create a program capable of checking a digital signature on a document. The program should use as inputs a file with the digital signature, a file with the signer’s public key certificate and a file with the signed contents. You should also display the identity of the entity that produced the signature (the subject). This is important as the user should know the identity of the user that created the signature.
Hint: Validating the key doesn’t use the Portuguese Citizen Card and
reuses the validation processes from the last laboratory guide. To
verify the signature, use padding.PKCS1v15()
as padding and
hashes.SHA1()
as the hash mechanism. Do not forget to validate the
certification chain, dates and purposes.
Virtual Smartcard
In alternative to the real PT eID Smart Card you can use a Virtual Smart Card with custom generated certificates. It also uses a custom generated PKI with intermediate Certification Authorities. Please adjust your code accordingly.
This was not througly tested!!! Here be dragons!!! But it works on my PC :)
In order to use this, download the VirtualSmartcard files with git clone
. Several
packages must be present, which varies according to the distribution. For linux ubuntu, the instructions are:
$ sudo apt update
$ sudo apt install autoconf automake build-essential libpcsclite-dev python3-crypto python3-pip libtool help2man
$ pip3 install argparse
The next step is to compile the software. Some libraries may be required. If something is missing, the script should provide some feedback
$ cd ..
$ cd virtualsmartcard
$ autoreconf --verbose --install
$ ./configure --sysconfdir=/etc
$ make
$ sudo make install
The library should be available at /usr/lib/pcsc/drivers/serial/libifdvpcd.so
. Please check it.
Then we need to stop pcscd
and run it on a terminal as root
.
$ systemctl stop pcscd
$ sudo pcscd -f -d
There should be a line displayed as follows, indicating that the libifdvpcd
driver was loaded. This is mandatory.
00000047 [XX] readerfactory.c:1074:RFInitializeReader() Attempting startup of Virtual PCD 00 01 using /usr/lib/pcsc/drivers/serial/libifdvpcd.so
00000130 [XX] readerfactory.c:863:RFLoadReader() Reusing already loaded driver for /usr/lib/pcsc/drivers/serial/libifdvpcd.so
Then go to the pteid
folder and generate a new Virtual PTEID Card. You can customize the script to use other subjects.
$ cd vsmartcard
$ cd pteid
$ python3 generate_pteid_card.py
Open another terminal and execute the virtual card.
$ cd virtualsmartcard/src/vpicc
$ cp ../../../pteid/card.json .
$ ./vicc -t PTEID -v
Finally, open another terminal and check if the card is available:
$ pkcs11-tool -L
Slot 0 (0x0): Virtual PCD 00 00
token label : CARTAO DE CIDADAO (Auth PIN)
token manufacturer : GEMALTO
token model : PKCS#15 emulated
token flags : login required, token initialized, PIN initialized, readonly
hardware version : 0.0
firmware version : 0.0
serial num : 9999000000035539
pin min/max : 4/8
Slot 1 (0x1): Virtual PCD 00 00
token label : CARTAO DE CIDADAO (Sign PIN)
token manufacturer : GEMALTO
token model : PKCS#15 emulated
token flags : login required, token initialized, PIN initialized, readonly
hardware version : 0.0
firmware version : 0.0
serial num : 9999000000035539
pin min/max : 4/8
Slot 2 (0x2): Virtual PCD 00 00
token label : CARTAO DE CIDADAO (Address PIN)
token manufacturer : GEMALTO
token model : PKCS#15 emulated
token flags : login required, token initialized, PIN initialized, readonly
hardware version : 0.0
firmware version : 0.0
serial num : 9999000000035539
pin min/max : 4/8
Slot 3 (0x4): Virtual PCD 00 01
(empty)
Then you can use it as a standard PT eID card, by any application. You need to keep the first two terminals open.
The first is the pcscd
daemon, which mediates access to cards, and the second is the Virtual Smart Card.
Only a subset of the methods is implemented, and it will crash if additional operations are requested. This is work in progress.
To test the card, create a signature over some data:
pkcs11-tool --login --sign -i data_to_sign.txt --pin 1111 -o signature.bin -m RSA-PKCS