Rudimentary Smart Card Emulation Implementation for GnuPG

26 December 2020

A lot of time has passed since the beginning of this semester, in which, me and one of my peers have decided to continue pursuing this project as the chosen topic for a college subject that encourages independent elaboration of our ideas.

As for a recap, the initial goal was to reuse existing hardware for a similar purpose as a smart card is used for in one of its applications: to protect encryption keys from being stolen while those are being used. This is achieved by storing these encryption keys on a separated device, and delegating the cryptographic tasks to be carried out in this safe environment. Only the results get sent back, never any of the keys, making retrieving them much harder for an external threat.

<img src=”/assets/img/key-container/new_simplified_architecture-b.png” width=700px alt=”New, simplified architecture” />

We have chosen GnuPG as our target application instead of OpenSSL with PKI-based keys, for these reasons:

  1. Although GnuPG does feature smart card support, compliant cards are not that widespread as the PKI-compatible ones are, to our best knowledge. While PKCS#11 cards are commonly found in enterprise environments as hardware tokens for enhancing security, the OpenPGP smart card, as a solution, is more community-focused. For in the latter case the cryptographic security mostly depends on the developer, we sense some room for improvement.
    • In the open source community, we think that GnuPG is the de-facto standard for signing software packages, messages, and other data. (Sub)keys are usually kept and used directly from the user’s disc, probably because most of the open source contributors - including ourselves, if we do - do not find this level of key security as important, as a company, which may risk serious damage by not caring to invest into the equipment.
    • However, for these people, our solution may become an alternative to consider, for in a lot of the cases, it would be ready to set up on an old, offline phone without a penny spent (as usual, if the project ever gets released). Therefore, we really hope that the first usable version will find an audience.
  2. Even if GnuPG may still require one to learn its command line interface, it still appears a much more user-targeted key management application to us, than OpenSSL, which could rather be described as the the go-to all-in-one cryptographic toolkit. With other words, we think that GnuPG targets the end user, while OpenSSL targets the system administrator (who may set up S/MIME and other protocols for the user).

Some minor architectural improvements

As the project went on, some of our ideas have matured, hopefully for the better.

  1. Although in general we still target older smart phones - as we expect unused ones to be accessible for those who are interested in this project -, we recently made an attempt to define more clearly what devices we wish to use for smart card substitution. Therefore, from now on, we talk about generic Key Container Devices (abbreviated as KC-device). This implies, that
    • in theory, such a device can be either a phone, a board with low power consumption, or a separated computer.
    • The software of the device consists of the portable core and the device-specific frontend (screen on the phone, leds and buttons on a board, etc.)
  2. We clearly see that a JSON-based REST API on the KC-device would rather introduce complications when it comes to binary data, with advantages that are somewhat hard to justify. Having HTTP resources could make sense, as this could provide a mean of separating API functions. However, maybe the format of the data should not be strictly defined, and using the same, binary-data ready csexp format that GnuPG operates internally with instead of JSON seems to be a better direction.

Nevertheless, seeing the REST API in action on the Android-based KC-device was still a valuable proof of concept.

scdaemon: dynamically loadable smart card backends

We have examined the source code of GnuPG and have found, that it is in fact quite modular, and builds upon an architecture that is based on separate processes that communicate with each other. This is carried out by a library called Assuan, which is also responsible for securing the data exchange in the memory. The following diagram was attached in the GnuPG source code documentation, and has shed some light on the inner workings:

<img src=”/assets/img/key-container/gnupg-card-architecture-b.png” width=800px alt=”GnuPG card architecture” />

As we see in this figure, through scdaemon, GnuPG supports multiple smart card reader backends (PC/CS, CT-API, and CCID, to be exact). From our perspective, the only problem is, that meanwhile multiple readers are supported, GnuPG is only compatible with smart cards running the OpenPGP application. That means, that if we wanted to implement the emulation at the level of the card reader, we had to implement a virtual, compliant smart card. While there is a reference implementation available for BasicCard programmable smart cards, reimplementing the software or emulating the BasicCard seemed to be the more difficult route, so we have taken another approach instead for a start.

Being an Assuan module, scdaemon defines a list of API functions that may be called by other programs - such as GnuPG itself. The implementation of some of these commands are specific to the latter mentioned OpenPGP application, while others are related to the module itself. With a little tweaking, we have provided a mean of overriding the card-specific ones by pointing at a custom shared object (kc_impl.so) to be loaded instead:

$ scdaemon --help
scdaemon (GnuPG) 2.2.20-beta16
(...)
Syntax: scdaemon [options] [command [args]]
Smartcard daemon for GnuPG

Options:
   --server                 run in server mode (foreground)
(...)
   --custom-backend FILE    use custom smart card backend
(...)

Such a shared object should be linked against the same library versions that scdaemon is linked against, and must reimplement the otherwise OpenPGP smart card software specific driver functions:

// backend-custom.h

#include <assuan.h>
#include <gpg-error.h>

/**
 * Implement this file in a shared library. Load with the --custom-backend option.
 */
gpg_error_t custom_cmd_serialno (assuan_context_t ctx, char *line);
gpg_error_t custom_cmd_learn (assuan_context_t ctx, char *line);
gpg_error_t custom_cmd_readcert (assuan_context_t ctx, char *line);
gpg_error_t custom_cmd_readkey (assuan_context_t ctx, char *line);
gpg_error_t custom_cmd_setdata (assuan_context_t ctx, char *line);
gpg_error_t custom_cmd_pksign (assuan_context_t ctx, char *line);
gpg_error_t custom_cmd_pkauth (assuan_context_t ctx, char *line);
gpg_error_t custom_cmd_pkdecrypt (assuan_context_t ctx, char *line);
gpg_error_t custom_cmd_getattr (assuan_context_t ctx, char *line);
gpg_error_t custom_cmd_setattr (assuan_context_t ctx, char *line);
gpg_error_t custom_cmd_writecert (assuan_context_t ctx, char *line);
gpg_error_t custom_cmd_writekey (assuan_context_t ctx, char *line);
gpg_error_t custom_cmd_genkey (assuan_context_t ctx, char *line);
gpg_error_t custom_cmd_random (assuan_context_t ctx, char *line);
gpg_error_t custom_cmd_passwd (assuan_context_t ctx, char *line);
gpg_error_t custom_cmd_checkpin (assuan_context_t ctx, char *line);
gpg_error_t custom_cmd_disconnect (assuan_context_t ctx, char *line);
gpg_error_t custom_cmd_apdu (assuan_context_t ctx, char *line);
gpg_error_t additional_cmd_getinfo (assuan_context_t ctx, char *line);
gpg_error_t additional_cmd_restart (assuan_context_t ctx, char *line);

Static implementation

Right now, we are working on a static implementation that does not contain actual logic, but is only capable for creating the same signature for the same file with the same key.

At this very moment, our implementation is able to report some basic data on the smart card, and the public exponents of an RSA key.

Reader ...........: Dummy reader
Application ID ...: D276000124010340FFFF123456780000
Application type .: OpenPGP
Version ..........: 3.40
Manufacturer .....: ?
Serial number ....: 12345678
Name of cardholder: John Doe
Language prefs ...: [not set]
Salutation .......: 
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: forced
Max. PIN lengths .: 0 0 0
PIN retry counter : 0 0 0
Signature counter : 0
General key info..: pub  rsa2048/8E242886C1A59F79 2020-09-08 John Doe <[email protected]>
sec#  rsa2048/8E242886C1A59F79  created: 2020-09-08  expires: soha      
ssb>  rsa2048/B28E6C292ADF668B  created: 2020-09-08  expires: soha      
                                card-no: FFFF 12345678

In the next two semesters, further progress shall be expected.

Check out our entry!

We are happy to announce that our work has received an award at Óbuda University at the local event “Tudományos Diákköri Konferencia” (≈”Scientific conference by students”). You may check the original, Hungarian version of the paper at the Contributions menu.

Download

kuklin_vajnai_biztonsagosabb_kulcshasznalat_2020.pdf

The Hungarian paper we have submitted in 2020

Icon

Soon after we chose an open source license, the development sources are going to be released under the same menu.

Coming soon

Taking advantage of the ability to reuse code, we utilize some of the same libraries on the KC-device which are present on the computer with the GnuPG installation. In an earlier article I have published PKGBUILD files for the compilation of native libraries for Android devices, however, that quick and dirty solution has introduced some problems that suggested the need of a more pragmatic approach.

In the next article, I am going to give a write-up on how Conan package manager could help us out.

As always, thanks for reading!