Skip links

Using the CardContact SmartCard USB HSM in an Ethereum PoA Chain

After testing the performance of Ethereum using PoA, we tested the usability of the CardContact SmartCard-HSM USB token on an ethereum Proof of Authority network. The HSM allows to store and use multiple encryption keys, both RSA and Elliptic Curves (including secp256k1), for applications like issuing certificates as a CA, and with any application that can interface with the PKCS#11 standard. In this guide we explain how to install it in a Linux Machine and get it started with a fork of the go-ethereum  that implements an extension of web3 to interface with the above mentioned standard.

Token Installation

Before we are able to use our token, we need to install a few dependencies to interface an administer it:

  1. Install OpenSC, it has packages in most of the usual Linux distros, you can found the appropriate way for your own here
  2. Download the Starterkit from CardContact’s site. Unzip it and run the .sh file found in the ‘linux’ folder inside it. After it declares that it found the libccid configuration, we can go on. If it failed, there is a problem with our OpenSC installation, make sure it was done properly.
  3. After it is done, install the XCA key management application, you can download it and see more detailed instructions as to how to do it in their site
  4. Now, you can set up the HSM. For most of this part you can follow the guide found as a PDF inside the Starterkit you downloaded earlier.
    1. Open XCA and create a new database as explained in the PDF. After that, follow along and select your PKCS#11 module. In my case (Ubuntu 18.04 LTS), it was found in /usr/lib/x86_64-linux-gnu/pkcs11/opensc-pkcs11.so, but it could vary.
    2. Now, instead of following the PDF guide, you have to enter the following command with the device plugged in to initialize it, entering our own pin (must be 6-16 characters long):

sc-hsm-tool --initialize --so-pin 3537363231383830 --pin 123456

Project setup

Preparation

Now that you’ve installed and initialized the token, you need to download and configure the modified version of geth, and create a new key to use.

  1. First, you must install the fork of geth 1.8.13 created by Github user gemalto, that you can download from this repo.
  2. After you downloaded and unzipped the files, open a terminal inside the folder and run make.
  3. Around this point you should also create the key you want to use to sign.
    1. Open XCA, open the previously created database and, with the HSM inserted, select “New Key”.
    2. A Dialog box opens and you are prompted to select a key name, that you could choose as you see fit, a Keytype, that must be “UserPin […] (EC Key of 192 – 320 bits)”, not a regular EC key, and a curve name, where you need to choose “secp256k1”, since is the curve that Ethereum uses to seal blocks and sign transactions.

After the key is created, you must prepare the private network.

Network setup

To be able to setup de PoA network with the key you just created, you need to know at least one address associated with it. For that, we chose to start a Proof of work network using the same repo, which  allowed us to also test that the PKCS#11 capabilities of it were working. First, we created a new genesis using puppeth (but you can do it the way you prefer it), and then we followed the following steps:

  1. Inside the geth repo folder we ran ./build/bin/geth init pow.json --datadir database/pow with pow.json being our genesis file
  2. Then ./build/bin/geth init pow.json --datadir database/pow --networkid 38969 dumpconfig > pow.toml to get the configuration file, with the correct network id form your genesis file
  3. Then, we edited the file as explained in the repository’s README, adding to the [Node] block the following lines (remember, if your opensc installed the library elsewhere, you have to change that):
    1. PKCS11Lib = "https://coinfabrik.b-cdn.net/usr/lib/x86_64-linux-gnu/pkcs11/opensc-pkcs11.so"
    2. NoPKCS11BIP32 = true
  4. Then, we ran  the geth instance with the new config file with ./build/bin/geth --datadir database/pow --networkid 38969 --config pow.toml console
  5. Now, inside geth console, you can derive the address:
    1. First, list your has wallets with personal.listWallets
    2. Then unlock the wallet with personal.openWallet("hsm://UserPIN (SmartCard-HSM)") . The parameter must match the wallet URL that appeared in the previous step. The password asked is the pin created when you initialized the device.
    3. Finally, derive an address form the key, using personal.newHsmAccount("hsm://UserPIN (SmartCard-HSM)") , again with the correct hsm url. Save that wallet since it’s the one you will be using to configure your poa network

Now, we are ready to create our private PoA network. The steps are fairly similar, the key differences are that, when creating the genesis block you should input the address we just derived from the key, and that you should use a different network id, datadir, and genesis and config files. When you reach the point where you open the geth console, now with the PoA network, you are ready to go.

Usage and conclusions

While testing it, we were able to check that the device works as intended. If we don’t open the wallet it is unable to start mining, if we close the wallet with personal.closeWallet("hsm://UserPIN (SmartCard-HSM)") the mining process immediately stops, and the same happens if we remove the device from the PC at any point. This proved to be a way that it’s both secure and portable to use a PoA network, since it allows to move the USB token from computer to compute physically, while the signing key remained secured inside.  We can only hope that this technology is adopted by the main geth and web3 projects to allow updated capabilities and continued support.