Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,11 @@ if(WOLFSSL_IOTSAFE)
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_IOTSAFE")
endif()

add_option("WOLFSSL_VAULTIC" "Enable WISeKey/SealSQ VaultIC support (default: disabled)" "no" "yes;no")
if(WOLFSSL_VAULTIC)
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_VAULTIC")
endif()
Comment thread
dgarske marked this conversation as resolved.

add_option("WOLFSSL_WOLFSENTRY" "Enable wolfSentry support (default: disabled)" "no" "yes;no")
if(WOLFSSL_WOLFSENTRY)
foreach(_o WOLFSSL_MD5)
Expand Down Expand Up @@ -4583,6 +4588,7 @@ set(HEADER_EXCLUDE
"wolfssl/wolfcrypt/port/cypress"
"wolfssl/wolfcrypt/port/Espressif"
"wolfssl/wolfcrypt/port/iotsafe"
"wolfssl/wolfcrypt/port/sealsq"
"wolfssl/wolfcrypt/port/nxp"
"wolfssl/wolfcrypt/port/pic"
"wolfssl/wolfcrypt/port/Renesas"
Expand Down
20 changes: 20 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -11674,6 +11674,13 @@ AC_ARG_ENABLE([iotsafe-hwrng],
[ ENABLED_IOTSAFE_HWRNG=no ]
)

# WISeKey/SealSQ VaultIC secure element
AC_ARG_ENABLE([vaultic],
[AS_HELP_STRING([--enable-vaultic],[Enable WISeKey/SealSQ VaultIC secure element support (default: disabled)])],
[ ENABLED_VAULTIC=$enableval ],
[ ENABLED_VAULTIC=no ]
)

# Make clean
AC_ARG_ENABLE([makeclean],
[AS_HELP_STRING([--enable-makeclean], [Enables forced "make clean" at the
Expand Down Expand Up @@ -12477,6 +12484,17 @@ then
ENABLED_IOTSAFE_HWRNG=yes
fi

if test "$ENABLED_VAULTIC" != "no"
then
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_VAULTIC"
ENABLED_VAULTIC=yes
# VaultIC port is implemented via PK callbacks
if test "$ENABLED_PKCALLBACKS" = "no"; then
ENABLED_PKCALLBACKS=yes
AM_CFLAGS="$AM_CFLAGS -DHAVE_PK_CALLBACKS"
fi
fi

if test "x$ENABLED_WOLFENGINE" = "xyes"
then
AM_CFLAGS="$AM_CFLAGS -DHAVE_AES_ECB"
Expand Down Expand Up @@ -13004,6 +13022,7 @@ AM_CONDITIONAL([BUILD_CAAM],[test "x$ENABLED_CAAM" != "xno"])
AM_CONDITIONAL([BUILD_QNXCAAM],[test "x$ENABLED_CAAM_QNX" = "xyes"])
AM_CONDITIONAL([BUILD_IOTSAFE],[test "x$ENABLED_IOTSAFE" = "xyes"])
AM_CONDITIONAL([BUILD_IOTSAFE_HWRNG],[test "x$ENABLED_IOTSAFE_HWRNG" = "xyes"])
AM_CONDITIONAL([BUILD_VAULTIC],[test "x$ENABLED_VAULTIC" = "xyes"])
AM_CONDITIONAL([BUILD_SE050],[test "x$ENABLED_SE050" = "xyes"])
AM_CONDITIONAL([BUILD_STSAFE],[test "x$ENABLED_STSAFE" != "xno"])
AM_CONDITIONAL([BUILD_RTL8735B],[test "x$ENABLED_RTL8735B" != "xno"])
Expand Down Expand Up @@ -13601,6 +13620,7 @@ echo " * PK callbacks: $ENABLED_PKCALLBACKS"
echo " * Crypto callbacks: $ENABLED_CRYPTOCB"
echo " * i.MX CAAM: $ENABLED_CAAM"
echo " * IoT-Safe: $ENABLED_IOTSAFE"
echo " * WISeKey/SealSQ VaultIC: $ENABLED_VAULTIC"
echo " * IoT-Safe HWRNG: $ENABLED_IOTSAFE_HWRNG"
echo " * NXP SE050: $ENABLED_SE050"
echo " * STMicro STSAFE: $ENABLED_STSAFE"
Expand Down
5 changes: 5 additions & 0 deletions wolfcrypt/src/include.am
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,11 @@ if BUILD_IOTSAFE
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/iotsafe/iotsafe.c
endif

if BUILD_VAULTIC
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/sealsq/vaultic.c
endif
EXTRA_DIST += wolfcrypt/src/port/sealsq/README.md


if BUILD_CAAM
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/caam/wolfcaam_init.c
Expand Down
174 changes: 174 additions & 0 deletions wolfcrypt/src/port/sealsq/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
# WISeKey / SealSQ VaultIC Port

This port offloads TLS ECC P-256 operations to a WISeKey/SealSQ VaultIC secure
element (for example the VaultIC 408 on the DEVKIT_VIC408) using wolfSSL's
public-key (PK) callbacks. The private key never leaves the chip.

## What it does

`wolfcrypt/src/port/sealsq/vaultic.c` provides:

* `WOLFSSL_VAULTIC_EccSignCb` - ECDSA P-256 sign on the device
* `WOLFSSL_VAULTIC_EccVerifyCb` - ECDSA P-256 verify on the device
* `WOLFSSL_VAULTIC_EccKeyGenCb` - ephemeral P-256 key generation on the device
* `WOLFSSL_VAULTIC_EccSharedSecretCb` - ECDH P-256 shared secret on the device
* `WOLFSSL_VAULTIC_LoadCertificates` - read the device and CA certificates
stored on the chip into a `WOLFSSL_CTX`
* `WOLFSSL_VAULTIC_SetupPkCallbacks` / `WOLFSSL_VAULTIC_SetupPkCallbackCtx` -
register the callbacks on a `WOLFSSL_CTX` / `WOLFSSL`

The key-generation and shared-secret (ECDH) callbacks can be compiled out by
defining `VLT_TLS_NO_ECDH`, matching the vendor library configuration.

## Dependencies

This port is glue only. It requires the external SealSQ **VaultIC-TLS SDK**,
which provides `vaultic_tls.h` and the `vlt_tls_*` P-256 API that talks to the
chip. That SDK is distributed by SealSQ and is not part of wolfSSL.

## Building

Enable the port and point the compiler/linker at the vendor SDK:

```sh
./configure --enable-vaultic \
CFLAGS="-I/path/to/VaultIC-TLS/vaultic_tls-4xx/src" \
LIBS="-lvaultic_tls_408"
make
```

`--enable-vaultic` defines `WOLFSSL_VAULTIC` and enables PK callbacks
(`HAVE_PK_CALLBACKS`) automatically. The port compiles to nothing when
`WOLFSSL_VAULTIC` is not defined.

### Building the port outside libwolfssl

Like other wolfSSL port files, `vaultic.c` is meant to be compiled as part of
libwolfssl (via `--enable-vaultic`), where it inherits the wolfSSL
configuration through `config.h`. If instead you compile `vaultic.c` in a
separate target (for example the SealSQ devkit builds it into its own
`vaultic_wolfssl` library alongside an `add_subdirectory(wolfssl)` CMake
build), two things are required so the file sees the wolfSSL configuration:

* Define `WOLFSSL_USE_OPTIONS_H` when compiling `vaultic.c`, so
`settings.h` pulls in the generated `wolfssl/options.h`. Without it the
wolfSSL headers fall back to defaults (`ecc_key` is incomplete,
`ECC_SECP256R1` is undeclared).
* Enable PK callbacks through the wolfSSL build option
(autotools `--enable-pkcallbacks`, CMake `WOLFSSL_PKCALLBACKS=yes`), not a
bare `-DHAVE_PK_CALLBACKS` compile flag. The generated `options.h` contains
`#undef HAVE_PK_CALLBACKS` for disabled options, which cancels a
command-line define once `options.h` is included.

## Usage

```c
WOLFSSL_CTX* ctx = wolfSSL_CTX_new(wolfTLS_client_method());

/* register the VaultIC ECC PK callbacks */
WOLFSSL_VAULTIC_SetupPkCallbacks(ctx);

/* load the device + CA certificates stored on the chip */
WOLFSSL_VAULTIC_LoadCertificates(ctx);

WOLFSSL* ssl = wolfSSL_new(ctx);
WOLFSSL_VAULTIC_SetupPkCallbackCtx(ssl, NULL);
/* ... proceed with the TLS handshake ... */
```

The VaultIC-TLS SDK must be initialized (`vlt_tls_init()`) before the
handshake and closed (`vlt_tls_close()`) afterwards; see the SealSQ devkit
sample applications.

## Building and provisioning with the SealSQ devkit

The SealSQ VaultIC-TLS devkit (for example `DEVKIT_VIC408_TLS_RPI`) drives the
whole build/provision/run flow with shell scripts. High-level orientation and
the files that matter:

* SDK library: `VaultIC-TLS/vaultic_tls/vaultic_tls-4xx/src` (`vaultic_tls.h`
API, `vaultic_tls_config.h`), on top of the low-level chip library
`vaultic_tls/vaultic_elib_408` (its Raspberry Pi I2C/SPI drivers live under
`src/arch/embedded/raspberry/pi3`, e.g. `vaultic_twi_driver.c`).
* Glue build: `vaultic_tls/vaultic_wolfssl/CMakeLists.txt` compiles this
port's `vaultic.c` and links it against `wolfssl` and `vaultic_tls_408`.
* Config: `demos/config.cfg` selects `PRODUCT` (408), `VAULTIC_COMM`
(`SPI` or `I2C`), and log level.
* Scripts: `demos/wolfssl/tls_client/scripts` - `install.sh` (set up the
CMake build trees), `build.sh` (build the perso apps, the glue, and the
demos), `perso_client_vaultic.sh` (provision the chip), `run_server.sh` and
`run_client_vaultic.sh` (start the plain server, then the VaultIC client).

Steps:

1. Set `demos/config.cfg` (`PRODUCT=408`, `VAULTIC_COMM=I2C` or `SPI`), then
run `install.sh` and `build.sh`. Point the glue at a wolfSSL tree that
contains this port (the devkit's `wolfssl_patch` copy is no longer needed
once the port is upstream). When the glue compiles `vaultic.c` in its own
library, apply the two flags from "Building the port outside libwolfssl"
above.
2. Provision the chip once with `perso_client_vaultic.sh`. It runs the
`perso_tls` app (`vaultic_tls-4xx/apps/perso_tls`) with the device key,
device cert, and root CA cert from `VaultIC-TLS/certificates`
(`deviceKey.der`, `deviceCert.der`, `rootCACert.der`), submitting the
manufacturer password supplied by your SealSQ FAE, then runs
`check_tls_perso` (`vaultic_tls-4xx/apps/check_tls_perso`) to read the
certificates back off the chip and confirm success.
3. Run `run_server.sh` in one shell and `run_client_vaultic.sh` in another to
perform TLS 1.2 and TLS 1.3 handshakes whose ECC operations run on the
VaultIC.

## Raspberry Pi I2C and clock stretching

This section is about the external VaultIC-TLS SDK's I2C transport on a
Raspberry Pi, not about the wolfSSL port itself, but it is the most common
thing that blocks bring-up, so it is documented here. The VaultIC is an I2C
(or SPI) secure element; when it is attached over I2C it stretches the clock
(holds SCL low) while it performs internal operations, and the Raspberry Pi
I2C hardware has long-standing trouble with clock-stretching peripherals.

Symptoms of the problem are `TWI Send/Receive failure` (status `CF0D`/`CF0F`),
`Block Protocol WARNING (comm error)` / `resync request` messages, and finally
`Block Protocol ERROR (too many rsync requests)`. Short exchanges (for example
reading a status) may succeed while longer, multi-block transfers (for example
the certificate writes done during personalization) fail.

### Raspberry Pi 2/3/4 (BCM I2C)

The classic workaround is to lower the I2C bus clock so the timing margins are
wide enough to tolerate the stretching. The VaultIC-TLS SDK's own I2C driver
tries to do this by writing the BCM I2C `DIV` register directly through
`/dev/mem` (which is why it wants to be run with `sudo`), using hardcoded
controller base addresses for the Pi 2/3 (`0x3f804000`) and Pi 4
(`0xfe804000`). A bus clock around 50 kHz is typically reliable.

### Raspberry Pi 5 (RP1 / DesignWare I2C) - use a bit-banged bus

The Pi 5 does not work with the SDK's built-in bitrate control: its I2C
controller lives in the RP1 chip (a Synopsys DesignWare controller behind

Check failure on line 148 in wolfcrypt/src/port/sealsq/README.md

View workflow job for this annotation

GitHub Actions / codespell

Synopsys ==> Synopsis
PCIe) at a different address, so the SDK's `/dev/mem` register poke targets a
controller that is not there and has no effect. Worse, the RP1 DesignWare
controller itself hangs on the VaultIC's clock stretching during longer
transfers, reporting `i2c_designware ...: SDA stuck at low` in `dmesg`.
Lowering `dtparam=i2c_arm_baudrate` (even down to 10 kHz) does not fix this,
because the failure is the controller mishandling the stretch, not a timing
margin.

The reliable fix on the Pi 5 is to drive the same SDA/SCL pins with the
kernel's software (bit-banged) I2C driver, which polls SCL and therefore
honours clock stretching correctly. In `/boot/firmware/config.txt`, disable
the hardware I2C on those pins and add a software bus on GPIO 2 (SDA) and
GPIO 3 (SCL):

```
# dtparam=i2c_arm=on
dtoverlay=i2c-gpio,i2c_gpio_sda=2,i2c_gpio_scl=3,i2c_gpio_delay_us=4
```

After rebooting, find the new bus (its `name` reads `i2c-gpio`, for example
`/dev/i2c-13`) and point the SDK's I2C device path at it (the VaultIC-TLS
elib hardcodes `/dev/i2c-1` in its Raspberry Pi TWI driver). With the
bit-banged bus, personalization and full TLS 1.2 / TLS 1.3 handshakes to the
VaultIC 408 complete with no I2C errors.

Alternatively, wiring the VaultIC over SPI avoids clock stretching entirely.
Loading
Loading