Skip to content

Commit

Permalink
LMS wolfBoot support.
Browse files Browse the repository at this point in the history
  • Loading branch information
philljj authored and danielinux committed Sep 6, 2023
1 parent f966f18 commit e23d450
Show file tree
Hide file tree
Showing 17 changed files with 910 additions and 10 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/test-renode-nrf52.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ jobs:
- name: Renode Tests RSA4096
run: ./tools/renode/docker-test.sh "SIGN=RSA4096"

# LMS TEST
- name: Renode Tests LMS-8-5-5
run: ./tools/renode/docker-test.sh "SIGN=LMS LMS_LEVELS=2 LMS_HEIGHT=5 LMS_WINTERNITZ=8 WOLFBOOT_SMALL_STACK=0 IMAGE_SIGNATURE_SIZE=2644 IMAGE_HEADER_SIZE=5288"

- name: Upload Output Dir
uses: actions/upload-artifact@v2
with:
Expand Down
49 changes: 49 additions & 0 deletions config/examples/sim-lms.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# LMS/HSS signature example, based on sim.config example.
#
# LMS/HSS is a post-quantum, stateful, hash-based signature scheme.
#
# The acceptable parameter values are those in RFC8554:
# levels = {1..8}
# height = {5, 10, 15, 20, 25}
# winternitz = {1, 2, 4, 8}
#
# The number of available signatures is:
# N = 2 ** (levels * height)
#
# LMS/HSS Signature sizes are directly proportional to the levels value,
# and inversely proportional to the Winternitz value. They grow only
# modestly with the height value.
#
# Key generation time is strongly determined by the height of the first
# level tree.
#
# Use the helper script
# tools/lms/lms_siglen
# to calculate your signature length given the chosen levels, height,
# Winternitz values.
#

ARCH=sim
TARGET=sim
SIGN?=LMS
HASH?=SHA256
LMS_LEVELS=2
LMS_HEIGHT=5
LMS_WINTERNITZ=8
WOLFBOOT_SMALL_STACK=0
SPI_FLASH=0
DEBUG=0
DELTA_UPDATES=0
IMAGE_SIGNATURE_SIZE=2644
IMAGE_HEADER_SIZE?=5288

# sizes should be multiple of system page size
WOLFBOOT_PARTITION_SIZE=0x40000
WOLFBOOT_SECTOR_SIZE=0x1000
WOLFBOOT_PARTITION_BOOT_ADDRESS=0x20000
# if on external flash, it should be multiple of system page size
WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x60000
WOLFBOOT_PARTITION_SWAP_ADDRESS=0xA0000

# required for keytools
WOLFBOOT_FIXED_PARTITIONS=1
85 changes: 85 additions & 0 deletions docs/PQ.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Post-Quantum Signatures

wolfBoot is adding support for post-quantum signatures. At present, support
for LMS/HSS signatures has been added.

## LMS/HSS

LMS/HSS is a post-quantum stateful hash-based signature scheme (HBS). It
is known for having small public and private keys, but larger signatures.
The signature size is tunable via the different LMS parameters.

Stateful HBS schemes are based on the security of their underlying hash
functions and Merkle trees, which are not expected to be broken by the advent
of cryptographically relevant quantum computers.

### Building with LMS Support

LMS/HSS support in wolfCrypt requires the hash-sigs library ( https://github.com/cisco/hash-sigs ).
Use the following procedure to prepare hash-sigs for building with wolfBoot:

```
$ cd lib
$ mkdir hash-sigs
$ls
CMakeLists.txt hash-sigs wolfssl wolfTPM
$ cd hash-sigs
$ mkdir lib
$ git clone https://github.com/cisco/hash-sigs.git src
$ cd src
$ git checkout b0631b8891295bf2929e68761205337b7c031726
$ git apply ../../../tools/lms/0001-Patch-to-support-wolfBoot-LMS-build.patch
```

Nothing more is needed, as wolfBoot will automatically produce the required
hash-sigs build artifacts.

Note: the hash-sigs project only builds static libraries:
- hss_verify.a: a single-threaded verify-only static lib.
- hss_lib.a: a single-threaded static lib.
- hss_lib_thread.a: a multi-threaded static lib.

The keytools utility links against `hss_lib.a`, as it needs full
keygen, signing, and verifying functionality. However wolfBoot
links directly with the subset of objects in the `hss_verify.a`
build rule, as it only requires verify functionality.

### Config

A new LMS sim example has been added here:
```
config/examples/sim-lms.config
```

The `LMS_LEVELS`, `LMS_HEIGHT`, and `LMS_WINTERNITZ`, `IMAGE_SIGNATURE_SIZE`,
and (optionally) `IMAGE_HEADER_SIZE` must be set:

```
SIGN?=LMS
...
LMS_LEVELS=2
LMS_HEIGHT=5
LMS_WINTERNITZ=8
...
IMAGE_SIGNATURE_SIZE=2644
IMAGE_HEADER_SIZE?=5288
```

In LMS the signature size is a function of the parameters. Use the added helper
script `tools/lms/lms_siglen.sh` to calculate your signature length given your
LMS parameters:
```
$./tools/lms/lms_siglen.sh
levels: 3
height: 5
winternitz: 8
#
total_len: 3992
```

### More Info

See these links for more info on LMS and wolfSSL/wolfCrypt:
- https://www.wolfssl.com/documentation/manuals/wolfssl/appendix07.html#post-quantum-stateful-hash-based-signatures
- https://github.com/wolfSSL/wolfssl-examples/tree/master/pq/stateful_hash_sig

6 changes: 6 additions & 0 deletions include/loader.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ extern "C" {
extern const unsigned char rsa4096_pub_key[];
extern unsigned int rsa4096_pub_key_len;
# define IMAGE_SIGNATURE_SIZE (512)
#elif defined(WOLFBOOT_SIGN_LMS)
/* Because signature size in LMS is function of
* LMS variables, IMAGE_SIGNATURE_SIZE is set in
* options.mk from the .config file. */
extern const unsigned char lms_pub_key[];
extern unsigned int lms_pub_key_len;
#elif !defined(WOLFBOOT_NO_SIGN)
# error "No public key available for given signing algorithm."
#endif /* Algorithm selection */
Expand Down
6 changes: 6 additions & 0 deletions include/wolfboot/wolfboot.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ extern "C" {
#define AUTH_KEY_ECC384 0x06
#define AUTH_KEY_ECC521 0x07
#define AUTH_KEY_RSA3072 0x08
#define AUTH_KEY_LMS 0x09



Expand All @@ -99,6 +100,7 @@ extern "C" {
#define HDR_IMG_TYPE_AUTH_ECC384 (AUTH_KEY_ECC384 << 8)
#define HDR_IMG_TYPE_AUTH_ECC521 (AUTH_KEY_ECC521 << 8)
#define HDR_IMG_TYPE_AUTH_RSA3072 (AUTH_KEY_RSA3072 << 8)
#define HDR_IMG_TYPE_AUTH_LMS (AUTH_KEY_LMS << 8)

#define HDR_IMG_TYPE_DIFF 0x00D0

Expand All @@ -115,6 +117,7 @@ extern "C" {
#define KEYSTORE_PUBKEY_SIZE_RSA2048 320
#define KEYSTORE_PUBKEY_SIZE_RSA3072 448
#define KEYSTORE_PUBKEY_SIZE_RSA4096 576
#define KEYSTORE_PUBKEY_SIZE_LMS 60

/* Mask for key permissions */
#define KEY_VERIFY_ALL (0xFFFFFFFFU)
Expand Down Expand Up @@ -194,6 +197,9 @@ extern "C" {
#elif defined(WOLFBOOT_SIGN_RSA4096)
# define HDR_IMG_TYPE_AUTH HDR_IMG_TYPE_AUTH_RSA4096
# define KEYSTORE_PUBKEY_SIZE KEYSTORE_PUBKEY_SIZE_RSA4096
#elif defined(WOLFBOOT_SIGN_LMS)
# define HDR_IMG_TYPE_AUTH HDR_IMG_TYPE_AUTH_LMS
# define KEYSTORE_PUBKEY_SIZE KEYSTORE_PUBKEY_SIZE_LMS
#else
# error "No valid authentication mechanism selected. " \
"Please select a valid SIGN= option."
Expand Down
58 changes: 58 additions & 0 deletions options.mk
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,64 @@ ifeq ($(SIGN),RSA4096)
endif
endif

ifeq ($(SIGN),LMS)
# For LMS the signature size is a function of the LMS parameters.
# All five of these parms must be set in the LMS .config file:
# LMS_LEVELS, LMS_HEIGHT, LMS_WINTERNITZ, IMAGE_SIGNATURE_SIZE,
# IMAGE_HEADER_SIZE

ifndef LMS_LEVELS
$(error LMS_LEVELS not set)
endif

ifndef LMS_HEIGHT
$(error LMS_HEIGHT not set)
endif

ifndef LMS_WINTERNITZ
$(error LMS_WINTERNITZ not set)
endif

ifndef IMAGE_SIGNATURE_SIZE
$(error IMAGE_SIGNATURE_SIZE not set)
endif

ifndef IMAGE_HEADER_SIZE
$(error IMAGE_HEADER_SIZE not set)
endif

LMSDIR = lib/hash-sigs
KEYGEN_OPTIONS+=--lms
SIGN_OPTIONS+=--lms
WOLFCRYPT_OBJS+= \
./$(LMSDIR)/src/hss_verify.o \
./$(LMSDIR)/src/hss_verify_inc.o \
./$(LMSDIR)/src/hss_common.o \
./$(LMSDIR)/src/hss_thread_single.o \
./$(LMSDIR)/src/hss_zeroize.o \
./$(LMSDIR)/src/lm_common.o \
./$(LMSDIR)/src/lm_ots_common.o \
./$(LMSDIR)/src/lm_ots_verify.o \
./$(LMSDIR)/src/lm_verify.o \
./$(LMSDIR)/src/endian.o \
./$(LMSDIR)/src/hash.o \
./$(LMSDIR)/src/sha256.o \
./lib/wolfssl/wolfcrypt/src/ext_lms.o \
./lib/wolfssl/wolfcrypt/src/memory.o \
./lib/wolfssl/wolfcrypt/src/wc_port.o \
./lib/wolfssl/wolfcrypt/src/hash.o
CFLAGS+=-D"WOLFBOOT_SIGN_LMS" -D"WOLFSSL_HAVE_LMS" -D"HAVE_LIBLMS" \
-D"LMS_LEVELS=$(LMS_LEVELS)" -D"LMS_HEIGHT=$(LMS_HEIGHT)" \
-D"LMS_WINTERNITZ=$(LMS_WINTERNITZ)" -I$(LMSDIR)/src \
-D"IMAGE_SIGNATURE_SIZE"=$(IMAGE_SIGNATURE_SIZE) \
-D"WOLFSSL_LMS_VERIFY_ONLY"
ifeq ($(WOLFBOOT_SMALL_STACK),1)
$(error WOLFBOOT_SMALL_STACK with LMS not supported)
else
STACK_USAGE=18064
endif
endif


ifeq ($(USE_GCC_HEADLESS),1)
CFLAGS+="-Wstack-usage=$(STACK_USAGE)"
Expand Down
67 changes: 67 additions & 0 deletions src/image.c
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,73 @@ static void wolfBoot_verify_signature(uint8_t key_slot,
#endif /* WOLFBOOT_SIGN_RSA2048 || WOLFBOOT_SIGN_3072 || \
* WOLFBOOT_SIGN_RSA4096 */

#ifdef WOLFBOOT_SIGN_LMS
#include <wolfssl/wolfcrypt/lms.h>
#ifdef HAVE_LIBLMS
#include <wolfssl/wolfcrypt/ext_lms.h>
#endif

static void wolfBoot_verify_signature(uint8_t key_slot,
struct wolfBoot_image *img, uint8_t *sig)
{
int ret = 0;
LmsKey lms;
word32 pub_len = 0;
uint8_t * pubkey = NULL;

wolfBoot_printf("info: LMS wolfBoot_verify_signature\n");

pubkey = keystore_get_buffer(key_slot);
if (pubkey == NULL) {
wolfBoot_printf("error: Lms pubkey not found\n");
return;
}

ret = wc_LmsKey_Init(&lms, NULL, INVALID_DEVID);
if (ret != 0) {
wolfBoot_printf("error: wc_LmsKey_Init returned %d\n", ret);
return;
}

/* Set the LMS parameters. */
ret = wc_LmsKey_SetParameters(&lms, LMS_LEVELS, LMS_HEIGHT,
LMS_WINTERNITZ);
if (ret != 0) {
/* Something is wrong with the pub key or LMS parameters. */
wolfBoot_printf("error: wc_LmsKey_SetParameters(%d, %d, %d)" \
" returned %d\n", LMS_LEVELS, LMS_HEIGHT,
LMS_WINTERNITZ, ret);
return;
}

wolfBoot_printf("info: using LMS parameters: L%d-H%d-W%d\n", LMS_LEVELS,
LMS_HEIGHT, LMS_WINTERNITZ);

/* Set the public key. */
ret = wc_LmsKey_ImportPubRaw(&lms, pubkey, KEYSTORE_PUBKEY_SIZE);
if (ret != 0) {
/* Something is wrong with the pub key or LMS parameters. */
wolfBoot_printf("error: wc_LmsKey_ImportPubRaw" \
" returned %d\n", ret);
return;
}

ret = wc_LmsKey_Verify(&lms, sig, IMAGE_SIGNATURE_SIZE, img->sha_hash,
WOLFBOOT_SHA_DIGEST_SIZE);

if (ret == 0) {
wolfBoot_printf("info: wc_LmsKey_Verify returned OK\n");
wolfBoot_image_confirm_signature_ok(img);
}
else {
wolfBoot_printf("error: wc_LmsKey_Verify returned %d\n", ret);
}

wc_LmsKey_Free(&lms);
}
#endif /* WOLFBOOT_SIGN_LMS */


/**
* @brief Get the specified header type from the external flash image.
*
Expand Down
4 changes: 4 additions & 0 deletions tools/config.mk
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ ifeq ($(ARCH),)
DISABLE_BACKUP?=0
WOLFBOOT_VERSION?=0
V?=0
LMS_LEVELS?=0
LMS_HEIGHT?=0
LMS_WINTERNITZ?=0
NO_MPU?=0
ENCRYPT?=0
ENCRYPT_WITH_CHACHA?=0
Expand Down Expand Up @@ -78,5 +81,6 @@ CONFIG_VARS:= ARCH TARGET SIGN HASH MCUXSDK MCUXPRESSO MCUXPRESSO_CPU MCUXPRESSO
WOLFBOOT_SMALL_STACK DELTA_UPDATES DELTA_BLOCK_SIZE \
WOLFBOOT_HUGE_STACK FORCE_32BIT\
ENCRYPT_WITH_CHACHA ENCRYPT_WITH_AES128 ENCRYPT_WITH_AES256 ARMORED \
LMS_LEVELS LMS_HEIGHT LMS_WINTERNITZ \
ELF

Loading

0 comments on commit e23d450

Please sign in to comment.