wxleong / pkcs11-optiga-tpm

OPTIGA™ TPM-Based PKCS #11 Token Setup and User Guide

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Github actions

Introduction

This document outlines the process of integrating an OPTIGA™ TPM SLx 967x TPM2.0 to establish a TPM2-based PKCS #11 cryptographic token.

PKCS #11, a Public-Key Cryptography Standard, establishes a standardized, platform-independent API for accessing cryptographic services from tokens, including hardware security modules (HSMs) and smart cards. This guide provides instructions for setting up a TPM2-based token.


Table of Contents


Prerequisites

The integration guide has been CI tested for compatibility with the following platform and operating system. Please refer to section GitHub Actions:

  • Platform: x86_64
  • Operating System: Ubuntu (22.04)

Preparing the Environment

One-Time Setup

Updates the package lists:

$ sudo apt update

Install generic packages:

$ sudo apt -y install autoconf-archive libcmocka0 libcmocka-dev procps \
    iproute2 build-essential git pkg-config gcc libtool automake libssl-dev \
    uthash-dev autoconf doxygen libjson-c-dev libini-config-dev \
    libcurl4-openssl-dev uuid-dev pandoc acl libglib2.0-dev xxd \
    libsqlite3-dev libyaml-dev python3-pip libp11-kit-dev dbus opensc \
    meson libtasn1-bin libnss3-tools

Install Python packages:

$ python3 -m pip install --upgrade pip==24.0
$ python3 -m pip install pyasn1_modules==0.2.8 cryptography==38.0.4 \
    pyyaml==6.0.1

Install tpm2-tss:

$ git clone https://github.com/tpm2-software/tpm2-tss ~/tpm2-tss
$ cd ~/tpm2-tss
$ git checkout 4.0.1
$ ./bootstrap
$ ./configure
$ make -j
$ sudo make install
$ sudo ldconfig

Install tpm2-tools:

$ git clone https://github.com/tpm2-software/tpm2-tools ~/tpm2-tools
$ cd ~/tpm2-tools
$ git checkout 5.6
$ ./bootstrap
$ ./configure
$ make -j
$ sudo make install
$ sudo ldconfig

Install tpm2-abrmd:

$ git clone https://github.com/tpm2-software/tpm2-abrmd ~/tpm2-abrmd
$ cd ~/tpm2-abrmd
$ git checkout 3.0.0
$ ./bootstrap
$ ./configure
$ make -j
$ sudo make install
$ sudo ldconfig

Install tpm2-pytss:

$ git clone https://github.com/tpm2-software/tpm2-pytss ~/tpm2-pytss
$ cd ~/tpm2-pytss
$ git checkout 2.2.1
$ python3 -m pip install -e .

Download the tpm2-pkcs11:

$ git clone https://github.com/tpm2-software/tpm2-pkcs11 ~/tpm2-pkcs11
$ cd ~/tpm2-pkcs11
$ git checkout 50a636bdb19220bf926cf6664e3084a315fe4480

Install tpm2-pkcs11, two options are available:

  1. ESYSDB (SQLite3) as the PKCS #11 backend:

    Disable the FAPI backend at build time by adding --disable-fapi to prevent unnecessary errors and warnings from the FAPI backend. Optionally, disable FAPI error logging by setting export TSS2_LOG=fapi+NONE.

    $ cd ~/tpm2-pkcs11
    $ git clean -fxd
    $ ./bootstrap
    $ ./configure --disable-fapi
    $ make -j
    $ sudo make install
    $ sudo ldconfig
    
  1. FAPI as the PKCS #11 backend:
    $ cd ~/tpm2-pkcs11
    $ git clean -fxd
    $ ./bootstrap
    $ ./configure
    $ make -j
    $ sudo make install
    $ sudo ldconfig
    

Install libtpms-based TPM emulator:

# Install dependencies
$ sudo apt install -y dh-autoreconf libtasn1-6-dev net-tools \
    libgnutls28-dev expect gawk socat libfuse-dev libseccomp-dev \
    make libjson-glib-dev gnutls-bin

# Install libtpms-devel
$ git clone https://github.com/stefanberger/libtpms ~/libtpms
$ cd ~/libtpms
$ git checkout v0.9.6
$ ./autogen.sh --with-tpm2 --with-openssl
$ make -j
$ sudo make install
$ sudo ldconfig

# Install Libtpms-based TPM emulator
$ git clone https://github.com/stefanberger/swtpm ~/swtpm
$ cd ~/swtpm
$ git checkout v0.8.1
$ ./autogen.sh --with-openssl --prefix=/usr
$ make -j
$ sudo make install
$ sudo ldconfig

Install the latest version of p11-kit to access a broader range of utilities. If installed via apt install p11-kit, only a limited set of subcommands is available:

It is important to set the installation path correctly for p11-kit to be able to locate the PKCS #11 module configuration files (e.g., tpm2_pkcs11.module from tpm2-pkcs11), which are located in /usr/share/p11-kit/modules/ in this setup. The PKCS #11 module configuration file is a file that contains a description of the PKCS #11 module and the path to the module (e.g., libtpm2_pkcs11.so from tpm2-pkcs11).

$ git clone https://github.com/p11-glue/p11-kit -b 0.25.3 --depth=1 ~/p11-kit
$ cd ~/p11-kit
$ meson setup _build
$ meson configure _build -Dprefix=/usr
$ meson compile -C _build
$ meson install -C _build
$ sudo ldconfig

Install the later version of GnuTLS from the source:

# Install dependencies
$ sudo apt install -y wget

# Download the source
$ cd ~
$ wget --no-verbose https://www.gnupg.org/ftp/gcrypt/gnutls/v3.8/gnutls-3.8.3.tar.xz
$ tar -xf gnutls-3.8.3.tar.xz

# Build and install the project
$ cd ~/gnutls-3.8.3
$ ./configure --with-included-unistring --disable-doc --disable-tests
$ make -j
$ sudo make install
$ sudo ldconfig

Recurring Setup

This guide utilizes the session dbus. While using the system dbus is possible, it is not included in this documentation.

Start a session dbus limited to the current login session:

$ export DBUS_SESSION_BUS_ADDRESS=`dbus-daemon --session --print-address --fork`

Launch the libtpms-based TPM emulator:

$ export SWTPM_PATH=$(mktemp -d)

# Create configuration files for swtpm_setup:
# - ~/.config/swtpm_setup.conf
# - ~/.config/swtpm-localca.conf
#   This file specifies the location of the CA keys and certificates:
#   - ~/.config/var/lib/swtpm-localca/*.pem
# - ~/.config/swtpm-localca.options
$ swtpm_setup --tpm2 --create-config-files overwrite,root

# Initialize the swtpm
$ swtpm_setup --tpm2 --config ~/.config/swtpm_setup.conf --tpm-state ${SWTPM_PATH} \
    --overwrite --create-ek-cert --create-platform-cert --write-ek-cert-files ${SWTPM_PATH}

# Launch the swtpm
$ swtpm socket --tpm2 --flags not-need-init --tpmstate dir=${SWTPM_PATH} \
    --server type=tcp,port=2321 --ctrl type=tcp,port=2322 &
$ sleep 5

Launch the TPM Resource Manager daemon; it facilitates communication via session dbus and acts as an intermediary to the TPM emulator:

$ tpm2-abrmd --allow-root --session --tcti=swtpm:host=127.0.0.1,port=2321 &
$ sleep 5

Specifies the TCTI using an environment variable:

$ export TPM2TOOLS_TCTI="tabrmd:bus_name=com.intel.tss2.Tabrmd,bus_type=session"
$ export TPM2_PKCS11_TCTI="tabrmd:bus_name=com.intel.tss2.Tabrmd,bus_type=session"

For convenience, use an alias to shorten the command:

$ TPM2_P11_PATH=`pkg-config --variable=p11_module_path tpm2-pkcs11`
$ alias pkcs11-tool-tpm2="pkcs11-tool --module ${TPM2_P11_PATH}/libtpm2_pkcs11.so"
$ alias tpm2_ptool="${HOME}/tpm2-pkcs11/tools/tpm2_ptool/tpm2_ptool.py"
$ alias

A simple test to verify that communication with the TPM is in order:

$ tpm2_getrandom --hex 16

Backend Initialization

To meet the requirements of the PKCS #11 interface, additional metadata needs to be saved to a data "store". The provider of this "store" is referred to as the backend of the PKCS #11 token, which includes the following backend options:

  1. ESYSDB (SQLite3)
  2. FAPI

ESYSDB (SQLite3) Backend

Clear the TPM:

$ tpm2_clear -c p

Set the token store location:

If not specified, the default path is set to $HOME/.tpm2_pkcs11/tpm2_pkcs11.sqlite3.

$ export TPM2_PKCS11_STORE=$(mktemp -d)

Leaving the TPM2_PKCS11_BACKEND environment variable unset or setting it to esysdb defaults to the SQLite3 backend:

$ export TPM2_PKCS11_BACKEND="esysdb"

FAPI Backend

Set the FAPI metadata store location:

$ export FAPI_METADATA_DIR=$(mktemp -d)

Initialize a TPM 2.0-based PKCS#11 Token with the TPM Feature API (FAPI) as backend. First, is to provisions a FAPI instance.

Update the FAPI configuration file at /usr/local/etc/tpm2-tss/fapi-config.json. The changes include:

  • Move all working directories to ${FAPI_METADATA_DIR}.
  • The profile can be P_RSA2048SHA256 or P_ECCP256SHA256. For better performance, P_ECCP256SHA256 may be used.
  • Additionally, updating the TCTI parameter allows switching between hardware or a simulated TPM. If using a TPM simulator, it is also possible to set it to ek_cert_less.
$ rm /usr/local/etc/tpm2-tss/fapi-config.json
$ cat > /usr/local/etc/tpm2-tss/fapi-config.json << EOF
$ {
$     "profile_name": "P_RSA2048SHA256",
$     "profile_dir": "/usr/local/etc/tpm2-tss/fapi-profiles/",
$     "user_dir": "${FAPI_METADATA_DIR}/user/keystore/",
$     "system_dir": "${FAPI_METADATA_DIR}/system/keystore/",
$     "tcti": "tabrmd:bus_name=com.intel.tss2.Tabrmd,bus_type=session",
$     "ek_cert_less": "yes",
$     "system_pcrs" : [],
$     "log_dir" : "${FAPI_METADATA_DIR}/eventlog/"
$ }
$ EOF
$ cat /usr/local/etc/tpm2-tss/fapi-config.json

Clear the TPM:

$ tpm2_clear -c p

Provision a FAPI instance. The Storage Root Key (SRK) will be created based on the profile located at profile_dir/profile_name and made persistent at handle 0x81000001 (as specified in the profile) without an authorization value. TPM metadata will be stored in the directory system_dir:

$ tss2_provision

Set the TPM2_PKCS11_BACKEND environment variable to fapi for using the FAPI backend:

$ export TPM2_PKCS11_BACKEND="fapi"

PKCS #11 Token Initialization

Initialize a TPM2-based PKCS #11 token. The options include:

  1. pkcs11-tool from OpenSC
  2. tpm2_ptool from tpm2-pkcs11 (ESYSDB)
  3. p11tool from GnuTLS

Late import of TPM persistent keys or externally stored keys into the TPM2-based PKCS #11 token using vendor-specific PKCS #11 attributes:

pkcs11-tool from OpenSC

Initialize a TPM2-based PKCS #11 token using pkcs11-tool.

If the backend is ESYSDB and the backend store is not found, this process automatically creates the tpm2_pkcs11.sqlite3 store, generates a SRK, and persistently stores it at the handle 0x81000001.

Create a token:

$ pkcs11-tool-tpm2 --slot-index 0 --init-token --label tpm2-token --so-pin sopin
$ pkcs11-tool-tpm2 --slot-index 0 --init-pin --so-pin sopin --login --pin userpin

List the token:

$ pkcs11-tool-tpm2 --list-token-slots

tpm2_ptool from tpm2-pkcs11 (ESYSDB)

This section only works with the ESYSDB backend. The tool directly modifies the ESYSDB backend store to make changes or additions. Subsequently, these changes will be reflected in the PKCS #11 interface.

Initialize a TPM2-based PKCS #11 token using the Python-based tpm2_ptool. The options include automatically generating the SRK (Storage Root Key) as the default behavior or manually specifying the primary key:

  1. Default Primary Key
  2. Custom Primary Key (Storage)
  3. Custom Primary Key (Platform)

Furthermore, tpm2_ptool enables the association of existing TPM externally stored keys (in Platform/Storage hierarchy) with the token:

For importing keys and certificates generated by third parties into the token using tpm2_ptool:

Default Primary Key

Create the backend store tpm2_pkcs11.sqlite3, generate a SRK, and persistently store it at handle 0x81000001:

If the hierarchy is protected by an authentication value, use the --hierarchy-auth option to set this value.

It is possible to set the authentication value of the primary key using the option --primary-auth.

$ pid=$(tpm2_ptool init --path $TPM2_PKCS11_STORE | grep id | sed 's/id: //')

Create a token:

$ tpm2_ptool addtoken --pid $pid --sopin sopin --userpin userpin \
    --label tpm2-token --path $TPM2_PKCS11_STORE

List the token:

$ pkcs11-tool-tpm2 --list-token-slots

Custom Primary Key (Storage)

Create the SRK:

$ tpm2_createprimary -G ecc -c primary.ctx
$ tpm2_evictcontrol -c primary.ctx 0x81000001

Create the backend store tpm2_pkcs11.sqlite3, associating it with the specified primary handle:

If the primary key is protected by an authentication value, use the --primary-auth option to set this value.

$ export TPM2_PKCS11_STORE=$(mktemp -d)
$ pid=$(tpm2_ptool init --primary-handle 0x81000001 --path $TPM2_PKCS11_STORE | grep id | sed 's/id: //')

Create the token:

$ tpm2_ptool addtoken --pid $pid --sopin sopin --userpin userpin \
    --label tpm2-token --path $TPM2_PKCS11_STORE

List the token:

$ pkcs11-tool-tpm2 --list-token-slots

Custom Primary Key (Platform)

Create the SRK:

$ tpm2_createprimary -C p -G ecc -c primary.ctx
$ tpm2_evictcontrol -C p -c primary.ctx 0x81800001

Create the backend store tpm2_pkcs11.sqlite3, associating it with the specified primary handle:

If the primary key is protected by an authentication value, use the --primary-auth option to set this value.

$ export TPM2_PKCS11_STORE=$(mktemp -d)
$ pid=$(tpm2_ptool init --primary-handle 0x81800001 --path $TPM2_PKCS11_STORE | grep id | sed 's/id: //')

Create the token:

$ tpm2_ptool addtoken --pid $pid --sopin sopin --userpin userpin \
    --label tpm2-token --path $TPM2_PKCS11_STORE

List the token:

$ pkcs11-tool-tpm2 --list-token-slots

Link Existing Ordinary Keys (Storage)

This requires a token initialized with a primary key in the storage hierarchy.

Create the ordinary keys:

$ tpm2_create -G rsa2048 -C 0x81000001 -u rsakey.pub -r rsakey.priv
$ tpm2_create -G ecc -C 0x81000001 -u ecckey.pub -r ecckey.priv

Link existing RSA and ECC keys to the token:

$ tpm2_ptool link --label tpm2-token --id 0 --key-label linked-rsa-2048 \
    --userpin userpin --path $TPM2_PKCS11_STORE rsakey.pub rsakey.priv
$ tpm2_ptool link --label tpm2-token --id 1 --key-label linked-ecc-p256 \
    --userpin userpin --path $TPM2_PKCS11_STORE ecckey.pub ecckey.priv

Read the slot number:

$ SLOT_INDEX=$(pkcs11-tool-tpm2 --list-token-slots | grep "): tpm2-token" | awk '{print $2}')

List the keys:

$ pkcs11-tool-tpm2 --slot-index $SLOT_INDEX --list-objects --login --pin userpin

Link Existing Ordinary Keys (Platform)

This requires a token initialized with a primary key in the platform hierarchy.

Create the ordinary keys:

$ tpm2_create -G rsa2048 -C 0x81800001 -u rsakey.pub -r rsakey.priv
$ tpm2_create -G ecc -C 0x81800001 -u ecckey.pub -r ecckey.priv

Link existing RSA and ECC keys to the token:

$ tpm2_ptool link --label tpm2-token --id 0 --key-label linked-rsa-2048 \
    --userpin userpin --path $TPM2_PKCS11_STORE rsakey.pub rsakey.priv
$ tpm2_ptool link --label tpm2-token --id 1 --key-label linked-ecc-p256 \
    --userpin userpin --path $TPM2_PKCS11_STORE ecckey.pub ecckey.priv

Read the slot number:

$ SLOT_INDEX=$(pkcs11-tool-tpm2 --list-token-slots | grep "): tpm2-token" | awk '{print $2}')

List the keys:

$ pkcs11-tool-tpm2 --slot-index $SLOT_INDEX --list-objects --login --pin userpin

Import 3rd Party Keys and Certificates

Generate an RSA key and a self-signed CA certificate using OpenSSL:

$ openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
    -keyout ca.key.pem -out ca.crt.pem \
    -subj "/C=DE/ST=Some-State/O=Some Inc./CN=dummy"

Import the key to the token:

$ tpm2_ptool import --label tpm2-token --key-label imported-ca-key \
    --userpin userpin --algorithm rsa --privkey ca.key.pem

Add the certificate to the token:

$ tpm2_ptool addcert --label tpm2-token --key-label imported-ca-key \
    --path $TPM2_PKCS11_STORE ca.crt.pem

Read the slot number:

$ SLOT_INDEX=$(pkcs11-tool-tpm2 --list-token-slots | grep "): tpm2-token" | awk '{print $2}')

List the keys and certificates:

$ pkcs11-tool-tpm2 --slot-index $SLOT_INDEX --list-objects --login --pin userpin

p11tool from GnuTLS

Initialize a TPM-based PKCS #11 token using p11tool.

If the backend is ESYSDB and the backend store is not found, this process automatically creates the tpm2_pkcs11.sqlite3 store, generates a SRK, and persistently stores it at the handle 0x81000001.

Get the token URL:

$ TOKEN_URL=`p11tool --list-token-urls | head -n 1`

Create a token:

$ p11tool --initialize --label tpm2-token --set-so-pin sopin "$TOKEN_URL"

Set user pin:

$ p11tool --initialize-pin --so-login --set-pin userpin "pkcs11:token=tpm2-token;pin-value=sopin"

key_import from tpm2-pkcs11

The key_import tool from tpm2-pkcs11 is a C program that utilizes PKCS #11 vendor-specific attributes to import TPM2 keys (as persistent handles or externally stored key objects, with or without auth value). This approach does not directly modify the backend store. Instead, it uses the PKCS #11 standard interface along with vendor-specific attributes to import the keys. The advantage of this approach is the reduced dependency on additional tooling needed to perform the key import operation, and it works well with either backend (ESYSDB or FAPI). For more examples, please refer to KEY_IMPORT_TOOL.md.

Create the ordinary keys that will be imported later:

# Externally stored key objects

$ tpm2_create -G rsa2048 -C 0x81000001 -u rsakey.pub -r rsakey.priv
$ tpm2_create -G ecc -C 0x81000001 -p ecckeyauth -u ecckey.pub -r ecckey.priv

# Persistent keys

$ tpm2_create -G rsa2048 -C 0x81000001 -p rsakeyauth -u rsakey_tmp.pub -r rsakey_tmp.priv
$ tpm2_load -C 0x81000001 -u rsakey_tmp.pub -r rsakey_tmp.priv -c rsakey_tmp.ctx
$ tpm2_evictcontrol -C o -c rsakey_tmp.ctx 0x81000011

$ tpm2_create -G ecc -C 0x81000001 -u ecckey_tmp.pub -r ecckey_tmp.priv
$ tpm2_load -C 0x81000001 -u ecckey_tmp.pub -r ecckey_tmp.priv -c ecckey_tmp.ctx
$ tpm2_evictcontrol -C o -c ecckey_tmp.ctx 0x81000012

Before proceeding, ensure that PKCS #11 token is initialized.

Read the slot number using the pkcs11_tool. The slot numbers returned by the tool start from 0, while the slot numbers in the tpm2-pkcs11 library start from 1:

$ SLOT_INDEX=$(pkcs11-tool-tpm2 --list-token-slots | grep "): tpm2-token" | awk '{print $2}')
$ TPM2_PKCS11_SLOT_INDEX=$((SLOT_INDEX + 1))

Import the externally stored key objects:

$ key_import --slot-id $TPM2_PKCS11_SLOT_INDEX --user-pin userpin \
    --tcti "$TPM2TOOLS_TCTI" \
    --parent-persistent-handle 0x81000001 \
    --public rsakey.pub \
    --private rsakey.priv \
    --key-label imported-rsa-2048-obj

$ key_import --slot-id $TPM2_PKCS11_SLOT_INDEX --user-pin userpin \
    --tcti "$TPM2TOOLS_TCTI" \
    --parent-persistent-handle 0x81000001 \
    --public ecckey.pub \
    --private ecckey.priv \
    --key-auth ecckeyauth \
    --key-label imported-ecc-p256-obj

Import the persistent keys:

$ key_import --slot-id $TPM2_PKCS11_SLOT_INDEX --user-pin userpin \
    --tcti "$TPM2TOOLS_TCTI" \
    --persistent-handle 0x81000011 \
    --key-auth rsakeyauth \
    --key-label imported-rsa-2048-persist

$ key_import --slot-id $TPM2_PKCS11_SLOT_INDEX --user-pin userpin \
    --tcti "$TPM2TOOLS_TCTI" \
    --persistent-handle 0x81000012 \
    --key-label imported-ecc-p256-persist

List the keys:

$ pkcs11-tool-tpm2 --slot-index $SLOT_INDEX --list-objects --login --pin userpin | tee log2verify
$ cat log2verify | grep imported-rsa-2048-obj
$ cat log2verify | grep imported-ecc-p256-obj
$ cat log2verify | grep imported-rsa-2048-persist
$ cat log2verify | grep imported-ecc-p256-persist
$ rm log2verify

Read the public components:

# key: imported-rsa-2048-obj

$ rsa_obj_id=$(echo -n imported-rsa-2048-obj | xxd -p)
$ pkcs11-tool-tpm2 --slot-index $SLOT_INDEX --login --pin userpin \
    --id $rsa_obj_id --type pubkey \
    --read-object --output-file rsa_obj.pub.der
$ openssl rsa -inform DER -outform PEM -in rsa_obj.pub.der -pubin \
    -out rsa_obj.pub.pem
$ cat rsa_obj.pub.pem

# key: imported-ecc-p256-obj

$ ecc_obj_id=$(echo -n imported-ecc-p256-obj | xxd -p)
$ pkcs11-tool-tpm2 --slot-index $SLOT_INDEX --login --pin userpin \
    --id $ecc_obj_id --type pubkey \
    --read-object --output-file ecc_obj.pub.der
$ openssl ec -inform DER -outform PEM -in ecc_obj.pub.der -pubin \
    -out ecc_obj.pub.pem
$ cat ecc_obj.pub.pem

# key: imported-rsa-2048-persist

$ rsa_persist_id=$(echo -n imported-rsa-2048-persist | xxd -p)
$ pkcs11-tool-tpm2 --slot-index $SLOT_INDEX --login --pin userpin \
    --id $rsa_persist_id --type pubkey \
    --read-object --output-file rsa_persist.pub.der
$ openssl rsa -inform DER -outform PEM -in rsa_persist.pub.der -pubin \
    -out rsa_persist.pub.pem
$ cat rsa_persist.pub.pem

# key: imported-ecc-p256-persist

$ ecc_persist_id=$(echo -n imported-ecc-p256-persist | xxd -p)
$ pkcs11-tool-tpm2 --slot-index $SLOT_INDEX --login --pin userpin \
    --id $ecc_persist_id --type pubkey \
    --read-object --output-file ecc_persist.pub.der
$ openssl ec -inform DER -outform PEM -in ecc_persist.pub.der -pubin \
    -out ecc_persist.pub.pem
$ cat ecc_persist.pub.pem

Create a file with random data:

$ pkcs11-tool-tpm2 --slot-index $SLOT_INDEX --generate-random 32 \
    --output-file data.plain

Perform RSA encryption and decryption:

# key: imported-rsa-2048-obj

$ openssl rsautl -encrypt -inkey rsa_obj.pub.pem -in data.plain \
        -pubin -out data.cipher
$ pkcs11-tool-tpm2 --slot-index $SLOT_INDEX --login --pin userpin \
    --id $rsa_obj_id --decrypt \
    --mechanism RSA-PKCS --input-file data.cipher \
    --output-file data.decipher
$ diff data.plain data.decipher

# key: imported-rsa-2048-persist

$ openssl rsautl -encrypt -inkey rsa_persist.pub.pem -in data.plain \
        -pubin -out data.cipher
$ pkcs11-tool-tpm2 --slot-index $SLOT_INDEX --login --pin userpin \
    --id $rsa_persist_id --decrypt \
    --mechanism RSA-PKCS --input-file data.cipher \
    --output-file data.decipher
$ diff data.plain data.decipher

Perform RSA sign and verification:

# key: imported-rsa-2048-obj

$ pkcs11-tool-tpm2 --slot-index $SLOT_INDEX --id $rsa_obj_id \
    --login --pin userpin --sign \
    --mechanism SHA256-RSA-PKCS --input-file data.plain \
    --output-file data.rsa.sig
$ openssl dgst -sha256 -verify rsa_obj.pub.pem \
    -signature data.rsa.sig data.plain

# key: imported-rsa-2048-persist

$ pkcs11-tool-tpm2 --slot-index $SLOT_INDEX --id $rsa_persist_id \
    --login --pin userpin --sign \
    --mechanism SHA256-RSA-PKCS --input-file data.plain \
    --output-file data.rsa.sig
$ openssl dgst -sha256 -verify rsa_persist.pub.pem \
    -signature data.rsa.sig data.plain

Perform ECC sign and verification:

# key: imported-ecc-p256-obj

$ pkcs11-tool-tpm2 --slot-index $SLOT_INDEX --id $ecc_obj_id \
    --login --pin userpin --sign \
    --mechanism ECDSA-SHA1 --signature-format openssl \
    --input-file data.plain --output-file data.ec.sig
$ openssl dgst -sha1 -verify ecc_obj.pub.pem \
    -signature data.ec.sig data.plain

# key: imported-ecc-p256-persist

$ pkcs11-tool-tpm2 --slot-index $SLOT_INDEX --id $ecc_persist_id \
    --login --pin userpin --sign \
    --mechanism ECDSA-SHA1 --signature-format openssl \
    --input-file data.plain --output-file data.ec.sig
$ openssl dgst -sha1 -verify ecc_persist.pub.pem \
    -signature data.ec.sig data.plain

Tools for Accessing PKCS #11 Tokens

Tools available for operations on a PKCS #11 token include:

pkcs11-tool from OpenSC

The pkcs11-tool is one of the command-line tools provided by OpenSC. This section introduces the tool through a series of practical examples, demonstrating its capabilities and usage.

The pkcs11-tool is installed during the setup stage through the installation of the opensc package.

Check the version of the opensc package and its dependencies:

$ apt show opensc
$ apt-cache depends opensc | grep Depends: | cut -d ":" -f2 | xargs dpkg -l

List available tokens:

$ pkcs11-tool-tpm2 --list-token-slots

Read the slot number:

$ SLOT_INDEX=$(pkcs11-tool-tpm2 --list-token-slots | grep "): tpm2-token" | awk '{print $2}')

Generate random bytes:

$ pkcs11-tool-tpm2 --slot-index $SLOT_INDEX --generate-random 32 --output-file data.plain

Change the SO pin:

$ pkcs11-tool-tpm2 --slot-index $SLOT_INDEX --change-pin --login --login-type so --so-pin sopin --new-pin sopin2

Restore the SO pin:

$ pkcs11-tool-tpm2 --slot-index $SLOT_INDEX --change-pin --login --login-type so --so-pin sopin2 --new-pin sopin

Change the user pin using user credential (from "userpin" to "upin"):

$ pkcs11-tool-tpm2 --slot-index $SLOT_INDEX --change-pin --login --pin userpin --new-pin upin

Change the user pin using SO credential (from "upin" to "userpin"):

# This is required for the FAPI backend; otherwise, the overwrite check will fail.
$ rm -rf ${FAPI_METADATA_DIR}/user/keystore/P_RSA2048SHA256/HS/SRK/tpm2-pkcs11-token-usr-00000001

$ pkcs11-tool-tpm2 --slot-index $SLOT_INDEX --init-pin --login --login-type so --so-pin sopin --new-pin userpin

Display supported mechanisms:

$ pkcs11-tool-tpm2 --slot-index $SLOT_INDEX --list-mechanisms

Create an RSA key:

$ pkcs11-tool-tpm2 --slot-index $SLOT_INDEX --id 00 --label rsa2048 --login --pin userpin \
    --keypairgen --key-type RSA:2048

Create an ECC key:

$ pkcs11-tool-tpm2 --slot-index $SLOT_INDEX --id 01 --label eccp256 --login --pin userpin \
    --keypairgen --usage-sign --key-type EC:secp256r1

List the created keys:

$ pkcs11-tool-tpm2 --slot-index $SLOT_INDEX --list-objects --login --pin userpin

Read the public component of the RSA key:

$ pkcs11-tool-tpm2 --slot-index $SLOT_INDEX --login --pin userpin --id 00 --type pubkey \
    --read-object --output-file rsa.pub.der
$ openssl rsa -inform DER -outform PEM -in rsa.pub.der -pubin -out rsa.pub.pem

Read the public component of the ECC key:

$ pkcs11-tool-tpm2 --slot-index $SLOT_INDEX --login --pin userpin --id 01 --type pubkey \
    --read-object --output-file ecc.pub.der
$ openssl ec -inform DER -outform PEM -in ecc.pub.der -pubin -out ecc.pub.pem

Perform RSA encryption and decryption:

$ openssl rsautl -encrypt -inkey rsa.pub.pem -in data.plain -pubin -out data.cipher
$ pkcs11-tool-tpm2 --slot-index $SLOT_INDEX --login --pin userpin --id 00 --decrypt \
    --mechanism RSA-PKCS --input-file data.cipher \
    --output-file data.decipher
$ diff data.plain data.decipher

Perform RSA signing and signature verification:

$ pkcs11-tool-tpm2 --slot-index $SLOT_INDEX --id 00 --login --pin userpin --sign \
    --mechanism SHA256-RSA-PKCS --input-file data.plain \
    --output-file data.rsa.sig
$ openssl dgst -sha256 -verify rsa.pub.pem -signature data.rsa.sig data.plain

Perform ECC signing and signature verification:

$ pkcs11-tool-tpm2 --slot-index $SLOT_INDEX --id 01 --login --pin userpin --sign \
    --mechanism ECDSA-SHA1 --signature-format openssl \
    --input-file data.plain --output-file data.ecc.sig
$ openssl dgst -sha1 -verify ecc.pub.pem -signature data.ecc.sig data.plain

Destroy the RSA key:

$ pkcs11-tool-tpm2 --slot-index $SLOT_INDEX --login --pin userpin --delete-object --type privkey --id 00
$ pkcs11-tool-tpm2 --slot-index $SLOT_INDEX --login --pin userpin --delete-object --type pubkey --id 00

Destroy the ECC key:

$ pkcs11-tool-tpm2 --slot-index $SLOT_INDEX --login --pin userpin --delete-object --type privkey --id 01
$ pkcs11-tool-tpm2 --slot-index $SLOT_INDEX --login --pin userpin --delete-object --type pubkey --id 01

libp11 from OpenSC (OpenSSL)

libp11 is a PKCS #11 engine plugin for the OpenSSL library, provided by OpenSC. Since the OpenSSL engine was deprecated with the release of OpenSSL 3, and OpenSSL now recommends using Providers instead of Engines, examples of using libp11 will not be covered here. Currently, OpenSC does not officially support a PKCS #11 provider, as discussed in this issue.

p11-kit

The p11-kit project includes the libp11-kit library for loading, enumerating, and managing PKCS #11 modules and also comes bundled with a command-line tool. This section introduces the tool through a series of practical examples, showcasing its capabilities and usage.

The p11-kit project is built and installed during the setup stage.

Please refer to the p11-kit installation section to learn how p11-kit discovers PKCS #11 modules (e.g., libtpm2_pkcs11.so from tpm2-pkcs11).

List available tokens:

$ p11-kit list-modules

Display a token information:

$ p11-kit list-tokens "pkcs11:token=tpm2-token"

Display supported mechanisms:

$ p11-kit list-mechanisms "pkcs11:token=tpm2-token"

Create an RSA key:

$ p11-kit generate-keypair --label rsa2048 --type rsa --bits 2048 --login "pkcs11:token=tpm2-token;pin-value=userpin"

Create an ECC key:

$ p11-kit generate-keypair --label eccp256 --type ecdsa --curve secp256r1 --login "pkcs11:token=tpm2-token;pin-value=userpin"

List the created keys:

$ p11-kit list-objects --login "pkcs11:object=rsa2048;pin-value=userpin"
$ p11-kit list-objects --login "pkcs11:object=eccp256;pin-value=userpin"

Read the public component of the RSA key:

$ p11-kit export-object --login "pkcs11:token=tpm2-token;object=rsa2048;type=public;pin-value=userpin" > rsa.pub.pem

Read the public component of the ECC key:

$ p11-kit export-object --login "pkcs11:token=tpm2-token;object=eccp256;type=public;pin-value=userpin" > ecc.pub.pem

Import a dummy certificate:

$ openssl req -x509 -newkey rsa:2048 -keyout ca.key.pem -out ca.cert.pem -sha256 -days 365 -nodes -subj "/CN=dummy"
$ p11-kit import-object --file ca.cert.pem --label dummy-cert --login "pkcs11:token=tpm2-token;pin-value=userpin"
$ p11-kit list-objects "pkcs11:object=dummy-cert"

Export the dummy certificate:

$ p11-kit export-object --login "pkcs11:token=tpm2-token;object=dummy-cert;pin-value=userpin" > ca.key.pem

Destroy the keys and certificate:

$ p11-kit delete-object --login "pkcs11:object=rsa2048;type=public;pin-value=userpin"
$ p11-kit delete-object --login "pkcs11:object=rsa2048;type=private;pin-value=userpin"
$ p11-kit delete-object --login "pkcs11:object=eccp256;type=public;pin-value=userpin"
$ p11-kit delete-object --login "pkcs11:object=eccp256;type=private;pin-value=userpin"
$ p11-kit delete-object --login "pkcs11:object=dummy-cert;pin-value=userpin"

p11tool from GnuTLS

The p11tool from GnuTLS is a command-line tool designed to interact with PKCS#11 tokens, utilizing the libp11-kit library from the p11-kit project.

The p11tool is installed during the setup stage through the gnutls-bin package, but it is overwritten by installing the GnuTLS project from source.

To set the pin, you may use the environment variable GNUTLS_PIN/GNUTLS_SO_PIN or include pin-value= in the URL.

Set the pin:

$ export GNUTLS_PIN="userpin"
$ export GNUTLS_SO_PIN="sopin"

Check the p11tool version:

$ p11tool --version

List available tokens:

$ p11tool --list-tokens

Change then restore the SO pin:

$ GNUTLS_SO_PIN=sopin GNUTLS_NEW_SO_PIN=sopin2 p11tool --initialize-so-pin "pkcs11:token=tpm2-token"
$ GNUTLS_SO_PIN=sopin2 GNUTLS_NEW_SO_PIN=sopin p11tool --initialize-so-pin "pkcs11:token=tpm2-token"

Change the user pin using SO credentials (for demonstration purposes, change to the same pin).

# This is required for the FAPI backend; otherwise, the overwrite check will fail.
$ rm -rf ${FAPI_METADATA_DIR}/user/keystore/P_RSA2048SHA256/HS/SRK/tpm2-pkcs11-token-usr-00000001

$ p11tool --initialize-pin --so-login --set-pin userpin "pkcs11:token=tpm2-token;pin-value=sopin"

Display supported mechanisms:

$ p11tool --list-mechanisms "pkcs11:token=tpm2-token"

Create an RSA key and output its public component:

$ p11tool --generate-privkey rsa --bits 2048 --label rsa2048 --outfile rsa.pub.pem --login "pkcs11:token=tpm2-token?pin-value=userpin"

Create an ECC key and output its public component:

$ p11tool --generate-privkey ecdsa --curve secp256r1 --label eccp256 --outfile ecc.pub.pem --login "pkcs11:token=tpm2-token?pin-value=userpin"

List all available objects:

$ p11tool --list-all --login "pkcs11:token=tpm2-token?pin-value=userpin"

Import a dummy certificate:

$ openssl req -x509 -newkey rsa:2048 -keyout ca.key.pem -out ca.cert.pem -sha256 -days 365 -nodes -subj "/CN=dummy"
$ p11tool --write --load-certificate ca.cert.pem --label dummy-cert --login "pkcs11:token=tpm2-token?pin-value=userpin"
$ p11tool --list-all-cert "pkcs11:token=tpm2-token"

Export the dummy certificate:

$ p11tool --export-chain "pkcs11:token=tpm2-token;object=dummy-cert" --outfile ca.cert.pem

Destroy the keys and certificate:

$ p11tool --delete --batch --login "pkcs11:token=tpm2-token;object=rsa2048?pin-value=userpin"
$ p11tool --delete --batch --login "pkcs11:token=tpm2-token;object=eccp256?pin-value=userpin"
$ p11tool --delete --batch --login "pkcs11:token=tpm2-token;object=dummy-cert?pin-value=userpin"

NSS Tools

Originally known as Netscape Security Services, Network Security Services (NSS) is a suite of libraries designed to support the cross-platform development of security-enabled client and server applications. The NSS-tools includes tools for developing, debugging, and managing applications that utilize these libraries.

NSS command-line tools are installed during the setup stage via the libnss3-tools package.

Check the version of the libnss3-tools package and its dependencies:

$ apt show libnss3-tools
$ apt-cache depends libnss3-tools | grep Depends: | cut -d ":" -f2 | xargs dpkg -l

Set the location of the NSS database path:

$ export NSSDB_DIR=$(mktemp -d)

Create an empty NSS database:

This process creates three files: cert9.db, key4.db, and pkcs11.txt. If no external token is specified, the internal slot will be used. An internal slot is a virtual slot maintained within the NSS software (NSS Internal PKCS #11 Module), and its associated certificate and key database are stored in cert9.db and key4.db, respectively. The list of loaded PKCS #11 modules is stored in pkcs11.txt.

$ certutil -N -d "sql:$NSSDB_DIR" --empty-password
$ ls -la $NSSDB_DIR

Generate a noise file for seeding purposes:

$ SLOT_INDEX=$(pkcs11-tool-tpm2 --list-token-slots | grep "): tpm2-token" | awk '{print $2}')
$ pkcs11-tool-tpm2 --slot-index $SLOT_INDEX --generate-random 32 --output-file noise.bin

# or

$ dd if=/dev/random of=noise.bin bs=32 count=1

Operations on NSS Internal PKCS #11 Module:

Display the list of modules and their associated slots:

$ modutil -list -dbdir "sql:$NSSDB_DIR" | grep "NSS Internal PKCS #11 Module"

Display the details of the module:

$ modutil -list "NSS Internal PKCS #11 Module" -dbdir "sql:$NSSDB_DIR"

Create a self-signed CA certificate and its associated CA key:

Make it non-interactive by adding echo -ne "y\ny" to respond to the following prompts:

  • Is this a CA certificate [y/N]?
  • Enter the path length constraint, press enter to skip [<0 for unlimited path]:
  • Is this a critical extension [y/N]?
$ echo -ne "y\ny" | certutil -S -s "CN=Software CA" \
    -n "software-ca" -x -t "C,C,C" -2 \
    -7 software-ca@example.com \
    --keyUsage certSigning,crlSigning,critical \
    --nsCertType objectSigningCA,critical \
    -d "sql:$NSSDB_DIR" -z noise.bin

List the CA key:

$ certutil -K -d "sql:$NSSDB_DIR" | grep "NSS Certificate DB:software-ca"

List the CA certificate:

$ certutil -L -d "sql:$NSSDB_DIR" | grep "software-ca"

Print the information of the CA certificate:

# Output in PEM encoding
$ certutil -L -d "sql:$NSSDB_DIR" -a -n "software-ca" > ca.crt.pem
$ openssl x509 -in ca.crt.pem -text -noout

# Output in human-readable format directly
$ certutil -L -d "sql:$NSSDB_DIR" -n "software-ca"

Create a client key and its associated Certificate Signing Request (CSR):

$ certutil -R -k rsa -g 2048 -s "CN=Example,O=Example Corp,C=DE" \
    -7 software-client@example.com \
    -d "sql:$NSSDB_DIR" -z noise.bin -a -o client.csr.pem

Print the information of the client CSR:

$ openssl req -in client.csr.pem -text -noout

List the client key:

The key will remain in an "orphan" state until the associated certificate is added.

$ certutil -K -d "sql:$NSSDB_DIR" | grep "orphan"

Convert the CSR from PEM encoding to DER encoding:

$ openssl req -in client.csr.pem -outform DER -out client.csr.der

Use the software CA to issue a certificate from the CSR:

# When the "-m" option is not specified in certutil, the serial number
# is generated based on the current time. Therefore, to ensure the
# uniqueness of the serial number, introduce a delay of 1 second.
$ sleep 1

$ certutil -C -c "software-ca" -i client.csr.der -o client.crt.der \
    -v 12 -w -1 -d "sql:$NSSDB_DIR" \
    --keyUsage digitalSignature,keyEncipherment,critical \
    -7 software-client@example.com

Add the client certificate to the NSS Certificate DB:

$ certutil -A -n "software-client" -t ",," -d "sql:$NSSDB_DIR" -i client.crt.der

Print the information of the client certificate:

# Output in PEM encoding
$ certutil -L -d "sql:$NSSDB_DIR" -a -n "software-client" > client.crt.pem
$ openssl x509 -in client.crt.pem -text -noout

# Output in human-readable format directly
$ certutil -L -d "sql:$NSSDB_DIR" -n "software-client"

List the client certificate chain:

$ certutil -O -d "sql:$NSSDB_DIR" -n "software-client"

List the client certificate:

$ certutil -L -d "sql:$NSSDB_DIR" | grep "software-client"

List the client key:

The key will no longer be in an "orphan" state.

$ certutil -K -d "sql:$NSSDB_DIR" | grep "NSS Certificate DB:software-client"

Create a message:

$ echo "Hello world!" > message.plain

Perform digital signing and verification using the client key:

# Sign
$ cmsutil -S -d "sql:$NSSDB_DIR" -N "software-client" -i message.plain -o message.sig.cms

# Verify
$ cmsutil -D -d "sql:$NSSDB_DIR" -i message.sig.cms

Perform digital signing and verification using the client key:

Use the -T option to suppress content in the CMS message. This means the message will be detached from the signature file. During signature verification, the message must be explicitly provided through the -c detached content option.

# Sign
$ cmsutil -S -d "sql:$NSSDB_DIR" -N "software-client" -T -i message.plain -o message.sig.cms

# Verify
$ cmsutil -D -d "sql:$NSSDB_DIR" -i message.sig.cms -c message.plain

Perform message encryption and decryption using the client key:

# Encrypt
$ cmsutil -E -d "sql:$NSSDB_DIR" -r "software-client" -i message.plain -o message.cipher.cms

# Decrypt
$ cmsutil -D -d "sql:$NSSDB_DIR" -i message.cipher.cms -o message.decipher.cms
$ diff message.plain message.decipher.cms

Delete the client key and its associated certificate:

Optionally, delete only the client certificate while retaining the key by: certutil -D -d "sql:$NSSDB_DIR" -n "software-client"

$ certutil -F -d "sql:$NSSDB_DIR" -n "software-client"

Operations on TPM2-based PKCS #11 Module:

Add the TPM2-based PKCS #11 module to the NSS database:

$ echo -ne "\n" | modutil -add "TPM2-based PKCS #11 Module" \
    -libfile "${HOME}/tpm2-pkcs11/src/.libs/libtpm2_pkcs11.so" \
    -dbdir "sql:$NSSDB_DIR"

Display the list of modules and their associated slots:

$ modutil -list -dbdir "sql:$NSSDB_DIR" | grep "TPM2-based PKCS #11 Module"
$ modutil -list -dbdir "sql:$NSSDB_DIR" | grep "tpm2-token"

Display the details of the module:

$ modutil -list "TPM2-based PKCS #11 Module" -dbdir "sql:$NSSDB_DIR"

Disable and then re-enable the module:

$ echo -ne "\n" | modutil -disable "TPM2-based PKCS #11 Module" -slot "tpm2-token" -dbdir "sql:$NSSDB_DIR"
$ echo -ne "\n" | modutil -enable "TPM2-based PKCS #11 Module" -slot "tpm2-token" -dbdir "sql:$NSSDB_DIR"

Save the user PIN to a file for non-interactive setup:

This is for demonstration purposes only. It is not secure to save the user PIN in a file that can be accessed by anyone.

$ echo "userpin" > userpin.txt

Create a self-signed CA certificate and its associated CA key:

Make it non-interactive by adding echo -ne "y\ny" to respond to the following prompts:

  • Is this a CA certificate [y/N]?
  • Enter the path length constraint, press enter to skip [<0 for unlimited path]:
  • Is this a critical extension [y/N]?

Although the operation is successful, it will report an error in the background because the current version of tpm2-pkcs11 does not support the vendor-defined object class CKO_NSS_TRUST. This error occurs during the creation of object class CKO_NSS_TRUST through C_CreateObject. This error may not be fatal here but may have side effects on subsequent operations. Use at your own risk.

$ echo -ne "y\ny" | certutil -S -h "tpm2-token" -f "userpin.txt" \
    -s "CN=TPM2 CA" -7 tpm2-ca@example.com \
    -n "tpm2-ca" -x -t "C,C,C" -2 \
    --keyUsage certSigning,crlSigning,critical \
    --nsCertType objectSigningCA,critical \
    -d "sql:$NSSDB_DIR" -z noise.bin

Create a TPM2 key and its associated Certificate Signing Request (CSR):

$ certutil -R -k rsa -g 2048 -s "CN=Example2,O=Example2 Corp,C=DE" \
    -d "sql:$NSSDB_DIR" -h "tpm2-token" -f "userpin.txt" \
    -7 tpm2-client@example.com \
    -z noise.bin -a -o tpm2-client.csr.pem

Print the information of the client CSR:

$ openssl req -in tpm2-client.csr.pem -text -noout

List the TPM2 key:

The key will remain in an "orphan" state until the associated certificate is added.

$ certutil -K -d "sql:$NSSDB_DIR" -h "tpm2-token" -f "userpin.txt" | grep "orphan"

Convert the CSR from PEM encoding to DER encoding:

$ openssl req -in tpm2-client.csr.pem -outform DER -out tpm2-client.csr.der

Use the TPM2 CA to issue a certificate from the CSR:

# When the "-m" option is not specified in certutil, the serial number
# is generated based on the current time. Therefore, to ensure the
# uniqueness of the serial number, introduce a delay of 1 second.
$ sleep 1

$ ~/pkcs11-optiga-tpm/scripts/cmdAutoFillPw.sh userpin \
    certutil -C -c "tpm2-token:tpm2-ca" \
    -i tpm2-client.csr.der -o tpm2-client.crt.der \
    -v 12 -w -1 -d "sql:$NSSDB_DIR" \
    --keyUsage digitalSignature,keyEncipherment,critical \
    -7 tpm2-client@example.com

Add the client certificate:

The same non-fatal error related to CKO_NSS_TRUST will be seen here.

Trust flag "u" is set automatically if the private key is present in the token.

$ certutil -A -n "tpm2-client" -t ",," -d "sql:$NSSDB_DIR" \
    -i tpm2-client.crt.der -h "tpm2-token" -f "userpin.txt"

Print the information of the client certificate:

# Output in PEM encoding
$ certutil -L -d "sql:$NSSDB_DIR" -a -n "tpm2-client" > tpm2-client.crt.pem
$ openssl x509 -in tpm2-client.crt.pem -text -noout

# Output in human-readable format directly
$ certutil -L -d "sql:$NSSDB_DIR" -n "tpm2-client"

List the client certificate chain:

$ ~/pkcs11-optiga-tpm/scripts/cmdAutoFillPw.sh userpin certutil -O \
    -d "sql:$NSSDB_DIR" -h "pkcs11:token=tpm2-token" -n "tpm2-token:tpm2-client"

List the client certificate:

$ certutil -L -d "sql:$NSSDB_DIR" -h "pkcs11:token=tpm2-token" -f "userpin.txt" \
    | grep "tpm2-token:tpm2-client"

List the TPM2 key:

The key will no longer be in an "orphan" state.

$ certutil -K -d "sql:$NSSDB_DIR" -h "pkcs11:token=tpm2-token" -f "userpin.txt" \
    | grep "tpm2-token:tpm2-client"

Create a message:

$ echo "Hello world!" > message.txt

Perform digital signing and verification using the client key:

# Sign
$ cmsutil -S -d "sql:$NSSDB_DIR" -N "tpm2-token:tpm2-client" \
    -f "userpin.txt" -i message.plain -o message.sig.cms

# Verify
$ cmsutil -D -d "sql:$NSSDB_DIR" -i message.sig.cms

Perform digital signing and verification using the client key:

Use the -T option to suppress content in the CMS message. This means the message will be detached from the signature file. During signature verification, the message must be explicitly provided through the -c detached content option.

# Sign
$ cmsutil -S -d "sql:$NSSDB_DIR" -N "tpm2-token:tpm2-client" \
    -f "userpin.txt" -T -i message.plain -o message.sig.cms

# Verify
$ cmsutil -D -d "sql:$NSSDB_DIR" -i message.sig.cms -c message.plain

Perform message encryption and decryption using the client key:

Message decryption is not functioning because tpm2-pkcs11 does not support C_UnwrapKey and session objects, and its implementation of C_CreateObject does not support creating objects of the class CKO_SECRET_KEY, which are necessary to store the message decryption AES key during the decryption process.

# Encrypt
$ ~/pkcs11-optiga-tpm/scripts/cmdAutoFillPw.sh userpin cmsutil -E -d "sql:$NSSDB_DIR" \
    -r "tpm2-token:tpm2-client" -i message.plain -o message.cipher.cms

# Decrypt
# Skipped

Delete the client key and its associated certificate:

Optionally, delete only the client certificate while retaining the key by: certutil -D -d "sql:$NSSDB_DIR" -h "tpm2-token" -f "userpin.txt" -n "tpm2-token:tpm2-client"

$ certutil -F -d "sql:$NSSDB_DIR" -h "tpm2-token" -f "userpin.txt" -n "tpm2-token:tpm2-client"

Housekeeping:

$ rm -rf $NSSDB_DIR
$ unset NSSDB_DIR

Housekeeping

Housekeeping (ESYSDB)

Clear the TPM:

$ tpm2_clear -c p

Remove the ESYSDB database:

$ rm -rf $TPM2_PKCS11_STORE
$ unset TPM2_PKCS11_STORE

This is only necessary if the platform hierarchy is utilized:

$ tpm2_evictcontrol -C p -c 0x81800001 || true

Housekeeping (FAPI)

Clear the TPM:

$ tpm2_clear -c p

Remove the FAPI metadata:

$ rm -rf $FAPI_METADATA_DIR
$ unset FAPI_METADATA_DIR

GitHub Actions

This section is intended for maintainers only.

GitHub Actions has been set up to automate the testing of this integration guide as part of the CI/CD process. The testing methodology involves extracting command lines from the markdown and running them in a Docker container. Please refer to script.sh to see the preparation of commands for testing. The process occurs seamlessly in the background, utilizing hidden tags in the README.md (visible in raw mode).

Commands are divided into sections using the markers <!--section:xxx--> and <!--section-end-->. This structure allows for the execution of specific sections multiple times (e.g., housekeeping) and allows for the flexibility of reordering or creating new test sequences. The test sequence construction (e.g., section 1 -> section 2 -> section 3 -> ...) is configurable.

To learn about the CI test sequence, refer to the README.md in raw mode and specifically look for <!--tests:.

For debugging, it is possible to download the executed test scripts from the Artifacts of a GitHub Actions run.


License

This project is licensed under the MIT License - see the LICENSE file for details.

About

OPTIGA™ TPM-Based PKCS #11 Token Setup and User Guide

License:MIT License


Languages

Language:Shell 100.0%