From 558f1d9d64eb2fa332e9ff6c32114dd08adc81fa Mon Sep 17 00:00:00 2001 From: David Garske Date: Wed, 22 Jul 2026 10:38:35 -0700 Subject: [PATCH] Add WISeKey/SealSQ VaultIC secure element port --- CMakeLists.txt | 6 + configure.ac | 20 ++ wolfcrypt/src/include.am | 5 + wolfcrypt/src/port/sealsq/README.md | 174 +++++++++ wolfcrypt/src/port/sealsq/vaultic.c | 445 ++++++++++++++++++++++++ wolfssl/wolfcrypt/include.am | 4 + wolfssl/wolfcrypt/port/sealsq/vaultic.h | 70 ++++ 7 files changed, 724 insertions(+) create mode 100644 wolfcrypt/src/port/sealsq/README.md create mode 100644 wolfcrypt/src/port/sealsq/vaultic.c create mode 100644 wolfssl/wolfcrypt/port/sealsq/vaultic.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 8705b5b022..40c0f2bcff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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() + add_option("WOLFSSL_WOLFSENTRY" "Enable wolfSentry support (default: disabled)" "no" "yes;no") if(WOLFSSL_WOLFSENTRY) foreach(_o WOLFSSL_MD5) @@ -4564,6 +4569,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" diff --git a/configure.ac b/configure.ac index fc422c8faf..c027ad3bfa 100644 --- a/configure.ac +++ b/configure.ac @@ -11801,6 +11801,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 @@ -12604,6 +12611,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" @@ -13140,6 +13158,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"]) @@ -13749,6 +13768,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" diff --git a/wolfcrypt/src/include.am b/wolfcrypt/src/include.am index fdd356e9ae..f0e7ca3c71 100644 --- a/wolfcrypt/src/include.am +++ b/wolfcrypt/src/include.am @@ -237,6 +237,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 diff --git a/wolfcrypt/src/port/sealsq/README.md b/wolfcrypt/src/port/sealsq/README.md new file mode 100644 index 0000000000..e3b9f5452b --- /dev/null +++ b/wolfcrypt/src/port/sealsq/README.md @@ -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 +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. diff --git a/wolfcrypt/src/port/sealsq/vaultic.c b/wolfcrypt/src/port/sealsq/vaultic.c new file mode 100644 index 0000000000..a69a387ffc --- /dev/null +++ b/wolfcrypt/src/port/sealsq/vaultic.c @@ -0,0 +1,445 @@ +/* vaultic.c + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL 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; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSL 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/* WISeKey/SealSQ VaultIC secure element port. Offloads TLS ECC P-256 + * operations (sign / verify / keygen / ECDH shared secret) to the VaultIC via + * wolfSSL's PK callbacks, and loads the device + CA certificates stored on the + * chip into a WOLFSSL_CTX. Requires the external SealSQ VaultIC-TLS SDK + * (vaultic_tls.h and the vlt_tls_* P256 API) on the include/link path. */ + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include + +#ifdef WOLFSSL_VAULTIC + +#ifndef HAVE_PK_CALLBACKS +#error WOLFSSL_VAULTIC requires HAVE_PK_CALLBACKS +#endif + +#include +#include +#include +#include +#include + +#include "vaultic_tls.h" /* vendor VaultIC-TLS SDK (external) */ + +#define P256_BYTE_SZ 32 + +#ifndef VLT_TLS_NO_ECDH +/** + * \brief Key Gen Callback (used by TLS server) + */ +int WOLFSSL_VAULTIC_EccKeyGenCb(WOLFSSL* ssl, ecc_key* key, word32 keySz, + int ecc_curve, void* ctx) +{ + int err; + byte pubKeyX[P256_BYTE_SZ] = {0}; + byte pubKeyY[P256_BYTE_SZ] = {0}; + + (void)ssl; + (void)ctx; + + WOLFSSL_MSG("WOLFSSL_VAULTIC_EccKeyGenCb"); + + /* check requested curve params */ + if (ecc_curve != ECC_SECP256R1) { + WOLFSSL_MSG("ecc_curve != ECC_SECP256R1"); + return NOT_COMPILED_IN; + } + if (keySz != P256_BYTE_SZ) { + WOLFSSL_MSG("keysize != 32. We are supporting ECC P256 case only"); + return NOT_COMPILED_IN; + } + + /* generate new ephemeral key on device */ + if (vlt_tls_keygen_P256(pubKeyX, pubKeyY) != 0) { + WOLFSSL_MSG("vlt_tls_keygen_P256"); + return WC_HW_E; + } + + /* load generated public key into key, used by wolfSSL */ + if ((err = wc_ecc_import_unsigned(key, pubKeyX, pubKeyY, NULL, + ecc_curve)) != 0) { + WOLFSSL_MSG("wc_ecc_import_unsigned"); + } + + return err; +} +#endif + +/** + * \brief Verify Certificate Callback. + * + */ +int WOLFSSL_VAULTIC_EccVerifyCb(WOLFSSL* ssl, + const unsigned char* sig, unsigned int sigSz, + const unsigned char* hash, unsigned int hashSz, + const unsigned char* keyDer, unsigned int keySz, + int* result, void* ctx) +{ + int err; + byte signature[2*P256_BYTE_SZ] = {0}; + byte *r, *s; + word32 r_len = P256_BYTE_SZ, s_len = P256_BYTE_SZ; + byte pubKeyX[P256_BYTE_SZ] = {0}; + byte pubKeyY[P256_BYTE_SZ] = {0}; + word32 pubKeyX_len = sizeof(pubKeyX); + word32 pubKeyY_len = sizeof(pubKeyY); + ecc_key key; + word32 inOutIdx = 0; + + WOLFSSL_MSG("WOLFSSL_VAULTIC_EccVerifyCb"); + + (void)ssl; + (void)ctx; + *result = 0; + + if (keyDer == NULL || sig == NULL || hash == NULL || result == NULL) { + return BAD_FUNC_ARG; + } + + if ((err = wc_ecc_init(&key)) != 0) { + WOLFSSL_MSG("wc_ecc_init"); + return err; + } + + /* Decode the public key */ + if ((err = wc_EccPublicKeyDecode(keyDer, &inOutIdx, &key, keySz)) != 0) { + WOLFSSL_MSG("wc_EccPublicKeyDecode"); + wc_ecc_free(&key); + return err; + } + + /* Extract Raw X and Y coordinates of the public key */ + if ((err = wc_ecc_export_public_raw(&key, pubKeyX, &pubKeyX_len, + pubKeyY, &pubKeyY_len)) != 0) { + WOLFSSL_MSG("wc_ecc_export_public_raw"); + wc_ecc_free(&key); + return err; + } + + /* Left pad public key */ + vlt_tls_left_pad_P256(pubKeyX, pubKeyX_len); + vlt_tls_left_pad_P256(pubKeyY, pubKeyY_len); + + /* Check requested curve */ + if (key.dp->id != ECC_SECP256R1) { + WOLFSSL_MSG("id != ECC_SECP256R1"); + wc_ecc_free(&key); + return NOT_COMPILED_IN; + } + + /* Extract R and S from signature */ + XMEMSET(signature, 0, sizeof(signature)); + r = &signature[0]; + s = &signature[sizeof(signature)/2]; + err = wc_ecc_sig_to_rs(sig, sigSz, r, &r_len, s, &s_len); + wc_ecc_free(&key); + if (err != 0) { + WOLFSSL_MSG("wc_ecc_sig_to_rs"); + return err; + } + + /* Left pad r & s */ + vlt_tls_left_pad_P256(r, r_len); + vlt_tls_left_pad_P256(s, s_len); + + /* Verify signature with VaultIC */ + if (vlt_tls_verify_signature_P256(hash, hashSz, signature, pubKeyX, + pubKeyY) != 0) { + WOLFSSL_MSG("vlt_tls_verify_signature_P256"); + return WC_HW_E; + } + else { + *result = 1; + return 0; + } +} + + +/** + * \brief Sign Certificate Callback. + */ +int WOLFSSL_VAULTIC_EccSignCb(WOLFSSL* ssl, const byte* in, + word32 inSz, byte* out, word32* outSz, + const byte* key, word32 keySz, void* ctx) +{ + int err; + byte sig_R[P256_BYTE_SZ] = {0}; + byte sig_S[P256_BYTE_SZ] = {0}; + + (void)ssl; + (void)ctx; + (void)key; + (void)keySz; + + WOLFSSL_MSG("WOLFSSL_VAULTIC_EccSignCb"); + + /* Sign input message using VaultIC */ + if (vlt_tls_compute_signature_P256(in, inSz, sig_R, sig_S) != 0) { + WOLFSSL_MSG("vlt_tls_compute_signature_P256"); + return WC_HW_E; + } + + /* Convert R and S to signature */ + if ((err = wc_ecc_rs_raw_to_sig(sig_R, P256_BYTE_SZ, sig_S, P256_BYTE_SZ, + out, outSz)) != 0) { + WOLFSSL_MSG("wc_ecc_rs_raw_to_sig"); + return err; + } + + return err; +} + +#ifndef VLT_TLS_NO_ECDH +/** + * \brief Create pre master secret using peer's public key and self private key. + */ +int WOLFSSL_VAULTIC_EccSharedSecretCb(WOLFSSL* ssl, ecc_key* otherPubKey, + unsigned char* pubKeyDer, unsigned int* pubKeySz, + unsigned char* out, unsigned int* outlen, + int side, void* ctx) +{ + int err; + byte otherPubKeyX[P256_BYTE_SZ] = {0}; + byte otherPubKeyY[P256_BYTE_SZ] = {0}; + word32 otherPubKeyX_len = sizeof(otherPubKeyX); + word32 otherPubKeyY_len = sizeof(otherPubKeyY); + byte pubKeyX[P256_BYTE_SZ] = {0}; + byte pubKeyY[P256_BYTE_SZ] = {0}; + ecc_key tmpKey; + + (void)ssl; + (void)ctx; + + WOLFSSL_MSG("WOLFSSL_VAULTIC_EccSharedSecretCb"); + + /* check requested curve */ + if (otherPubKey->dp->id != ECC_SECP256R1) { + WOLFSSL_MSG("id != ECC_SECP256R1"); + return NOT_COMPILED_IN; + } + + /* for client: create and export public key */ + if (side == WOLFSSL_CLIENT_END) { + + /* Export otherPubKey raw X and Y */ + err = wc_ecc_export_public_raw(otherPubKey, + &otherPubKeyX[0], &otherPubKeyX_len, + &otherPubKeyY[0], &otherPubKeyY_len); + if (err != 0) { + WOLFSSL_MSG("wc_ecc_export_public_raw"); + return err; + } + vlt_tls_left_pad_P256(otherPubKeyX, otherPubKeyX_len); + vlt_tls_left_pad_P256(otherPubKeyY, otherPubKeyY_len); + + + /* TLS v1.2 and older we must generate a key here for the client only. + * TLS v1.3 calls key gen early with key share */ + if (wolfSSL_GetVersion(ssl) < WOLFSSL_TLSV1_3) { + + if (vlt_tls_keygen_P256(pubKeyX, pubKeyY) != 0) { + WOLFSSL_MSG("vlt_tls_keygen_P256"); + return WC_HW_E; + } + + /* convert raw unsigned public key to X.963 format for TLS */ + if ((err = wc_ecc_init(&tmpKey)) != 0) { + WOLFSSL_MSG("wc_ecc_init"); + return err; + } + + if ((err = wc_ecc_import_unsigned(&tmpKey, pubKeyX, pubKeyY, + NULL, ECC_SECP256R1)) != 0) { + WOLFSSL_MSG("wc_ecc_import_unsigned"); + wc_ecc_free(&tmpKey); + return err; + } + + if ((err = wc_ecc_export_x963(&tmpKey, pubKeyDer, pubKeySz)) != 0) { + WOLFSSL_MSG("wc_ecc_export_x963"); + wc_ecc_free(&tmpKey); + return err; + } + + wc_ecc_free(&tmpKey); + } + } + + /* for server: import public key */ + else if (side == WOLFSSL_SERVER_END) { + if ((err = wc_ecc_init(&tmpKey)) != 0) { + WOLFSSL_MSG("wc_ecc_init"); + return err; + } + + /* import peer's key and export as raw unsigned for hardware */ + if ((err = wc_ecc_import_x963_ex(pubKeyDer, *pubKeySz, &tmpKey, + ECC_SECP256R1)) != 0) { + WOLFSSL_MSG("wc_ecc_import_x963_ex"); + wc_ecc_free(&tmpKey); + return err; + } + + if ((err = wc_ecc_export_public_raw(&tmpKey, otherPubKeyX, + &otherPubKeyX_len, otherPubKeyY, &otherPubKeyY_len)) != 0) { + WOLFSSL_MSG("wc_ecc_export_public_raw"); + wc_ecc_free(&tmpKey); + return err; + } + vlt_tls_left_pad_P256(otherPubKeyX, otherPubKeyX_len); + vlt_tls_left_pad_P256(otherPubKeyY, otherPubKeyY_len); + + wc_ecc_free(&tmpKey); + } + else { + return BAD_FUNC_ARG; + } + + /* Compute shared secret */ + if (vlt_tls_compute_shared_secret_P256(otherPubKeyX, otherPubKeyY, + out) != 0) { + WOLFSSL_MSG("vlt_tls_compute_shared_secret_P256"); + return WC_HW_E; + } + + *outlen = P256_BYTE_SZ; + + return 0; +} +#endif + +/** + * \brief Read VaultIC Certificates and add them to wolfssl context + */ +int WOLFSSL_VAULTIC_LoadCertificates(WOLFSSL_CTX* ctx) +{ + int ret = -1; + + /* CA certificate */ + unsigned char *ca_cert = NULL; + int sizeof_ca_cert = 0; + + /* Device certificate */ + unsigned char *device_cert = NULL; + int sizeof_device_cert = 0; + + /* Read Device certificate in VaultIC */ + WOLFSSL_MSG("Read Device Certificate in VaultIC"); + + if ((sizeof_device_cert = vlt_tls_get_cert_size(SSL_VIC_DEVICE_CERT)) + == -1) { + WOLFSSL_MSG("No Device Certificate found in VaultIC"); + return -1; + } + + device_cert = (unsigned char*)XMALLOC(sizeof_device_cert, NULL, + DYNAMIC_TYPE_ECC_BUFFER); + if (device_cert == NULL) { + WOLFSSL_MSG("malloc device_cert"); + return MEMORY_E; + } + + if (vlt_tls_read_cert(device_cert, SSL_VIC_DEVICE_CERT) != 0) { + WOLFSSL_MSG("vlt_tls_read_cert Device"); + goto free_cert_buffers; + } + + WOLFSSL_MSG("[Device certificate]"); + WOLFSSL_BUFFER(device_cert, sizeof_device_cert); + + /* Read CA certificate in VaultIC */ + WOLFSSL_MSG("Read CA Certificate in VaultIC"); + if ((sizeof_ca_cert = vlt_tls_get_cert_size(SSL_VIC_CA_CERT)) == -1) { + WOLFSSL_MSG("No CA Certificate found in VaultIC"); + goto free_cert_buffers; + } + + ca_cert = (unsigned char*)XMALLOC(sizeof_ca_cert, NULL, + DYNAMIC_TYPE_ECC_BUFFER); + if (ca_cert == NULL) { + WOLFSSL_MSG("malloc ca_cert"); + goto free_cert_buffers; + } + + if (vlt_tls_read_cert(ca_cert, SSL_VIC_CA_CERT) != 0) { + WOLFSSL_MSG("vlt_tls_read_cert CA"); + goto free_cert_buffers; + } + + WOLFSSL_MSG("[CA certificate]"); + WOLFSSL_BUFFER(ca_cert, sizeof_ca_cert); + + /* Load CA certificate into WOLFSSL_CTX */ + if ((ret = wolfSSL_CTX_load_verify_buffer(ctx, ca_cert, + sizeof_ca_cert, WOLFSSL_FILETYPE_ASN1)) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("failed to load CA certificate"); + goto free_cert_buffers; + } + + /* Load Device certificate into WOLFSSL_CTX */ + if ((ret = wolfSSL_CTX_use_certificate_buffer(ctx, device_cert, + sizeof_device_cert, WOLFSSL_FILETYPE_ASN1)) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("failed to load Device certificate"); + goto free_cert_buffers; + } + + /* VaultIC certificates successfully injected into wolfSSL */ + ret = 0; + +free_cert_buffers: + if (ca_cert != NULL) + XFREE(ca_cert, NULL, DYNAMIC_TYPE_ECC_BUFFER); + if (device_cert != NULL) + XFREE(device_cert, NULL, DYNAMIC_TYPE_ECC_BUFFER); + + return ret; +} + + +int WOLFSSL_VAULTIC_SetupPkCallbacks(WOLFSSL_CTX* ctx) +{ + wolfSSL_CTX_SetEccSignCb(ctx, WOLFSSL_VAULTIC_EccSignCb); + wolfSSL_CTX_SetEccVerifyCb(ctx, WOLFSSL_VAULTIC_EccVerifyCb); +#ifndef VLT_TLS_NO_ECDH + wolfSSL_CTX_SetEccKeyGenCb(ctx, WOLFSSL_VAULTIC_EccKeyGenCb); + wolfSSL_CTX_SetEccSharedSecretCb(ctx, WOLFSSL_VAULTIC_EccSharedSecretCb); +#endif + return 0; +} + +int WOLFSSL_VAULTIC_SetupPkCallbackCtx(WOLFSSL* ssl, void* user_ctx) +{ +#ifndef VLT_TLS_NO_ECDH + wolfSSL_SetEccKeyGenCtx(ssl, user_ctx); + wolfSSL_SetEccSharedSecretCtx(ssl, user_ctx); +#endif + wolfSSL_SetEccSignCtx(ssl, user_ctx); + wolfSSL_SetEccVerifyCtx(ssl, user_ctx); + return 0; +} + +#endif /* WOLFSSL_VAULTIC */ diff --git a/wolfssl/wolfcrypt/include.am b/wolfssl/wolfcrypt/include.am index d10b3cb3dd..6deb44ebc9 100644 --- a/wolfssl/wolfcrypt/include.am +++ b/wolfssl/wolfcrypt/include.am @@ -226,6 +226,10 @@ if BUILD_IOTSAFE nobase_include_HEADERS+= wolfssl/wolfcrypt/port/iotsafe/iotsafe.h endif +if BUILD_VAULTIC +nobase_include_HEADERS+= wolfssl/wolfcrypt/port/sealsq/vaultic.h +endif + if BUILD_PSA nobase_include_HEADERS+= wolfssl/wolfcrypt/port/psa/psa.h endif diff --git a/wolfssl/wolfcrypt/port/sealsq/vaultic.h b/wolfssl/wolfcrypt/port/sealsq/vaultic.h new file mode 100644 index 0000000000..63b670eda1 --- /dev/null +++ b/wolfssl/wolfcrypt/port/sealsq/vaultic.h @@ -0,0 +1,70 @@ +/* vaultic.h + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL 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; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSL 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/* WISeKey/SealSQ VaultIC secure element port (PK callbacks) */ + +#ifndef _WOLFPORT_VAULTIC_H_ +#define _WOLFPORT_VAULTIC_H_ + +#include + +#ifdef WOLFSSL_VAULTIC + +#include +#include + +#ifdef __cplusplus + extern "C" { +#endif + +WOLFSSL_API int WOLFSSL_VAULTIC_EccKeyGenCb(WOLFSSL* ssl, ecc_key* key, + word32 keySz, int ecc_curve, void* ctx); + +WOLFSSL_API int WOLFSSL_VAULTIC_EccVerifyCb(WOLFSSL* ssl, + const unsigned char* sig, unsigned int sigSz, + const unsigned char* hash, unsigned int hashSz, + const unsigned char* keyDer, unsigned int keySz, + int* result, void* ctx); + +WOLFSSL_API int WOLFSSL_VAULTIC_EccSignCb(WOLFSSL* ssl, + const byte* in, word32 inSz, + byte* out, word32* outSz, + const byte* key, word32 keySz, void* ctx); + +WOLFSSL_API int WOLFSSL_VAULTIC_EccSharedSecretCb(WOLFSSL* ssl, + ecc_key* otherKey, + unsigned char* pubKeyDer, unsigned int* pubKeySz, + unsigned char* out, unsigned int* outlen, + int side, void* ctx); + +WOLFSSL_API int WOLFSSL_VAULTIC_LoadCertificates(WOLFSSL_CTX* ctx); + +/* Helper API's for setting up callbacks */ +WOLFSSL_API int WOLFSSL_VAULTIC_SetupPkCallbacks(WOLFSSL_CTX* ctx); +WOLFSSL_API int WOLFSSL_VAULTIC_SetupPkCallbackCtx(WOLFSSL* ssl, void* user_ctx); + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* WOLFSSL_VAULTIC */ + +#endif /* _WOLFPORT_VAULTIC_H_ */