Home

Awesome

Authors

Andrea Barisani
andrea.barisani@withsecure.com | andrea@inversepath.com

Introduction

The GoKey application implements a USB smartcard in pure Go with support for:

In combination with the TamaGo framework GoKey is meant to be executed on ARM bare metal on hardware such as the USB armory Mk II.

:warning: the SSH management console only works on Linux or macOS hosts.

GoKey demo

Security model

When running on secure booted NXP i.MX6ULL devices, the built-in Data Co-Processor (DCP) is used to provide device specific hardware encryption.

A device specific random 256-bit OTPMK key is fused in each NXP i.MX6ULL SoC at manufacturing time, this key is unreadable and can only be used by the DCP for AES encryption/decryption of user data, through the Secure Non-Volatile Storage (SNVS) companion block.

The OTPMK is used to derive device specific keys, which can be used for the following operations:

On units which are not secure booted (not recommended):

For certain users and uses, a non secure booted device might lead to an acceptable level of risk in case of a stolen device, nonetheless it is highly recommended to always use a secure booted device for all configurations and to leverage on SNVS features (see Compiling).

On a secure booted unit the GoKey firmware, bundled with private keys encrypted with the device unique key, can be built by compiling on the device itself with the mxs-dcp kernel module loaded.

The module is included in all USB armory Mk II standard Debian base image releases.

Deviations from OpenPGP standard support

These are security features, not bugs:

These are current limitations:

Comparison with conventional smartcards

A conventional smartcard authenticates the user typically with a numeric PIN, this cardholder authentication unlocks the code paths that allow use of key material and/or management functions. The secret key material is stored in an internal flash unencrypted, relaying on the physical barrier and simple read protection mechanisms for its security.

In other words a conventional smartcard does not employ encryption of data at rest and its code has internal access to key material unconditionally.

Futher, traditional smartcards require physical security measures to prevent tampering attacks such as glitching or memory extraction, as there is opportunity for an attacker in possession of a stolen card to try and extract key material.

The GoKey firmware, when running on the USB armory Mk II, employs a different security model as all data at rest is either authenticated, by secure boot, or encrypted. The private OpenPGP keys are actually encrypted twice, the first layer for the benefit of the hardware so that only authenticated code can unwrap the key and the second layer for the benefit of user authentication.

Therefore the GoKey firmware does not need to be stored on an internal flash with read protection but is meant to be accessible by anyone, as it is authenticated by the hardware and only holds encrypted content which can be unlocked by a specific device and a specific user.

Additionally, to help mitigating attacks against the first layer of hardware key wrapping, hardware decryption can be configured to take place only when a user is successfully authenticated through the management interface.

The security model of GoKey, opposed to conventional smartcards, entails that a stolen device gives no opportunity for an attacker to extract private key material unless the user private SSH key (or secure boot process) as well as OpenPGP key passphrases are compromised, when all security features are used.

Last but not least, thanks to the TamaGo framework, GoKey on the USB armory Mk II employs a runtime environment written in pure high-level, memory safe, Go code and without the dependency of an OS, or any other C based dependency. This dramatically reduces the attack surface while increasing implementation trustworthiness.

The following table summarizes the fundamental technological differences with a traditional smartcard:

Hardware typeTrust anchorData protectionRuntime environmentApplication environmentRequires tamper proofingEncryption at rest
Traditional smartcardsFlash protectionFlash protectionJCOPJCOP appletsYesNo
GoKey on USB armory Mk IISecure bootSoC security elementBare metal GoBare metal GoNoYes

The following table summarizes the multiple authentication options available, depending on OpenPGP and GoKey configuration, which enhance the traditional smartcard authentication model:

OpenPGP passphraseGoKey authentication (see SNVS=ssh)Comment
NoneNoneNo security, device can be used without any authentication
Yes over VERIFYNoneLow security, passphrase transmitted in plaintext over USB
Yes over SSHNoneBetter security, passphrase transmitted securely
Yes over VERIFYYesGood security, plaintext passphrase but standard SSH authentication required to enable key use
NoneYesGood security and convenience, standard SSH authentication required for hardware key decryption
Yes over SSHYesHigh security, standard SSH authentication enables key use, passphrase transmitted securely

Tutorial

The next sections detail the compilation, configuration, execution and operation for bare metal, virtualized and simulated environments.

A simplified tutorial for secure booted USB armory Mk II boards is available in the project wiki.

Compiling

Unless otherwise stated, all commands shown are relative to this repository directory:

git clone https://github.com/usbarmory/GoKey && cd GoKey

As a pre-requisite for all compilation targets, the following environment variables must be set or passed to the make command:

:warning: the SSH management console only works on Linux or macOS hosts, it must be disabled for Windows hosts.

OpenPGP

OpenPGP smartcard secret keys are typically made of 3 subkeys: signature, decryption, authentication.

The GoKey card cannot import keys while running as any runtime change is not allowed (see Deviations from OpenPGP standard support), only key bundling at compile time is currently supported.

There are several resources on-line on OpenPGP key creation and should all be applicable to GoKey as long as the smartcard specific keytocard command is not used, but rather keys are exported armored and passed via PGP_SECRET_KEY at compile time.

Some good references to start:

Finally always ensure that existing keys are imported with minimal content, an example preparation is the following:

gpg --armor --export-options export-minimal,export-clean --export-secret-key ID

:warning: Please note that only RSA, ECDSA, ECDH keys are supported. Any other key (such as ElGamal, Ed25519) will not work.

U2F keys

To enable U2F support using the fidati library, the following variables can be set:

The attestation key material can be created using the gen-cert tool from the fidati library.

On USB armory Mk II rev. β models the ATECC608B security element is used as hardware backed monotonic counter for U2F purposes. The counter runs out at 2097151, which is considered a range sufficient for its intended purpose.

On USB armory Mk II rev. γ models a 32-bit monotonic counter is saved on the internal eMMC in an unused reserved sector.

The U2F library performs peer-specific key derivation using a master secret (U2F Key Wrapping), GoKey derives such master secret using the SNVS to obtain an authenticated device specific value.

When the management interface is disabled, FIDO U2F user presence is automatically acknowledged, otherwise it can be configured at initialization through the management interface (see Management).

Building the bare metal executable

Build the TamaGo compiler (or use the latest binary release):

wget https://github.com/usbarmory/tamago-go/archive/refs/tags/latest.zip
unzip latest.zip
cd tamago-go-latest/src && ./all.bash
cd ../bin && export TAMAGO=`pwd`/go

Please note that if performed on the USB armory Mk II, due to this issue, this requires adding some temporary swap space to be disabled and removed after this step is completed (to prevent eMMC wear), alternatively you can cross compile from another host or use the latest binary release).

Build the gokey.imx application executable with the desired variables:

make imx CROSS_COMPILE=arm-none-eabi- NAME="Alice" PGP_SECRET_KEY=<secret key path> SSH_PUBLIC_KEY=<public key path> SSH_PRIVATE_KEY=<private key path>

For signed images to be executed on secure booted USB armory Mk II devices, which enable use of Secure Non-Volatile Storage (SNVS), the imx_signed target should be used with the relevant HAB_KEYS set:

make imx_signed CROSS_COMPILE=arm-none-eabi- NAME="Alice" PGP_SECRET_KEY=<secret key path> SSH_PUBLIC_KEY=<public key path> SSH_PRIVATE_KEY=<private key path> HAB_KEYS=<secure boot keys path> SNVS=ssh

OpenPGP host configuration

macOS

The GoKey USB smartcard works out of the box on modern macOS installations with GPG Suite.

Linux

The GoKey USB smartcard has been tested with libccid, used by OpenSC on most Linux distributions.

The libccid library now supports GoKey vendor and product IDs, if your installed version is older than this change apply the following instructions.

To enable detection an entry must be added in libccid_Info.plist (typically located in /etc):

<string>0x1209</string>
<string>0x2702</string>
<string>USB armory Mk II</string>

The GoKey USB smartcard, once the CCID driver entries are added as in the previous section, can then be used as any other smartcard via OpenSC on Linux.

You can refer to Arch Linux smartcards documentation for configuration documentation.

Windows

Windows does not support Ethernet over USB devices implemented with CDC-ECM, therefore the SSH management console must be disabled (e.g. SNVS can be non empty but not to ssh, see Compiling)

Smartcard operation has not been tested but should be possible with software that uses up-to-date smartcard drivers.

Executing

USB armory Mk II: imx image

Follow these instructions using the built gokey.imx or gokey_signed.imx image.

USB armory Mk II: existing bootloader

Copy the built gokey binary on an external microSD card (replace $dev with 0) or the internal eMMC (replace $dev with 1), then launch it from the U-Boot console as follows:

ext2load mmc $dev:1 0x90000000 gokey
bootelf -p 0x90000000

For non-interactive execution modify U-Boot configuration accordingly.

Operation

GoKey can be conveniently accessed from either the USB armory Type-C plug (e.g. USB armory directly connected to a Type-C host port) or receptacle (e.g. USB armory connected with a Type-C to Type-A cable).

Management interface

When running on bare metal the GoKey firmware exposes, on top of the USB CCID smartcard and/or U2F token interfaces, an SSH server started on Ethernet over USB.

The SSH server authenticates the user using the public key passed at compilation time with the SSH_PUBLIC_KEY environment variable. Any username can be passed when connecting. If empty the SSH interface is disabled.

A private key for the SSH server can be optionally passed at compilation time with the SSH_PRIVATE_KEY environment variable, on secure booted units it can also be deterministically generated at each boot (see Compiling).

The server responds on address 10.0.0.10, with standard port 22, and can be used to securely message passphrase verification, in alternative to smartcard clients which issue unencrypted VERIFY commands with PIN/passphrases, signal U2F user presence and perform additional management functions.

  help                          # this help
  exit, quit                    # close session
  rand                          # gather 32 bytes from TRNG via crypto/rand
  reboot                        # restart
  status                        # display smartcard/token status

  init                          # initialize OpenPGP smartcard
  lock   (all|sig|dec)          # OpenPGP key(s) lock
  unlock (all|sig|dec)          # OpenPGP key(s) unlock, prompts passphrase

  rpc                           # PKCS#11 RPC socket
                                # use with 'ssh -L p11kit.sock:127.0.0.1:22'

  u2f                           # initialize U2F token w/  user presence test
  u2f !test                     # initialize U2F token w/o user presence test
  p                             # confirm user presence

Note that to prevent plaintext transmission of the PIN/passphrase, the VERIFY command requested by any OpenPGP host client will take any PIN (>= 6 characters) if the relevant OpenPGP key has been already unlocked over SSH.

OpenPGP smartcard

You should be able to use the GoKey smartcard like any other OpenPGP card, you can test its operation with the following commands:

When checking card status note that a > after key information tags indicate that the key is stored on a smartcard.

U2F token

The U2F functionality can be used with any website or application that supports FIDO U2F.

When the SSH interface is enabled (see Management) the U2F functionality must be initialized with the u2f command, user presence can be demonstrated with the p command (not required if u2f !test is used for initialization).

When the SSH interface is disabled user presence is automatically acknowledged at each request.

PKCS#11 token

When the SSH interface is enabled (see Management) a GoKey protected ECDSA/RSA key can be exposed through PKCS#11 over RPC through an SSH forwarded Unix socket.

A direct SSH TCP forward to a Unix socket exposes GoKey PKCS#11 over RPC interface:

$ ssh -N -L p11kit.sock:127.0.0.1:22 10.0.0.10

This allows use of such key through PKCS#11 API clients, the following example illustrates integration with OpenSSL.

$ export P11_KIT_SERVER_ADDRESS=unix:path=p11kit.sock
$ pkcs11-tool --module /usr/lib/pkcs11/p11-kit-client.so --list-slots

Available slots:
Slot 0 (0x1): example-slot
  token label        : GoKey
  token manufacturer : WithSecure Foundry
  token model        : USB armory Mk II
  token flags        : token initialized, readonly
  hardware version   : 2.0
  firmware version   : 0.1
  serial num         : C148261A
  pin min/max        : 0/0

$ pkcs11-tool --module /usr/lib/pkcs11/p11-kit-client.so --list-objects

Using slot 0 with a present token (0x1)
Certificate Object; type = X.509 cert
  subject:    DN:
  serial:     75A3F93B15D62D15
  ID:         010275a3f93b15d62d15
Private Key Object; RSA
  Usage:      decrypt, sign
  Access:     sensitive, always sensitive, never extractable
Public Key Object; RSA 2048 bits
  ID:         010275a3f93b15d62d15
  Usage:      encrypt, verify
  Access:     none

LED status

On the USB armory Mk II the LEDs are used as follows:

LEDOnOff
blue + whiteat startup: card is initializing¹card has been initialized
blueone or more OpenPGP private subkeys are unlockedall OpenPGP private subkeys are locked
whiteOpenPGP security operation in progressno security operation in progress
whiteblinking: U2F user presence is requestedno presence requested

¹ With SNVS=ssh both LEDs remain on until the init command has been issued over SSH management interface.

Debugging

Virtual Smart Card

The virtual smart card project allows testing of GoKey OpenPGP functionality in userspace.

Build the gokey_vpcd application executable:

make gokey_vpcd PGP_SECRET_KEY=<secret key path>

On the host install vsmartcard, Arch Linux users can use the virtualsmartcard AUR package.

Ensure that a configuration for vpcd is added in your pcsc configuration. On Arch Linux the following is automatically created in /etc/reader.conf.d:

FRIENDLYNAME "Virtual PCD"
DEVICENAME   /dev/null:0x8C7B
LIBPATH      //usr/lib/pcsc/drivers/serial/libifdvpcd.so
CHANNELID    0x8C7B

Launch the PC/SC daemon:

sudo systemctl start pcscd

Launch the built gokey_vpcd executable:

./gokey_vpcd -c 127.0.0.1:35963

The same executable can also be used to test the PKCS#11 token interface, a relevant P11_KIT_SERVER_ADDRESS variable is returned upon execution of gokey_vpcd.

Send manual commands to GnuPG smart-card daemon (SCD)

gpg-connect-agent "SCD RANDOM 256" /bye | perl -pe 'chomp;s/^D\s//;s/%(0[AD]|25)/chr(hex($1))/eg;if(eof&&/^OK$/){exit}'

License

GoKey | https://github.com/usbarmory/GoKey
Copyright (c) WithSecure Corporation

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation under version 3 of the License.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

See accompanying LICENSE file for full details.