Add XMSS/XMSSMT wolfCrypt hooks.

pull/6840/head
jordan 2023-10-05 09:18:50 -05:00
parent 96205fc80d
commit 33d4b331fb
12 changed files with 2288 additions and 29 deletions

43
INSTALL
View File

@ -371,7 +371,7 @@ We also have vcpkg ports for wolftpm, wolfmqtt and curl.
resulting packages are placed in the root directory of the
project.
18. Building for RHEL, Fedora, CentOS, SUSE, and openSUSE
19. Building for RHEL, Fedora, CentOS, SUSE, and openSUSE
To generate a .rpm package, configure wolfSSL with the desired
configuration. Then run `make rpm` to generate a .rpm package
@ -380,3 +380,44 @@ We also have vcpkg ports for wolftpm, wolfmqtt and curl.
resulting packages are placed in the root directory of the
project.
20. Building with xmss-reference lib for XMSS/XMSS^MT support [EXPERIMENTAL]
Experimental support for XMSS/XMSS^MT has been achieved by integration
with the xmss-reference implementation from RFC 8391 (XMSS: eXtended
Merkle Signature Scheme). We support a patched version of xmss-reference
based on this git commit:
171ccbd26f098542a67eb5d2b128281c80bd71a6
At the time of writing this, this is the HEAD of the master branch of
the xmss-reference project.
How to get the xmss-reference library:
$ mkdir ~/xmss
$ cd ~/xmss
$ git clone https://github.com/XMSS/xmss-reference.git src
$ cd src
$ git checkout 171ccbd26f098542a67eb5d2b128281c80bd71a6
$ git apply <path to xmss reference patch>
The patch may be found in the wolfssl-examples repo here:
pq/stateful_hash_sig/0001-Patch-to-support-xmss-reference-integration.patch
Note that this patch adds wolfCrypt SHA256 hashing to xmss-reference, and
thus benefits from all the same asm speedups as wolfCrypt SHA hashing.
Depending on architecture you may build with --enable-intelasm, or
and --enable-armasm, and see 30-50% speedups in XMSS/XMSS^MT.
For full keygen, signing, verifying, and benchmarking support, build
wolfSSL with:
$ ./configure \
--enable-xmss \
--with-libxmss=<path to xmss src dir>
$ make
Run the benchmark against XMSS/XMSS^MT with:
$ ./wolfcrypt/benchmark/benchmark -xmss_xmssmt
For a leaner xmss verify-only build, build with
$ ./configure \
--enable-xmss=verify-only \
--with-libxmss=<path to xmss src dir>
$ make

View File

@ -1141,6 +1141,79 @@ then
fi
# XMSS
AC_ARG_ENABLE([xmss],
[AS_HELP_STRING([--enable-xmss],[Enable stateful XMSS/XMSS^MT signatures (default: disabled)])],
[ ENABLED_XMSS=$enableval ],
[ ENABLED_XMSS=no ]
)
ENABLED_WC_XMSS=no
for v in `echo $ENABLED_XMSS | tr "," " "`
do
case $v in
yes)
;;
no)
;;
verify-only)
XMSS_VERIFY_ONLY=yes
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_XMSS_VERIFY_ONLY -DXMSS_VERIFY_ONLY"
;;
wolfssl)
ENABLED_WC_XMSS=yes
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_XMSS"
;;
*)
AC_MSG_ERROR([Invalid choice for XMSS []: $ENABLED_XMSS.])
break;;
esac
done
if test "$ENABLED_XMSS" != "no"
then
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_XMSS"
if test "$ENABLED_WC_XMSS" = "no";
then
# Default is to use hash-sigs XMSS lib. Make sure it's enabled.
if test "$ENABLED_LIBXMSS" = "no"; then
AC_MSG_ERROR([The default implementation for XMSS is the xmss-reference lib.
Please use --with-libxmss.])
fi
fi
fi
# libxmss
# Get the path to xmss-reference.
ENABLED_LIBXMSS="no"
trylibxmssdir=""
AC_ARG_WITH([libxmss],
[AS_HELP_STRING([--with-libxmss=PATH],[PATH to xmss-reference root dir. EXPERIMENTAL!])],
[
AC_MSG_CHECKING([for libxmss])
trylibxmssdir=$withval
if test -e $trylibxmssdir; then
libxmss_linked=yes
else
AC_MSG_ERROR([libxmss isn't found.
If it's already installed, specify its path using --with-libxmss=/dir/])
fi
XMSS_ROOT=$trylibxmssdir
AC_MSG_RESULT([yes])
AM_CFLAGS="$AM_CFLAGS -DHAVE_LIBXMSS -I$trylibxmssdir"
ENABLED_LIBXMSS="yes"
AC_SUBST([XMSS_ROOT])
],
[XMSS_ROOT=""]
)
# LMS
AC_ARG_ENABLE([lms],
[AS_HELP_STRING([--enable-lms],[Enable stateful LMS/HSS signatures (default: disabled)])],
@ -8999,6 +9072,7 @@ AM_CONDITIONAL([BUILD_CRL_MONITOR],[test "x$ENABLED_CRL_MONITOR" = "xyes"])
AM_CONDITIONAL([BUILD_USER_RSA],[test "x$ENABLED_USER_RSA" = "xyes"] )
AM_CONDITIONAL([BUILD_USER_CRYPTO],[test "x$ENABLED_USER_CRYPTO" = "xyes"])
AM_CONDITIONAL([BUILD_LIBLMS],[test "x$ENABLED_LIBLMS" = "xyes"])
AM_CONDITIONAL([BUILD_LIBXMSS],[test "x$ENABLED_LIBXMSS" = "xyes"])
AM_CONDITIONAL([BUILD_LIBOQS],[test "x$ENABLED_LIBOQS" = "xyes"])
AM_CONDITIONAL([BUILD_WNR],[test "x$ENABLED_WNR" = "xyes"])
AM_CONDITIONAL([BUILD_SRP],[test "x$ENABLED_SRP" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"])
@ -9431,6 +9505,11 @@ echo " * ED448: $ENABLED_ED448"
echo " * ED448 streaming: $ENABLED_ED448_STREAM"
echo " * LMS: $ENABLED_LMS"
echo " * LMS wolfSSL impl: $ENABLED_WC_LMS"
echo " * XMSS: $ENABLED_XMSS"
echo " * XMSS wolfSSL impl: $ENABLED_WC_XMSS"
if test "$ENABLED_LIBXMSS" = "yes"; then
echo " * XMSS_ROOT: $XMSS_ROOT"
fi
echo " * KYBER: $ENABLED_KYBER"
echo " * KYBER wolfSSL impl: $ENABLED_WC_KYBER"
echo " * ECCSI $ENABLED_ECCSI"
@ -9486,6 +9565,7 @@ echo " * Persistent session cache: $ENABLED_SAVESESSION"
echo " * Persistent cert cache: $ENABLED_SAVECERT"
echo " * Atomic User Record Layer: $ENABLED_ATOMICUSER"
echo " * Public Key Callbacks: $ENABLED_PKCALLBACKS"
echo " * libxmss: $ENABLED_LIBXMSS"
echo " * liblms: $ENABLED_LIBLMS"
echo " * liboqs: $ENABLED_LIBOQS"
echo " * Whitewood netRandom: $ENABLED_WNR"

View File

@ -807,6 +807,18 @@ if BUILD_LIBLMS
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/ext_lms.c
endif
if BUILD_LIBXMSS
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/ext_xmss.c
src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(XMSS_ROOT)/params.c
src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(XMSS_ROOT)/thash.c
src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(XMSS_ROOT)/hash_address.c
src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(XMSS_ROOT)/wots.c
src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(XMSS_ROOT)/xmss.c
src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(XMSS_ROOT)/xmss_core_fast.c
src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(XMSS_ROOT)/xmss_commons.c
src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(XMSS_ROOT)/utils.c
endif
if BUILD_LIBZ
src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/compress.c
endif

View File

@ -150,18 +150,24 @@
#endif
#ifdef WOLFSSL_HAVE_KYBER
#include <wolfssl/wolfcrypt/kyber.h>
#ifdef WOLFSSL_WC_KYBER
#include <wolfssl/wolfcrypt/wc_kyber.h>
#endif
#if defined(HAVE_LIBOQS) || defined(HAVE_PQM4)
#include <wolfssl/wolfcrypt/ext_kyber.h>
#endif
#ifdef WOLFSSL_WC_KYBER
#include <wolfssl/wolfcrypt/wc_kyber.h>
#endif
#if defined(HAVE_LIBOQS) || defined(HAVE_PQM4)
#include <wolfssl/wolfcrypt/ext_kyber.h>
#endif
#endif
#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY)
#include <wolfssl/wolfcrypt/lms.h>
#ifdef HAVE_LIBLMS
#include <wolfssl/wolfcrypt/ext_lms.h>
#ifdef HAVE_LIBLMS
#include <wolfssl/wolfcrypt/ext_lms.h>
#endif
#endif
#if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY)
#include <wolfssl/wolfcrypt/xmss.h>
#ifdef HAVE_LIBXMSS
#include <wolfssl/wolfcrypt/ext_xmss.h>
#endif
#endif
#ifdef WOLFCRYPT_HAVE_ECCSI
#include <wolfssl/wolfcrypt/eccsi.h>
@ -576,6 +582,7 @@
/* Post-Quantum Stateful Hash-Based sig algorithms. */
#define BENCH_LMS_HSS 0x00000001
#define BENCH_XMSS_XMSSMT 0x00000002
/* Other */
#define BENCH_RNG 0x00000001
@ -596,6 +603,11 @@
#endif
#endif
#if (defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY)) || \
(defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY))
#define BENCH_PQ_STATEFUL_HBS
#endif
/* Benchmark all compiled in algorithms.
* When 1, ignore other benchmark algorithm values.
* 0, only benchmark algorithm values set.
@ -870,7 +882,7 @@ static const bench_alg bench_other_opt[] = {
#endif /* !WOLFSSL_BENCHMARK_ALL && !NO_MAIN_DRIVER */
#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY)
#if defined(BENCH_PQ_STATEFUL_HBS)
typedef struct bench_pq_hash_sig_alg {
/* Command line option string. */
const char* str;
@ -880,10 +892,15 @@ typedef struct bench_pq_hash_sig_alg {
static const bench_pq_hash_sig_alg bench_pq_hash_sig_opt[] = {
{ "-pq_hash_sig", 0xffffffff},
#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY)
{ "-lms_hss", BENCH_LMS_HSS},
#endif
#if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY)
{ "-xmss_xmssmt", BENCH_XMSS_XMSSMT},
#endif
{ NULL, 0}
};
#endif /* if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) */
#endif /* BENCH_PQ_STATEFUL_HBS */
#if defined(HAVE_PQC) && defined(HAVE_LIBOQS)
/* The post-quantum-specific mapping of command line option to bit values and
@ -2856,6 +2873,12 @@ static void* benchmarks_do(void* args)
}
#endif /* if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) */
#if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY)
if (bench_all || (bench_pq_hash_sig_algs & BENCH_XMSS_XMSSMT)) {
bench_xmss();
}
#endif /* if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) */
#ifdef HAVE_ECC
if (bench_all || (bench_asym_algs & BENCH_ECC_MAKEKEY) ||
(bench_asym_algs & BENCH_ECC) ||
@ -8075,6 +8098,248 @@ void bench_lms(void)
#endif /* if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) */
#if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY)
static int xmss_write_key_mem(const byte * priv, word32 privSz, void *context)
{
/* WARNING: THIS IS AN INSECURE WRITE CALLBACK THAT SHOULD ONLY
* BE USED FOR TESTING PURPOSES! Production applications should
* write only to non-volatile storage. */
XMEMCPY(context, priv, privSz);
return WC_XMSS_RC_SAVED_TO_NV_MEMORY;
}
static int xmss_read_key_mem(byte * priv, word32 privSz, void *context)
{
/* WARNING: THIS IS AN INSECURE READ CALLBACK THAT SHOULD ONLY
* BE USED FOR TESTING PURPOSES! */
XMEMCPY(priv, context, privSz);
return WC_XMSS_RC_READ_TO_MEMORY;
}
static void bench_xmss_sign_verify(const char * params)
{
WC_RNG rng;
XmssKey key;
word32 pkSz = 0;
word32 skSz = 0;
int freeRng = 0;
int freeKey = 0;
unsigned char * sk = NULL;
const char * msg = "XMSS post quantum signature test";
word32 msgSz = (word32) XSTRLEN(msg);
int ret = 0;
byte * sig = NULL;
word32 sigSz = 0;
int times = 0;
int count = 0;
double start = 0.0F;
#ifndef HAVE_FIPS
ret = wc_InitRng_ex(&rng, HEAP_HINT, INVALID_DEVID);
#else
ret = wc_InitRng(&rng);
#endif
if (ret != 0) {
fprintf(stderr, "error: wc_InitRng failed: %d\n", ret);
goto exit_xmss_sign_verify;
}
freeRng = 1;
ret = wc_XmssKey_Init(&key, NULL, INVALID_DEVID);
if (ret != 0) {
fprintf(stderr, "wc_XmssKey_Init failed: %d\n", ret);
goto exit_xmss_sign_verify;
}
ret = wc_XmssKey_SetParamStr(&key, params);
if (ret != 0) {
fprintf(stderr, "wc_XmssKey_SetParamStr failed: %d\n", ret);
goto exit_xmss_sign_verify;
}
ret = wc_XmssKey_GetPubLen(&key, &pkSz);
if (pkSz != XMSS_SHA256_PUBLEN) {
fprintf(stderr, "error: xmss pub len: got %d, expected %d\n", pkSz,
XMSS_SHA256_PUBLEN);
goto exit_xmss_sign_verify;
}
ret = wc_XmssKey_GetPrivLen(&key, &skSz);
if (ret != 0 || skSz <= 0) {
fprintf(stderr, "error: wc_XmssKey_GetPrivLen failed\n");
goto exit_xmss_sign_verify;
}
ret = wc_XmssKey_GetSigLen(&key, &sigSz);
if (ret != 0 || sigSz <= 0) {
fprintf(stderr, "error: wc_XmssKey_GetSigLen failed\n");
goto exit_xmss_sign_verify;
}
/* Allocate secret keys.*/
sk = XMALLOC(skSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
if (sk == NULL) {
fprintf(stderr, "error: allocate xmss sk failed\n");
goto exit_xmss_sign_verify;
}
/* Allocate signature array. */
sig = XMALLOC(sigSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
if (sig == NULL) {
fprintf(stderr, "error: allocate xmss sig failed\n");
goto exit_xmss_sign_verify;
}
ret = wc_XmssKey_SetWriteCb(&key, xmss_write_key_mem);
if (ret != 0) {
fprintf(stderr, "error: wc_XmssKey_SetWriteCb failed: %d\n", ret);
goto exit_xmss_sign_verify;
}
ret = wc_XmssKey_SetReadCb(&key, xmss_read_key_mem);
if (ret != 0) {
fprintf(stderr, "error: wc_XmssKey_SetReadCb failed: %d\n", ret);
goto exit_xmss_sign_verify;
}
ret = wc_XmssKey_SetContext(&key, (void *) sk);
if (ret != 0) {
fprintf(stderr, "error: wc_XmssKey_SetContext failed: %d\n", ret);
goto exit_xmss_sign_verify;
}
#if defined(DEBUG_WOLFSSL) || defined(WOLFSSL_DEBUG_NONBLOCK)
fprintf(stderr, "params: %s\n", params);
fprintf(stderr, "pkSz: %d\n", pkSz);
fprintf(stderr, "skSz: %d\n", skSz);
fprintf(stderr, "sigSz: %d\n", sigSz);
#endif
/* Making the private key is the bottleneck
* for larger heights. Only print load time in debug builds. */
#if defined(DEBUG_WOLFSSL)
bench_stats_start(&count, &start);
#endif /* if defined DEBUG_WOLFSSL*/
ret = wc_XmssKey_MakeKey(&key, &rng);
if (ret != 0) {
printf("wc_XmssKey_MakeKey failed: %d\n", ret);
goto exit_xmss_sign_verify;
}
count +=1;
#if defined(DEBUG_WOLFSSL)
bench_stats_check(start);
bench_stats_asym_finish(params, (int)skSz, "load", 0,
count, start, ret);
#endif /* if defined DEBUG_WOLFSSL*/
freeKey = 1;
count = 0;
bench_stats_start(&count, &start);
do {
/* XMSS is stateful. Async queuing not practical. */
for (times = 0; times < ntimes; ++times) {
ret = wc_XmssKey_Sign(&key, sig, &sigSz, (byte *) msg, msgSz);
if (ret) {
printf("wc_XmssKey_Sign failed: %d\n", ret);
goto exit_xmss_sign_verify;
}
}
count += times;
} while (bench_stats_check(start));
bench_stats_asym_finish(params, (int)sigSz, "sign", 0,
count, start, ret);
count = 0;
bench_stats_start(&count, &start);
do {
/* XMSS is stateful. Async queuing not practical. */
for (times = 0; times < ntimes; ++times) {
ret = wc_XmssKey_Verify(&key, sig, sigSz, (byte *) msg, msgSz);
if (ret) {
printf("wc_XmssKey_Verify failed: %d\n", ret);
goto exit_xmss_sign_verify;
}
}
count += times;
} while (bench_stats_check(start));
exit_xmss_sign_verify:
bench_stats_asym_finish(params, (int)sigSz, "verify", 0,
count, start, ret);
/* Cleanup everything. */
if (sig != NULL) {
XFREE(sig, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
sig = NULL;
}
if (sk != NULL) {
XFREE(sk, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
sk = NULL;
}
if (freeRng) {
wc_FreeRng(&rng);
freeRng = 0;
}
if (freeKey) {
wc_XmssKey_Free(&key);
freeKey = 0;
}
if (sig != NULL) {
XFREE(sig, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
sig = NULL;
}
return;
}
void bench_xmss(void)
{
/* All NIST SP 800-208 approved SHA256 XMSS/XMSS^MT parameter
* sets.
*
* note: not testing "XMSS-SHA2_16_256", "XMSS-SHA2_20_256",
* and "XMSSMT-SHA2_60/3_256", because their keygen can be
* very slow, their signatures and private keys quite large,
* and xmss private keys are not portable across different
* XMSS/XMSS^MT implementations.
*
* The bottleneck in key generation is the height of the first
* level tree (or h/d).
*
* h is the total height of the hyper tree, and d the number of
* trees.
* */
/* h/d h d */
bench_xmss_sign_verify("XMSS-SHA2_10_256"); /* 10 10 1 */
/* bench_xmss_sign_verify("XMSS-SHA2_16_256"); */ /* 16 16 1 */
/* bench_xmss_sign_verify("XMSS-SHA2_20_256"); */ /* 20 20 1 */
bench_xmss_sign_verify("XMSSMT-SHA2_20/2_256"); /* 10 20 2 */
bench_xmss_sign_verify("XMSSMT-SHA2_20/4_256"); /* 5 20 4 */
bench_xmss_sign_verify("XMSSMT-SHA2_40/4_256"); /* 10 40 4 */
bench_xmss_sign_verify("XMSSMT-SHA2_40/8_256"); /* 5 40 8 */
/* bench_xmss_sign_verify("XMSSMT-SHA2_60/3_256"); */ /* 20 60 3 */
bench_xmss_sign_verify("XMSSMT-SHA2_60/6_256"); /* 10 60 6 */
bench_xmss_sign_verify("XMSSMT-SHA2_60/12_256"); /* 5 60 12 */
return;
}
#endif /* if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) */
#ifdef HAVE_ECC
/* Maximum ECC name plus null terminator:
@ -10410,10 +10675,10 @@ static void Usage(void)
print_alg(bench_pq_asym_opt2[i].str, &line);
#endif /* HAVE_LIBOQS && HAVE_SPHINCS */
#endif /* HAVE_PQC */
#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY)
#if defined(BENCH_PQ_STATEFUL_HBS)
for (i=0; bench_pq_hash_sig_opt[i].str != NULL; i++)
print_alg(bench_pq_hash_sig_opt[i].str, &line);
#endif /* if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) */
#endif /* BENCH_PQ_STATEFUL_HBS */
printf("\n");
#endif /* !WOLFSSL_BENCHMARK_ALL */
e++;
@ -10676,7 +10941,7 @@ int wolfcrypt_benchmark_main(int argc, char** argv)
}
}
#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY)
#if defined(BENCH_PQ_STATEFUL_HBS)
/* post-quantum stateful hash-based signatures */
for (i=0; !optMatched && bench_pq_hash_sig_opt[i].str != NULL; i++) {
if (string_matches(argv[1], bench_pq_hash_sig_opt[i].str)) {
@ -10685,7 +10950,7 @@ int wolfcrypt_benchmark_main(int argc, char** argv)
optMatched = 1;
}
}
#endif
#endif /* BENCH_PQ_STATEFUL_HBS */
#endif
if (!optMatched) {
printf("Option not recognized: %s\n", argv[1]);

View File

@ -102,6 +102,7 @@ void bench_rsa_key(int useDeviceID, word32 keySz);
void bench_dh(int useDeviceID);
void bench_kyber(int type);
void bench_lms(void);
void bench_xmss(void);
void bench_ecc_curve(int curveId);
void bench_eccMakeKey(int useDeviceID, int curveId);
void bench_ecc(int useDeviceID, int curveId);

View File

@ -0,0 +1,894 @@
/* ext_xmss.c
*
* Copyright (C) 2006-2023 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 2 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
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <wolfssl/wolfcrypt/settings.h>
#include <wolfssl/wolfcrypt/error-crypt.h>
#include <wolfssl/wolfcrypt/logging.h>
#ifdef WOLFSSL_HAVE_XMSS
#include <wolfssl/wolfcrypt/ext_xmss.h>
#ifdef NO_INLINE
#include <wolfssl/wolfcrypt/misc.h>
#else
#define WOLFSSL_MISC_INCLUDED
#include <wolfcrypt/src/misc.c>
#endif
/* Init an Xmss key.
*
* Call this before setting the parms of an Xmss key.
*
* key [in] The Xmss key to init.
* heap [in] Unused.
* devId [in] Unused.
*
* returns 0 on success.
* returns BAD_FUNC_ARG when a parameter is NULL.
* */
int wc_XmssKey_Init(XmssKey * key, void * heap, int devId)
{
if (key == NULL) {
return BAD_FUNC_ARG;
}
(void) heap;
(void) devId;
ForceZero(key, sizeof(XmssKey));
#ifndef WOLFSSL_XMSS_VERIFY_ONLY
key->sk = NULL;
key->write_private_key = NULL;
key->read_private_key = NULL;
key->context = NULL;
#endif /* ifndef WOLFSSL_XMSS_VERIFY_ONLY */
key->state = WC_XMSS_STATE_INITED;
return 0;
}
/* Sets the Xmss key parameters, given an oid.
*
* Note: XMSS and XMSS^MT parameter sets do have overlapping
* oids, therefore is_xmssmt is necessary to toggle.
*
* key [in] The Xmss key to set.
* oid [in] The Xmss parameter set oid.
* is_xmssmt [in] 1 The oid is assumed to be XMSS^MT.
* 0 The oid is assumed to be XMSS.
*
* returns 0 on success.
* returns BAD_FUNC_ARG when a parameter is NULL.
* returns -1 on parse failure.
* */
static int wc_XmssKey_SetOid(XmssKey * key, uint32_t oid, int is_xmssmt)
{
int ret = 0;
if (key == NULL || oid == 0) {
return BAD_FUNC_ARG;
}
/* Parse the oid and load the xmss params structure. */
if (is_xmssmt) {
ret = xmssmt_parse_oid(&key->params, oid);
}
else {
ret = xmss_parse_oid(&key->params, oid);
}
if (ret != 0) {
WOLFSSL_MSG("error: xmss parse oid failed");
return -1;
}
/* Finally, sanity check that this is a supported parameter set.
*
* We are only supporting XMSS/XMSS^MT with SHA256 parameter sets
* that NIST SP 800-208 has standardized. See patched xmss-reference
* params.h for the defines. */
if (key->params.func != XMSS_SHA2 ||
key->params.n != XMSS_SHA256_N ||
key->params.padding_len != XMSS_SHA256_PADDING_LEN ||
key->params.wots_w != 16 ||
key->params.wots_len != XMSS_SHA256_WOTS_LEN) {
WOLFSSL_MSG("error: unsupported XMSS/XMSS^MT parameter set");
return -1;
}
key->oid = oid;
key->is_xmssmt = is_xmssmt;
key->state = WC_XMSS_STATE_PARMSET;
return 0;
}
/* Set the Xmss key parameter string.
*
* The input string must be one of the supported parm set names in
* the "Name" section from the table in wolfssl/wolfcrypt/xmss.h,
* e.g. "XMSS-SHA2_10_256" or "XMSSMT-SHA2_20/4_256".
*
* key [in] The Xmss key to set.
* str [in] The XMSS/XMSS^MT parameter string.
*
* returns 0 on success.
* returns BAD_FUNC_ARG when a parameter is NULL.
* returns -1 on failure.
* */
int wc_XmssKey_SetParamStr(XmssKey * key, const char * str)
{
int ret = 0;
uint32_t oid = 0;
int is_xmssmt = 0;
if (key == NULL || str == NULL) {
return BAD_FUNC_ARG;
}
if (key->state != WC_XMSS_STATE_INITED) {
WOLFSSL_MSG("error: xmss key needs init");
return BAD_FUNC_ARG;
}
switch(XSTRLEN(str)) {
case XMSS_NAME_LEN:
is_xmssmt = 0;
break;
case XMSSMT_NAME_MIN_LEN:
case XMSSMT_NAME_MAX_LEN:
is_xmssmt = 1;
break;
default:
WOLFSSL_MSG("error: xmss param str invalid length");
return BAD_FUNC_ARG;
}
/* Convert xmss param string to oid. */
if (is_xmssmt) {
ret = xmssmt_str_to_oid(&oid, str);
}
else {
ret = xmss_str_to_oid(&oid, str);
}
if (ret != 0) {
WOLFSSL_MSG("error: xmssmt_str_to_oid failed");
return -1;
}
return wc_XmssKey_SetOid(key, oid, is_xmssmt);
}
/* Force zeros and frees the Xmss key from memory.
*
* This does not touch the private key saved to non-volatile storage.
*
* This is the only function that frees the key->sk array.
*
* key [in] The Xmss key.
*
* returns void
* */
void wc_XmssKey_Free(XmssKey* key)
{
if (key == NULL) {
return;
}
#ifndef WOLFSSL_XMSS_VERIFY_ONLY
if (key->sk != NULL) {
ForceZero(key->sk, key->sk_len);
XFREE(key->sk, NULL, DYNAMIC_TYPE_TMP_BUFFER);
key->sk = NULL;
}
#endif /* ifndef WOLFSSL_XMSS_VERIFY_ONLY */
ForceZero(key, sizeof(XmssKey));
key->state = WC_XMSS_STATE_FREED;
return;
}
#ifndef WOLFSSL_XMSS_VERIFY_ONLY
/* Sets the Xmss write private key callback.
*
* The callback must be able to write/update the private key to
* non-volatile storage.
*
* key [in] The Xmss key.
* write_cb [in] The write private key callback.
*
* returns 0 on success.
* returns BAD_FUNC_ARG when a parameter is NULL.
* returns -1 on failure.
* */
int wc_XmssKey_SetWriteCb(XmssKey * key, write_private_key_cb write_cb)
{
if (key == NULL || write_cb == NULL) {
return BAD_FUNC_ARG;
}
/* Changing the write callback of an already working key is forbidden. */
if (key->state == WC_XMSS_STATE_OK) {
WOLFSSL_MSG("error: wc_XmssKey_SetWriteCb: key in use");
return -1;
}
key->write_private_key = write_cb;
return 0;
}
/* Sets the Xmss read private key callback.
*
* The callback must be able to read the private key from
* non-volatile storage.
*
* key [in] The Xmss key.
* read_cb [in] The read private key callback.
*
* returns 0 on success.
* returns BAD_FUNC_ARG when a parameter is NULL.
* returns -1 on failure.
* */
int wc_XmssKey_SetReadCb(XmssKey * key, read_private_key_cb read_cb)
{
if (key == NULL || read_cb == NULL) {
return BAD_FUNC_ARG;
}
/* Changing the read callback of an already working key is forbidden. */
if (key->state == WC_XMSS_STATE_OK) {
WOLFSSL_MSG("error: wc_XmssKey_SetReadCb: key in use");
return -1;
}
key->read_private_key = read_cb;
return 0;
}
/* Sets the Xmss context to be used by write and read callbacks.
*
* E.g. this could be a filename if the callbacks write/read to file.
*
* key [in] The Xmss key.
* context [in] The context pointer.
*
* returns 0 on success.
* returns BAD_FUNC_ARG when a parameter is NULL.
* returns -1 on failure.
* */
int wc_XmssKey_SetContext(XmssKey * key, void * context)
{
if (key == NULL || context == NULL) {
return BAD_FUNC_ARG;
}
/* Setting context of an already working key is forbidden. */
if (key->state == WC_XMSS_STATE_OK) {
WOLFSSL_MSG("error: wc_XmssKey_SetContext: key in use");
return -1;
}
key->context = context;
return 0;
}
/* Allocates the Xmss secret key (sk) array.
*
* The XMSS/XMSS^MT secret key length is a function of the
* parameters, and can't be allocated until the param string
* has been set with SetParamStr.
*
* This is only called by MakeKey() and Reload().
*
* Note: the Xmss sk array is force zeroed after every use.
*
* key [in] The Xmss key.
*
* returns 0 on success.
* returns BAD_FUNC_ARG when a parameter is NULL.
* returns -1 on failure.
* */
static int wc_XmssKey_AllocSk(XmssKey* key)
{
int ret = 0;
if (key == NULL) {
return BAD_FUNC_ARG;
}
if (key->sk != NULL) {
WOLFSSL_MSG("error: xmss secret key already exists");
return -1;
}
/* The XMSS/XMSS^MT secret key length is a function of the
* parameters. Therefore can't allocate this until param
* string has been set. */
ret = wc_XmssKey_GetPrivLen(key, &key->sk_len);
if (ret != 0 || key->sk_len <= 0) {
WOLFSSL_MSG("error: wc_XmssKey_GetPrivLen failed");
return -1;
}
key->sk = XMALLOC(key->sk_len, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (key->sk == NULL) {
WOLFSSL_MSG("error: malloc Xmss key->sk failed");
return -1;
}
ForceZero(key->sk, key->sk_len);
return 0;
}
/* Make the XMSS/XMSS^MT private/public key pair. The key must have its parameters
* set before calling this.
*
* Write/read callbacks, and context data, must be set prior.
* Key must have parameters set.
*
* This function and Reload() are the only functions that allocate
* key->sk array. wc_XmssKey_FreeKey is the only function that
* deallocates key->sk.
*
* key [in] The Xmss key to make.
* rng [in] Initialized WC_RNG pointer.
*
* returns 0 on success.
* returns BAD_FUNC_ARG when a parameter is NULL.
* returns -1 on verify fail.
* */
int wc_XmssKey_MakeKey(XmssKey* key, WC_RNG * rng)
{
int ret = 0;
enum wc_XmssRc cb_rc = WC_XMSS_RC_NONE;
if (key == NULL || rng == NULL) {
return BAD_FUNC_ARG;
}
if (key->state != WC_XMSS_STATE_PARMSET) {
WOLFSSL_MSG("error: XmssKey not ready for generation");
return -1;
}
if (key->write_private_key == NULL || key->read_private_key == NULL) {
WOLFSSL_MSG("error: XmssKey write/read callbacks are not set");
return -1;
}
if (key->context == NULL) {
WOLFSSL_MSG("error: XmssKey context is not set");
return -1;
}
/* Allocate sk array. */
ret = wc_XmssKey_AllocSk(key);
if (ret != 0) {
return ret;
}
/* Finally make the secret public key pair. Immediately write it to NV
* storage and then clear from memory. */
if (key->is_xmssmt) {
ret = xmssmt_keypair(key->pk, key->sk, key->oid, rng);
}
else {
ret = xmss_keypair(key->pk, key->sk, key->oid, rng);
}
if (ret == 0) {
cb_rc = key->write_private_key(key->sk, key->sk_len, key->context);
}
ForceZero(key->sk, key->sk_len);
if (ret != 0) {
WOLFSSL_MSG("error: xmss keypair failed");
key->state = WC_XMSS_STATE_BAD;
return -1;
}
if (cb_rc != WC_XMSS_RC_SAVED_TO_NV_MEMORY) {
WOLFSSL_MSG("error: xmss write to NV storage failed");
key->state = WC_XMSS_STATE_BAD;
return -1;
}
key->state = WC_XMSS_STATE_OK;
return 0;
}
/* This function allocates the secret key buffer, and does a
* quick sanity check to verify the secret key is readable
* from NV storage, and then force zeros the key from memory.
*
* On success it sets the key state to OK.
*
* Use this function to resume signing with an already existing
* xmss key pair.
*
* Write/read callbacks, and context data, must be set prior.
* Key must have parameters set.
*
* Returns 0 on success.
*
* This function and MakeKey are the only functions that allocate
* key->sk array. wc_XmssKey_FreeKey is the only function that
* deallocates key->sk.
*
* key [in] Xmss key to load.
*
* returns 0 on success.
* returns BAD_FUNC_ARG when a parameter is NULL.
* returns -1 on load fail.
* */
int wc_XmssKey_Reload(XmssKey * key)
{
int ret = 0;
enum wc_XmssRc cb_rc = WC_XMSS_RC_NONE;
if (key == NULL) {
return BAD_FUNC_ARG;
}
if (key->state != WC_XMSS_STATE_PARMSET) {
WOLFSSL_MSG("error: XmssKey not ready for reload");
return -1;
}
if (key->write_private_key == NULL || key->read_private_key == NULL) {
WOLFSSL_MSG("error: XmssKey write/read callbacks are not set");
return -1;
}
if (key->context == NULL) {
WOLFSSL_MSG("error: XmssKey context is not set");
return -1;
}
/* Allocate sk array. */
ret = wc_XmssKey_AllocSk(key);
if (ret != 0) {
return ret;
}
/* Read the current secret key from NV storage. Force clear it
* immediately. This is just to sanity check the secret key
* is readable from permanent storage. */
cb_rc = key->read_private_key(key->sk, key->sk_len, key->context);
ForceZero(key->sk, key->sk_len);
if (cb_rc != WC_XMSS_RC_READ_TO_MEMORY) {
WOLFSSL_MSG("error: xmss read from NV storage failed");
key->state = WC_XMSS_STATE_BAD;
return -1;
}
key->state = WC_XMSS_STATE_OK;
return 0;
}
/* Gets the XMSS/XMSS^MT private key length.
*
* Parameters must be set before calling this, as the key size (sk_bytes)
* is a function of the parameters.
*
* Note: the XMSS/XMSS^MT private key format is implementation specific,
* and not standardized. Interoperability of Xmss private keys should
* not be expected.
*
* key [in] The Xmss key.
* len [out] The length of the private key in bytes.
*
* returns 0 on success.
* returns BAD_FUNC_ARG when a parameter is NULL.
* returns -1 on sign fail.
* */
int wc_XmssKey_GetPrivLen(const XmssKey * key, word32 * len)
{
if (key == NULL || len == NULL) {
return BAD_FUNC_ARG;
}
if (key->state != WC_XMSS_STATE_OK && key->state != WC_XMSS_STATE_PARMSET) {
/* params.sk_bytes not set yet. */
return -1;
}
*len = XMSS_OID_LEN + (word32) key->params.sk_bytes;
return 0;
}
/* Signs the message using the Xmss secret key, and
* updates the secret key on NV storage.
*
* Both operations must succeed to be considered
* successful.
*
* On success: sets key state to WC_XMSS_STATE_OK.
* On failure: sets key state to WC_XMSS_STATE_BAD
*
* If no signatures are left, sets state to WC_XMSS_STATE_NOSIGS.
*/
static void wc_XmssKey_SignUpdate(XmssKey* key, byte * sig, word32 * sigLen,
const byte * msg, int msgLen)
{
int ret = -1;
unsigned long long len = *sigLen;
enum wc_XmssRc cb_rc = WC_XMSS_RC_NONE;
/* Set the key state to bad by default. State is presumed bad
* unless a correct sign and update operation happen together. */
key->state = WC_XMSS_STATE_BAD;
*sigLen = 0;
/* Read the current secret key from NV storage.*/
cb_rc = key->read_private_key(key->sk, key->sk_len, key->context);
if (cb_rc == WC_XMSS_RC_READ_TO_MEMORY) {
/* Read was good. Now sign and update the secret key in memory. */
if (key->is_xmssmt) {
ret = xmssmt_sign(key->sk, sig, &len, msg, msgLen);
}
else {
ret = xmss_sign(key->sk, sig, &len, msg, msgLen);
}
if (ret == 0 && len == key->params.sig_bytes) {
/* The signature succeeded. key->sk is now updated and must be
* committed to NV storage. */
cb_rc = key->write_private_key(key->sk, key->sk_len, key->context);
if (cb_rc == WC_XMSS_RC_SAVED_TO_NV_MEMORY) {
/* key->sk was successfully committed to NV storage. Set the
* key state to OK, and set the sigLen. */
key->state = WC_XMSS_STATE_OK;
*sigLen = (word32) len;
}
else {
/* Write to NV storage failed. Erase the signature from
* memory. */
ForceZero(sig, key->params.sig_bytes);
WOLFSSL_MSG("error: xmss write_private_key failed");
}
}
else if (ret == -2) {
/* Signature space exhausted. */
key->state = WC_XMSS_STATE_NOSIGS;
WOLFSSL_MSG("error: no xmss signatures remaining");
}
else {
/* Something failed or inconsistent in signature. Erase the
* signature just to be safe. */
ForceZero(sig, key->params.sig_bytes);
WOLFSSL_MSG("error: xmss sign failed");
}
}
else {
/* Read from NV storage failed. */
WOLFSSL_MSG("error: xmss read_private_key failed");
}
/* Force zero the secret key from memory always. */
ForceZero(key->sk, key->sk_len);
return;
}
/* Sign the message using the Xmss secret key.
*
* key [in] Xmss key to use to sign.
* sig [in] Buffer to write signature into.
* sigLen [in/out] On in, size of buffer.
* On out, the length of the signature in bytes.
* msg [in] Message to sign.
* msgLen [in] Length of the message in bytes.
*
* returns 0 on success.
* returns -1 on sign fail.
* returns BAD_FUNC_ARG when a parameter is NULL.
* returns BUFFER_E when sigLen is too small.
*/
int wc_XmssKey_Sign(XmssKey* key, byte * sig, word32 * sigLen, const byte * msg,
int msgLen)
{
if (key == NULL || sig == NULL || sigLen == NULL || msg == NULL) {
return BAD_FUNC_ARG;
}
if (msgLen <= 0) {
return BAD_FUNC_ARG;
}
if (*sigLen < key->params.sig_bytes) {
/* Signature buffer too small. */
WOLFSSL_MSG("error: xmss sig buffer too small");
return BUFFER_E;
}
if (key->state == WC_XMSS_STATE_NOSIGS) {
WOLFSSL_MSG("error: xmss signatures exhausted");
return -1;
}
else if (key->state != WC_XMSS_STATE_OK) {
/* The key had an error the last time it was used, and we
* can't guarantee its state. */
WOLFSSL_MSG("error: can't sign, xmss key not in good state");
return -1;
}
/* Finally, sign and update the secret key. */
wc_XmssKey_SignUpdate(key, sig, sigLen, msg, msgLen);
return (key->state == WC_XMSS_STATE_OK) ? 0 : -1;
}
#endif /* ifndef WOLFSSL_XMSS_VERIFY_ONLY*/
/* Get the XMSS/XMSS^MT public key length. The public key
* is static in size and does not depend on parameters,
* other than the choice of SHA256 as hashing function.
*
* key [in] The Xmss key.
* len [out] The length of the public key.
*
* returns 0 on success.
* returns BAD_FUNC_ARG when a parameter is NULL.
*/
int wc_XmssKey_GetPubLen(const XmssKey * key, word32 * len)
{
if (key == NULL || len == NULL) {
return BAD_FUNC_ARG;
}
*len = XMSS_SHA256_PUBLEN;
return 0;
}
/* Export a generated public key and parameter set from one XmssKey
* to another. Use this to prepare a signature verification XmssKey
* that is pub only.
*
* keyDst [out] Destination key for copy.
* keySrc [in] Source key for copy.
*
* returns 0 on success.
* returns BAD_FUNC_ARG when a parameter is NULL.
* */
int wc_XmssKey_ExportPub(XmssKey * keyDst, const XmssKey * keySrc)
{
if (keyDst == NULL || keySrc == NULL) {
return BAD_FUNC_ARG;
}
ForceZero(keyDst, sizeof(XmssKey));
XMEMCPY(keyDst->pk, keySrc->pk, sizeof(keySrc->pk));
keyDst->oid = keySrc->oid;
keyDst->is_xmssmt = keySrc->is_xmssmt;
/* Mark keyDst as verify only, to prevent misuse. */
keyDst->state = WC_XMSS_STATE_VERIFYONLY;
return 0;
}
/* Exports the raw XMSS public key buffer from key to out buffer.
* The out buffer should be large enough to hold the public key, and
* outLen should indicate the size of the buffer.
*
* key [in] Xmss key.
* out [out] Array holding public key.
* outLen [in/out] On in, size of buffer.
* On out, the length of the public key.
*
* returns 0 on success.
* returns -1 on failure.
* returns BAD_FUNC_ARG when a parameter is NULL.
* returns BUFFER_E if array is too small.
* */
int wc_XmssKey_ExportPubRaw(const XmssKey * key, byte * out, word32 * outLen)
{
int ret = 0;
word32 pubLen = 0;
if (key == NULL || out == NULL || outLen == NULL) {
return BAD_FUNC_ARG;
}
ret = wc_XmssKey_GetPubLen(key, &pubLen);
if (ret != 0) {
WOLFSSL_MSG("error: wc_XmssKey_GetPubLen failed");
return -1;
}
if (*outLen < pubLen) {
return BUFFER_E;
}
XMEMCPY(out, key->pk, pubLen);
*outLen = pubLen;
return 0;
}
/* Imports a raw public key buffer from in array to XmssKey key.
*
* The XMSS parameters must be set first with wc_XmssKey_SetParamStr,
* and inLen must match the length returned by wc_XmssKey_GetPubLen.
*
* key [in] Xmss key.
* in [in] Array holding public key.
* inLen [in] Length of array in bytes.
*
* returns 0 on success.
* returns BAD_FUNC_ARG when a parameter is NULL.
* returns BUFFER_E if array is incorrect size.
* returns -1 on failure.
* */
int wc_XmssKey_ImportPubRaw(XmssKey * key, const byte * in, word32 inLen)
{
int ret = 0;
word32 pubLen = 0;
if (key == NULL || in == NULL) {
return BAD_FUNC_ARG;
}
if (key->state != WC_XMSS_STATE_PARMSET) {
/* Xmss key not ready for import. Param str must be set first. */
WOLFSSL_MSG("error: xmss key not ready for import");
return -1;
}
ret = wc_XmssKey_GetPubLen(key, &pubLen);
if (ret != 0) {
WOLFSSL_MSG("error: wc_XmssKey_GetPubLen failed");
return -1;
}
if (inLen != pubLen) {
/* Something inconsistent. Parameters weren't set, or input
* pub key is wrong.*/
return BUFFER_E;
}
XMEMCPY(key->pk, in, pubLen);
key->state = WC_XMSS_STATE_VERIFYONLY;
return 0;
}
/* Gets the XMSS/XMSS^MT signature length.
*
* Parameters must be set before calling this, as the signature size
* is a function of the parameters.
*
* Note: call this before wc_XmssKey_Sign or Verify so you know the
* length of the required signature buffer.
*
* key [in] Xmss key to use to sign.
* len [out] The length of the signature in bytes.
*
* returns 0 on success.
* returns BAD_FUNC_ARG when a parameter is NULL.
* returns -1 on sign fail.
* */
int wc_XmssKey_GetSigLen(const XmssKey * key, word32 * len)
{
if (key == NULL || len == NULL) {
return BAD_FUNC_ARG;
}
if (key->state != WC_XMSS_STATE_OK && key->state != WC_XMSS_STATE_PARMSET) {
return -1;
}
*len = key->params.sig_bytes;
return 0;
}
/* Verify the signature using the Xmss public key.
*
* Requires that Xmss parameters have been set with
* wc_XmssKey_SetParamStr, and that a public key is available
* from importing or MakeKey().
*
* Call wc_XmssKey_GetSigLen() before this function to determine
* length of the signature buffer.
*
* key [in] Xmss key to use to verify.
* sig [in] Signature to verify.
* sigLen [in] Size of signature in bytes.
* msg [in] Message to verify.
* msgLen [in] Length of the message in bytes.
*
* returns 0 on success.
* returns -1 on verify fail.
* returns BAD_FUNC_ARG when a parameter is NULL.
* returns BUFFER_E when sigLen is too small.
*/
int wc_XmssKey_Verify(XmssKey * key, const byte * sig, word32 sigLen,
const byte * msg, int msgLen)
{
int ret = 0;
unsigned long long msg_len = 0;
msg_len = msgLen;
if (key == NULL || sig == NULL || msg == NULL) {
return BAD_FUNC_ARG;
}
if (sigLen < key->params.sig_bytes) {
/* Signature buffer too small. */
return BUFFER_E;
}
if (key->state != WC_XMSS_STATE_OK &&
key->state != WC_XMSS_STATE_VERIFYONLY) {
/* Xmss key not ready for verification. Param str must be
* set first, and Reload() called. */
WOLFSSL_MSG("error: xmss key not ready for verification");
return -1;
}
if (key->is_xmssmt) {
ret = xmssmt_sign_open(msg, &msg_len, sig, sigLen, key->pk);
}
else {
ret = xmss_sign_open(msg, &msg_len, sig, sigLen, key->pk);
}
if (ret != 0 || (int) msg_len != msgLen) {
WOLFSSL_MSG("error: xmss verify failed");
return -1;
}
return ret;
}
#endif /* WOLFSSL_HAVE_XMSS */

View File

@ -0,0 +1,26 @@
/* wc_xmss.c
*
* Copyright (C) 2006-2023 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 2 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
*/
#include <wolfssl/wolfcrypt/settings.h>
#ifdef WOLFSSL_HAVE_XMSS
#error "Contact wolfSSL to get the implementation of this file"
#endif

View File

@ -293,6 +293,12 @@ const byte const_byte_array[] = "A+Gd\0\0\0";
#include <wolfssl/wolfcrypt/ext_kyber.h>
#endif
#endif
#if defined(WOLFSSL_HAVE_XMSS)
#include <wolfssl/wolfcrypt/xmss.h>
#ifdef HAVE_LIBXMSS
#include <wolfssl/wolfcrypt/ext_xmss.h>
#endif
#endif
#if defined(WOLFSSL_HAVE_LMS)
#include <wolfssl/wolfcrypt/lms.h>
#ifdef HAVE_LIBLMS
@ -577,6 +583,14 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t scrypt_test(void);
#ifdef WOLFSSL_HAVE_KYBER
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t kyber_test(void);
#endif
#if defined(WOLFSSL_HAVE_XMSS)
#if !defined(WOLFSSL_XMSS_VERIFY_ONLY)
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t xmss_test(void);
#endif
#if defined(WOLFSSL_XMSS_VERIFY_ONLY) && !defined(WOLFSSL_SMALL_STACK)
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t xmss_test_verify_only(void);
#endif
#endif
#if defined(WOLFSSL_HAVE_LMS)
#if !defined(WOLFSSL_LMS_VERIFY_ONLY)
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test(void);
@ -1623,6 +1637,22 @@ options: [-s max_relative_stack_bytes] [-m max_relative_heap_memory_bytes]\n\
TEST_PASS("KYBER test passed!\n");
#endif
#if defined(WOLFSSL_HAVE_XMSS)
#if !defined(WOLFSSL_XMSS_VERIFY_ONLY)
if ( (ret = xmss_test()) != 0)
TEST_FAIL("XMSS test failed!\n", ret);
else
TEST_PASS("XMSS test passed!\n");
#endif
#if defined(WOLFSSL_XMSS_VERIFY_ONLY) && !defined(WOLFSSL_SMALL_STACK)
if ( (ret = xmss_test_verify_only()) != 0)
TEST_FAIL("XMSS test failed!\n", ret);
else
TEST_PASS("XMSS test passed!\n");
#endif
#endif /* if defined(WOLFSSL_HAVE_XMSS) */
#if defined(WOLFSSL_HAVE_LMS)
#if !defined(WOLFSSL_LMS_VERIFY_ONLY)
if ( (ret = lms_test()) != 0)
@ -35091,6 +35121,616 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t kyber_test(void)
}
#endif /* WOLFSSL_HAVE_KYBER */
#if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY)
static int xmss_write_key_mem(const byte * priv, word32 privSz, void *context)
{
/* WARNING: THIS IS AN INSECURE WRITE CALLBACK THAT SHOULD ONLY
* BE USED FOR TESTING PURPOSES! Production applications should
* write only to non-volatile storage. */
XMEMCPY(context, priv, privSz);
return WC_XMSS_RC_SAVED_TO_NV_MEMORY;
}
static int xmss_read_key_mem(byte * priv, word32 privSz, void *context)
{
/* WARNING: THIS IS AN INSECURE READ CALLBACK THAT SHOULD ONLY
* BE USED FOR TESTING PURPOSES! */
XMEMCPY(priv, context, privSz);
return WC_XMSS_RC_READ_TO_MEMORY;
}
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t xmss_test(void)
{
int i = 0;
int j = 0;
int ret = -1;
int ret2 = -1;
XmssKey signingKey;
XmssKey verifyKey;
WC_RNG rng;
word32 pkSz = 0;
word32 skSz = 0;
word32 sigSz = 0;
word32 bufSz = 0;
unsigned char * sk = NULL;
unsigned char * old_sk = NULL;
const char * msg = "XMSS post quantum signature test";
word32 msgSz = (word32) XSTRLEN(msg);
const char * param = "XMSSMT-SHA2_20/4_256";
byte * sig = NULL;
#ifndef HAVE_FIPS
ret = wc_InitRng_ex(&rng, HEAP_HINT, INVALID_DEVID);
#else
ret = wc_InitRng(&rng);
#endif
if (ret != 0) { return WC_TEST_RET_ENC_EC(ret); }
ret = wc_XmssKey_Init(&signingKey, NULL, INVALID_DEVID);
if (ret != 0) { return WC_TEST_RET_ENC_EC(ret); }
ret = wc_XmssKey_Init(&verifyKey, NULL, INVALID_DEVID);
if (ret != 0) { return WC_TEST_RET_ENC_EC(ret); }
/* Set the parameter string to the signing key, and
* get sizes for secret key, pub key, and signature. */
ret = wc_XmssKey_SetParamStr(&signingKey, param);
if (ret != 0) { return WC_TEST_RET_ENC_EC(ret); }
ret = wc_XmssKey_GetPubLen(&signingKey, &pkSz);
if (ret != 0) { return WC_TEST_RET_ENC_EC(ret); }
if (pkSz != XMSS_SHA256_PUBLEN) {
return WC_TEST_RET_ENC_EC(pkSz);
}
ret = wc_XmssKey_GetPrivLen(&signingKey, &skSz);
if (ret != 0) { return WC_TEST_RET_ENC_EC(ret); }
ret = wc_XmssKey_GetSigLen(&signingKey, &sigSz);
if (ret != 0) { return WC_TEST_RET_ENC_EC(ret); }
/* Allocate signature array. */
sig = XMALLOC(sigSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
if (sig == NULL) { return WC_TEST_RET_ENC_ERRNO; }
bufSz = sigSz;
#if defined(DEBUG_WOLFSSL) || defined(WOLFSSL_DEBUG_NONBLOCK)
fprintf(stderr, "param: %s\n", param);
fprintf(stderr, "pkSz: %d\n", pkSz);
fprintf(stderr, "skSz: %d\n", skSz);
fprintf(stderr, "sigSz: %d\n", sigSz);
#endif
/* Allocate current and old secret keys.*/
sk = XMALLOC(skSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
if (sk == NULL) { return WC_TEST_RET_ENC_ERRNO; }
old_sk = XMALLOC(skSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
if (old_sk == NULL) { return WC_TEST_RET_ENC_ERRNO; }
XMEMSET(sk, 0, skSz);
XMEMSET(old_sk, 0, skSz);
XMEMSET(sig, 0, sigSz);
ret = wc_XmssKey_SetWriteCb(&signingKey, xmss_write_key_mem);
if (ret != 0) { return WC_TEST_RET_ENC_EC(ret); }
ret = wc_XmssKey_SetReadCb(&signingKey, xmss_read_key_mem);
if (ret != 0) { return WC_TEST_RET_ENC_EC(ret); }
ret = wc_XmssKey_SetContext(&signingKey, (void *) sk);
if (ret != 0) { return WC_TEST_RET_ENC_EC(ret); }
ret = wc_XmssKey_MakeKey(&signingKey, &rng);
if (ret != 0) { return WC_TEST_RET_ENC_EC(ret); }
/* Export the pub to a verify key. */
ret = wc_XmssKey_ExportPub(&verifyKey, &signingKey);
if (ret != 0) { return WC_TEST_RET_ENC_EC(ret); }
/* Repeat a few times to check that:
* 1. The secret key is mutated on each sign.
* 2. We can verify each new signature.
* Only do a few times, because the full signature space
* for this parameter set is huge. */
for (i = 0; i < 10; ++i) {
XMEMCPY(old_sk, sk, skSz);
ret = wc_XmssKey_Sign(&signingKey, sig, &sigSz, (byte *) msg, msgSz);
if (ret != 0) { return WC_TEST_RET_ENC_I(i); }
if (sigSz != bufSz) { return WC_TEST_RET_ENC_I(i); }
/* Old secret key and current secret key should not match. */
ret = XMEMCMP(old_sk, sk, skSz);
if (ret == 0) { return WC_TEST_RET_ENC_I(i); }
ret = wc_XmssKey_Verify(&verifyKey, sig, sigSz, (byte *) msg, msgSz);
if (ret != 0) { return WC_TEST_RET_ENC_I(i); }
/* Flip bits in a few places throughout the signature, stepping in multiple
* of hash size. These should all fail with -1. */
for (j = 0; j < (int) sigSz; j+= 4 * 32) {
sig[j] ^= 1;
ret2 = wc_XmssKey_Verify(&verifyKey, sig, sigSz, (byte *) msg,
msgSz);
if (ret2 != -1) {
/* Verify passed when it should have failed. */
return WC_TEST_RET_ENC_I(j);
}
/* Flip this spot back. */
sig[j] ^= 1;
}
}
/* Cleanup everything. */
if (sig != NULL) {
XFREE(sig, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
sig = NULL;
}
if (sk != NULL) {
XFREE(sk, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
sk = NULL;
}
if (old_sk != NULL) {
XFREE(old_sk, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
old_sk = NULL;
}
wc_XmssKey_Free(&signingKey);
wc_FreeRng(&rng);
return ret;
}
#endif /*if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY)*/
#if defined(WOLFSSL_HAVE_XMSS) && defined(WOLFSSL_XMSS_VERIFY_ONLY) && \
!defined(WOLFSSL_SMALL_STACK)
/* A simple xmss verify only test using:
* XMSS-SHA2_10_256
* pub len: 68
* msg len: 32
* sig len: 2500
*
* These were generated with the test xmss_fast, from the unpatched
* xmss-reference repository:
* https://github.com/XMSS/xmss-reference
* */
static byte xmss_pub[XMSS_SHA256_PUBLEN] =
{
0x00,0x00,0x00,0x01,0xA5,0x41,0x31,0x96,
0x0A,0xF9,0xF3,0xB2,0x4B,0x2E,0x5B,0x3E,
0xCA,0x74,0xAD,0x6C,0xA5,0x89,0xAD,0x2C,
0x0E,0x96,0xB3,0x54,0xFB,0x5B,0x63,0x50,
0x96,0x81,0xE2,0x59,0x72,0x10,0x09,0x54,
0xBB,0x39,0xAC,0xEE,0x78,0xEF,0x95,0xEC,
0x01,0x1D,0xF0,0x36,0x68,0xE2,0xC4,0xA5,
0x2F,0x60,0x42,0x7E,0xD3,0x8E,0xAA,0x27,
0xC9,0xB7,0x39,0x4E
};
static byte xmss_msg[32] =
{
0x07,0x9F,0x80,0x86,0xDB,0x76,0x27,0xDF,
0xED,0x5B,0x2A,0x81,0x60,0x60,0x7D,0xB4,
0xE8,0x7A,0x69,0x45,0x20,0x6B,0xA2,0x96,
0xC0,0x21,0xA5,0x46,0x29,0x63,0x9B,0x37
};
/* This was actually the 5th signature produced from
* xmss_fast test in xmss-reference. */
static byte xmss_sig[2500] =
{
0x00,0x00,0x00,0x05,0xF0,0x15,0x34,0xBA,
0x92,0x03,0x6A,0xB9,0xA5,0x23,0x86,0x11,
0xAE,0x65,0x0A,0x5C,0x78,0x2C,0xC9,0xBE,
0x7E,0xA6,0xDC,0xA2,0x8B,0xA9,0x9C,0x50,
0xF6,0x61,0x8D,0x9D,0xD7,0xE9,0xC0,0xF8,
0x67,0xCD,0x8A,0xC4,0x9B,0x74,0x96,0x07,
0x5D,0xF2,0xC9,0xCC,0x28,0x05,0xB1,0xBE,
0x5E,0xA4,0xBA,0xBE,0xAB,0xD8,0x21,0x6B,
0x21,0x5F,0xAB,0xB7,0x6C,0xEC,0x2F,0xC8,
0xC6,0x74,0x3E,0x97,0x1B,0xC3,0x45,0x57,
0xAF,0xAA,0x1E,0xA8,0xF2,0x86,0xA8,0xAA,
0x43,0x6D,0x66,0xE9,0x81,0x14,0xDE,0x09,
0x39,0xD2,0xAF,0xD1,0x4C,0xE7,0x75,0x18,
0x0D,0xAA,0x29,0xA1,0x92,0x53,0xCC,0xE9,
0xF3,0x0B,0x1E,0x3B,0xE2,0xAE,0x80,0x0C,
0xE7,0x7A,0x7C,0x13,0x8A,0x28,0xC6,0x5F,
0x0A,0xA4,0xA3,0x73,0x0A,0x3A,0xC2,0xA6,
0x3B,0xB4,0x30,0x67,0xC0,0x36,0x18,0xA1,
0x58,0xCD,0xAD,0x54,0x36,0x64,0xCE,0xFD,
0x52,0xFF,0x70,0x7E,0x09,0xFB,0x13,0xA2,
0xEA,0xDF,0x67,0x8D,0x6C,0x42,0xB2,0x78,
0xF5,0x7D,0x5C,0x4B,0xF7,0x8E,0xCF,0x3E,
0xB7,0xC6,0xC1,0x23,0xFA,0x65,0xDE,0xD2,
0xFA,0x40,0x51,0x97,0x0D,0x52,0x32,0x76,
0x7E,0x82,0x8D,0xD0,0xB9,0x1E,0x62,0xD9,
0x1E,0xC1,0xDB,0x40,0x43,0x37,0x4A,0x23,
0x8A,0x1D,0x35,0xFA,0xF4,0x53,0x11,0x5A,
0xB5,0x6D,0x1E,0x8B,0x22,0xC8,0x7D,0x2A,
0xE4,0x94,0xAA,0x25,0x20,0x40,0x96,0xDB,
0x82,0x62,0xBA,0x8F,0x8B,0x45,0xCB,0x4F,
0x35,0x88,0x33,0xEB,0xEF,0xB3,0xBA,0xA7,
0x09,0x72,0xB3,0x4C,0xEC,0xF2,0xC3,0xC7,
0x5E,0x02,0x6C,0x41,0x93,0xCB,0x3C,0x89,
0x12,0x09,0x68,0x54,0x8E,0xEC,0x6A,0x7E,
0x20,0xE1,0x70,0x3D,0x8C,0xEB,0xB4,0x36,
0xBE,0x91,0xBE,0x97,0xB5,0xA6,0x34,0x16,
0x95,0x0F,0x10,0x26,0xA9,0x13,0x80,0x88,
0x9C,0xAA,0x68,0xEC,0x34,0x70,0x4A,0x15,
0x9B,0x5E,0x57,0x05,0x87,0x1C,0xF8,0x35,
0x45,0x29,0xE9,0x6E,0xF2,0x70,0x13,0x42,
0x89,0x4E,0x77,0xC0,0x18,0xC7,0x55,0x6D,
0xE7,0xFA,0x0D,0x63,0x83,0x16,0x19,0x01,
0x2D,0xFD,0x31,0x14,0x94,0xCA,0x3E,0x0E,
0xD6,0x11,0x34,0x81,0x57,0x58,0xEC,0x24,
0xA4,0x17,0x63,0xD3,0x25,0x00,0xBF,0x7D,
0x78,0x5D,0xC5,0xD8,0xC6,0xC1,0xBD,0x8C,
0xD0,0x94,0x0A,0xB1,0x33,0xA5,0x4B,0x31,
0x25,0xF5,0xAF,0xE7,0x84,0x26,0xAA,0x05,
0xBB,0xF3,0x9A,0xAF,0x58,0x36,0x40,0xEF,
0x3D,0xA2,0xBD,0xCA,0xA1,0x8D,0x2F,0x6D,
0x54,0xD2,0x62,0x33,0x09,0xAE,0xE6,0x73,
0xD6,0x44,0xE8,0x7C,0x5C,0x39,0x2B,0x78,
0x94,0x14,0xC7,0xC9,0xAF,0xEC,0x77,0x36,
0xA1,0x61,0x61,0xF1,0xD0,0x09,0xA2,0xEE,
0xE7,0x55,0xD7,0x35,0x89,0x89,0x9B,0xCF,
0xFA,0xA6,0x09,0x1E,0x3B,0xBD,0x5D,0xD9,
0x25,0xE7,0xED,0xDD,0x7C,0xF0,0x1C,0x57,
0xE0,0x06,0xBB,0x08,0x39,0x59,0xDF,0xD7,
0xAF,0x4B,0x88,0x0D,0x87,0x8F,0x4A,0xF3,
0x1C,0xD4,0x4B,0xB3,0xE2,0xF3,0x1B,0x86,
0x4F,0xCD,0x35,0x75,0xE2,0x03,0xF9,0x1D,
0xBF,0x3E,0xD1,0x7B,0xC7,0x23,0x11,0x75,
0x5F,0x92,0x0D,0x98,0xEE,0x14,0xE1,0xDA,
0x7A,0x02,0x17,0x47,0x6B,0x41,0xEA,0x47,
0xA1,0xAF,0x06,0x79,0x1A,0x52,0x6F,0x19,
0x31,0x70,0x71,0xBD,0xC2,0x61,0x8D,0xB7,
0xEE,0x6B,0x69,0x2A,0xE8,0x21,0x7A,0x95,
0xBE,0x86,0x2A,0xA1,0xF4,0xE2,0x2F,0x17,
0x02,0xFD,0xAD,0x17,0x9F,0x0A,0x0A,0x78,
0xA9,0x92,0x30,0x21,0x72,0x2B,0x28,0xF8,
0xF2,0x3E,0x05,0xD5,0xAC,0xC0,0x82,0xF8,
0xD2,0xDA,0xD0,0xA3,0xBC,0x93,0xDB,0xA5,
0x46,0xDE,0x14,0x1E,0xD4,0x3A,0x5D,0x79,
0x3D,0x31,0x4B,0x06,0xCE,0x22,0x29,0x3C,
0x98,0xB6,0x18,0x8A,0xAE,0xF7,0xBA,0x22,
0x88,0xA1,0xEE,0xC0,0x14,0x4C,0x4A,0xA0,
0x57,0x0A,0xD3,0x18,0xA2,0x3D,0xDD,0xC7,
0x83,0x73,0xFC,0x38,0x9B,0x31,0xA3,0xE1,
0x17,0x76,0xA1,0xA2,0x69,0xFC,0xAB,0x08,
0x80,0x72,0x8D,0xF5,0xE4,0x14,0xB7,0x6B,
0x03,0xFF,0xE8,0x11,0x4B,0x06,0x55,0x7E,
0x36,0x21,0x2F,0xD7,0x54,0x82,0xC9,0x31,
0xB4,0x85,0x68,0x41,0xEF,0x75,0xB0,0x3A,
0xEA,0x4F,0xE0,0xEC,0x72,0xCC,0x33,0x96,
0xCE,0x7D,0xAD,0xDD,0x0D,0x27,0x05,0x6E,
0xA2,0xD4,0x11,0x07,0xD8,0x7D,0x27,0xD4,
0x80,0x8F,0x00,0x22,0xE4,0xFC,0x2C,0x9D,
0xD5,0xD8,0x18,0x7F,0x4E,0xF4,0xB9,0x7F,
0xEF,0xD6,0x00,0x08,0x5C,0x05,0x04,0x1E,
0x9A,0xC6,0x8D,0xCC,0x19,0xD9,0x0B,0x06,
0xCC,0x6A,0x17,0xE2,0x03,0x23,0xDB,0x1C,
0xBC,0xA2,0xB9,0xA2,0x95,0x3C,0x73,0xD8,
0xFF,0xE6,0x0E,0xAE,0x04,0xB2,0xFC,0x91,
0x4F,0xEF,0x8A,0x58,0xB7,0x31,0x68,0x4C,
0x1E,0xD0,0x5B,0x85,0xCC,0x03,0xDC,0xF4,
0xAC,0xDB,0x03,0x9B,0x35,0x33,0x08,0x71,
0xD0,0x50,0x8D,0xDC,0xE3,0x3A,0x98,0x40,
0x41,0x80,0xDD,0x35,0xE1,0xA2,0xAF,0x14,
0x9A,0xDB,0xD3,0x68,0x14,0xE2,0x50,0x7A,
0x76,0x3F,0xE4,0xA4,0x1B,0xAA,0xC1,0x06,
0x87,0x9A,0x92,0xF9,0xBE,0x9E,0x86,0x8C,
0x92,0x1D,0x74,0xB1,0x7F,0x27,0x43,0xC0,
0xEE,0x2E,0xC2,0x6C,0x6D,0xAA,0x0C,0x0E,
0x71,0xC9,0x56,0xD6,0x3A,0x56,0xCB,0x90,
0xD1,0x7E,0x6E,0x1C,0x6A,0x00,0x2D,0x02,
0x2C,0x96,0xF0,0x2A,0x37,0x37,0x18,0x07,
0x0B,0xF4,0xB4,0x8C,0x30,0xF2,0xA4,0xAB,
0x66,0xFB,0x8B,0x22,0xC0,0x00,0x7E,0x05,
0xB6,0xF9,0x95,0x49,0x33,0xA1,0xDC,0x97,
0x0C,0x5C,0x61,0x46,0xE2,0xD7,0x87,0x4B,
0xC4,0xC7,0x5F,0x26,0x06,0x84,0xD7,0x47,
0x05,0xF1,0x33,0xFF,0x85,0x85,0xB2,0xBD,
0x1F,0x44,0xC6,0xC2,0x7D,0x51,0xBE,0x0E,
0xB5,0xC4,0x44,0x2F,0xFE,0x73,0x5F,0xF4,
0xA4,0xEF,0xE2,0xF1,0x73,0x0B,0xEF,0x3E,
0x2B,0xD7,0xCC,0x9F,0xDA,0x1A,0x7E,0x92,
0x39,0xA1,0x55,0xBF,0x60,0x0A,0xDB,0x23,
0x74,0xFE,0xE7,0x05,0x63,0xA9,0x85,0x52,
0x9F,0xCC,0xC3,0xFF,0xF6,0x6C,0x1B,0x4E,
0x4F,0x01,0xBD,0xC3,0xEB,0x37,0xEC,0x29,
0x21,0x3B,0x2C,0xC9,0x2E,0x93,0x20,0x3E,
0x19,0xC0,0x8B,0xE8,0x33,0xCD,0xC6,0x6A,
0x6E,0x72,0x13,0x15,0xA1,0x90,0x20,0x0C,
0x14,0x66,0xED,0xCC,0xA4,0xDD,0x7F,0x58,
0x53,0xBC,0x4A,0x68,0xFC,0x86,0x3E,0xAA,
0xF1,0x17,0x0F,0x3E,0x20,0x54,0x93,0xF4,
0x98,0xBF,0xB4,0x07,0x05,0xBD,0x70,0xE7,
0xD7,0x34,0xFD,0xE3,0x69,0xDF,0xCD,0xF5,
0x1A,0x73,0x6E,0xC9,0x2B,0x21,0xFB,0xB8,
0x7E,0x44,0x10,0x83,0x56,0xCE,0xD5,0x15,
0x9A,0x75,0xFC,0x91,0x8E,0x6B,0x9E,0x1A,
0x3A,0x33,0x39,0x35,0xB4,0x0D,0x74,0xF4,
0xFB,0x4C,0x0E,0x37,0xFE,0x82,0x95,0x46,
0x6B,0xD2,0x6E,0xEE,0xCD,0x4D,0x38,0xAF,
0x0A,0xAA,0xF1,0xD5,0xA4,0x7C,0x04,0xD8,
0xB9,0xDB,0x11,0x68,0x88,0x35,0x41,0xDE,
0x31,0x33,0x0C,0xDC,0x2D,0x4C,0xA8,0x20,
0xCC,0x2C,0x4C,0x63,0xAB,0xBA,0xDF,0x48,
0x84,0xD5,0x25,0xBC,0x70,0xE3,0x49,0xAA,
0x43,0xCA,0x8B,0xE7,0x9F,0xDD,0x20,0x76,
0x9B,0x38,0xF4,0xBA,0x4D,0x4E,0x34,0x4A,
0xAF,0x81,0xE7,0x0B,0xEC,0xE9,0x59,0xC1,
0x35,0x22,0x7F,0x69,0x46,0x62,0xD2,0x18,
0x6E,0x1F,0x79,0xD1,0xAD,0xC3,0x84,0x95,
0x96,0xB2,0x18,0x58,0x5E,0x7E,0x0C,0x25,
0x0A,0x0F,0x69,0xA3,0x1D,0xEC,0x29,0xCB,
0xDA,0xA2,0xD1,0x1A,0x10,0xA5,0x52,0xC3,
0x62,0x1E,0xC5,0x83,0xFF,0xA3,0x56,0xC2,
0xFD,0x87,0x3B,0x57,0x52,0x98,0x36,0x95,
0x77,0x6B,0xE5,0x49,0x10,0x8E,0x39,0xDD,
0xCA,0x4B,0xB3,0x9F,0x4C,0x0C,0x11,0x62,
0xF3,0x22,0x78,0xDB,0x48,0xEB,0x68,0xFE,
0xE4,0x2A,0xE9,0xAA,0x8F,0x7A,0x2F,0x69,
0xA5,0xC5,0x03,0x2D,0xEF,0x62,0xA8,0x71,
0x65,0x06,0x40,0x84,0x10,0x0F,0xF2,0xED,
0xBC,0x70,0x71,0x69,0x24,0xA2,0xBF,0x83,
0x39,0xDD,0xFA,0xA2,0x7B,0xE5,0xEC,0x3D,
0xFE,0x3B,0x52,0x6E,0x3D,0x82,0xA6,0x2A,
0x86,0x01,0x61,0x51,0x63,0xBF,0xF9,0x0A,
0x06,0x72,0xF1,0xD5,0x39,0x0C,0xBA,0xC9,
0x78,0xC6,0x77,0x22,0xE4,0x96,0x6E,0xB1,
0x48,0x62,0x84,0x62,0x2D,0xEA,0x49,0x56,
0x50,0x86,0x3F,0x90,0xC3,0x01,0x42,0x45,
0xED,0xE6,0x9A,0x65,0x19,0x93,0x7F,0x48,
0x16,0xF2,0x50,0xA7,0x70,0xB3,0xF5,0xDB,
0x0E,0x5E,0x22,0x9E,0x64,0x04,0x26,0x69,
0xC1,0x16,0xEE,0x65,0x08,0x82,0x27,0x65,
0xEC,0x3D,0xDF,0x51,0x5E,0x2D,0xE8,0x76,
0xF2,0xE3,0xE4,0x24,0x04,0x88,0x06,0x0F,
0xB2,0x7B,0x9B,0x72,0x3D,0x4C,0x7D,0x6A,
0x1F,0xB2,0xA2,0xD2,0x35,0xD6,0x40,0x25,
0xC2,0x0B,0x25,0xF9,0xDF,0x26,0xE4,0xDC,
0xFB,0xB1,0x84,0x84,0x77,0x1B,0x45,0x51,
0x60,0xD5,0xF0,0xB6,0x09,0xE6,0xBC,0xE3,
0x1C,0x70,0x96,0x2C,0xD3,0x9D,0x7D,0x7F,
0xB1,0x70,0xDA,0x79,0xB8,0x74,0x99,0xBF,
0x84,0x95,0xCC,0x93,0xD7,0x51,0xDD,0x66,
0xD3,0x70,0x0C,0x75,0x86,0x09,0x06,0xFD,
0x66,0x14,0x80,0xCD,0xF3,0x59,0xB4,0x92,
0x5F,0xE4,0xEE,0x00,0xA8,0xB0,0x8B,0x5C,
0x3E,0xDB,0x8A,0x9C,0x0B,0xB5,0x99,0xC2,
0x0D,0x81,0x09,0x06,0x6C,0x28,0xC0,0x7E,
0xA5,0x07,0x70,0x64,0xD7,0x41,0xF4,0xC3,
0x66,0x61,0x1C,0xA8,0x51,0xF6,0x3C,0xBA,
0xE0,0x94,0xA3,0x11,0x8C,0x2E,0xBA,0x13,
0xB2,0x47,0x48,0x93,0xB4,0x1A,0x2C,0x9A,
0x6E,0x8E,0x30,0x66,0x7B,0xD3,0xBB,0x3B,
0x5D,0x97,0x0D,0xE4,0xEA,0x24,0x28,0x9E,
0xB4,0x88,0xCE,0x1D,0x7D,0x6F,0x39,0xB3,
0x87,0x21,0xE5,0x08,0x93,0xF0,0xD4,0x9D,
0x2D,0x91,0xC9,0xFD,0x0C,0x74,0x34,0xB4,
0x1F,0xFE,0xDA,0xDC,0x10,0x5B,0x8D,0x2B,
0x87,0xD3,0x42,0xB4,0xAE,0x32,0x9C,0xAE,
0x4C,0x99,0xD8,0xED,0x44,0x41,0x07,0xE0,
0x8F,0xBD,0xA5,0x7C,0x5A,0xDF,0x91,0x29,
0x00,0xB5,0x4B,0xC3,0x3A,0x40,0x6C,0x48,
0xAB,0x2A,0xF3,0x02,0xCB,0xB3,0x69,0xDA,
0x06,0x0C,0x4D,0x5C,0x45,0xC3,0x28,0xAC,
0x7A,0x01,0xD4,0xF8,0xCB,0x07,0x63,0x89,
0x09,0x34,0x78,0xA7,0x14,0x39,0xCF,0x2D,
0x94,0x8D,0x7A,0x4E,0x4E,0xBD,0xC4,0x32,
0xAB,0x21,0xC9,0xDA,0x3F,0x5F,0x04,0x6B,
0x14,0x40,0x18,0x18,0x2F,0xF9,0x46,0x17,
0x57,0x54,0x9B,0x28,0x7B,0xBD,0xF9,0xA2,
0x13,0xAC,0x69,0x24,0xB1,0x31,0x39,0xBF,
0x8D,0x75,0xC3,0xFD,0x03,0x54,0x5A,0xFD,
0xD4,0x7A,0xB7,0x56,0x4F,0x66,0x43,0x57,
0x1B,0xFB,0xF9,0x92,0x7A,0x83,0xE6,0xFF,
0xB4,0xBA,0x83,0xD2,0x61,0x8E,0x4A,0x82,
0x82,0xA8,0xF5,0x0C,0xD2,0x43,0x53,0xA8,
0x85,0x0A,0xD4,0x69,0x7B,0x04,0x71,0x3B,
0x80,0x49,0x27,0x47,0x12,0xB6,0xB0,0xEA,
0x90,0x0A,0xFA,0xA8,0xC8,0x78,0x61,0xDE,
0x30,0x12,0xBB,0xDC,0xA6,0x57,0x56,0x30,
0x6E,0xF1,0xA8,0x3B,0xF6,0x09,0x07,0xEA,
0x31,0xE2,0x08,0x23,0x31,0x0F,0xD4,0x34,
0xE3,0x60,0xC2,0x2B,0xDB,0x5A,0x99,0xCF,
0xD4,0x6B,0x4E,0x75,0x65,0x35,0xE8,0x8B,
0x93,0x7D,0xCA,0x11,0x47,0xF0,0x3E,0x11,
0x5C,0xD1,0xEE,0x4B,0x11,0xB4,0x65,0x2B,
0x6B,0x79,0xC0,0x86,0x60,0xA4,0x4B,0x24,
0xA0,0x5C,0x70,0x34,0xC3,0x7C,0xE7,0x4F,
0x97,0x89,0x4D,0xFE,0x22,0x89,0x3A,0xE9,
0x07,0xB9,0x1A,0x86,0xB8,0x7A,0x12,0x38,
0xE1,0x24,0x46,0xBC,0x9B,0x21,0xCD,0xAC,
0x30,0xAB,0x98,0x21,0x31,0xC5,0x17,0x3F,
0x1E,0x56,0xC3,0x18,0xCE,0xF0,0xA1,0xCC,
0xFF,0x9D,0xA8,0x53,0xAF,0x74,0x77,0x54,
0x02,0x9A,0x8F,0xA4,0xD4,0xBD,0xB2,0x1A,
0xBA,0x52,0x2E,0x19,0xBE,0x49,0x11,0x45,
0x02,0x01,0x7A,0xBF,0x28,0xD6,0x18,0xED,
0xBD,0xCE,0xE4,0xDE,0xB5,0xF1,0x53,0x5D,
0x65,0xF9,0x5F,0x83,0x8F,0x2D,0xF2,0x82,
0xA0,0x2D,0x28,0xD3,0x0A,0x9E,0x0F,0x7F,
0xC7,0xC4,0x43,0x7F,0xC3,0x0E,0x06,0xEB,
0x4E,0xB4,0x2D,0xFA,0xDD,0x48,0xAB,0xF4,
0x7D,0x41,0x48,0x33,0x5A,0xE6,0x70,0x02,
0xE7,0x71,0x8D,0xD9,0x6B,0x0C,0x5A,0x8F,
0xA4,0xC1,0xB7,0x4E,0x96,0x83,0xD6,0xA7,
0x1D,0xF1,0x88,0xB3,0x6E,0xF4,0x12,0xA9,
0xF6,0x31,0x69,0x66,0xFE,0xFE,0x02,0xF2,
0x86,0x6D,0xBB,0x57,0x51,0x8C,0x4C,0xE9,
0x7C,0x92,0x3E,0x3A,0xD3,0x2D,0xA8,0x82,
0x53,0x84,0x26,0x89,0xBB,0xCC,0x13,0x12,
0x3D,0x94,0xBB,0xDF,0x3D,0x4C,0xDF,0x27,
0x9B,0x1F,0xB8,0xB6,0xE4,0xEA,0xA2,0x07,
0xF8,0x4D,0x42,0x8F,0x29,0x90,0xFE,0x21,
0x20,0xE9,0x55,0x02,0xAD,0x90,0xA7,0x77,
0x4E,0x29,0xB6,0xD9,0x14,0x94,0xB2,0x25,
0xA4,0xB2,0x0E,0x96,0x31,0xAB,0x9E,0x93,
0x49,0xAC,0xA9,0xCB,0x68,0x22,0xBA,0xB8,
0x57,0x5C,0x9D,0x65,0xC1,0xF1,0xFC,0x99,
0x7C,0x3C,0xE9,0xEA,0x4B,0x29,0x22,0x2F,
0xDB,0x17,0x21,0x8D,0xB0,0x13,0xBF,0xEE,
0x7D,0xE4,0x8B,0x6D,0x17,0xE0,0x53,0x92,
0x0B,0x32,0x6B,0xB1,0x65,0x2E,0xA7,0x83,
0xFD,0x62,0x62,0xE3,0xAA,0x81,0xE8,0xD6,
0xF7,0xB1,0x30,0x65,0x80,0x9F,0x77,0x1E,
0x4A,0xEA,0xE8,0x45,0x32,0x12,0x3A,0xFB,
0x22,0xE9,0xA9,0xF6,0xCB,0xAB,0xA8,0x0C,
0x20,0xA8,0x7C,0xF9,0xF7,0x53,0xC1,0xB4,
0xC0,0x5D,0x06,0x45,0xDD,0x7E,0xA7,0x34,
0xA1,0x21,0xC2,0x62,0xAB,0x22,0x45,0x3D,
0x73,0x4C,0x26,0xD1,0x1A,0xB2,0xF0,0xB2,
0x6D,0x11,0x70,0x58,0xAA,0xF5,0xA4,0xF5,
0xF8,0x0B,0x3D,0xC1,0xF6,0x17,0x70,0x15,
0xCD,0x72,0x02,0x7E,0x4E,0x94,0x96,0x0A,
0x56,0xCC,0xA5,0xA3,0xB3,0x7E,0xDD,0x5A,
0x72,0xD2,0xFB,0xAC,0x3D,0x0E,0x66,0x65,
0xE9,0x08,0x6C,0xB0,0x1C,0xE2,0x1A,0x82,
0xF6,0xF3,0x34,0x89,0x73,0x02,0x5B,0x42,
0x6D,0x40,0x61,0xB6,0xE0,0xE6,0x53,0x32,
0xA5,0x72,0x17,0x4F,0x3B,0x51,0x4F,0xBC,
0x00,0xE0,0x69,0x26,0xA9,0xAE,0x83,0xE3,
0x73,0x7F,0x71,0x97,0xE0,0xDC,0x7C,0x63,
0x9C,0x85,0x5F,0xDF,0x7D,0xE4,0x6C,0xD8,
0xA9,0x3A,0x6F,0x5E,0x4A,0x2E,0xB0,0xE7,
0x8B,0x45,0xE2,0x90,0x05,0x37,0xE8,0xAB,
0x49,0x48,0x4C,0xC0,0x59,0x1D,0x8C,0x46,
0x5B,0x84,0xE0,0x83,0xCE,0xEA,0x4B,0xF9,
0xD4,0xDC,0x63,0xDF,0x79,0xB7,0x5C,0x11,
0x25,0x7F,0x90,0x2E,0x0A,0x38,0x03,0xEA,
0xEA,0xA1,0x26,0x52,0x20,0x19,0xA3,0xBE,
0xFC,0x9D,0xB7,0x6E,0xA6,0x58,0x8E,0x6D,
0xC5,0x58,0xE9,0xED,0x2F,0x55,0x43,0x8B,
0x03,0x8B,0xE6,0xA4,0xC2,0x25,0x4B,0x36,
0xBA,0xD3,0x27,0x48,0x40,0x2E,0x87,0xA2,
0xD4,0x12,0xC6,0x05,0x36,0x03,0x11,0x51,
0xD1,0xF2,0xAC,0x71,0x2C,0xB6,0xC3,0xA5,
0x57,0x0F,0xAF,0x4B,0xBD,0xCD,0x47,0x4C,
0x3A,0x52,0x6F,0x47,0xE7,0x0B,0xB7,0xD5,
0xF7,0xA6,0x39,0x63,0x82,0x08,0x4C,0x41,
0x0E,0x2A,0x52,0x42,0x5A,0xEA,0x59,0xC7,
0x94,0xFB,0xD0,0x88,0x47,0x27,0xF6,0x97,
0x03,0x9E,0x29,0xB8,0x3A,0x67,0xE6,0xF3,
0x95,0xA7,0x42,0xC1,0x96,0xD1,0x9A,0xA6,
0xF0,0x09,0x0C,0xEA,0xE0,0xAB,0x0F,0x15,
0xE9,0xC3,0xEB,0xA5,0x89,0x86,0x98,0x32,
0x83,0xAB,0x30,0x33,0xAE,0x90,0x8D,0x2E,
0xB3,0xAA,0x91,0xA6,0xD9,0xA4,0x4A,0x54,
0xE0,0xD3,0x08,0xCC,0x79,0xCE,0xE4,0x15,
0x31,0xA6,0xCE,0x61,0xCF,0x03,0x06,0xEE,
0x8E,0xE2,0x64,0x29,0xD1,0x54,0x9B,0xD0,
0x5F,0x09,0x2B,0x8B,0xD5,0xF8,0xD4,0x7D,
0xF1,0x97,0x32,0xD9,0xEA,0x5A,0x0E,0x10,
0x8C,0x4D,0xFB,0x55,0xE6,0x27,0x0C,0xBA,
0xC1,0x73,0xC1,0x73,0xE3,0x1C,0x09,0xB3,
0x6F,0xB4,0x12,0xFA,0xF3,0x29,0xDC,0x23,
0x32,0xED,0x80,0x87,0x83,0xC2,0xF6,0x07,
0xB5,0xA9,0x22,0xDE,0x66,0x1A,0xA7,0x4A,
0x86,0xF1,0x39,0x9B,0xF4,0xE7,0x50,0x15,
0x4A,0x55,0x3C,0x93,0xB9,0xF9,0xFD,0xDC,
0xB3,0x5D,0x73,0x52
};
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t xmss_test_verify_only(void)
{
int ret = -1;
int ret2 = -1;
int j = 0;
XmssKey verifyKey;
word32 pkSz = 0;
word32 sigSz = 0;
const char * param = "XMSS-SHA2_10_256";
ret = wc_XmssKey_Init(&verifyKey, NULL, INVALID_DEVID);
if (ret != 0) { return WC_TEST_RET_ENC_EC(ret); }
ret = wc_XmssKey_SetParamStr(&verifyKey, param);
if (ret != 0) { return WC_TEST_RET_ENC_EC(ret); }
ret = wc_XmssKey_GetPubLen(&verifyKey, &pkSz);
if (ret != 0) { return WC_TEST_RET_ENC_EC(ret); }
if (pkSz != XMSS_SHA256_PUBLEN) {
return WC_TEST_RET_ENC_EC(pkSz);
}
ret = wc_XmssKey_GetSigLen(&verifyKey, &sigSz);
if (ret != 0) { return WC_TEST_RET_ENC_EC(ret); }
#if defined(DEBUG_WOLFSSL) || defined(WOLFSSL_DEBUG_NONBLOCK)
fprintf(stderr, "param: %s\n", param);
fprintf(stderr, "pkSz: %d\n", pkSz);
fprintf(stderr, "sigSz: %d\n", sigSz);
#endif
if (sigSz != sizeof(xmss_sig)) {
return WC_TEST_RET_ENC_EC(sigSz);
}
ret = wc_XmssKey_ImportPubRaw(&verifyKey, xmss_pub, XMSS_SHA256_PUBLEN);
if (ret != 0) { return WC_TEST_RET_ENC_EC(ret); }
ret = wc_XmssKey_Verify(&verifyKey, xmss_sig, sizeof(xmss_sig),
(byte *) xmss_msg, sizeof(xmss_msg));
if (ret != 0) {
printf("error: wc_XmssKey_Verify returned %d, expected 0\n", ret);
return WC_TEST_RET_ENC_EC(ret);
}
/* Flip bits in message. This should fail. */
xmss_msg[sizeof(xmss_msg) / 2] ^= 1;
ret2 = wc_XmssKey_Verify(&verifyKey, xmss_sig, sizeof(xmss_sig),
(byte *) xmss_msg, sizeof(xmss_msg));
if (ret2 != -1) {
printf("error: wc_XmssKey_Verify returned %d, expected -1\n", ret2);
return WC_TEST_RET_ENC_EC(ret);
}
/* Flip it back. This should pass again. */
xmss_msg[sizeof(xmss_msg) / 2] ^= 1;
ret = wc_XmssKey_Verify(&verifyKey, xmss_sig, sizeof(xmss_sig),
(byte *) xmss_msg, sizeof(xmss_msg));
if (ret != 0) {
printf("error: wc_XmssKey_Verify returned %d, expected 0\n", ret);
return WC_TEST_RET_ENC_EC(ret);
}
/* Flip bits in a few places throughout the signature, stepping in multiple
* of hash size. These should all fail with -1. */
for (j = 0; j < (int) sizeof(xmss_sig); j+= 4 * 32) {
xmss_sig[j] ^= 1;
ret2 = wc_XmssKey_Verify(&verifyKey, xmss_sig, sizeof(xmss_sig),
(byte *) xmss_msg, sizeof(xmss_msg));
if (ret2 != -1) {
/* Verify passed when it should have failed. */
return WC_TEST_RET_ENC_I(j);
}
/* Flip this spot back. */
xmss_sig[j] ^= 1;
}
/* Cleanup everything. */
wc_XmssKey_Free(&verifyKey);
return ret;
}
#endif /* if defined(WOLFSSL_HAVE_XMSS) && defined(WOLFSSL_XMSS_VERIFY_ONLY) &&
* !defined(WOLFSSL_SMALL_STACK) */
#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY)
static int lms_write_key_mem(const byte * priv, word32 privSz, void *context)
@ -35116,7 +35756,10 @@ static int lms_read_key_mem(byte * priv, word32 privSz, void *context)
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test(void)
{
int ret;
int i = 0;
int j = 0;
int ret = -1;
int ret2 = -1;
int sigsLeft = 0;
LmsKey signingKey;
LmsKey verifyKey;
@ -35138,6 +35781,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test(void)
XMEMSET(priv, 0, sizeof(priv));
XMEMSET(old_priv, 0, sizeof(old_priv));
XMEMSET(sig, 0, WC_TEST_LMS_SIG_LEN);
#ifndef HAVE_FIPS
ret = wc_InitRng_ex(&rng, HEAP_HINT, INVALID_DEVID);
@ -35190,7 +35834,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test(void)
}
/* 2 ** 5 should be the max number of signatures */
for (size_t i = 0; i < 32; ++i) {
for (i = 0; i < 32; ++i) {
/* We should have remaining signstures. */
sigsLeft = wc_LmsKey_SigsLeft(&signingKey);
if (sigsLeft == 0) {
@ -35203,7 +35847,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test(void)
/* The updated private key should not match the old one. */
if (XMEMCMP(old_priv, priv, sizeof(priv)) == 0) {
printf("error: current priv key should not match old: %zu\n", i);
printf("error: current priv key should not match old: %d\n", i);
return WC_TEST_RET_ENC_I(i);
}
@ -35211,6 +35855,22 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test(void)
ret = wc_LmsKey_Verify(&verifyKey, sig, sigSz, (byte *) msg, msgSz);
if (ret != 0) { return WC_TEST_RET_ENC_I(i); }
/* Flip bits in a few places throughout the signature, stepping in multiple
* of hash size. These should all fail with -1. */
for (j = 0; j < (int) sigSz; j+= 4 * 32) {
sig[j] ^= 1;
ret2 = wc_LmsKey_Verify(&verifyKey, sig, sigSz, (byte *) msg,
msgSz);
if (ret2 != -1) {
/* Verify passed when it should have failed. */
return WC_TEST_RET_ENC_I(j);
}
/* Flip this spot back. */
sig[j] ^= 1;
}
}
/* This should be the last signature. */
@ -35243,6 +35903,15 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test(void)
* signature length: 1456
* */
/* "wolfSSL LMS example message!" without null terminator. */
static byte lms_msg[28] =
{
0x77,0x6F,0x6C,0x66,0x53,0x53,0x4C,0x20,
0x4C,0x4D,0x53,0x20,0x65,0x78,0x61,0x6D,
0x70,0x6C,0x65,0x20,0x6D,0x65,0x73,0x73,
0x61,0x67,0x65,0x21
};
static byte lms_L1H10W8_pub[HSS_MAX_PUBLIC_KEY_LEN] =
{
0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x06,
@ -35445,15 +36114,16 @@ static byte lms_L1H10W8_sig[LMS_L1H10W8_SIGLEN] =
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test_verify_only(void)
{
int ret;
LmsKey verifyKey;
word32 sigSz = 0;
const char * msg = "wolfSSL LMS example message!";
word32 msgSz = (word32) XSTRLEN(msg);
word32 pubLen = 0;
int levels = 0;
int height = 0;
int winternitz = 0;
int ret = -1;
int ret2 = -1;
int j = 0;
LmsKey verifyKey;
word32 sigSz = 0;
word32 msgSz = sizeof(lms_msg);
word32 pubLen = 0;
int levels = 0;
int height = 0;
int winternitz = 0;
ret = wc_LmsKey_Init(&verifyKey, NULL, INVALID_DEVID);
if (ret != 0) { return WC_TEST_RET_ENC_EC(ret); }
@ -35492,12 +36162,47 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test_verify_only(void)
}
ret = wc_LmsKey_Verify(&verifyKey, lms_L1H10W8_sig, LMS_L1H10W8_SIGLEN,
(byte *) msg, msgSz);
(byte *) lms_msg, msgSz);
if (ret != 0) {
printf("error: wc_LmsKey_Verify returned %d\n", ret);
return WC_TEST_RET_ENC_EC(ret);
}
/* Flip bits in message. This should fail. */
lms_msg[msgSz / 2] ^= 1;
ret2 = wc_LmsKey_Verify(&verifyKey, lms_L1H10W8_sig, LMS_L1H10W8_SIGLEN,
(byte *) lms_msg, msgSz);
if (ret2 != -1) {
printf("error: wc_LmsKey_Verify returned %d, expected -1\n", ret2);
return WC_TEST_RET_ENC_EC(ret);
}
/* Flip it back. This should pass again. */
lms_msg[msgSz / 2] ^= 1;
ret = wc_LmsKey_Verify(&verifyKey, lms_L1H10W8_sig, LMS_L1H10W8_SIGLEN,
(byte *) lms_msg, msgSz);
if (ret != 0) {
printf("error: wc_LmsKey_Verify returned %d, expected 0\n", ret);
return WC_TEST_RET_ENC_EC(ret);
}
/* Flip bits in a few places throughout the signature, stepping in multiple
* of hash size. These should all fail with -1. */
for (j = 0; j < (int) sigSz; j+= 4 * 32) {
lms_L1H10W8_sig[j] ^= 1;
ret2 = wc_LmsKey_Verify(&verifyKey, lms_L1H10W8_sig,
LMS_L1H10W8_SIGLEN,
(byte *) lms_msg, msgSz);
if (ret2 != -1) {
/* Verify passed when it should have failed. */
return WC_TEST_RET_ENC_I(j);
}
/* Flip this spot back. */
lms_L1H10W8_sig[j] ^= 1;
}
wc_LmsKey_Free(&verifyKey);
return ret;
}

View File

@ -0,0 +1,56 @@
/* ext_xmss.h
*
* Copyright (C) 2006-2023 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 2 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
*/
#ifndef EXT_XMSS_H
#define EXT_XMSS_H
#ifdef WOLFSSL_HAVE_XMSS
#include <wolfssl/wolfcrypt/xmss.h>
#if !defined(HAVE_LIBXMSS)
#error "This code requires libxmss"
#endif
#include <xmss.h>
#include <params.h>
#if defined(WOLFSSL_WC_XMSS)
#error "This code is incompatible with wolfCrypt's implementation of XMSS."
#endif
struct XmssKey {
unsigned char pk[XMSS_SHA256_PUBLEN];
uint32_t oid;
int is_xmssmt;
xmss_params params;
#ifndef WOLFSSL_XMSS_VERIFY_ONLY
/* The secret key length is a function of xmss_params. */
unsigned char * sk;
word32 sk_len;
write_private_key_cb write_private_key; /* Callback to write/update key. */
read_private_key_cb read_private_key; /* Callback to read key. */
void * context; /* Context arg passed to callbacks. */
#endif /* ifndef WOLFSSL_XMSS_VERIFY_ONLY */
enum wc_XmssState state;
};
#endif /* WOLFSSL_HAVE_XMSS */
#endif /* EXT_XMSS_H */

View File

@ -81,7 +81,10 @@ nobase_include_HEADERS+= \
wolfssl/wolfcrypt/sm4.h \
wolfssl/wolfcrypt/lms.h \
wolfssl/wolfcrypt/wc_lms.h \
wolfssl/wolfcrypt/ext_lms.h
wolfssl/wolfcrypt/ext_lms.h \
wolfssl/wolfcrypt/xmss.h \
wolfssl/wolfcrypt/wc_xmss.h \
wolfssl/wolfcrypt/ext_xmss.h
noinst_HEADERS+= \
wolfssl/wolfcrypt/port/aria/aria-crypt.h \

View File

@ -0,0 +1,23 @@
/* wc_xmss.h
*
* Copyright (C) 2006-2023 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 2 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
*/
#error "Contact wolfSSL to get the implementation of this file"

View File

@ -0,0 +1,153 @@
/* xmss.h
*
* Copyright (C) 2006-2023 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 2 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
*/
/*!
\file wolfssl/wolfcrypt/xmss.h
*/
#ifndef WOLF_CRYPT_XMSS_H
#define WOLF_CRYPT_XMSS_H
#include <wolfssl/wolfcrypt/types.h>
#include <wolfssl/wolfcrypt/random.h>
#ifdef WOLFSSL_HAVE_XMSS
/* Note on XMSS/XMSS^MT pub/priv key sizes:
* - The XMSS/XMSS^MT pub key has a defined format and size.
* - The XMSS/XMSS^MT private key is implementation and parameter
* specific. It does not have a standardized format or size.
*
* The XMSS/XMSS^MT public and secret key format and length is:
* PK = OID || root || SEED;
* PK_len = 4 + 2 * n
*
* SK = OID || (implementation defined)
* SK_len = 4 + (implementation defined)
*
* where n is the number of bytes in the hash function, which is 32
* in this SHA256 implementation.
*
* However the private key is implementation specific. For example,
* in xmss-reference the private key size varies from 137 bytes to
* 1377 bytes between slow and fast implementations with param name
* "XMSSMT-SHA2_20/2_256".
*
* References:
* - RFC 8391
* - Table 2 of Kampanakis, Fluhrer, IACR, 2017.
* */
#define XMSS_SHA256_PUBLEN (68)
/* Supported XMSS/XMSS^MT parameter set names:
* We are supporting all SHA256 parameter sets with n=32 and
* Winternitz=16, from RFC 8391 and NIST SP 800-208.
*
* ----------------------------------------------------------
* | Name Oid n w len h d |
* XMSS: | "XMSS-SHA2_10_256" 0x00000001 32 16 67 10 1 |
* | "XMSS-SHA2_16_256" 0x00000002 32 16 67 16 1 |
* | "XMSS-SHA2_20_256" 0x00000003 32 16 67 20 1 |
* | |
* XMSSMT: | "XMSSMT-SHA2_20/2_256" 0x00000001 32 16 67 20 2 |
* | "XMSSMT-SHA2_20/4_256" 0x00000002 32 16 67 20 4 |
* | "XMSSMT-SHA2_40/2_256" 0x00000003 32 16 67 40 2 |
* | "XMSSMT-SHA2_40/4_256" 0x00000004 32 16 67 40 4 |
* | "XMSSMT-SHA2_40/8_256" 0x00000005 32 16 67 40 8 |
* | "XMSSMT-SHA2_60/3_256" 0x00000006 32 16 67 60 3 |
* | "XMSSMT-SHA2_60/6_256" 0x00000007 32 16 67 60 6 |
* | "XMSSMT-SHA2_60/12_256" 0x00000008 32 16 67 60 12 |
* ----------------------------------------------------------
*
* Note that some XMSS and XMSSMT names do have overlapping Oids.
*
* References:
* 1. NIST SP 800-208
* 2. RFC 8391
* */
#define XMSS_NAME_LEN (16) /* strlen("XMSS-SHA2_10_256") */
#define XMSSMT_NAME_MIN_LEN (20) /* strlen("XMSSMT-SHA2_20/2_256") */
#define XMSSMT_NAME_MAX_LEN (21) /* strlen("XMSSMT-SHA2_60/12_256") */
typedef struct XmssKey XmssKey;
/* Private key write and read callbacks. */
typedef int (*write_private_key_cb)(const byte * priv, word32 privSz, void *context);
typedef int (*read_private_key_cb)(byte * priv, word32 privSz, void *context);
/* Return codes returned by private key callbacks. */
enum wc_XmssRc {
WC_XMSS_RC_NONE,
WC_XMSS_RC_BAD_ARG, /* Bad arg in read or write callback. */
WC_XMSS_RC_WRITE_FAIL, /* Write or update private key failed. */
WC_XMSS_RC_READ_FAIL, /* Read private key failed. */
WC_XMSS_RC_SAVED_TO_NV_MEMORY, /* Wrote private key to nonvolatile storage. */
WC_XMSS_RC_READ_TO_MEMORY /* Read private key from storage. */
};
/* enum wc_XmssState is to help track the state of an XMSS Key. */
enum wc_XmssState {
WC_XMSS_STATE_FREED, /* Key has been freed from memory. */
WC_XMSS_STATE_INITED, /* Key has been inited, ready to set parms.*/
WC_XMSS_STATE_PARMSET, /* Parms are set, ready to MakeKey or Reload. */
WC_XMSS_STATE_OK, /* Able to sign signatures and verify. */
WC_XMSS_STATE_VERIFYONLY, /* A public only XmssKey. */
WC_XMSS_STATE_BAD, /* Can't guarantee key's state. */
WC_XMSS_STATE_NOSIGS /* Signatures exhausted. */
};
#ifdef __cplusplus
extern "C" {
#endif
WOLFSSL_API int wc_XmssKey_Init(XmssKey * key, void * heap, int devId);
WOLFSSL_API int wc_XmssKey_SetParamStr(XmssKey * key, const char * str);
#ifndef WOLFSSL_XMSS_VERIFY_ONLY
WOLFSSL_API int wc_XmssKey_SetWriteCb(XmssKey * key,
write_private_key_cb write_cb);
WOLFSSL_API int wc_XmssKey_SetReadCb(XmssKey * key,
read_private_key_cb read_cb);
WOLFSSL_API int wc_XmssKey_SetContext(XmssKey * key, void * context);
WOLFSSL_API int wc_XmssKey_MakeKey(XmssKey * key, WC_RNG * rng);
WOLFSSL_API int wc_XmssKey_Reload(XmssKey * key);
WOLFSSL_API int wc_XmssKey_GetPrivLen(const XmssKey * key, word32 * len);
WOLFSSL_API int wc_XmssKey_Sign(XmssKey * key, byte * sig, word32 * sigSz,
const byte * msg, int msgSz);
WOLFSSL_API int wc_XmssKey_SigsLeft(XmssKey * key);
#endif /* ifndef WOLFSSL_XMSS_VERIFY_ONLY */
WOLFSSL_API void wc_XmssKey_Free(XmssKey * key);
WOLFSSL_API int wc_XmssKey_GetSigLen(const XmssKey * key, word32 * len);
WOLFSSL_API int wc_XmssKey_GetPubLen(const XmssKey * key, word32 * len);
WOLFSSL_API int wc_XmssKey_ExportPub(XmssKey * keyDst, const XmssKey * keySrc);
WOLFSSL_API int wc_XmssKey_ExportPubRaw(const XmssKey * key, byte * out,
word32 * outLen);
WOLFSSL_API int wc_XmssKey_ImportPubRaw(XmssKey * key, const byte * in,
word32 inLen);
WOLFSSL_API int wc_XmssKey_Verify(XmssKey * key, const byte * sig, word32 sigSz,
const byte * msg, int msgSz);
WOLFSSL_API const char * wc_XmssKey_RcToStr(enum wc_XmssRc lmsRc);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* WOLFSSL_HAVE_XMSS */
#endif /* WOLF_CRYPT_XMSS_H */