XMSS wolfBoot support.

pull/389/head
jordan 2023-11-03 11:10:26 -05:00 committed by Daniele Lacamera
parent 9b12acfed3
commit 79aadb5cc1
14 changed files with 3399 additions and 22 deletions

View File

@ -0,0 +1,26 @@
# XMSS/XMSS^MT/HSS signature example, based on sim.config example.
#
#
ARCH=sim
TARGET=sim
SIGN?=XMSS
HASH?=SHA256
XMSS_PARAMS='XMSS-SHA2_10_256'
WOLFBOOT_SMALL_STACK=0
SPI_FLASH=0
DEBUG=0
DELTA_UPDATES=0
IMAGE_SIGNATURE_SIZE=2500
IMAGE_HEADER_SIZE?=5000
# 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

View File

@ -1,17 +1,27 @@
# Post-Quantum Signatures
wolfBoot is adding support for post-quantum signatures. At present, support
for LMS/HSS signatures has been added.
for LMS/HSS (https://www.rfc-editor.org/rfc/rfc8554.html), and XMSS/XMSS^MT
(https://www.rfc-editor.org/rfc/rfc8391.html) 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.
LMS/HSS and XMSS/XMSS^MT are both post-quantum stateful hash-based signature
(HBS) schemes. They are known for having small public keys, relatively fast
signing and verifying operations, but larger signatures. Their signature sizes
however are tunable via their different parameters, which affords a space-time
tradeoff.
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.
of cryptographically relevant quantum computers. For this reason they have
been recommended by both NIST SP 800-208, and the NSAs CNSA 2.0 suite.
See these links for more info on stateful HBS support 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
## LMS/HSS
### Building with LMS Support
@ -44,7 +54,7 @@ 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
### LMS Config
A new LMS sim example has been added here:
```
@ -69,17 +79,66 @@ 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
$ ./tools/lms/lms_siglen.sh 2 5 8
levels: 2
height: 5
winternitz: 8
signature length: 2644
```
### More Info
## XMSS/XMSS^MT
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
### Building with XMSS Support
XMSS/XMSS^MT support in wolfCrypt requires a patched version of the
xmss-reference library ( https://github.com/XMSS/xmss-reference.git ).
Use the following procedure to prepare xmss-reference for building with
wolfBoot:
```
$ cd lib
$ git clone https://github.com/XMSS/xmss-reference.git xmss
$ ls
CMakeLists.txt wolfPKCS11 wolfTPM wolfssl xmss
$ cd xmss
$ git checkout 171ccbd26f098542a67eb5d2b128281c80bd71a6
$ git apply ../../../tools/xmss/0001-Patch-to-support-wolfSSL-xmss-reference-integration.patch
```
The patch creates an addendum readme, `patch_readme.md`, with further comments.
Nothing more is needed beyond the patch step, as wolfBoot will handle building
the xmss build artifacts it requires.
### XMSS Config
A new XMSS sim example has been added here:
```
config/examples/sim-xmss.config
```
The `XMSS_PARAMS`, `IMAGE_SIGNATURE_SIZE`, and (optionally) `IMAGE_HEADER_SIZE`
must be set:
```
SIGN?=XMSS
...
XMSS_PARAMS='XMSS-SHA2_10_256'
...
IMAGE_SIGNATURE_SIZE=2500
IMAGE_HEADER_SIZE?=5000
```
The `XMSS_PARAMS` may be any SHA256 parameter set string from Tables 10 and 11
from NIST SP 800-208. Use the helper script `tools/xmss/xmss_siglen.sh` to
calculate your signature length given your XMSS/XMSS^MT parameter string, e.g.:
```
$ ./tools/xmss/xmss_siglen.sh XMSS-SHA2_10_256
parameter set: XMSS-SHA2_10_256
signature length: 2500
```
```
$ ./tools/xmss/xmss_siglen.sh XMSSMT-SHA2_20/2_256
parameter set: XMSSMT-SHA2_20/2_256
signature length: 4963
```

View File

@ -67,6 +67,9 @@ extern "C" {
* options.mk from the .config file. */
extern const unsigned char lms_pub_key[];
extern unsigned int lms_pub_key_len;
#elif defined(WOLFBOOT_SIGN_XMSS)
extern const unsigned char xmss_pub_key[];
extern unsigned int xmss_pub_key_len;
#elif !defined(WOLFBOOT_NO_SIGN)
# error "No public key available for given signing algorithm."
#endif /* Algorithm selection */

View File

@ -85,6 +85,7 @@ extern "C" {
#define AUTH_KEY_ECC521 0x07
#define AUTH_KEY_RSA3072 0x08
#define AUTH_KEY_LMS 0x09
#define AUTH_KEY_XMSS 0x10
@ -105,6 +106,7 @@ extern "C" {
#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_AUTH_XMSS (AUTH_KEY_XMSS << 8)
#define HDR_IMG_TYPE_DIFF 0x00D0
@ -122,6 +124,7 @@ extern "C" {
#define KEYSTORE_PUBKEY_SIZE_RSA3072 448
#define KEYSTORE_PUBKEY_SIZE_RSA4096 576
#define KEYSTORE_PUBKEY_SIZE_LMS 60
#define KEYSTORE_PUBKEY_SIZE_XMSS 68
/* Mask for key permissions */
#define KEY_VERIFY_ALL (0xFFFFFFFFU)
@ -222,6 +225,11 @@ extern "C" {
# ifndef WOLFBOOT_UNIVERSAL_KEYSTORE
# define KEYSTORE_PUBKEY_SIZE KEYSTORE_PUBKEY_SIZE_LMS
# endif
#elif defined(WOLFBOOT_SIGN_XMSS)
# define HDR_IMG_TYPE_AUTH HDR_IMG_TYPE_AUTH_XMSS
# ifndef WOLFBOOT_UNIVERSAL_KEYSTORE
# define KEYSTORE_PUBKEY_SIZE KEYSTORE_PUBKEY_SIZE_XMSS
# endif
#else
# error "No valid authentication mechanism selected. " \
"Please select a valid SIGN= option."

View File

@ -381,6 +381,46 @@ ifeq ($(SIGN),LMS)
endif
endif
ifeq ($(SIGN),XMSS)
ifndef XMSS_PARAMS
$(error XMSS_PARAMS 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
XMSSDIR = lib/xmss
KEYGEN_OPTIONS+=--xmss
SIGN_OPTIONS+=--xmss
WOLFCRYPT_OBJS+= \
./$(XMSSDIR)/params.o \
./$(XMSSDIR)/thash.o \
./$(XMSSDIR)/hash_address.o \
./$(XMSSDIR)/wots.o \
./$(XMSSDIR)/xmss.o \
./$(XMSSDIR)/xmss_core_fast.o \
./$(XMSSDIR)/xmss_commons.o \
./$(XMSSDIR)/utils.o \
./lib/wolfssl/wolfcrypt/src/ext_xmss.o \
./lib/wolfssl/wolfcrypt/src/memory.o \
./lib/wolfssl/wolfcrypt/src/wc_port.o \
./lib/wolfssl/wolfcrypt/src/hash.o
CFLAGS+=-D"WOLFBOOT_SIGN_XMSS" -D"WOLFSSL_HAVE_XMSS" -D"HAVE_LIBXMSS" \
-DXMSS_PARAMS=\"$(XMSS_PARAMS)\" -I$(XMSSDIR) \
-D"IMAGE_SIGNATURE_SIZE"=$(IMAGE_SIGNATURE_SIZE) \
-D"WOLFSSL_XMSS_VERIFY_ONLY" -D"XMSS_VERIFY_ONLY"
ifeq ($(WOLFBOOT_SMALL_STACK),1)
$(error WOLFBOOT_SMALL_STACK with XMSS not supported)
else
STACK_USAGE=18064
endif
endif
ifeq ($(RAM_CODE),1)
CFLAGS+= -D"RAM_CODE"
endif

View File

@ -382,6 +382,71 @@ static void wolfBoot_verify_signature(uint8_t key_slot,
}
#endif /* WOLFBOOT_SIGN_LMS */
#ifdef WOLFBOOT_SIGN_XMSS
#include <wolfssl/wolfcrypt/xmss.h>
#ifdef HAVE_LIBXMSS
#include <wolfssl/wolfcrypt/ext_xmss.h>
#endif
static void wolfBoot_verify_signature(uint8_t key_slot,
struct wolfBoot_image *img, uint8_t *sig)
{
int ret = 0;
XmssKey xmss;
word32 pub_len = 0;
uint8_t * pubkey = NULL;
wolfBoot_printf("info: XMSS wolfBoot_verify_signature\n");
pubkey = keystore_get_buffer(key_slot);
if (pubkey == NULL) {
wolfBoot_printf("error: Xmss pubkey not found\n");
return;
}
ret = wc_XmssKey_Init(&xmss, NULL, INVALID_DEVID);
if (ret != 0) {
wolfBoot_printf("error: wc_XmssKey_Init returned %d\n", ret);
return;
}
wolfBoot_printf("info: using XMSS parameters: %s\n", XMSS_PARAMS);
/* Set the XMSS parameters. */
ret = wc_XmssKey_SetParamStr(&xmss, XMSS_PARAMS);
if (ret != 0) {
/* Something is wrong with the pub key or XMSS parameters. */
wolfBoot_printf("error: wc_XmssKey_SetParamStr(%s)" \
" returned %d\n", XMSS_PARAMS, ret);
return;
}
wolfBoot_printf("info: using XMSS parameters: %s\n", XMSS_PARAMS);
/* Set the public key. */
ret = wc_XmssKey_ImportPubRaw(&xmss, pubkey, KEYSTORE_PUBKEY_SIZE);
if (ret != 0) {
/* Something is wrong with the pub key or LMS parameters. */
wolfBoot_printf("error: wc_XmssKey_ImportPubRaw" \
" returned %d\n", ret);
return;
}
ret = wc_XmssKey_Verify(&xmss, sig, IMAGE_SIGNATURE_SIZE, img->sha_hash,
WOLFBOOT_SHA_DIGEST_SIZE);
if (ret == 0) {
wolfBoot_printf("info: wc_XmssKey_Verify returned OK\n");
wolfBoot_image_confirm_signature_ok(img);
}
else {
wolfBoot_printf("error: wc_XmssKey_Verify returned %d\n", ret);
}
wc_XmssKey_Free(&xmss);
}
#endif /* WOLFBOOT_SIGN_XMSS */
#endif /* WOLFBOOT_TPM && WOLFBOOT_TPM_VERIFY */

View File

@ -34,6 +34,7 @@ ifeq ($(ARCH),)
LMS_LEVELS?=0
LMS_HEIGHT?=0
LMS_WINTERNITZ?=0
XMSS_PARAMS?=XMSS-SHA2_10_256
NO_MPU?=0
ENCRYPT?=0
ENCRYPT_WITH_CHACHA?=0
@ -93,4 +94,5 @@ CONFIG_VARS:= ARCH TARGET SIGN HASH MCUXSDK MCUXPRESSO MCUXPRESSO_CPU MCUXPRESSO
ENCRYPT_WITH_CHACHA ENCRYPT_WITH_AES128 ENCRYPT_WITH_AES256 ARMORED \
LMS_LEVELS LMS_HEIGHT LMS_WINTERNITZ \
WOLFBOOT_UNIVERSAL_KEYSTORE \
XMSS_PARAMS \
ELF

View File

@ -25,6 +25,15 @@ ifeq ($(SIGN),LMS)
-D"LMS_WINTERNITZ=$(LMS_WINTERNITZ)"
endif
ifeq ($(SIGN),XMSS)
$(info xmss params: $(XMSS_PARAMS))
XMSSDIR = $(WOLFBOOTDIR)/lib/xmss
CFLAGS +=-DWOLFBOOT_SIGN_XMSS -DWOLFSSL_HAVE_XMSS -DHAVE_LIBXMSS -I$(XMSSDIR) \
-D"IMAGE_SIGNATURE_SIZE"=$(IMAGE_SIGNATURE_SIZE) \
-DXMSS_PARAMS=\"$(XMSS_PARAMS)\"
endif
# option variables
DEBUG_FLAGS = -g -DDEBUG -DDEBUG_SIGNTOOL -DDEBUG_WOLFSSL -DDEBUG_WOLFSSL_VERBOSE
SANITIZE_FLAGS = -fsanitize=address
@ -75,16 +84,33 @@ OBJS_REAL=\
$(WOLFDIR)/wolfcrypt/src/tfm.o \
$(WOLFDIR)/wolfcrypt/src/wc_port.o \
$(WOLFDIR)/wolfcrypt/src/wolfmath.o \
$(WOLFDIR)/wolfcrypt/src/ext_lms.o
$(WOLFDIR)/wolfcrypt/src/ext_lms.o \
$(WOLFDIR)/wolfcrypt/src/ext_xmss.o
OBJS_REAL+=\
$(WOLFBOOTDIR)/src/delta.o
ifeq ($(SIGN),XMSS)
OBJS_REAL+=\
$(XMSSDIR)/params.o \
$(XMSSDIR)/thash.o \
$(XMSSDIR)/hash_address.o \
$(XMSSDIR)/wots.o \
$(XMSSDIR)/xmss.o \
$(XMSSDIR)/xmss_core_fast.o \
$(XMSSDIR)/xmss_commons.o \
$(XMSSDIR)/utils.o
endif
OBJS_VIRT=$(addprefix $(OBJDIR), $(notdir $(OBJS_REAL)))
vpath %.c $(WOLFDIR)/wolfcrypt/src/
vpath %.c $(WOLFBOOTDIR)/src/
vpath %.c ./
ifeq ($(SIGN),XMSS)
vpath %.c $(XMSSDIR)/
endif
.PHONY: clean all
all: $(WOLFBOOTDIR)/include/target.h sign keygen
@ -114,6 +140,9 @@ $(OBJDIR)/%.o: $(WOLFBOOTDIR)/src/%.c
$(OBJDIR)/%.o: $(WOLFDIR)/wolfcrypt/src/%.c
$(Q)$(CC) $(CFLAGS) -c -o $@ $<
$(XMSSDIR)/src/%.o: $(XMSSDIR)/src/%.c
$(Q)$(CC) $(CFLAGS) -c -o $@ $<
# build templates
sign: $(OBJS_VIRT) $(LIBS) sign.o
@echo "Building signing tool"

View File

@ -68,6 +68,13 @@
#endif
#endif
#if defined(WOLFSSL_HAVE_XMSS)
#include <wolfssl/wolfcrypt/xmss.h>
#ifdef HAVE_LIBXMSS
#include <wolfssl/wolfcrypt/ext_xmss.h>
#endif
#endif
#include <wolfssl/wolfcrypt/random.h>
#include <wolfssl/wolfcrypt/error-crypt.h>
#ifdef DEBUG_SIGNTOOL
@ -91,6 +98,7 @@
#define KEYGEN_ECC521 7
#define KEYGEN_RSA3072 8
#define KEYGEN_LMS 9
#define KEYGEN_XMSS 10
/* Globals */
static FILE *fpub, *fpub_image;
@ -236,7 +244,8 @@ const char KType[][17] = {
"AUTH_KEY_ECC384",
"AUTH_KEY_ECC521",
"AUTH_KEY_RSA3072",
"AUTH_KEY_LMS"
"AUTH_KEY_LMS",
"AUTH_KEY_XMSS"
};
const char KSize[][29] = {
@ -249,7 +258,8 @@ const char KSize[][29] = {
"KEYSTORE_PUBKEY_SIZE_ECC384",
"KEYSTORE_PUBKEY_SIZE_ECC521",
"KEYSTORE_PUBKEY_SIZE_RSA3072",
"KEYSTORE_PUBKEY_SIZE_LMS"
"KEYSTORE_PUBKEY_SIZE_LMS",
"KEYSTORE_PUBKEY_SIZE_XMSS"
};
const char KName[][8] = {
@ -262,7 +272,8 @@ const char KName[][8] = {
"ECC384",
"ECC521",
"RSA3072",
"LMS"
"LMS",
"XMSS"
};
#define MAX_PUBKEYS 64
@ -306,6 +317,9 @@ static uint32_t get_pubkey_size(uint32_t keyType)
case KEYGEN_LMS:
size = KEYSTORE_PUBKEY_SIZE_LMS;
break;
case KEYGEN_XMSS:
size = KEYSTORE_PUBKEY_SIZE_XMSS;
break;
default:
size = 0;
}
@ -595,6 +609,97 @@ static void keygen_lms(const char *priv_fname, uint32_t id_mask)
}
#endif /* if defined(WOLFSSL_HAVE_LMS) */
#if defined(WOLFSSL_HAVE_XMSS)
#include "../xmss/xmss_common.h"
static void keygen_xmss(const char *priv_fname, uint32_t id_mask)
{
FILE * fpriv;
XmssKey key;
int ret;
word32 priv_sz = 0;
byte xmss_pub[XMSS_SHA256_PUBLEN];
word32 pub_len = sizeof(xmss_pub);
ret = wc_XmssKey_Init(&key, NULL, INVALID_DEVID);
if (ret != 0) {
fprintf(stderr, "error: wc_XmssKey_Init returned %d\n", ret);
exit(1);
}
ret = wc_XmssKey_SetParamStr(&key, XMSS_PARAMS);
if (ret != 0) {
fprintf(stderr, "error: wc_XmssKey_SetParamStr(%s)" \
" returned %d\n", XMSS_PARAMS, ret);
exit(1);
}
printf("info: using XMSS parameters: %s\n", XMSS_PARAMS);
ret = wc_XmssKey_SetWriteCb(&key, xmss_write_key);
if (ret != 0) {
fprintf(stderr, "error: wc_XmssKey_SetWriteCb returned %d\n", ret);
exit(1);
}
ret = wc_XmssKey_SetReadCb(&key, xmss_read_key);
if (ret != 0) {
fprintf(stderr, "error: wc_XmssKey_SetReadCb returned %d\n", ret);
exit(1);
}
ret = wc_XmssKey_SetContext(&key, (void *) priv_fname);
if (ret != 0) {
fprintf(stderr, "error: wc_XmssKey_SetContext returned %d\n", ret);
exit(1);
}
/* Make the key pair. */
ret = wc_XmssKey_MakeKey(&key, &rng);
if (ret != 0) {
fprintf(stderr, "error: wc_XmssKey_MakeKey returned %d\n", ret);
exit(1);
}
/* Get the XMSS/XMSS^MT secret key length. */
ret = wc_XmssKey_GetPrivLen(&key, &priv_sz);
if (ret != 0 || priv_sz <= 0) {
printf("error: wc_XmssKey_GetPrivLen returned %d\n",
ret);
exit(1);
}
ret = wc_XmssKey_ExportPubRaw(&key, xmss_pub, &pub_len);
if (ret != 0) {
fprintf(stderr, "error: wc_XmssKey_ExportPubRaw returned %d\n", ret);
exit(1);
}
if (pub_len != sizeof(xmss_pub)) {
fprintf(stderr, "error: wc_XmssKey_ExportPubRaw returned pub_len=%d\n" \
", expected %zu\n", pub_len, sizeof(xmss_pub));
exit(1);
}
/* Append the public key to the private keyfile. */
fpriv = fopen(priv_fname, "r+");
if (!fpriv) {
fprintf(stderr, "error: fopen(%s, \"r+\") returned %d\n", priv_fname,
ret);
exit(1);
}
fseek(fpriv, priv_sz, SEEK_SET);
fwrite(xmss_pub, KEYSTORE_PUBKEY_SIZE_XMSS, 1, fpriv);
fclose(fpriv);
keystore_add(KEYGEN_XMSS, xmss_pub, KEYSTORE_PUBKEY_SIZE_XMSS, priv_fname, id_mask);
wc_XmssKey_Free(&key);
}
#endif /* if defined(WOLFSSL_HAVE_XMSS) */
static void key_gen_check(const char *kfilename)
{
FILE *f;
@ -663,6 +768,12 @@ static void key_generate(uint32_t ktype, const char *kfilename, uint32_t id_mask
keygen_lms(kfilename, id_mask);
break;
#endif
#ifdef WOLFSSL_HAVE_XMSS
case KEYGEN_XMSS:
keygen_xmss(kfilename, id_mask);
break;
#endif
} /* end switch */
}
@ -815,6 +926,11 @@ int main(int argc, char** argv)
else if (strcmp(argv[i], "--lms") == 0) {
keytype = KEYGEN_LMS;
}
#endif
#if defined(WOLFSSL_HAVE_XMSS)
else if (strcmp(argv[i], "--xmss") == 0) {
keytype = KEYGEN_XMSS;
}
#endif
else if (strcmp(argv[i], "--force") == 0) {
force = 1;

View File

@ -108,6 +108,13 @@ static inline int fp_truncate(FILE *f, size_t len)
#endif
#endif
#if defined(WOLFSSL_HAVE_XMSS)
#include <wolfssl/wolfcrypt/xmss.h>
#ifdef HAVE_LIBXMSS
#include <wolfssl/wolfcrypt/ext_xmss.h>
#endif
#endif
#ifdef DEBUG_SIGNTOOL
#include <wolfssl/wolfcrypt/logging.h>
#endif
@ -169,6 +176,7 @@ static inline int fp_truncate(FILE *f, size_t len)
#define SIGN_ECC384 HDR_IMG_TYPE_AUTH_ECC384
#define SIGN_ECC521 HDR_IMG_TYPE_AUTH_ECC521
#define SIGN_LMS HDR_IMG_TYPE_AUTH_LMS
#define SIGN_XMSS HDR_IMG_TYPE_AUTH_XMSS
#define ENC_OFF 0
@ -203,6 +211,10 @@ static void header_append_tag(uint8_t* header, uint32_t* idx, uint16_t tag,
#include "../lms/lms_common.h"
#endif
#ifdef WOLFSSL_HAVE_XMSS
#include "../xmss/xmss_common.h"
#endif
/* Globals */
static const char wolfboot_delta_file[] = "/tmp/wolfboot-delta.bin";
@ -222,6 +234,9 @@ static union {
#ifdef WOLFSSL_HAVE_LMS
LmsKey lms;
#endif
#ifdef WOLFSSL_HAVE_XMSS
XmssKey xmss;
#endif
} key;
struct cmd_options {
@ -736,6 +751,57 @@ static uint8_t *load_key(uint8_t **key_buffer, uint32_t *key_buffer_sz,
}
}
#endif /* WOLFSSL_HAVE_LMS */
#ifdef WOLFSSL_HAVE_XMSS
FALL_THROUGH;
case SIGN_XMSS:
ret = -1;
if (CMD.sign == SIGN_AUTO) {
/* XMSS is stateful and requires additional config, and is not
* compatible with SIGN_AUTO. */
printf("error: SIGN_AUTO with XMSS is not supported\n");
}
else {
/* The XMSS file callbacks will handle writing and reading the
* private key. We only need to set the public key here.
*
* If both priv/pub are present:
* - The first ?? bytes is the private key.
* - The next 60 bytes is the public key. */
word32 priv_sz = 0;
int xmss_ret = 0;
xmss_ret = wc_XmssKey_GetPrivLen(&key.xmss, &priv_sz);
if (xmss_ret != 0 || priv_sz <= 0) {
printf("error: wc_XmssKey_GetPrivLen returned %d\n",
xmss_ret);
break;
}
printf("info: xmss sk len: %d\n", priv_sz);
printf("info: xmss pk len: %d\n", KEYSTORE_PUBKEY_SIZE_XMSS);
if (*key_buffer_sz == (priv_sz + KEYSTORE_PUBKEY_SIZE_XMSS)) {
/* priv + pub */
*pubkey = (*key_buffer) + priv_sz;
*pubkey_sz = (*key_buffer_sz) - priv_sz;
ret = 0;
}
else if (*key_buffer_sz == KEYSTORE_PUBKEY_SIZE_XMSS) {
/* pub only. */
*pubkey = (*key_buffer);
*pubkey_sz = KEYSTORE_PUBKEY_SIZE_XMSS;
ret = 0;
}
else {
/* We don't recognize this as an XMSS pub or private key. */
printf("error: unrecognized XMSS key size: %d\n",
*key_buffer_sz );
}
}
#endif /* WOLFSSL_HAVE_XMSS */
break;
} /* end switch (CMD.sign) */
@ -868,6 +934,35 @@ static int sign_digest(int sign, int hash_algo,
}
else
#endif /* WOLFSSL_HAVE_LMS */
#ifdef WOLFSSL_HAVE_XMSS
if (sign == SIGN_XMSS) {
ret = wc_XmssKey_Init(&key.xmss, NULL, INVALID_DEVID);
/* Set the callbacks, so XMSS can update the private key while signing */
if (ret == 0) {
ret = wc_XmssKey_SetWriteCb(&key.xmss, xmss_write_key);
}
if (ret == 0) {
ret = wc_XmssKey_SetReadCb(&key.xmss, xmss_read_key);
}
if (ret == 0) {
ret = wc_XmssKey_SetContext(&key.xmss, (void*)CMD.key_file);
}
if (ret == 0) {
ret = wc_XmssKey_SetParamStr(&key.xmss, XMSS_PARAMS);
}
if (ret == 0) {
ret = wc_XmssKey_Reload(&key.xmss);
}
if (ret == 0) {
ret = wc_XmssKey_Sign(&key.xmss, signature, signature_sz, digest,
digest_sz);
}
if (ret != 0) {
fprintf(stderr, "error signing with XMSS: %d\n", ret);
}
}
else
#endif /* WOLFSSL_HAVE_XMSS */
{
ret = NOT_COMPILED_IN;
}
@ -1769,6 +1864,12 @@ int main(int argc, char** argv)
CMD.sign = SIGN_LMS;
sign_str = "LMS";
}
#endif
#ifdef WOLFSSL_HAVE_XMSS
else if (strcmp(argv[i], "--xmss") == 0) {
CMD.sign = SIGN_XMSS;
sign_str = "XMSS";
}
#endif
else if (strcmp(argv[i], "--sha256") == 0) {
CMD.hash_algo = HASH_SHA256;
@ -1980,6 +2081,39 @@ int main(int argc, char** argv)
CMD.signature_sz = sig_sz;
}
#endif /* WOLFSSL_HAVE_LMS */
#ifdef WOLFSSL_HAVE_XMSS
else if (CMD.sign == SIGN_XMSS) {
int xmss_ret = 0;
word32 sig_sz = 0;
xmss_ret = wc_XmssKey_Init(&key.xmss, NULL, INVALID_DEVID);
if (xmss_ret != 0) {
fprintf(stderr, "error: wc_XmssKey_Init returned %d\n", xmss_ret);
exit(1);
}
xmss_ret = wc_XmssKey_SetParamStr(&key.xmss, XMSS_PARAMS);
if (xmss_ret != 0) {
fprintf(stderr, "error: wc_XmssKey_SetParamStr(%s)" \
" returned %d\n", XMSS_PARAMS, ret);
exit(1);
}
printf("info: using XMSS parameters: %s\n", XMSS_PARAMS);
xmss_ret = wc_XmssKey_GetSigLen(&key.xmss, &sig_sz);
if (xmss_ret != 0) {
fprintf(stderr, "error: wc_XmssKey_GetSigLen returned %d\n",
xmss_ret);
exit(1);
}
printf("info: XMSS signature size: %d\n", sig_sz);
CMD.header_sz = 2 * sig_sz;
CMD.signature_sz = sig_sz;
}
#endif /* WOLFSSL_HAVE_XMSS */
if (((CMD.sign != NO_SIGN) && (CMD.signature_sz == 0)) ||
CMD.header_sz == 0) {

View File

@ -53,6 +53,9 @@ endif
ifeq ($(SIGN),LMS)
SIGN_ARGS+= --lms
endif
ifeq ($(SIGN),XMSS)
SIGN_ARGS+= --xmss
endif
# Make sign hash argument
ifeq ($(HASH),SHA256)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,146 @@
/* xmss_common.h
*
* Common callback functions used by XMSS to write/read the private
* key file.
*
*
* Copyright (C) 2023 wolfSSL Inc.
*
* This file is part of wolfBoot.
*
* wolfBoot 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 2 of the License, or
* (at your option) any later version.
*
* wolfBoot 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
*/
#ifndef XMSS_COMMON_H
#define XMSS_COMMON_H
static enum wc_XmssRc xmss_write_key(const byte * priv, word32 privSz, void * context)
{
FILE * file = NULL;
const char * filename = NULL;
int n_cmp = 0;
size_t n_read = 0;
size_t n_write = 0;
byte * buff = NULL;
int err = 0;
if (priv == NULL || context == NULL || privSz == 0) {
fprintf(stderr, "error: invalid write args\n");
return WC_XMSS_RC_BAD_ARG;
}
filename = context;
/* Open file for read and write. */
file = fopen(filename, "r+");
if (!file) {
/* Create the file if it didn't exist. */
file = fopen(filename, "w+");
if (!file) {
fprintf(stderr, "error: fopen(%s, \"w+\") failed: %d\n", filename,
ferror(file));
return WC_XMSS_RC_WRITE_FAIL;
}
}
n_write = fwrite(priv, 1, privSz, file);
if (n_write != privSz) {
fprintf(stderr, "error: wrote %zu, expected %d: %d\n", n_write, privSz,
ferror(file));
return WC_XMSS_RC_WRITE_FAIL;
}
err = fclose(file);
if (err) {
fprintf(stderr, "error: fclose returned %d\n", err);
return WC_XMSS_RC_WRITE_FAIL;
}
/* Verify private key data has actually been written to persistent
* storage correctly. */
file = fopen(filename, "r+");
if (!file) {
fprintf(stderr, "error: fopen(%s, \"r+\") failed: %d\n", filename,
ferror(file));
return WC_XMSS_RC_WRITE_FAIL;
}
buff = malloc(privSz);
if (buff == NULL) {
fprintf(stderr, "error: malloc(%d) failed\n", privSz);
return WC_XMSS_RC_WRITE_FAIL;
}
XMEMSET(buff, 0, n_write);
n_read = fread(buff, 1, n_write, file);
if (n_read != n_write) {
fprintf(stderr, "error: read %zu, expected %zu: %d\n", n_read, n_write,
ferror(file));
free(buff);
return WC_XMSS_RC_WRITE_FAIL;
}
n_cmp = XMEMCMP(buff, priv, n_write);
free(buff);
buff = NULL;
if (n_cmp != 0) {
fprintf(stderr, "error: write data was corrupted: %d\n", n_cmp);
return WC_XMSS_RC_WRITE_FAIL;
}
err = fclose(file);
if (err) {
fprintf(stderr, "error: fclose returned %d\n", err);
return WC_XMSS_RC_WRITE_FAIL;
}
return WC_XMSS_RC_SAVED_TO_NV_MEMORY;
}
static enum wc_XmssRc xmss_read_key(byte * priv, word32 privSz, void * context)
{
FILE * file = NULL;
const char * filename = NULL;
size_t n_read = 0;
if (priv == NULL || context == NULL || privSz == 0) {
fprintf(stderr, "error: invalid read args\n");
return WC_XMSS_RC_BAD_ARG;
}
filename = context;
file = fopen(filename, "rb");
if (!file) {
fprintf(stderr, "error: fopen(%s, \"rb\") failed\n", filename);
return WC_XMSS_RC_READ_FAIL;
}
n_read = fread(priv, 1, privSz, file);
if (n_read != privSz) {
fprintf(stderr, "error: read %zu, expected %d: %d\n", n_read, privSz,
ferror(file));
return WC_XMSS_RC_READ_FAIL;
}
fclose(file);
return WC_XMSS_RC_READ_TO_MEMORY;
}
#endif /* XMSS_COMMON_H */

View File

@ -0,0 +1,93 @@
#!/bin/bash
#
# Prints the XMSS/XMSS^MT signature length given a parameter set string.
#
# References:
# - https://www.rfc-editor.org/rfc/rfc8391.html
# - https://eprint.iacr.org/2017/349.pdf
print_usage_and_exit() {
echo "usage:"
echo " ./xmss_siglen.sh <parameter string>"
echo ""
echo "examples:"
echo " ./xmss_siglen.sh XMSS-SHA2_10_256"
echo " ./xmss_siglen.sh XMSS-SHA2_16_256"
echo " ./xmss_siglen.sh XMSS-SHA2_20_256"
echo " ./xmss_siglen.sh XMSSMT-SHA2_20/2_256"
echo " ./xmss_siglen.sh XMSSMT-SHA2_20/4_256"
echo " ./xmss_siglen.sh XMSSMT-SHA2_40/2_256"
echo " ./xmss_siglen.sh XMSSMT-SHA2_40/4_256"
echo " ./xmss_siglen.sh XMSSMT-SHA2_40/8_256"
echo " ./xmss_siglen.sh XMSSMT-SHA2_60/3_256"
echo " ./xmss_siglen.sh XMSSMT-SHA2_60/6_256"
echo " ./xmss_siglen.sh XMSSMT-SHA2_60/12_256"
exit 1
}
if [ $# -ne 1 ]; then
print_usage_and_exit
fi
param=$1
len=${#param}
n=32
p=67
h=0
d=1
if [[ "$len" != @("16"|"20"|"21") ]]; then
echo "error: invalid len: $len"
exit 1
fi
if [[ $len == 16 ]]; then
# Must be one of these three:
# - "XMSS-SHA2_10_256"
# - "XMSS-SHA2_16_256"
# - "XMSS-SHA2_20_256"
if [[ $param =~ "XMSS-SHA2_" && $param =~ "_256" ]]; then
h=$(echo $param | cut -c 11-12)
else
echo "error: invalid param string: $param"
exit 1
fi
# In XMSS the signature length is:
# siglen = 4 + n(p + h + 1)
siglen=$((4 + n * (p + h + 1)))
else
# Must be one of these 8:
# - "XMSSMT-SHA2_20/2_256"
# - "XMSSMT-SHA2_20/4_256"
# - "XMSSMT-SHA2_40/2_256"
# - "XMSSMT-SHA2_40/4_256"
# - "XMSSMT-SHA2_40/8_256"
# - "XMSSMT-SHA2_60/3_256"
# - "XMSSMT-SHA2_60/6_256"
# - "XMSSMT-SHA2_60/12_256"
#
if [[ $param =~ "XMSSMT-SHA2_" && $param =~ "_256" ]]; then
h=$(echo $param | cut -c 13-14)
else
echo "error: invalid param string: $param"
exit 1
fi
if [[ $len == 20 ]]; then
d=$(echo $param | cut -c 16-16)
else
d=$(echo $param | cut -c 16-17)
fi
# In XMSS^MT the signature length is:
# siglen = Sum[h]/8 + n (Sum[p] + Sum[h] + 1)
#
# Where Sum[h] means the total height of the hyper-tree.
# Note: The Sum[h]/8 must be rounded up.
siglen=$((((h + 7) / 8) + n * ((d * p) + h + 1)))
fi
echo "parameter set: $param"
echo "signature length: $siglen"