In our previous post, we’ve built a Resens Edge Gateway that can communicate with AWS IoT cloud platform. However, certificates and keys are stored as files on the SD card, which is a security risk. And so we’ve looked for a way to keep these as secrets.

This article shows our steps to setup cryptoauthlib as PKCS11 provider on the gateway with a Microchip ATECC608A module connecting to its I2C1 port.

See here to know more about Microchip’s solution for AWS IoT Greengrass Hardware Security Interface, and here for more instructions of how to setup the system.

PKCS11 Linux Setup

First, we need to update libp11 on the system. Let’s install the build dependencies

$ sudo apt-get build-dep libengine-pkcs11-openssl1.1

Then get the latest version of libp11

$ git clone https://github.com/OpenSC/libp11.git

Build and setup the library

$ cd libp11
$ ./bootstrap
$ ./configure
$ make
$ sudo make install

Build and install cryptoauthlib with PKCS11 support

Enable source build in Raspberry Pi by editing sources.list as follows

$ sudo nano /etc/apt/sources.list

Then un-comment the line start with deb-src and run update

$sudo apt-get update

Next, install the build dependencies for the system

$ sudo apt-get install cmake libudev-dev

Get the latest version of cryptoauthlib with PKCS11 support

$ git clone --single-branch -b pkcs11 https://github.com/MicrochipTech/cryptoauthlib

After cloning the library, we need to update the source code to make sure it can communicate with the ATECC608A chip connecting to the Raspberry Pi board.

If we are not doing this hardware modification, we may later get an error saying pkcs11_init: PKCS #11 initialization error when running command $ p11tool --listall. More about this error can be seen here.

Update cryptoauthlib source code to match with the hardware

To edit the source code, we need to check which I2C port on the Raspberry Pi board the ATECC608A is connecting to, and what is its I2C address. Check the hardware connection and Raspberry Pi pin out to know whether I2C0 or I2C1 bus is using (I’ll assume we are using I2C1 bus), and run this command to find out the security chip I2C address:

$ sudo i2cdetect -y 1

Remember to shift left the I2C address by 1 bit to know the I2C chip address. I’ll assume i2cdetect command found an I2C device at 0x35, then the corresponding address is 0x6A.

In the cryptoauthlib source code folder, open the file cryptoauthlib/lib/atca_cfgs.c and modify cfg_ateccx08a_i2c_default, the default hardware configuration struct, to match the hardware connection. See the example below:

/** \brief default configuration for an ECCx08A device */
ATCAIfaceCfg cfg_ateccx08a_i2c_default = {
    .iface_type                 = ATCA_I2C_IFACE,
    .devtype                    = ATECC608A,
    {
        .atcai2c.slave_address  = 0x6A,
        .atcai2c.bus            = 1,
        .atcai2c.baud           = 400000,
        //.atcai2c.baud = 100000,
    },
    .wake_delay                 = 1500,
    .rx_retries                 = 20
};

Build and install the library

Run the build configuration tools:

$ cd cryptoauthlib
$ cmake .

Build the library:

$ make

Install the library:

$ sudo make install

Configure the cryptoauthlib PKCS11 library

Edit the file /etc/cryptoauthlib/cryptoauthlib.conf

# Cryptoauthlib Configuration File
filestore = /var/lib/cryptoauthlib

Copy the configuration template, /var/lib/cryptoauthlib/slot.conf.tmpl, into slot configuration files

$ cd /var/lib/cryptoauthlib
$ cp slot.conf.tmpl 0.conf

Then edit 0.conf to match with the I2C chip address:

# Reserved Configuration for a device
# The objects in this file will be created and marked as undeletable
# These are processed in order. Configuration parameters must be comma
# delimited and may not contain spaces

interface = i2c,0x6A
freeslots = 1,2,3

# Slot 0 is the primary private key
object = private,device,0

# Slot 10 is the certificate data for the device's public key
#object = certificate,device,10

# Slot 12 is the intermedate/signer certificate data
#object = certificate,signer,12

# Slot 15 is a public key
object = public,root,15

Using p11-kit-proxy

Install it

$ sudo apt-get install p11-kit

Create or edit the global configuration file /etc/pkcs11/pkcs11.conf:

# This setting controls whether to load user configuration from the
# ~/.config/pkcs11 directory. Possible values:
#    none: No user configuration
#    merge: Merge the user config over the system configuration (default)
#    only: Only user configuration, ignore system configuration
user-config: merge

Create a module configuration file, which can be either a user module file ~/.config/pkcs11/modules/cryptoauthlib.module or global module file /usr/share/p11-kit/modules/cryptoauthlib.module:

module: /usr/lib/libcryptoauth.so
critical: yes
trust-policy: yes
managed: yes
log-calls: no

or /usr/local/etc/pkcs11/modules/cryptoauthlib.module and ~/.config/pkcs11/pkcs11.conf files.

Testing

We can use p11tool or Microchip Python tool, to test the setup.

Install p11tool

$ sudo apt-get install gnutls-bin

And run

p11tool --list-all

After this, we should see a response from the ATECC608A security device

[email protected]:~/Downloads/cryptoauthlib $ p11tool --list-all
Object 0:
        URL: pkcs11:model=ATECC608A;manufacturer=Microchip%20Technology%20Inc;serial=6C3D2FFAFF80;token=0123EE;object=device;type=private
Token '0123EE' with URL 'pkcs11:model=ATECC608A;manufacturer=Microchip%20Technology%20Inc;serial=6C3D2FFAFF80;token=0123EE' requires user PIN

Setup AWS IoT Certificate for the Gateway

As explained in this previous post, we’ve set up the Resens Edge Gateway based on AWS IoT Greengrass Core using certificate and keys downloaded from AWS IoT. Now we want to replace the keys with ones generated by the ATECC608A device.

On Raspberry Pi, create a CSR using openssl

$ openssl req -engine pkcs11 -key "pkcs11:token=0123EE;object=device;type=private" -keyform engine -new -out new_device.csr -subj "/CN=NEW CSR EXAMPLE"

and verify it

openssl req -in new_device.csr -verify -text -noout

Submit the CSR to AWS to obtain the connection certificate

See here for more references.

In AWS IoT:

  • Select Secure, Certificates, Create a certificate, and select Create with CSR.
  • Select the created CSR file and press Upload file.
  • Download the certificate, and save it to /greengrass/certs/ on Raspberry Pi.
  • Remember to activate the certificate and attach a policy with it.

Edit config.json file to use the pkcs11 provider

Modify the /greengrass/config/config.json file:

  • Remove the caPath, certPath, and keyPath properties from the coreThing object.
  • Edit the crypto as follows:
{
  "crypto": {
    "caPath": "file:///greengrass/certs/root.ca.pem",
    "PKCS11": {
      "OpenSSLEngine": "/usr/lib/arm-linux-gnueabihf/engines-1.1/pkcs11.so",
       "P11Provider": "/usr/lib/arm-linux-gnueabihf/p11-kit-proxy.so",
       "slotLabel": "0123EE",
       "slotUserPin": "1234"
    },
    "principals": {
      "IoTCertificate": {
        "privateKeyPath": "pkcs11:token=0123EE;object=device;type=private",
        "certificatePath": "file:///path-to-core-device-certificate"
      }
    }
  },
  "coreThing" : {
    "thingArn" : "arn:aws:iot:aws-region:aws-account-id:thing/thing-name",
    "iotHost" : "HOST_PREFIX_HERE.iot.aws-region.amazonaws.com",
    "ggHost" : "greengrass.iot.aws-region.amazonaws.com",
    "keepAlive" : 600
  },
  "runtime" : {
    "cgroup" : {
      "useSystemd" : "yes"
    }
  },
  "managedRespawn" : false
}

slotUserPin: the one we set during initialise the ATECC608A device.

certificatePath: path to the certificate downloaded in the previous step, i.e. in /greengrass/certs/.

HOST_PREFIX_HERE: AWS IoT endpoint.

thing-name: name of the Greengrass core on AWS IoT, for example ResensTestGroup_Core.

After doing all this, the Resens Edge Gateway should now be able to connect to AWS IoT as normal.