From c4960344352e502dc965fbd8ea0e3f0887b7538d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Wed, 15 Jul 2026 12:03:29 +0200 Subject: [PATCH] Add verify-only LMS/HSS and XMSS/XMSS^MT support (RFC 8554 / RFC 8391) Add PKCS#11 verify-only support for the stateful hash-based signature schemes LMS/HSS (RFC 8554) and XMSS/XMSS^MT (RFC 8391), backed by wolfSSL and gated behind the --enable-lms and --enable-xmss build options. Interface: - Key types CKK_HSS, CKK_XMSS, CKK_XMSSMT and mechanisms CKM_HSS, CKM_XMSS, CKM_XMSSMT, using the OASIS PKCS#11 v3.3 standard constant values (not vendor-defined). - Public keys are imported as ordinary token or session objects from the raw RFC 8554 / RFC 8391 public key in CKA_VALUE. wolfSSL derives the parameter set from the key bytes; supplied CKA_HSS_* parameter attributes and the XMSS CKA_PARAMETER_SET OID are validated against the key, and a mismatch is rejected with CKR_ATTRIBUTE_VALUE_INVALID. - HSS parameter attributes (CKA_HSS_LEVELS, CKA_HSS_LMS_TYPE(S), CKA_HSS_LMOTS_TYPE(S)) and the XMSS CKA_PARAMETER_SET are exposed on read. CKA_HSS_KEYS_REMAINING is a private-key state property and is reported as unavailable in a verify-only build. - C_Verify checks the mechanism against the key type, and reports a wrong-length signature or an empty message (for XMSS) as an invalid signature rather than a function failure. Constraints (verify-only): - Key generation (CKM_*_KEY_PAIR_GEN) and private-key import are rejected. Copying any HBS key is prohibited so that future sign-capable builds can never duplicate one-time-signature state. Persistence: - Public keys are stored and reloaded from disk via the new store types WOLFPKCS11_STORE_HSSKEY_PUB (0x11) and WOLFPKCS11_STORE_XMSSKEY_PUB (0x13), with 0x10 and 0x12 reserved for future private keys. Tests: - Known-answer verification, parameter-set validation, token-object persistence across a library reload, and negative cases covering private-key import, wrong mechanism/key-type pairings, and malformed, wrong-length, and structurally invalid public keys. --- .github/workflows/build-workflow.yml | 2 +- .github/workflows/cmake.yml | 4 +- .github/workflows/unit-test.yml | 16 + CMakeLists.txt | 57 ++ cmake/options.h.in | 4 + configure.ac | 61 ++ src/crypto.c | 207 +++++- src/internal.c | 961 +++++++++++++++++++++++++++ src/slot.c | 32 + tests/hbs_kat.h | 670 +++++++++++++++++++ tests/hbs_persistence_test.c | 463 +++++++++++++ tests/include.am | 8 + tests/pkcs11v3test.c | 943 +++++++++++++++++++++++++- wolfpkcs11/internal.h | 37 ++ wolfpkcs11/pkcs11.h | 44 ++ wolfpkcs11/store.h | 6 + 16 files changed, 3498 insertions(+), 17 deletions(-) create mode 100644 tests/hbs_kat.h create mode 100644 tests/hbs_persistence_test.c diff --git a/.github/workflows/build-workflow.yml b/.github/workflows/build-workflow.yml index 02661a4d..675661bf 100644 --- a/.github/workflows/build-workflow.yml +++ b/.github/workflows/build-workflow.yml @@ -36,7 +36,7 @@ jobs: working-directory: ./wolfssl run: | ./configure --enable-cryptocb --enable-aescfb --enable-rsapss --enable-keygen --enable-pwdbased --enable-scrypt --enable-md5 \ - --enable-mldsa C_EXTRA_FLAGS="-DWOLFSSL_PUBLIC_MP -DWC_RSA_DIRECT -DHAVE_AES_ECB -DHAVE_AES_KEYWRAP" + --enable-mldsa --enable-lms --enable-xmss C_EXTRA_FLAGS="-DWOLFSSL_PUBLIC_MP -DWC_RSA_DIRECT -DHAVE_AES_ECB -DHAVE_AES_KEYWRAP" - name: wolfssl make install working-directory: ./wolfssl run: make diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 89324407..e8c73717 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -45,7 +45,8 @@ jobs: -DWOLFSSL_SHA:BOOL=yes -DWOLFSSL_SHA224:BOOL=yes -DWOLFSSL_SHA3:STRING=yes -DWOLFSSL_SHA384:BOOL=yes \ -DWOLFSSL_SHA512:BOOL=yes -DWOLFSSL_SHAKE128:STRING=yes -DWOLFSSL_SHAKE256:STRING=yes \ -DWOLFSSL_SP_MATH_ALL:BOOL=yes -DWOLFSSL_X86_64_BUILD_ASM:BOOL=yes -DWOLFSSL_MLKEM=1 \ - -DWOLFSSL_LMS=1 -DWOLFSSL_LMSSHA256192=1 -DWOLFSSL_DILITHIUM:BOOL=yes -DWOLFSSL_PUBLIC_MP:BOOL=yes \ + -DWOLFSSL_LMS=1 -DWOLFSSL_LMSSHA256192=1 -DWOLFSSL_XMSS=1 \ + -DWOLFSSL_DILITHIUM:BOOL=yes -DWOLFSSL_PUBLIC_MP:BOOL=yes \ -DWOLFSSL_WC_RSA_DIRECT:BOOL=yes -DCMAKE_BUILD_TYPE=Release \ .. cmake --build . @@ -64,6 +65,7 @@ jobs: -DWOLFPKCS11_AESECB:BOOL=yes -DWOLFPKCS11_AESCTS:BOOL=yes -DWOLFPKCS11_AESCMAC:BOOL=yes \ -DWOLFPKCS11_PBKDF2:BOOL=yes -DWOLFPKCS11_SHA3:BOOL=yes -DWOLFPKCS11_PKCS11_V3_0:BOOL=yes \ -DWOLFPKCS11_PKCS11_V3_2:BOOL=yes -DWOLFPKCS11_MLDSA:BOOL=yes -DWOLFPKCS11_MLKEM:BOOL=yes \ + -DWOLFPKCS11_LMS:BOOL=yes -DWOLFPKCS11_XMSS:BOOL=yes \ -DCMAKE_MODULE_PATH="$GITHUB_WORKSPACE/install/${CMAKE_INSTALL_LIBDIR}" \ .. cmake --build . diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index df6ccaee..8cfcb303 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -110,6 +110,22 @@ jobs: uses: ./.github/workflows/build-workflow.yml with: config: --enable-mlkem + lms: + uses: ./.github/workflows/build-workflow.yml + with: + config: --enable-lms + xmss: + uses: ./.github/workflows/build-workflow.yml + with: + config: --enable-xmss + lms_xmss: + uses: ./.github/workflows/build-workflow.yml + with: + config: --enable-lms --enable-xmss + lms_xmss_static: + uses: ./.github/workflows/build-workflow.yml + with: + config: --enable-lms --enable-xmss --disable-shared debug: uses: ./.github/workflows/build-workflow.yml with: diff --git a/CMakeLists.txt b/CMakeLists.txt index 0dc93e23..bf4ada64 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -509,6 +509,54 @@ if(WOLFPKCS11_MLKEM) list(APPEND WOLFPKCS11_DEFINITIONS "-DWOLFPKCS11_MLKEM") endif() +# LMS/HSS (RFC 8554) verify + public-key import (default: disabled) +add_option("WOLFPKCS11_LMS" + "Enable wolfPKCS11 LMS/HSS verification and public-key import (default: disabled)" + "no" "yes;no" +) + +if(WOLFPKCS11_LMS AND NOT WOLFPKCS11_SHA256) + message(STATUS "LMS/HSS requires SHA-256 support (disabled); disabling WOLFPKCS11_LMS") + override_cache(WOLFPKCS11_LMS "no") +endif() + +if(WOLFPKCS11_LMS) + if(NOT WOLFPKCS11_PKCS11_V3_2) + message(STATUS "LMS/HSS requires PKCS#11 v3.2 support — enabling WOLFPKCS11_PKCS11_V3_2 automatically") + override_cache(WOLFPKCS11_PKCS11_V3_2 "yes") + if(NOT WOLFPKCS11_PKCS11_V3_0) + override_cache(WOLFPKCS11_PKCS11_V3_0 "yes") + list(APPEND WOLFPKCS11_DEFINITIONS "-DWOLFPKCS11_PKCS11_V3_0") + endif() + list(APPEND WOLFPKCS11_DEFINITIONS "-DWOLFPKCS11_PKCS11_V3_2") + endif() + list(APPEND WOLFPKCS11_DEFINITIONS "-DWOLFPKCS11_LMS") +endif() + +# XMSS/XMSS^MT (RFC 8391) verify + public-key import (default: disabled) +add_option("WOLFPKCS11_XMSS" + "Enable wolfPKCS11 XMSS/XMSS^MT verification and public-key import (default: disabled)" + "no" "yes;no" +) + +if(WOLFPKCS11_XMSS AND NOT WOLFPKCS11_SHA256) + message(STATUS "XMSS requires SHA-256 support (disabled); disabling WOLFPKCS11_XMSS") + override_cache(WOLFPKCS11_XMSS "no") +endif() + +if(WOLFPKCS11_XMSS) + if(NOT WOLFPKCS11_PKCS11_V3_2) + message(STATUS "XMSS requires PKCS#11 v3.2 support — enabling WOLFPKCS11_PKCS11_V3_2 automatically") + override_cache(WOLFPKCS11_PKCS11_V3_2 "yes") + if(NOT WOLFPKCS11_PKCS11_V3_0) + override_cache(WOLFPKCS11_PKCS11_V3_0 "yes") + list(APPEND WOLFPKCS11_DEFINITIONS "-DWOLFPKCS11_PKCS11_V3_0") + endif() + list(APPEND WOLFPKCS11_DEFINITIONS "-DWOLFPKCS11_PKCS11_V3_2") + endif() + list(APPEND WOLFPKCS11_DEFINITIONS "-DWOLFPKCS11_XMSS") +endif() + # If wolfpkcs11/options.h exists, delete it to avoid # a mixup with build/wolfpkcs11/options.h. @@ -728,6 +776,15 @@ if(WOLFPKCS11_TESTS) add_wpkcs11_test(${test_target} ${CMAKE_CURRENT_SOURCE_DIR}/tests/${test_target}.c) endforeach() + + # HBS (LMS/HSS, XMSS/XMSS^MT) public-key persistence test. Only built when + # the feature is enabled; the test exits 77 (skip) when no token store is + # available, so treat that as a skip rather than a failure. + if(WOLFPKCS11_LMS OR WOLFPKCS11_XMSS) + add_wpkcs11_test(hbs_persistence_test + ${CMAKE_CURRENT_SOURCE_DIR}/tests/hbs_persistence_test.c) + set_tests_properties(hbs_persistence_test PROPERTIES SKIP_RETURN_CODE 77) + endif() endif() if(WOLFPKCS11_EXAMPLES) diff --git a/cmake/options.h.in b/cmake/options.h.in index 85137980..594bcdb3 100644 --- a/cmake/options.h.in +++ b/cmake/options.h.in @@ -96,6 +96,10 @@ extern "C" { #cmakedefine WOLFPKCS11_MLDSA #undef WOLFPKCS11_MLKEM #cmakedefine WOLFPKCS11_MLKEM +#undef WOLFPKCS11_LMS +#cmakedefine WOLFPKCS11_LMS +#undef WOLFPKCS11_XMSS +#cmakedefine WOLFPKCS11_XMSS #undef WOLFPKCS11_TPM #cmakedefine WOLFPKCS11_TPM #undef WOLFPKCS11_NSS diff --git a/configure.ac b/configure.ac index ae5bfb2e..2ef69ffa 100644 --- a/configure.ac +++ b/configure.ac @@ -566,6 +566,65 @@ then AM_CFLAGS="$AM_CFLAGS -DWOLFPKCS11_MLKEM" fi +# LMS/HSS (RFC 8554) verification and public-key import. Requires wolfSSL +# built with --enable-lms (WOLFSSL_HAVE_LMS). Sign/keygen are a separate, +# later feature; this flag provides verify + public-key import only. +AC_ARG_ENABLE([lms], + [AS_HELP_STRING([--enable-lms],[Enable LMS/HSS verification and public-key import (default: disabled)])], + [ ENABLED_LMS=$enableval ], + [ ENABLED_LMS=no ] + ) + +if test "$ENABLED_SHA256" = "no" +then + if test "$ENABLED_LMS" = "yes"; then + echo "LMS/HSS requires SHA-256 support (disabled), disabling LMS/HSS" + fi + ENABLED_LMS=no +fi + +if test "$ENABLED_LMS" = "yes" +then + if test "$ENABLED_PKCS11V3_2" = "no"; then + ENABLED_PKCS11V3_2=yes + AM_CFLAGS="$AM_CFLAGS -DWOLFPKCS11_PKCS11_V3_2" + if test "$ENABLED_PKCS11V3_0" = "no"; then + ENABLED_PKCS11V3_0=yes + AM_CFLAGS="$AM_CFLAGS -DWOLFPKCS11_PKCS11_V3_0" + fi + fi + AM_CFLAGS="$AM_CFLAGS -DWOLFPKCS11_LMS" +fi + +# XMSS/XMSS^MT (RFC 8391) verification and public-key import. Requires wolfSSL +# built with --enable-xmss (WOLFSSL_HAVE_XMSS). Verify + public-key import only. +AC_ARG_ENABLE([xmss], + [AS_HELP_STRING([--enable-xmss],[Enable XMSS/XMSS^MT verification and public-key import (default: disabled)])], + [ ENABLED_XMSS=$enableval ], + [ ENABLED_XMSS=no ] + ) + +if test "$ENABLED_SHA256" = "no" +then + if test "$ENABLED_XMSS" = "yes"; then + echo "XMSS requires SHA-256 support (disabled), disabling XMSS" + fi + ENABLED_XMSS=no +fi + +if test "$ENABLED_XMSS" = "yes" +then + if test "$ENABLED_PKCS11V3_2" = "no"; then + ENABLED_PKCS11V3_2=yes + AM_CFLAGS="$AM_CFLAGS -DWOLFPKCS11_PKCS11_V3_2" + if test "$ENABLED_PKCS11V3_0" = "no"; then + ENABLED_PKCS11V3_0=yes + AM_CFLAGS="$AM_CFLAGS -DWOLFPKCS11_PKCS11_V3_0" + fi + fi + AM_CFLAGS="$AM_CFLAGS -DWOLFPKCS11_XMSS" +fi + AM_CONDITIONAL([BUILD_STATIC],[test "x$enable_shared" = "xno"]) @@ -755,6 +814,8 @@ echo " * ECC: $ENABLED_ECC" echo " * HKDF: $ENABLED_HKDF" echo " * ML-DSA: $ENABLED_MLDSA" echo " * ML-KEM: $ENABLED_MLKEM" +echo " * LMS/HSS verify: $ENABLED_LMS" +echo " * XMSS/XMSS^MT verify: $ENABLED_XMSS" echo " * NSS modifications: $ENABLED_NSS" echo " * Default token path: $WOLFPKCS11_DEFAULT_TOKEN_PATH" echo " * PKCS#11 Version 3.0: $ENABLED_PKCS11V3_0" diff --git a/src/crypto.c b/src/crypto.c index b4ce9c9e..5a4b808e 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -145,6 +145,31 @@ static CK_ATTRIBUTE_TYPE mlKemKeyParams[] = { #define MLKEM_KEY_PARAMS_CNT (sizeof(mlKemKeyParams)/sizeof(*mlKemKeyParams)) #endif +#ifdef WOLFPKCS11_LMS +/* HSS public-key attributes (PKCS#11 v3.3 HSS profile). data[0..2] are the + * optional CK_ULONG parameters CKA_HSS_LEVELS, CKA_HSS_LMS_TYPE and + * CKA_HSS_LMOTS_TYPE (validated against the key when supplied; otherwise + * self-derived from it); data[3] = raw RFC 8554 public key. */ +static CK_ATTRIBUTE_TYPE hssKeyParams[] = { + CKA_HSS_LEVELS, + CKA_HSS_LMS_TYPE, + CKA_HSS_LMOTS_TYPE, + CKA_VALUE +}; +#define HSS_KEY_PARAMS_CNT (sizeof(hssKeyParams)/sizeof(*hssKeyParams)) +#endif + +#ifdef WOLFPKCS11_XMSS +/* XMSS/XMSS^MT key data attributes. data[0] = optional CKA_PARAMETER_SET + * (the OID as a CK_ULONG; when supplied it is validated against the OID in the + * public key and a mismatch is rejected), data[1] = raw XMSS public key. */ +static CK_ATTRIBUTE_TYPE xmssKeyParams[] = { + CKA_PARAMETER_SET, + CKA_VALUE +}; +#define XMSS_KEY_PARAMS_CNT (sizeof(xmssKeyParams)/sizeof(*xmssKeyParams)) +#endif + /* Secret key data attributes. */ static CK_ATTRIBUTE_TYPE secretKeyParams[] = { CKA_VALUE_LEN, @@ -184,16 +209,51 @@ static CK_ATTRIBUTE_TYPE trustParams[] = { #define TRUST_PARAMS_CNT (sizeof(trustParams)/sizeof(*trustParams)) #endif -/* Identify maximum count for stack array. */ -#ifndef NO_RSA -#define OBJ_MAX_PARAMS RSA_KEY_PARAMS_CNT -#elif defined(HAVE_ECC) -#define OBJ_MAX_PARAMS EC_KEY_PARAMS_CNT -#elif !defined(NO_DH) -#define OBJ_MAX_PARAMS DH_KEY_PARAMS_CNT -#else -#define OBJ_MAX_PARAMS SECRET_KEY_PARAMS_CNT +/* The SetAttributeValue stack arrays data[]/len[] must hold the largest + * attribute set of any enabled key or object type (see the cnt assignments in + * SetAttributeValue). Default the optional counts to zero so the maximum below + * is well defined in every build: a token with RSA disabled but LMS enabled + * still needs room for the four HSS slots, for example. */ +#ifndef RSA_KEY_PARAMS_CNT +#define RSA_KEY_PARAMS_CNT 0 +#endif +#ifndef EC_KEY_PARAMS_CNT +#define EC_KEY_PARAMS_CNT 0 +#endif +#ifndef MLDSA_KEY_PARAMS_CNT +#define MLDSA_KEY_PARAMS_CNT 0 +#endif +#ifndef DH_KEY_PARAMS_CNT +#define DH_KEY_PARAMS_CNT 0 +#endif +#ifndef MLKEM_KEY_PARAMS_CNT +#define MLKEM_KEY_PARAMS_CNT 0 +#endif +#ifndef HSS_KEY_PARAMS_CNT +#define HSS_KEY_PARAMS_CNT 0 +#endif +#ifndef XMSS_KEY_PARAMS_CNT +#define XMSS_KEY_PARAMS_CNT 0 #endif +#ifndef TRUST_PARAMS_CNT +#define TRUST_PARAMS_CNT 0 +#endif + +/* Compile-time maximum of two attribute counts. */ +#define WP11_PARAMS_MAX(a, b) ((a) > (b) ? (a) : (b)) + +/* Identify maximum count for stack array. */ +#define OBJ_MAX_PARAMS \ + WP11_PARAMS_MAX(RSA_KEY_PARAMS_CNT, \ + WP11_PARAMS_MAX(EC_KEY_PARAMS_CNT, \ + WP11_PARAMS_MAX(MLDSA_KEY_PARAMS_CNT, \ + WP11_PARAMS_MAX(DH_KEY_PARAMS_CNT, \ + WP11_PARAMS_MAX(MLKEM_KEY_PARAMS_CNT, \ + WP11_PARAMS_MAX(HSS_KEY_PARAMS_CNT, \ + WP11_PARAMS_MAX(XMSS_KEY_PARAMS_CNT, \ + WP11_PARAMS_MAX(SECRET_KEY_PARAMS_CNT, \ + WP11_PARAMS_MAX(DATA_PARAMS_CNT, \ + WP11_PARAMS_MAX(CERT_PARAMS_CNT, TRUST_PARAMS_CNT)))))))))) typedef struct AttributeType { CK_ATTRIBUTE_TYPE attr; /* Crypto-Ki attribute */ @@ -275,6 +335,12 @@ static AttributeType attrType[] = { { CKA_SEED, ATTR_TYPE_DATA }, { CKA_ENCAPSULATE, ATTR_TYPE_BOOL }, { CKA_DECAPSULATE, ATTR_TYPE_BOOL }, + { CKA_HSS_LEVELS, ATTR_TYPE_ULONG }, + { CKA_HSS_LMS_TYPE, ATTR_TYPE_ULONG }, + { CKA_HSS_LMOTS_TYPE, ATTR_TYPE_ULONG }, + { CKA_HSS_LMS_TYPES, ATTR_TYPE_DATA }, + { CKA_HSS_LMOTS_TYPES, ATTR_TYPE_DATA }, + { CKA_HSS_KEYS_REMAINING, ATTR_TYPE_ULONG }, #ifdef WOLFPKCS11_NSS { CKA_CERT_SHA1_HASH, ATTR_TYPE_DATA }, { CKA_CERT_MD5_HASH, ATTR_TYPE_DATA }, @@ -891,6 +957,19 @@ static CK_RV SetAttributeValue(WP11_Session* session, WP11_Object* obj, cnt = MLKEM_KEY_PARAMS_CNT; break; #endif + #ifdef WOLFPKCS11_LMS + case CKK_HSS: + attrs = hssKeyParams; + cnt = HSS_KEY_PARAMS_CNT; + break; + #endif + #ifdef WOLFPKCS11_XMSS + case CKK_XMSS: + case CKK_XMSSMT: + attrs = xmssKeyParams; + cnt = XMSS_KEY_PARAMS_CNT; + break; + #endif #ifdef WOLFPKCS11_HKDF case CKK_HKDF: #endif @@ -965,6 +1044,31 @@ static CK_RV SetAttributeValue(WP11_Session* session, WP11_Object* obj, ret = WP11_Object_SetMlKemKey(obj, data, len); break; #endif + #ifdef WOLFPKCS11_LMS + case CKK_HSS: + ret = WP11_Object_SetHssKey(obj, data, len); + /* Importing parses the caller-supplied public key, so any + * failure other than out-of-memory means the CKA_VALUE or a + * parameter attribute is bad (wrong length, unknown LMS/LMOTS + * type, unparsable header), not an internal fault. MEMORY_E + * falls through to CKR_DEVICE_MEMORY below. */ + if (ret != 0 && ret != MEMORY_E) { + return CKR_ATTRIBUTE_VALUE_INVALID; + } + break; + #endif + #ifdef WOLFPKCS11_XMSS + case CKK_XMSS: + case CKK_XMSSMT: + ret = WP11_Object_SetXmssKey(obj, data, len); + /* As for HSS: any non-memory import failure is a bad + * attribute value (truncated key, unknown/invalid OID, + * unparsable header), not an internal fault. */ + if (ret != 0 && ret != MEMORY_E) { + return CKR_ATTRIBUTE_VALUE_INVALID; + } + break; + #endif #ifndef NO_AES case CKK_AES: #endif @@ -1371,10 +1475,40 @@ static CK_RV CreateObject(WP11_Session* session, CK_ATTRIBUTE_PTR pTemplate, return CKR_ATTRIBUTE_VALUE_INVALID; objType = *(CK_ULONG*)attr->pValue; - if (objType != CKK_RSA && objType != CKK_EC && objType != CKK_DH && - objType != CKK_AES && objType != CKK_HKDF && - objType != CKK_GENERIC_SECRET && objType != CKK_ML_DSA && - objType != CKK_ML_KEM) { + /* Only accept key types whose feature is compiled in. CKA_KEY_TYPE for + * a disabled type is rejected here with CKR_ATTRIBUTE_VALUE_INVALID + * rather than reaching the SetAttributeValue key-type switch and + * returning the less appropriate CKR_OBJECT_HANDLE_INVALID. The guards + * mirror that switch. CKK_GENERIC_SECRET is always available. */ + if (objType != CKK_GENERIC_SECRET + #ifndef NO_RSA + && objType != CKK_RSA + #endif + #ifdef HAVE_ECC + && objType != CKK_EC + #endif + #ifndef NO_DH + && objType != CKK_DH + #endif + #ifndef NO_AES + && objType != CKK_AES + #endif + #ifdef WOLFPKCS11_HKDF + && objType != CKK_HKDF + #endif + #ifdef WOLFPKCS11_MLDSA + && objType != CKK_ML_DSA + #endif + #ifdef WOLFPKCS11_MLKEM + && objType != CKK_ML_KEM + #endif + #ifdef WOLFPKCS11_LMS + && objType != CKK_HSS + #endif + #ifdef WOLFPKCS11_XMSS + && objType != CKK_XMSS && objType != CKK_XMSSMT + #endif + ) { return CKR_ATTRIBUTE_VALUE_INVALID; } } @@ -6021,6 +6155,34 @@ CK_RV C_VerifyInit(CK_SESSION_HANDLE hSession, init |= WP11_INIT_MLDSA_VERIFY; break; #endif +#ifdef WOLFPKCS11_LMS + case CKM_HSS: + if (type != CKK_HSS) + return CKR_KEY_TYPE_INCONSISTENT; + if (pMechanism->pParameter != NULL || + pMechanism->ulParameterLen != 0) + return CKR_MECHANISM_PARAM_INVALID; + init |= WP11_INIT_HSS_VERIFY; + break; +#endif +#ifdef WOLFPKCS11_XMSS + case CKM_XMSS: + if (type != CKK_XMSS) + return CKR_KEY_TYPE_INCONSISTENT; + if (pMechanism->pParameter != NULL || + pMechanism->ulParameterLen != 0) + return CKR_MECHANISM_PARAM_INVALID; + init |= WP11_INIT_XMSS_VERIFY; + break; + case CKM_XMSSMT: + if (type != CKK_XMSSMT) + return CKR_KEY_TYPE_INCONSISTENT; + if (pMechanism->pParameter != NULL || + pMechanism->ulParameterLen != 0) + return CKR_MECHANISM_PARAM_INVALID; + init |= WP11_INIT_XMSS_VERIFY; + break; +#endif #ifndef NO_HMAC #ifndef NO_MD5 case CKM_MD5_HMAC: @@ -6354,6 +6516,25 @@ CK_RV C_Verify(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, (int)ulDataLen, &stat, obj, session); break; #endif +#ifdef WOLFPKCS11_LMS + case CKM_HSS: + if (!WP11_Session_IsOpInitialized(session, WP11_INIT_HSS_VERIFY)) + return CKR_OPERATION_NOT_INITIALIZED; + + ret = WP11_Hss_Verify(pSignature, (word32)ulSignatureLen, pData, + (word32)ulDataLen, &stat, obj); + break; +#endif +#ifdef WOLFPKCS11_XMSS + case CKM_XMSS: + case CKM_XMSSMT: + if (!WP11_Session_IsOpInitialized(session, WP11_INIT_XMSS_VERIFY)) + return CKR_OPERATION_NOT_INITIALIZED; + + ret = WP11_Xmss_Verify(pSignature, (word32)ulSignatureLen, pData, + (word32)ulDataLen, &stat, obj); + break; +#endif #ifndef NO_HMAC #ifndef NO_MD5 case CKM_MD5_HMAC: diff --git a/src/internal.c b/src/internal.c index dad45296..a35ec84f 100644 --- a/src/internal.c +++ b/src/internal.c @@ -265,6 +265,12 @@ struct WP11_Object { #endif #ifdef WOLFPKCS11_MLKEM MlKemKey* mlKemKey; /* ML-KEM key object */ + #endif + #ifdef WOLFPKCS11_LMS + LmsKey* lmsKey; /* LMS/HSS key object (verify) */ + #endif + #ifdef WOLFPKCS11_XMSS + XmssKey* xmssKey; /* XMSS/XMSS^MT key object (verify) */ #endif WP11_Data* symmKey; /* Symmetric key object */ WP11_GenericData genericData; /* Generic data object */ @@ -1477,6 +1483,18 @@ static int wolfPKCS11_Store_Name(int type, CK_ULONG id1, CK_ULONG id2, char* nam str, id1, id2); break; #endif +#ifdef WOLFPKCS11_LMS + case WOLFPKCS11_STORE_HSSKEY_PUB: + ret = XSNPRINTF(name, nameLen, "%s/wp11_hsskey_pub_%016lx_%016lx", + str, id1, id2); + break; +#endif +#ifdef WOLFPKCS11_XMSS + case WOLFPKCS11_STORE_XMSSKEY_PUB: + ret = XSNPRINTF(name, nameLen, "%s/wp11_xmsskey_pub_%016lx_%016lx", + str, id1, id2); + break; +#endif default: ret = -1; @@ -2575,6 +2593,35 @@ int wp11_Object_AllocateTypeData(WP11_Object* object) } break; #endif + #ifdef WOLFPKCS11_LMS + case CKK_HSS: + if (object->data.lmsKey == NULL) { + object->data.lmsKey = (LmsKey*)XMALLOC( + sizeof(LmsKey), NULL, DYNAMIC_TYPE_KEY); + if (object->data.lmsKey == NULL) { + ret = MEMORY_E; + } + else { + XMEMSET(object->data.lmsKey, 0, sizeof(LmsKey)); + } + } + break; + #endif + #ifdef WOLFPKCS11_XMSS + case CKK_XMSS: + case CKK_XMSSMT: + if (object->data.xmssKey == NULL) { + object->data.xmssKey = (XmssKey*)XMALLOC( + sizeof(XmssKey), NULL, DYNAMIC_TYPE_KEY); + if (object->data.xmssKey == NULL) { + ret = MEMORY_E; + } + else { + XMEMSET(object->data.xmssKey, 0, sizeof(XmssKey)); + } + } + break; + #endif #ifndef NO_DH case CKK_DH: if (object->data.dhKey == NULL) { @@ -3057,6 +3104,21 @@ int WP11_Object_Copy(WP11_Object *src, WP11_Object *dest) case CKK_DH: return BAD_FUNC_ARG; #endif +#ifdef WOLFPKCS11_LMS + case CKK_HSS: +#endif +#ifdef WOLFPKCS11_XMSS + case CKK_XMSS: + case CKK_XMSSMT: +#endif +#if defined(WOLFPKCS11_LMS) || defined(WOLFPKCS11_XMSS) + /* Copying is prohibited for all LMS/XMSS keys. Public keys + * carry no secret state, but future sign-capable builds add + * private keys whose one-time signature state must never be + * duplicated; rejecting every HBS key copy keeps that + * invariant uniform across key classes. */ + return BAD_FUNC_ARG; +#endif #ifndef NO_AES case CKK_AES: #endif @@ -5234,6 +5296,783 @@ static int wp11_Object_Store_MlKemKey(WP11_Object* object, int tokenId, } #endif /* WOLFPKCS11_MLKEM */ +#ifdef WOLFPKCS11_LMS +/* =========================================================================== + * LMS/HSS (RFC 8554): verification and public-key import. + * + * Verify-only: this build imports raw HSS public keys and verifies + * signatures. There is no private-key/keygen/sign or persisted signature + * state here. The public key is self-describing, so wolfSSL derives the + * parameter set from the key bytes on import; the CKA_HSS_LEVELS / + * CKA_HSS_LMS_TYPE / CKA_HSS_LMOTS_TYPE attributes are optional and, when + * supplied, are validated against the imported key. + * ========================================================================= */ + +/* Map tree height -> RFC 8554 LMS typecode. Returns 0 on unknown height. */ +static CK_LMS_TYPE wp11_HssHeightToLmsType(int h) +{ + switch (h) { + case 5: return CKL_LMS_SHA256_M32_H5; + case 10: return CKL_LMS_SHA256_M32_H10; + case 15: return CKL_LMS_SHA256_M32_H15; + case 20: return CKL_LMS_SHA256_M32_H20; + case 25: return CKL_LMS_SHA256_M32_H25; + default: return 0; + } +} + +/* Map Winternitz -> LMOTS typecode. Returns 0 on unknown. */ +static CK_LMOTS_TYPE wp11_HssWToLmotsType(int w) +{ + switch (w) { + case 1: return CKL_LMOTS_SHA256_N32_W1; + case 2: return CKL_LMOTS_SHA256_N32_W2; + case 4: return CKL_LMOTS_SHA256_N32_W4; + case 8: return CKL_LMOTS_SHA256_N32_W8; + default: return 0; + } +} + +/* Import a raw HSS public key into the given wolfSSL LmsKey. wolfSSL derives + * the parameter set from the key bytes (RFC 8554 self-describing public key), + * so no parameters need to be set first. On failure the (partially + * initialized) key is NOT freed here; the caller owns it. */ +static int wp11_HssImportPub(LmsKey* key, int devId, const byte* pub, + word32 pubLen) +{ + int ret; + + ret = wc_LmsKey_Init(key, NULL, devId); + if (ret == 0) + ret = wc_LmsKey_ImportPubRaw(key, pub, pubLen); + return ret; +} + +/* Validate caller-supplied HSS parameter attributes against the parameters + * wolfSSL derived from the just-imported public key. Per the PKCS#11 v3.3 HSS + * profile the public-key parameters are the individual CK_ULONG attributes + * CKA_HSS_LEVELS, CKA_HSS_LMS_TYPE (top-level tree height encoding) and + * CKA_HSS_LMOTS_TYPE (Winternitz encoding). Each is optional; a supplied value + * that does not match the key is rejected with BAD_FUNC_ARG. levelsAttr, + * lmsAttr and lmotsAttr are the raw attribute buffers (NULL when absent) with + * lengths levelsLen/lmsLen/lmotsLen. */ +static int wp11_HssCheckParamAttrs(LmsKey* key, + const byte* levelsAttr, word32 levelsLen, + const byte* lmsAttr, word32 lmsLen, + const byte* lmotsAttr, word32 lmotsLen) +{ + int ret, levels = 0, height = 0, winternitz = 0; + CK_ULONG v; + + ret = wc_LmsKey_GetParameters(key, &levels, &height, &winternitz); + if (ret != 0) + return ret; + if (levelsAttr != NULL) { + if (levelsLen != sizeof(v)) + return BAD_FUNC_ARG; + XMEMCPY(&v, levelsAttr, sizeof(v)); + if (v != (CK_ULONG)levels) + return BAD_FUNC_ARG; + } + if (lmsAttr != NULL) { + if (lmsLen != sizeof(v)) + return BAD_FUNC_ARG; + XMEMCPY(&v, lmsAttr, sizeof(v)); + if (v != (CK_ULONG)wp11_HssHeightToLmsType(height)) + return BAD_FUNC_ARG; + } + if (lmotsAttr != NULL) { + if (lmotsLen != sizeof(v)) + return BAD_FUNC_ARG; + XMEMCPY(&v, lmotsAttr, sizeof(v)); + if (v != (CK_ULONG)wp11_HssWToLmotsType(winternitz)) + return BAD_FUNC_ARG; + } + return 0; +} + +/* Serialize the public key: keyData holds the raw RFC 8554 HSS public key. */ +static int wp11_Object_Encode_HssKey(WP11_Object* object) +{ + int ret; + word32 pubLen = 0; + + if (object->objClass != CKO_PUBLIC_KEY) + return NOT_AVAILABLE_E; /* verify-only: no private-key objects */ + + ret = wc_LmsKey_GetPubLen(object->data.lmsKey, &pubLen); + if (ret == 0) { + XFREE(object->keyData, NULL, DYNAMIC_TYPE_TMP_BUFFER); + object->keyData = (unsigned char*)XMALLOC(pubLen, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (object->keyData == NULL) + ret = MEMORY_E; + } + if (ret == 0) { + ret = wc_LmsKey_ExportPubRaw(object->data.lmsKey, object->keyData, + &pubLen); + if (ret == 0) + object->keyDataLen = (int)pubLen; + } + /* On failure release the buffer so a later store does not skip re-encoding + * (keyData != NULL) and persist an uninitialised buffer with a stale + * length. This is public key material only, so no zeroization is needed. */ + if (ret != 0) { + XFREE(object->keyData, NULL, DYNAMIC_TYPE_TMP_BUFFER); + object->keyData = NULL; + object->keyDataLen = 0; + } + return ret; +} + +/* Reconstruct the live wolfSSL key from the serialized public key in keyData. */ +static int wp11_Object_Decode_HssKey(WP11_Object* object) +{ + int ret; + + if (object->objClass != CKO_PUBLIC_KEY) + return NOT_AVAILABLE_E; + + /* Reload from the stored raw public key; wolfSSL re-derives the parameter + * set from the key bytes (no separate parameters are persisted). */ + ret = wp11_HssImportPub(object->data.lmsKey, object->devId, + object->keyData, (word32)object->keyDataLen); + /* The object owns the live key on all paths (the import helper never frees + * it), so encoded stays 0 for WP11_Object_Free to do the single free. */ + object->encoded = 0; + return ret; +} + +static int wp11_Object_Load_HssKey(WP11_Object* object, int tokenId, int objId) +{ + int ret; + void* storage = NULL; + + ret = wp11_storage_open_readonly(WOLFPKCS11_STORE_HSSKEY_PUB, tokenId, + objId, &storage); + if (ret == 0) { + ret = wp11_storage_read_alloc_array(storage, &object->keyData, + &object->keyDataLen); + wp11_storage_close(storage); + } + return ret; +} + +static int wp11_Object_Store_HssKey(WP11_Object* object, int tokenId, int objId) +{ + int ret = 0; + void* storage = NULL; + + if (object->keyData == NULL) + ret = wp11_Object_Encode_HssKey(object); + if (ret == 0) + ret = wp11_storage_open(WOLFPKCS11_STORE_HSSKEY_PUB, tokenId, objId, + object->keyDataLen, &storage); + if (ret == 0) { + ret = wp11_storage_write_array(storage, object->keyData, + object->keyDataLen); + wp11_storage_close(storage); + } + return ret; +} + +/* Import an HSS public key from a C_CreateObject template. Following the + * PKCS#11 v3.3 HSS profile the collected attributes are data[0]=CKA_HSS_LEVELS, + * data[1]=CKA_HSS_LMS_TYPE, data[2]=CKA_HSS_LMOTS_TYPE (all optional CK_ULONG) + * and data[3]=CKA_VALUE, the raw RFC 8554 public key. wolfSSL derives the + * parameter set from the key bytes; any supplied CKA_HSS_* attribute is + * validated against the derived parameters and a mismatch is rejected. + * Private-key import is rejected: caller-supplied stateful private material is + * a forgery vector and out of scope for verify-only support. */ +int WP11_Object_SetHssKey(WP11_Object* object, unsigned char** data, + CK_ULONG* len) +{ + int ret = 0; + LmsKey* newKey = NULL; + + if (object == NULL || data == NULL || len == NULL) + return BAD_FUNC_ARG; + if (object->objClass != CKO_PUBLIC_KEY) + return BAD_FUNC_ARG; + /* A public key must carry its value. There is no keygen path in a + * verify-only build that would populate it later, so an absent + * CKA_VALUE is an incomplete template rather than a deferred import; + * reject it instead of creating an unusable object. */ + if (data[3] == NULL) + return BAD_FUNC_ARG; + + if (object->onToken) + WP11_Lock_LockRW(object->lock); + + /* Import into a temporary key and swap it in only after it fully validates, + * so a failed re-import (C_SetAttributeValue with a new CKA_VALUE) leaves + * the existing key unchanged as PKCS#11 requires. */ + newKey = (LmsKey*)XMALLOC(sizeof(LmsKey), NULL, DYNAMIC_TYPE_KEY); + if (newKey == NULL) + ret = MEMORY_E; + if (ret == 0) { + XMEMSET(newKey, 0, sizeof(LmsKey)); + ret = wp11_HssImportPub(newKey, object->devId, data[3], + (word32)len[3]); + } + if (ret == 0) { + ret = wp11_HssCheckParamAttrs(newKey, data[0], (word32)len[0], + data[1], (word32)len[1], data[2], (word32)len[2]); + } + if (ret == 0) { + /* Replace the live key and drop the cached serialization so a later + * store re-encodes from the new key instead of persisting stale bytes. */ + if (object->data.lmsKey != NULL) { + if (!object->encoded) + wc_LmsKey_Free(object->data.lmsKey); + XFREE(object->data.lmsKey, NULL, DYNAMIC_TYPE_KEY); + } + object->data.lmsKey = newKey; + object->encoded = 0; + newKey = NULL; + XFREE(object->keyData, NULL, DYNAMIC_TYPE_TMP_BUFFER); + object->keyData = NULL; + object->keyDataLen = 0; + } + if (newKey != NULL) { + wc_LmsKey_Free(newKey); + XFREE(newKey, NULL, DYNAMIC_TYPE_KEY); + } + + if (object->onToken) + WP11_Lock_UnlockRW(object->lock); + return ret; +} + +/* Verify an HSS signature over a raw message. Stateless on the verifier. */ +int WP11_Hss_Verify(unsigned char* sig, word32 sigLen, unsigned char* data, + word32 dataLen, int* stat, WP11_Object* pub) +{ + int ret; + word32 expSigLen = 0; + + if (pub == NULL || pub->data.lmsKey == NULL || stat == NULL) + return BAD_FUNC_ARG; + + /* Verification only reads the key: wc_LmsKey_Verify works from a locally + * allocated LmsState, so a shared RO lock is safe for concurrent verifies + * on the same token object. */ + if (pub->onToken) + WP11_Lock_LockRO(pub->lock); + + /* A signature whose length does not match the key's parameter set cannot + * be valid; report it as an invalid signature (stat = 0 -> + * CKR_SIGNATURE_INVALID) rather than letting wolfSSL's length check + * surface as a function failure. */ + if (wc_LmsKey_GetSigLen(pub->data.lmsKey, &expSigLen) == 0 && + sigLen != expSigLen) { + *stat = 0; + ret = 0; + } + else { + /* Unlike XMSS, whose wolfSSL verify rejects a zero-length message with + * BAD_FUNC_ARG, wc_LmsKey_Verify accepts an empty message, so HSS needs + * no dataLen == 0 special-case here (see WP11_Xmss_Verify). */ + ret = wc_LmsKey_Verify(pub->data.lmsKey, sig, sigLen, data, + (int)dataLen); + /* Only a genuine verification mismatch (SIG_VERIFY_E) maps to stat=0. + * Remaining argument/state errors surface as a function failure so + * they are not silently reported as an invalid signature. */ + if (ret == 0) { + *stat = 1; + } + else if (ret == SIG_VERIFY_E) { + *stat = 0; + ret = 0; + } + else { + *stat = 0; + } + } + + if (pub->onToken) + WP11_Lock_UnlockRO(pub->lock); + + return ret; +} + +/* Serve HSS-specific attributes from a public-key object. */ +static int HssObject_GetAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, + byte* data, CK_ULONG* len) +{ + int ret = 0; + int levels = 0, height = 0, winternitz = 0; + + if (object == NULL || object->data.lmsKey == NULL || len == NULL) + return BAD_FUNC_ARG; + + switch (type) { + case CKA_HSS_LEVELS: { + CK_ULONG v; + ret = wc_LmsKey_GetParameters(object->data.lmsKey, &levels, + &height, &winternitz); + if (ret == 0) { + v = (CK_ULONG)levels; + if (data == NULL) + *len = sizeof(v); + else if (*len < sizeof(v)) { + *len = sizeof(v); + ret = BUFFER_E; + } + else { + XMEMCPY(data, &v, sizeof(v)); + *len = sizeof(v); + } + } + break; + } + case CKA_HSS_LMS_TYPE: { + CK_LMS_TYPE v; + ret = wc_LmsKey_GetParameters(object->data.lmsKey, &levels, + &height, &winternitz); + if (ret == 0) { + v = wp11_HssHeightToLmsType(height); + if (v == 0) + ret = NOT_AVAILABLE_E; + else if (data == NULL) + *len = sizeof(v); + else if (*len < sizeof(v)) { + *len = sizeof(v); + ret = BUFFER_E; + } + else { + XMEMCPY(data, &v, sizeof(v)); + *len = sizeof(v); + } + } + break; + } + case CKA_HSS_LMOTS_TYPE: { + CK_LMOTS_TYPE v; + ret = wc_LmsKey_GetParameters(object->data.lmsKey, &levels, + &height, &winternitz); + if (ret == 0) { + v = wp11_HssWToLmotsType(winternitz); + if (v == 0) + ret = NOT_AVAILABLE_E; + else if (data == NULL) + *len = sizeof(v); + else if (*len < sizeof(v)) { + *len = sizeof(v); + ret = BUFFER_E; + } + else { + XMEMCPY(data, &v, sizeof(v)); + *len = sizeof(v); + } + } + break; + } + case CKA_HSS_LMS_TYPES: + case CKA_HSS_LMOTS_TYPES: { + /* wolfSSL uses uniform LMS/LMOTS parameters across all HSS levels, so + * every array entry is the top-level type. Per-level types (allowed + * by the PKCS#11 v3.3 profile) are not expressible by wolfSSL and are + * not supported here. */ + CK_ULONG total; + CK_ULONG fill; + int i; + ret = wc_LmsKey_GetParameters(object->data.lmsKey, &levels, + &height, &winternitz); + if (ret == 0) { + total = (CK_ULONG)(sizeof(CK_ULONG) * levels); + fill = (type == CKA_HSS_LMS_TYPES) + ? wp11_HssHeightToLmsType(height) + : wp11_HssWToLmotsType(winternitz); + if (fill == 0) + ret = NOT_AVAILABLE_E; + else if (data == NULL) + *len = total; + else if (*len < total) { + *len = total; + ret = BUFFER_E; + } + else { + for (i = 0; i < levels; i++) + XMEMCPY(data + i * sizeof(CK_ULONG), &fill, + sizeof(CK_ULONG)); + *len = total; + } + } + break; + } + case CKA_HSS_KEYS_REMAINING: + /* Remaining-signature count is a private-key/state property; not + * available in a verify-only build. Return NOT_AVAILABLE_E like the + * default arm; C_GetAttributeValue then sets ulValueLen. */ + ret = NOT_AVAILABLE_E; + break; + case CKA_VALUE: + if (object->objClass == CKO_PUBLIC_KEY) { + word32 pubLen = 0; + ret = wc_LmsKey_GetPubLen(object->data.lmsKey, &pubLen); + if (ret == 0) { + if (data == NULL) + *len = pubLen; + else if (*len < pubLen) { + *len = pubLen; + ret = BUFFER_E; + } + else { + ret = wc_LmsKey_ExportPubRaw(object->data.lmsKey, + data, &pubLen); + if (ret == 0) + *len = pubLen; + } + } + } + else { + *len = CK_UNAVAILABLE_INFORMATION; + ret = NOT_AVAILABLE_E; + } + break; + default: + ret = NOT_AVAILABLE_E; + break; + } + return ret; +} +#endif /* WOLFPKCS11_LMS */ + +#ifdef WOLFPKCS11_XMSS +/* =========================================================================== + * XMSS/XMSS^MT (RFC 8391): verification and public-key import. + * + * Verify-only. One wolfSSL XmssKey type serves both XMSS and XMSS^MT; the + * PKCS#11 key type (CKK_XMSS vs CKK_XMSSMT) selects which via the is_xmssmt + * flag. The raw public key carries the parameter-set OID in its leading + * bytes, so wc_XmssKey_ImportPubRaw_ex derives the parameter set on import. + * A CKA_PARAMETER_SET attribute is optional and, when supplied, is validated + * against the OID in the key. + * ========================================================================= */ + +/* Length of the parameter-set OID prefix in a raw RFC 8391 public key. wolfSSL + * only exposes XMSS_OID_LEN when built with WOLFSSL_HAVE_XMSS and it is absent + * from some released headers, so define our own to keep the build independent + * of the wolfSSL version. */ +#define WP11_XMSS_OID_LEN 4 + +/* Big-endian 32-bit read from a byte buffer (used to read the XMSS OID). */ +static word32 wp11_HbsReadU32(const byte* p) +{ + return ((word32)p[0] << 24) | ((word32)p[1] << 16) + | ((word32)p[2] << 8) | (word32)p[3]; +} + +/* Import a raw XMSS/XMSS^MT public key into the given wolfSSL XmssKey, deriving + * the parameter set from the embedded OID. is_xmssmt disambiguates the XMSS and + * XMSS^MT OID namespaces (which overlap) and comes from the PKCS#11 key type. + * When the caller supplies a CKA_PARAMETER_SET (params != NULL, the OID as a + * CK_ULONG) it must match the OID in the public key. On failure the key is NOT + * freed here; the caller owns it. */ +static int wp11_XmssImportPub(XmssKey* key, int is_xmssmt, int devId, + const byte* pub, word32 pubLen, const byte* params, word32 paramsLen) +{ + int ret; + + ret = wc_XmssKey_Init(key, NULL, devId); + if (ret == 0 && params != NULL) { + CK_ULONG userOid; + if (paramsLen != sizeof(CK_ULONG) || pubLen < WP11_XMSS_OID_LEN) { + ret = BAD_FUNC_ARG; + } + else { + XMEMCPY(&userOid, params, sizeof(userOid)); + if (userOid != (CK_ULONG)wp11_HbsReadU32(pub)) + ret = BAD_FUNC_ARG; + } + } + if (ret == 0) + ret = wc_XmssKey_ImportPubRaw_ex(key, pub, pubLen, is_xmssmt); + return ret; +} + +/* Serialize the public key: keyData holds the raw RFC 8391 public key. */ +static int wp11_Object_Encode_XmssKey(WP11_Object* object) +{ + int ret; + word32 pubLen = 0; + + if (object->objClass != CKO_PUBLIC_KEY) + return NOT_AVAILABLE_E; + + ret = wc_XmssKey_GetPubLen(object->data.xmssKey, &pubLen); + if (ret == 0) { + XFREE(object->keyData, NULL, DYNAMIC_TYPE_TMP_BUFFER); + object->keyData = (unsigned char*)XMALLOC(pubLen, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (object->keyData == NULL) + ret = MEMORY_E; + } + if (ret == 0) { + ret = wc_XmssKey_ExportPubRaw(object->data.xmssKey, object->keyData, + &pubLen); + if (ret == 0) + object->keyDataLen = (int)pubLen; + } + /* On failure release the buffer so a later store does not skip re-encoding + * (keyData != NULL) and persist an uninitialised buffer with a stale + * length. This is public key material only, so no zeroization is needed. */ + if (ret != 0) { + XFREE(object->keyData, NULL, DYNAMIC_TYPE_TMP_BUFFER); + object->keyData = NULL; + object->keyDataLen = 0; + } + return ret; +} + +static int wp11_Object_Decode_XmssKey(WP11_Object* object) +{ + int ret; + + if (object->objClass != CKO_PUBLIC_KEY) + return NOT_AVAILABLE_E; + + /* Reload from the stored raw public key; wolfSSL re-derives the parameter + * set from the embedded OID (no separate parameter set is persisted). */ + ret = wp11_XmssImportPub(object->data.xmssKey, + (object->type == CKK_XMSSMT) ? 1 : 0, object->devId, object->keyData, + (word32)object->keyDataLen, NULL, 0); + /* Object owns the key on all paths; encoded stays 0 for the single free in + * WP11_Object_Free. See wp11_Object_Decode_HssKey. */ + object->encoded = 0; + return ret; +} + +static int wp11_Object_Load_XmssKey(WP11_Object* object, int tokenId, int objId) +{ + int ret; + void* storage = NULL; + + ret = wp11_storage_open_readonly(WOLFPKCS11_STORE_XMSSKEY_PUB, tokenId, + objId, &storage); + if (ret == 0) { + ret = wp11_storage_read_alloc_array(storage, &object->keyData, + &object->keyDataLen); + wp11_storage_close(storage); + } + return ret; +} + +static int wp11_Object_Store_XmssKey(WP11_Object* object, int tokenId, + int objId) +{ + int ret = 0; + void* storage = NULL; + + if (object->keyData == NULL) + ret = wp11_Object_Encode_XmssKey(object); + if (ret == 0) + ret = wp11_storage_open(WOLFPKCS11_STORE_XMSSKEY_PUB, tokenId, objId, + object->keyDataLen, &storage); + if (ret == 0) { + ret = wp11_storage_write_array(storage, object->keyData, + object->keyDataLen); + wp11_storage_close(storage); + } + return ret; +} + +/* Import an XMSS/XMSS^MT public key from a C_CreateObject template. data[1] is + * the raw RFC 8391 public key; data[0] (CKA_PARAMETER_SET, the OID as a + * CK_ULONG) is optional and, when present, is validated against the key. + * Private-key import is rejected. */ +int WP11_Object_SetXmssKey(WP11_Object* object, unsigned char** data, + CK_ULONG* len) +{ + int ret = 0; + XmssKey* newKey = NULL; + + if (object == NULL || data == NULL || len == NULL) + return BAD_FUNC_ARG; + if (object->objClass != CKO_PUBLIC_KEY) + return BAD_FUNC_ARG; + /* A public key must carry its value; an absent CKA_VALUE is an + * incomplete template (no keygen path fills it later). Reject it. */ + if (data[1] == NULL) + return BAD_FUNC_ARG; + + if (object->onToken) + WP11_Lock_LockRW(object->lock); + + /* Import into a temporary key and swap it in only after it validates, so a + * failed re-import leaves the existing key unchanged (PKCS#11 requires a + * failed C_SetAttributeValue to be a no-op). */ + newKey = (XmssKey*)XMALLOC(sizeof(XmssKey), NULL, DYNAMIC_TYPE_KEY); + if (newKey == NULL) + ret = MEMORY_E; + if (ret == 0) { + XMEMSET(newKey, 0, sizeof(XmssKey)); + ret = wp11_XmssImportPub(newKey, (object->type == CKK_XMSSMT) ? 1 : 0, + object->devId, data[1], (word32)len[1], data[0], (word32)len[0]); + } + if (ret == 0) { + /* Replace the live key and drop the cached serialization so a later + * store re-encodes from the new key. */ + if (object->data.xmssKey != NULL) { + if (!object->encoded) + wc_XmssKey_Free(object->data.xmssKey); + XFREE(object->data.xmssKey, NULL, DYNAMIC_TYPE_KEY); + } + object->data.xmssKey = newKey; + object->encoded = 0; + newKey = NULL; + XFREE(object->keyData, NULL, DYNAMIC_TYPE_TMP_BUFFER); + object->keyData = NULL; + object->keyDataLen = 0; + } + if (newKey != NULL) { + wc_XmssKey_Free(newKey); + XFREE(newKey, NULL, DYNAMIC_TYPE_KEY); + } + + if (object->onToken) + WP11_Lock_UnlockRW(object->lock); + return ret; +} + +/* Verify an XMSS/XMSS^MT signature over a raw message. Stateless. */ +int WP11_Xmss_Verify(unsigned char* sig, word32 sigLen, unsigned char* data, + word32 dataLen, int* stat, WP11_Object* pub) +{ + int ret; + word32 expSigLen = 0; + + if (pub == NULL || pub->data.xmssKey == NULL || stat == NULL) + return BAD_FUNC_ARG; + + /* Verification only reads the key: wc_XmssKey_Verify works from a locally + * allocated XmssState, so a shared RO lock is safe for concurrent verifies + * on the same token object. */ + if (pub->onToken) + WP11_Lock_LockRO(pub->lock); + + /* A wrong-length signature cannot be valid for this key; report it as an + * invalid signature rather than a function failure. wolfSSL's XMSS verify + * also rejects a zero-length message with BAD_FUNC_ARG; treat that the same + * way (an invalid verification, not an internal failure). */ + if (wc_XmssKey_GetSigLen(pub->data.xmssKey, &expSigLen) == 0 && + sigLen != expSigLen) { + *stat = 0; + ret = 0; + } + else if (dataLen == 0) { + *stat = 0; + ret = 0; + } + else { + ret = wc_XmssKey_Verify(pub->data.xmssKey, sig, sigLen, data, + (int)dataLen); + /* Only SIG_VERIFY_E maps to stat=0; other argument/state errors + * surface as a function failure so they are not silently reported as + * an invalid signature. */ + if (ret == 0) { + *stat = 1; + } + else if (ret == SIG_VERIFY_E) { + *stat = 0; + ret = 0; + } + else { + *stat = 0; + } + } + + if (pub->onToken) + WP11_Lock_UnlockRO(pub->lock); + + return ret; +} + +/* Serve XMSS-specific attributes from a public-key object. */ +static int XmssObject_GetAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, + byte* data, CK_ULONG* len) +{ + int ret = 0; + + if (object == NULL || object->data.xmssKey == NULL || len == NULL) + return BAD_FUNC_ARG; + + switch (type) { + case CKA_VALUE: + if (object->objClass == CKO_PUBLIC_KEY) { + word32 pubLen = 0; + ret = wc_XmssKey_GetPubLen(object->data.xmssKey, &pubLen); + if (ret == 0) { + if (data == NULL) + *len = pubLen; + else if (*len < pubLen) { + *len = pubLen; + ret = BUFFER_E; + } + else { + ret = wc_XmssKey_ExportPubRaw(object->data.xmssKey, + data, &pubLen); + if (ret == 0) + *len = pubLen; + } + } + } + else { + *len = CK_UNAVAILABLE_INFORMATION; + ret = NOT_AVAILABLE_E; + } + break; + case CKA_PARAMETER_SET: { + /* The XMSS parameter set is identified by the OID in the leading + * bytes of the raw public key; return it as a CK_ULONG. */ + CK_ULONG v; + word32 pubLen = 0; + byte* raw; + + if (object->objClass != CKO_PUBLIC_KEY) { + *len = CK_UNAVAILABLE_INFORMATION; + ret = NOT_AVAILABLE_E; + break; + } + if (data == NULL) { + *len = sizeof(v); + break; + } + if (*len < sizeof(v)) { + *len = sizeof(v); + ret = BUFFER_E; + break; + } + ret = wc_XmssKey_GetPubLen(object->data.xmssKey, &pubLen); + if (ret == 0 && pubLen < WP11_XMSS_OID_LEN) + ret = NOT_AVAILABLE_E; + if (ret == 0) { + raw = (byte*)XMALLOC(pubLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (raw == NULL) { + ret = MEMORY_E; + } + else { + ret = wc_XmssKey_ExportPubRaw(object->data.xmssKey, raw, + &pubLen); + if (ret == 0) { + v = (CK_ULONG)wp11_HbsReadU32(raw); + XMEMCPY(data, &v, sizeof(v)); + *len = sizeof(v); + } + XFREE(raw, NULL, DYNAMIC_TYPE_TMP_BUFFER); + } + } + break; + } + default: + ret = NOT_AVAILABLE_E; + break; + } + return ret; +} +#endif /* WOLFPKCS11_XMSS */ + /** * Decode the symmetric key - requires decryption. * @@ -5536,6 +6375,17 @@ static int wp11_Object_Load(WP11_Object* object, int tokenId, int objId) ret = wp11_Object_Load_MlKemKey(object, tokenId, objId); break; #endif + #ifdef WOLFPKCS11_LMS + case CKK_HSS: + ret = wp11_Object_Load_HssKey(object, tokenId, objId); + break; + #endif + #ifdef WOLFPKCS11_XMSS + case CKK_XMSS: + case CKK_XMSSMT: + ret = wp11_Object_Load_XmssKey(object, tokenId, objId); + break; + #endif #ifndef NO_AES case CKK_AES: #endif @@ -5717,6 +6567,17 @@ static int wp11_Object_Store(WP11_Object* object, int tokenId, int objId) ret = wp11_Object_Store_MlKemKey(object, tokenId, objId); break; #endif + #ifdef WOLFPKCS11_LMS + case CKK_HSS: + ret = wp11_Object_Store_HssKey(object, tokenId, objId); + break; + #endif + #ifdef WOLFPKCS11_XMSS + case CKK_XMSS: + case CKK_XMSSMT: + ret = wp11_Object_Store_XmssKey(object, tokenId, objId); + break; + #endif #ifndef NO_AES case CKK_AES: #endif @@ -5787,6 +6648,17 @@ static int wp11_Object_Decode(WP11_Object* object) ret = wp11_Object_Decode_MlKemKey(object); break; #endif + #ifdef WOLFPKCS11_LMS + case CKK_HSS: + ret = wp11_Object_Decode_HssKey(object); + break; + #endif + #ifdef WOLFPKCS11_XMSS + case CKK_XMSS: + case CKK_XMSSMT: + ret = wp11_Object_Decode_XmssKey(object); + break; + #endif #ifndef NO_AES case CKK_AES: #endif @@ -5874,6 +6746,17 @@ static int wp11_Object_Encode(WP11_Object* object, int protect) } break; #endif + #ifdef WOLFPKCS11_LMS + case CKK_HSS: + ret = wp11_Object_Encode_HssKey(object); + break; + #endif + #ifdef WOLFPKCS11_XMSS + case CKK_XMSS: + case CKK_XMSSMT: + ret = wp11_Object_Encode_XmssKey(object); + break; + #endif #ifndef NO_AES case CKK_AES: #endif @@ -5971,6 +6854,17 @@ static int wp11_Object_Unstore(WP11_Object* object, int tokenId, int objId) storeObjType = WOLFPKCS11_STORE_MLKEMKEY_PUB; break; #endif + #ifdef WOLFPKCS11_LMS + case CKK_HSS: + storeObjType = WOLFPKCS11_STORE_HSSKEY_PUB; + break; + #endif + #ifdef WOLFPKCS11_XMSS + case CKK_XMSS: + case CKK_XMSSMT: + storeObjType = WOLFPKCS11_STORE_XMSSKEY_PUB; + break; + #endif #ifndef NO_AES case CKK_AES: #endif @@ -7959,6 +8853,12 @@ static int wp11_init_get_op_category(int init) case WP11_INIT_AES_CMAC_VERIFY: case WP11_INIT_TLS_MAC_VERIFY: case WP11_INIT_MLDSA_VERIFY: +#ifdef WOLFPKCS11_LMS + case WP11_INIT_HSS_VERIFY: +#endif +#ifdef WOLFPKCS11_XMSS + case WP11_INIT_XMSS_VERIFY: +#endif return WP11_OP_VERIFY; default: @@ -9349,6 +10249,23 @@ void WP11_Object_Free(WP11_Object* object) XFREE(object->data.mlKemKey, NULL, DYNAMIC_TYPE_KEY); object->data.mlKemKey = NULL; } + #endif + #ifdef WOLFPKCS11_LMS + if (object->type == CKK_HSS && object->data.lmsKey != NULL) { + if (!object->encoded) + wc_LmsKey_Free(object->data.lmsKey); + XFREE(object->data.lmsKey, NULL, DYNAMIC_TYPE_KEY); + object->data.lmsKey = NULL; + } + #endif + #ifdef WOLFPKCS11_XMSS + if ((object->type == CKK_XMSS || object->type == CKK_XMSSMT) && + object->data.xmssKey != NULL) { + if (!object->encoded) + wc_XmssKey_Free(object->data.xmssKey); + XFREE(object->data.xmssKey, NULL, DYNAMIC_TYPE_KEY); + object->data.xmssKey = NULL; + } #endif if ((object->type == CKK_AES || object->type == CKK_GENERIC_SECRET || object->type == CKK_HKDF) && object->data.symmKey != NULL) { @@ -11613,6 +12530,17 @@ int WP11_Object_GetAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, byte* data, ret = MlKemObject_GetAttr(object, type, data, len); break; #endif +#ifdef WOLFPKCS11_LMS + case CKK_HSS: + ret = HssObject_GetAttr(object, type, data, len); + break; +#endif +#ifdef WOLFPKCS11_XMSS + case CKK_XMSS: + case CKK_XMSSMT: + ret = XmssObject_GetAttr(object, type, data, len); + break; +#endif #ifndef NO_AES case CKK_AES: #endif @@ -11940,6 +12868,13 @@ int WP11_Object_SetAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, byte* data, #ifdef WOLFPKCS11_MLDSA case CKK_ML_DSA: #endif +#ifdef WOLFPKCS11_LMS + case CKK_HSS: +#endif +#ifdef WOLFPKCS11_XMSS + case CKK_XMSS: + case CKK_XMSSMT: +#endif #ifndef NO_DH case CKK_DH: #endif @@ -12037,6 +12972,14 @@ int WP11_Object_SetAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, byte* data, #ifdef WOLFPKCS11_MLKEM case CKK_ML_KEM: break; +#endif +#ifdef WOLFPKCS11_XMSS + /* CKA_PARAMETER_SET carries the XMSS/XMSS^MT OID. HSS (CKK_HSS) + * has no such attribute in the PKCS#11 profile, so it is not + * listed here and falls through to the default rejection. */ + case CKK_XMSS: + case CKK_XMSSMT: + break; #endif default: ret = BAD_FUNC_ARG; @@ -12097,6 +13040,24 @@ int WP11_Object_SetAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, byte* data, case CKA_WOLFSSL_DEVID: object->devId = (int)(*(CK_ULONG*)data); break; +#ifdef WOLFPKCS11_LMS + case CKA_HSS_LEVELS: + case CKA_HSS_LMS_TYPE: + case CKA_HSS_LMOTS_TYPE: + case CKA_HSS_LMS_TYPES: + case CKA_HSS_LMOTS_TYPES: + case CKA_HSS_KEYS_REMAINING: + /* HSS parameter attributes are key-derived and read-only. The + * WP11_Object_SetHssKey template pass validates the scalar forms + * against the public key and rejects a value-less or mismatched set + * (CKR_ATTRIBUTE_VALUE_INVALID) before this runs; the array and + * keys-remaining forms are values served by HssObject_GetAttr. + * Accept them all as a no-op on an HSS object so recreating one from + * its own attributes is not rejected. */ + if (object->type != CKK_HSS) + ret = BAD_FUNC_ARG; + break; +#endif #ifdef WOLFSSL_STM32U5_DHUK case CKA_WOLFSSL_DHUK_IV: diff --git a/src/slot.c b/src/slot.c index 4764eef4..3789cae7 100644 --- a/src/slot.c +++ b/src/slot.c @@ -382,6 +382,13 @@ static CK_MECHANISM_TYPE mechanismList[] = { CKM_ML_KEM_KEY_PAIR_GEN, CKM_ML_KEM, #endif +#ifdef WOLFPKCS11_LMS + CKM_HSS, +#endif +#ifdef WOLFPKCS11_XMSS + CKM_XMSS, + CKM_XMSSMT, +#endif #ifndef NO_AES CKM_AES_KEY_GEN, #ifdef HAVE_AES_KEY_WRAP @@ -640,6 +647,20 @@ static CK_MECHANISM_INFO mldsaMechInfo = { CKF_SIGN | CKF_VERIFY }; #endif +#ifdef WOLFPKCS11_LMS +/* Info on the HSS (LMS) verify mechanism. PKCS#11 does not define a key-size + * semantics for stateful hash-based signatures (bits vs bytes), so report the + * "not applicable" 0..0 envelope. Verify-only: no CKF_SIGN. */ +static CK_MECHANISM_INFO hssMechInfo = { + 0, 0, CKF_VERIFY +}; +#endif +#ifdef WOLFPKCS11_XMSS +/* Info on the XMSS / XMSS^MT verify mechanisms. 0..0 envelope, verify-only. */ +static CK_MECHANISM_INFO xmssMechInfo = { + 0, 0, CKF_VERIFY +}; +#endif #ifdef WOLFPKCS11_HKDF static CK_MECHANISM_INFO hkdfMechInfo = { 1, 16320, CKF_DERIVE @@ -998,6 +1019,17 @@ CK_RV C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, XMEMCPY(pInfo, &mldsaMechInfo, sizeof(CK_MECHANISM_INFO)); break; #endif +#ifdef WOLFPKCS11_LMS + case CKM_HSS: + XMEMCPY(pInfo, &hssMechInfo, sizeof(CK_MECHANISM_INFO)); + break; +#endif +#ifdef WOLFPKCS11_XMSS + case CKM_XMSS: + case CKM_XMSSMT: + XMEMCPY(pInfo, &xmssMechInfo, sizeof(CK_MECHANISM_INFO)); + break; +#endif #ifdef WOLFPKCS11_HKDF case CKM_HKDF_DERIVE: XMEMCPY(pInfo, &hkdfMechInfo, sizeof(CK_MECHANISM_INFO)); diff --git a/tests/hbs_kat.h b/tests/hbs_kat.h new file mode 100644 index 00000000..a920dcc4 --- /dev/null +++ b/tests/hbs_kat.h @@ -0,0 +1,670 @@ +/* hbs_kat.h - Known-answer test vectors for stateful hash-based signatures + * (LMS/HSS RFC 8554, XMSS/XMSS^MT RFC 8391). Shared by pkcs11v3test.c and + * hbs_persistence_test.c. Produced once with a sign-capable wolfSSL build; + * the verify-only feature imports the raw public key and checks the signature. + */ + +#ifndef WOLFPKCS11_TESTS_HBS_KAT_H +#define WOLFPKCS11_TESTS_HBS_KAT_H + +#if defined(WOLFPKCS11_LMS) || defined(WOLFPKCS11_XMSS) + +/* Message signed by the KAT vectors (must match the generator). */ +static CK_BYTE hbs_kat_msg[] = "wolfPKCS11 HBS verify KAT message"; +#define HBS_KAT_MSG_LEN (sizeof(hbs_kat_msg) - 1) + +#endif /* WOLFPKCS11_LMS || WOLFPKCS11_XMSS */ + +#ifdef WOLFPKCS11_LMS +/* HSS L1/H5/W4 known-answer vector (RFC 8554). */ +static const CK_BYTE hss_kat_pub[60] = { +0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x03,0x01,0x00,0xcb,0x7f, +0x59,0xf1,0xd8,0x0e,0x0b,0xcc,0x8b,0x8d,0x82,0xd9,0xe6,0x5a,0xa4,0x23,0x20,0x5b, +0xa1,0xe9,0x3d,0x49,0x7e,0x5a,0x66,0x4a,0x1f,0xf3,0x60,0x7e,0x11,0x39,0x37,0x06, +0x39,0xa5,0x8a,0xff,0xee,0x3e,0x72,0x3c,0xfa,0x8c,0xd6,0x78, +}; +static const CK_BYTE hss_kat_sig[2352] = { +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x9f,0x22,0xed,0xa6, +0xe4,0xfd,0xec,0x72,0x18,0x09,0xc9,0x3d,0x98,0x07,0x01,0x2c,0xfb,0x06,0x5d,0x46, +0x57,0x81,0x70,0xa4,0x5d,0x84,0x18,0xd9,0xe0,0x3c,0xca,0x5e,0x51,0x9e,0x55,0xe3, +0xce,0x83,0x76,0x73,0xf9,0x7e,0x65,0x0d,0xce,0x9d,0xc1,0x84,0x20,0x8b,0x44,0x9b, +0xd8,0x22,0x97,0x3c,0x28,0xed,0x76,0x2c,0xa5,0xbd,0xec,0x70,0x87,0x38,0x4e,0x0f, +0x4d,0x93,0xc1,0x0f,0x68,0xe3,0x73,0xe2,0xf2,0x19,0x7b,0xc1,0xe9,0x33,0xb4,0x18, +0x5e,0xe3,0x32,0x84,0xc6,0xdb,0xe7,0x1d,0xce,0x30,0xde,0x55,0xda,0x60,0xc2,0x81, +0xf9,0xb1,0xe6,0x10,0xed,0xc8,0xb0,0x45,0xb8,0xb3,0x41,0x1e,0xf0,0x04,0x2d,0x3c, +0xc6,0x7b,0x24,0x74,0xaa,0xd0,0x7b,0x99,0x9a,0xaa,0xe6,0x51,0x40,0xaf,0x87,0x6b, +0xee,0x42,0x33,0x76,0xf7,0x53,0x8c,0xa1,0x79,0x06,0x3e,0xf6,0x90,0x89,0x89,0x51, +0x86,0x8f,0xd5,0xd6,0x23,0x68,0x7e,0x71,0x63,0x3c,0xd1,0xd0,0xc4,0xb1,0xfb,0xe2, +0x4a,0x15,0xc9,0x9d,0xf4,0x19,0x52,0x37,0xaf,0x55,0xe1,0x0b,0xea,0xd5,0xc8,0xca, +0xe9,0x45,0xb6,0x6f,0x95,0xd8,0xdb,0x93,0x8f,0x90,0xdb,0xb1,0x6e,0x10,0xd2,0x0d, +0x43,0x85,0x4e,0xc2,0xc8,0x99,0x84,0x6d,0x2b,0x3e,0x39,0xf3,0xe4,0x41,0x95,0x34, +0xdf,0x8c,0x80,0xad,0xc0,0x16,0x8e,0x9c,0xe1,0xea,0x36,0xb4,0xfc,0x04,0x28,0x91, +0xd8,0xd8,0xb2,0x0a,0xac,0xf7,0x47,0x0e,0x60,0x73,0xaa,0x96,0x93,0xef,0x9b,0xfe, +0xe0,0x31,0xbc,0x6c,0x76,0xc8,0xae,0x1f,0x2b,0xe5,0xc8,0x0b,0x31,0x52,0x79,0x49, +0x58,0xeb,0x60,0xe7,0x3a,0x96,0x39,0x62,0xe4,0xc2,0x63,0xd1,0xde,0x71,0x48,0x79, +0xf3,0xc5,0x9f,0xf5,0x58,0xa2,0x07,0xb6,0xe4,0x26,0x42,0x3c,0x8b,0x94,0x21,0xf7, +0xad,0x1a,0xf1,0x24,0x45,0x3d,0x53,0x63,0x6c,0x1a,0x9e,0x92,0x69,0x0e,0x3b,0x79, +0x93,0x17,0x2c,0xfd,0x5a,0x1f,0xdd,0x3e,0xa0,0x0d,0x16,0xf9,0x66,0x21,0x22,0x74, +0xfe,0x3e,0xa1,0x09,0x1e,0x2d,0x7d,0x6f,0xc4,0x20,0xaf,0x3c,0x34,0x8a,0xc9,0x04, +0xf4,0x0b,0x67,0x71,0x0e,0x80,0x7b,0x31,0xa9,0xe7,0x38,0x30,0xf9,0xb9,0x67,0x98, +0xa0,0xc7,0x76,0x81,0x42,0xd9,0xef,0xc6,0x49,0x47,0xbd,0x25,0x79,0x10,0x76,0xe0, +0x65,0xdb,0xa8,0x3b,0x07,0x5f,0x59,0xad,0x39,0x9a,0xbf,0xf4,0x98,0xf2,0xa6,0x19, +0x1e,0x7a,0x47,0xc8,0x79,0x23,0x93,0x2b,0xee,0xc0,0x5f,0xd5,0xd2,0x1c,0x2a,0xdb, +0x81,0xa7,0xa8,0xd4,0x0b,0x92,0x2e,0x99,0xac,0x24,0x84,0x21,0x5c,0xc7,0xc0,0x06, +0xea,0x26,0xbe,0xb1,0x01,0xa8,0x4f,0x8a,0xfb,0xb8,0x10,0x9a,0x38,0x79,0xbf,0x74, +0x7b,0x3e,0x72,0xfa,0x3f,0xbf,0x7c,0xb2,0x62,0x16,0x34,0xd5,0x79,0x11,0xfd,0x9c, +0xd8,0x24,0xb9,0x84,0xab,0xdd,0x65,0xf8,0xad,0x73,0x7b,0x36,0x8c,0xe7,0x17,0x5e, +0xdc,0xd7,0xa9,0x95,0x8d,0x08,0x22,0xa7,0x38,0x94,0x9e,0x97,0x6e,0xb8,0x1b,0x1c, +0x05,0x21,0x4f,0x26,0x93,0x7a,0x38,0x6b,0x2b,0xa6,0x02,0x12,0x13,0x50,0x84,0x9a, +0x1d,0x4c,0x4f,0xb5,0x68,0x43,0x2b,0xa5,0xb9,0x34,0x3f,0x22,0x0c,0x36,0xbf,0xc7, +0x09,0x2e,0xf8,0xbf,0xd2,0xaf,0x94,0xfb,0xa6,0x07,0xa0,0xa7,0x0b,0x32,0xad,0x5d, +0xc1,0xdb,0xd2,0x2a,0x57,0x01,0x0b,0x75,0xca,0x4d,0xb6,0xa4,0xc3,0xc6,0x65,0x76, +0x23,0x03,0xb7,0xe3,0x37,0xf3,0x17,0x7e,0xf7,0x47,0x9f,0x8e,0x8d,0xd3,0x16,0x47, +0x7a,0x6d,0x58,0x53,0x4f,0x82,0xe9,0x76,0xd5,0x32,0x0b,0xc5,0x26,0x34,0x84,0x45, +0xc1,0xa8,0x00,0xaf,0xf8,0xac,0x7a,0xc4,0xb6,0xff,0x0e,0xbd,0xb0,0xfb,0x7f,0x49, +0xb9,0x6c,0xf4,0x5e,0x5d,0x17,0x56,0x23,0x55,0x61,0xec,0x9b,0x40,0xfc,0x0b,0x9d, +0x90,0xec,0x40,0x01,0x76,0x02,0x33,0xd3,0x84,0x25,0xa7,0x8e,0x2a,0xc8,0x8b,0xec, +0x0c,0x38,0xa6,0x71,0x31,0x7b,0x2a,0x87,0x06,0x62,0xa2,0x0e,0xa2,0x25,0xad,0x09, +0x95,0xb0,0x64,0x93,0x44,0x87,0x46,0x6e,0xcc,0x9f,0x07,0xe3,0x7b,0x24,0x2e,0xf6, +0xa8,0xdd,0x7c,0xa3,0xfa,0xb7,0x7f,0x6b,0x27,0x20,0x29,0x67,0x37,0x31,0x96,0xc5, +0x70,0x76,0xcb,0x38,0xfb,0x28,0x63,0x73,0x3f,0x9f,0xab,0xe1,0x13,0x91,0x8f,0xa8, +0xce,0x9f,0x73,0xf5,0xc4,0x6b,0x2c,0x90,0x8e,0x77,0x9d,0xb1,0x3e,0x9e,0x77,0xb7, +0xb8,0x72,0x06,0xe8,0x38,0x91,0x20,0xd6,0x39,0xaf,0xec,0x03,0x17,0x40,0xbc,0xbd, +0x86,0x36,0x1d,0x58,0x9b,0xb3,0x6e,0xe7,0xd5,0xe6,0xeb,0x73,0x13,0x06,0x27,0x99, +0x7a,0x95,0xb5,0x28,0xd5,0x45,0xa9,0x67,0x28,0x2b,0xa4,0x5a,0x08,0x8c,0x31,0xa5, +0xbd,0xdf,0x49,0xe4,0xf3,0x81,0x11,0xa9,0x97,0x02,0xd9,0x58,0xb1,0x12,0xab,0xae, +0xd3,0xd4,0x6b,0xc6,0x02,0x03,0xeb,0x35,0x1f,0x25,0x91,0x2d,0x2f,0x07,0xbb,0x03, +0xe8,0x33,0x29,0x86,0x76,0xe3,0x72,0xac,0x9c,0x74,0x1c,0x02,0x19,0x9d,0xdc,0x14, +0x8d,0x3b,0xd8,0xd2,0xe8,0x26,0x29,0x81,0x5a,0x21,0xb6,0xd6,0xaa,0x45,0xcd,0x67, +0xda,0xb4,0x61,0x22,0x9d,0x45,0x97,0xf5,0x12,0x07,0x61,0x8b,0xc8,0xdd,0x5e,0x20, +0x95,0xa1,0x0d,0x7c,0x95,0x76,0xf5,0x38,0xda,0xe6,0x09,0x2b,0xe9,0x20,0x50,0xbd, +0x4d,0xd6,0x2f,0x3a,0xad,0x72,0x2a,0x7f,0x8e,0x00,0xec,0x66,0xb0,0x31,0x21,0x9c, +0x43,0x25,0x16,0x04,0xb5,0x29,0x0a,0xf3,0xd7,0x3b,0xe6,0x4a,0xe6,0x1d,0xea,0x4b, +0x7c,0x55,0xe5,0x43,0x17,0x34,0x22,0xee,0x3d,0x2f,0x75,0xe3,0x26,0xef,0xe6,0x7e, +0xc3,0x2a,0x5d,0xb9,0x59,0xcd,0xba,0x0d,0x57,0xf3,0x56,0x1b,0xea,0x3c,0x52,0x2c, +0x17,0xc6,0xdb,0x47,0x64,0x3b,0x90,0x33,0xea,0x78,0x3a,0x2a,0xc7,0xe9,0x1f,0xfe, +0x57,0x84,0x32,0x85,0x74,0x76,0x05,0xc4,0xbf,0xde,0x35,0xdd,0x28,0x78,0x80,0xe2, +0xd1,0x1b,0x29,0x24,0x6a,0xe2,0x43,0x87,0x34,0x2e,0x3f,0xf2,0x4b,0x2a,0x28,0xd3, +0x92,0x59,0x42,0xce,0x72,0xd6,0x21,0x1e,0x2d,0xb8,0x29,0xb6,0x2d,0x39,0x3c,0xa4, +0x41,0xa9,0xe2,0xc9,0x02,0x13,0x70,0xe0,0x4e,0xa0,0xb6,0x66,0x5f,0xdb,0x84,0x2e, +0xfb,0x16,0x50,0xe5,0xb6,0x0c,0xe8,0xf8,0xce,0xa2,0x54,0x73,0x9f,0xac,0x00,0x8f, +0xaa,0x39,0x14,0xfb,0x8d,0x64,0xfe,0x54,0x72,0xab,0xcd,0x64,0x3c,0x5e,0x81,0xfe, +0x3b,0x6b,0x52,0x6b,0x15,0x4e,0x3d,0x9f,0x60,0x4b,0x4b,0x55,0x87,0x16,0x28,0xef, +0x7b,0x2a,0x0e,0x17,0x69,0xfc,0xf9,0xdb,0xd1,0x80,0x02,0x06,0xe9,0xb4,0x30,0x8b, +0x51,0x9f,0x52,0x8e,0xa4,0xa3,0xd4,0xde,0x58,0x56,0x9d,0xa1,0x14,0xa1,0x73,0x29, +0xd3,0x94,0x82,0x8c,0xaa,0x44,0x54,0xd0,0x65,0xb5,0x4d,0x1f,0xd0,0x18,0x6b,0xe7, +0x24,0xe7,0xd3,0xed,0x34,0x5c,0x59,0x89,0x1c,0x49,0x98,0x6c,0x77,0x17,0x0c,0xe4, +0x91,0x37,0x9e,0x41,0x95,0x36,0x8a,0x06,0x9d,0x46,0xc5,0x5a,0xac,0x53,0x0d,0xe2, +0x3c,0x04,0x73,0xad,0x45,0x39,0x3c,0x4d,0x16,0x6e,0xaa,0x88,0xec,0xa1,0xdb,0xd7, +0x78,0xfd,0xe4,0x9c,0xb7,0x30,0xfc,0x40,0xbb,0xe8,0x09,0xdf,0x48,0xb2,0x2f,0xa3, +0x26,0x88,0xba,0x74,0xcc,0x32,0x1b,0x10,0x59,0x4d,0xa7,0x4c,0xd5,0x28,0x08,0x0e, +0x97,0xda,0x6b,0x75,0xdd,0xd0,0x25,0x08,0x84,0x05,0x3b,0x9a,0xcb,0x76,0xf1,0xfd, +0x07,0xe7,0x73,0x1d,0x53,0x42,0x63,0xfc,0x07,0x9d,0xf8,0x94,0xa6,0xd7,0xc4,0x02, +0x2e,0x8d,0x0d,0x84,0x26,0xd5,0x26,0x0f,0x3a,0xdd,0x68,0xf3,0x8c,0x40,0xa8,0xcf, +0x30,0x7e,0x85,0xd6,0x1c,0x8d,0x29,0x63,0x0d,0x48,0x92,0x17,0x08,0x67,0x35,0x2b, +0x13,0x4d,0xd3,0x2b,0x23,0x83,0x8e,0x90,0xc3,0x0e,0x93,0xea,0x7b,0xcd,0xd8,0x39, +0x33,0x68,0x62,0x5a,0x47,0xed,0x96,0x92,0xec,0x11,0xa0,0x20,0x83,0x96,0x5f,0x04, +0x5c,0x93,0x6d,0xf8,0x7c,0x18,0xd1,0xd4,0xed,0x85,0xff,0x01,0xed,0xba,0x33,0x87, +0x10,0x08,0x9e,0x1c,0xc9,0xe0,0x97,0xcb,0x6d,0x4c,0x97,0xf6,0xdf,0x27,0x3f,0x82, +0xa3,0xab,0x03,0x97,0xbb,0x11,0x16,0x01,0x78,0x89,0xe5,0x8b,0x28,0xc0,0xc7,0x1c, +0x36,0x00,0x0a,0xf1,0x8d,0xc5,0x1f,0x99,0xd6,0x2d,0x51,0xda,0x8e,0xbe,0xe0,0xb7, +0xfe,0x77,0x28,0x90,0x7f,0xeb,0x66,0x66,0xcd,0x05,0x94,0xf5,0xe3,0x01,0x39,0x65, +0x59,0x54,0x57,0x2a,0x27,0xc4,0x4d,0x9c,0x69,0x7b,0xa6,0xd0,0x4d,0x54,0x6b,0x03, +0xba,0x44,0xff,0x3c,0x4b,0x36,0x46,0xc3,0x00,0x5e,0xba,0xdb,0xe3,0x3f,0x04,0xc7, +0x2a,0x7b,0x09,0xfc,0x2a,0x58,0x3f,0x1f,0x0b,0x13,0x92,0xe7,0xd5,0x49,0xf5,0x8e, +0x48,0xec,0x95,0x47,0x39,0xe0,0x75,0x18,0x7e,0xaa,0xaa,0x30,0x7e,0x46,0x1b,0x51, +0x95,0xb7,0xb3,0xa9,0x26,0x00,0x3e,0xeb,0xf6,0x59,0x54,0xb9,0xf3,0x4c,0x12,0x34, +0x92,0x9a,0x9d,0x8f,0xe4,0x92,0x4a,0x9d,0xbe,0xde,0xa4,0x20,0x52,0x08,0x72,0x6b, +0xa1,0x29,0xb0,0x24,0x44,0x5e,0x69,0x94,0xe4,0x56,0xfb,0x44,0xde,0xf6,0x5a,0x9a, +0x10,0x55,0xbf,0x59,0xb6,0x17,0x15,0xeb,0x5a,0x8c,0xca,0x87,0xe7,0x84,0x60,0xad, +0xbb,0x60,0x04,0x31,0x0a,0xa1,0xdf,0x2d,0xef,0x03,0x67,0x4b,0xaa,0x3e,0xdd,0xcc, +0xbc,0xfc,0xdc,0x05,0x03,0x57,0x15,0x44,0x95,0x4f,0xe3,0xf8,0xd6,0x1a,0x29,0xe9, +0x10,0xf1,0xf4,0x50,0x59,0xaa,0xc0,0xe7,0x95,0x07,0x7c,0xa6,0x76,0xfa,0x80,0x48, +0xf4,0xf2,0xff,0xea,0xd8,0x27,0x3c,0x87,0x66,0xa6,0x47,0x47,0x80,0x1c,0x15,0x19, +0x76,0x76,0xa1,0x9d,0x5a,0x88,0xf6,0x24,0xf4,0x32,0xe0,0x4d,0x66,0xeb,0xd0,0x7b, +0x42,0xde,0x67,0xa6,0x92,0x11,0x89,0x61,0x92,0xc6,0x59,0x8d,0x89,0xfa,0x8b,0x15, +0x73,0x6f,0xb3,0x22,0xdf,0xfa,0x42,0xdc,0xdd,0x1e,0x8b,0xb7,0xda,0xf7,0x3b,0xd7, +0x5d,0x0d,0xbd,0x8d,0xf8,0x74,0xba,0xfb,0xf8,0x6d,0x50,0x45,0x1c,0xe6,0xb5,0x9f, +0x84,0x73,0x0b,0x79,0x02,0xa7,0x52,0xcb,0xca,0x1b,0xc4,0x4c,0x44,0x14,0xf0,0xb2, +0x2a,0x32,0x71,0x6b,0x86,0xf9,0xde,0x4f,0xb8,0x65,0x5e,0xc5,0x8c,0xe2,0x92,0x01, +0x2f,0x8c,0xa3,0x28,0x04,0xe6,0xb6,0x6a,0x75,0x53,0x93,0xe7,0x6f,0xdd,0xa5,0xa6, +0x78,0x05,0x9a,0x2d,0xf1,0x2d,0xd0,0x7d,0xf3,0xf7,0xff,0xcc,0xf0,0xa8,0x2b,0x55, +0xdd,0xa4,0xbe,0x2c,0xa0,0x4e,0x1f,0xcd,0x4a,0x15,0x5c,0xdb,0xfc,0xee,0x8d,0x4b, +0xc7,0x3b,0xea,0xca,0x70,0x7b,0xcc,0x30,0xd1,0x05,0xd2,0x29,0x33,0x85,0x30,0x84, +0x31,0x6b,0xcd,0xff,0x9f,0xfc,0x5c,0x9d,0xb3,0xc9,0xd9,0x6e,0xaf,0x25,0x86,0x1b, +0xc8,0xcb,0x52,0x07,0x34,0x9e,0x00,0x66,0x35,0xa9,0xf2,0xb4,0x2a,0x75,0xe5,0x76, +0x8e,0xfc,0xfa,0x1d,0x8e,0xe8,0x5a,0x85,0x82,0xf2,0x68,0x94,0x2a,0x46,0x7d,0x9a, +0xb0,0x74,0x1b,0xd9,0x73,0x19,0xca,0xaf,0xdd,0x1f,0xc5,0x36,0x0d,0x14,0x62,0x0e, +0xd1,0x33,0x62,0x26,0x75,0x81,0x60,0x2a,0x2b,0x8c,0x45,0x14,0x99,0x9e,0xdf,0xad, +0xc7,0x00,0x24,0x1d,0x83,0xcf,0xc9,0x23,0xd9,0x3f,0xe2,0x84,0xc0,0x81,0xd9,0xbd, +0x16,0xdb,0x0d,0x51,0x6f,0x79,0x50,0x47,0x35,0x9b,0xff,0x67,0x9b,0x27,0xd1,0xcc, +0x07,0x15,0x14,0x53,0x45,0x37,0xdf,0x56,0xfe,0x22,0xb9,0x1c,0xac,0xda,0xe1,0xe1, +0x1f,0xf8,0xfc,0x11,0xc2,0x95,0xb3,0xa6,0xd5,0x25,0xaa,0x62,0xd2,0x0d,0x58,0x02, +0xc9,0x39,0x57,0x8f,0xca,0xee,0x4a,0x85,0xe4,0x7f,0xfd,0x3e,0xa4,0x07,0x19,0x35, +0x39,0x41,0x93,0x2e,0xef,0x42,0x32,0x18,0xfe,0xd4,0x09,0x16,0x77,0xdd,0x51,0x54, +0xac,0x28,0xcd,0x5b,0x29,0x9c,0x07,0x23,0xc9,0xf0,0xe8,0x50,0x35,0x37,0x0d,0xb3, +0x9e,0x47,0x5a,0x02,0x9d,0x54,0xc1,0x1f,0xad,0x4d,0xb5,0x9f,0x1f,0xc3,0x66,0xf7, +0x3c,0xbf,0x78,0xd4,0x1f,0xd1,0x44,0x57,0xf2,0xaa,0xfb,0xe8,0x9e,0x07,0x5d,0xbf, +0x08,0x60,0xd9,0xff,0xd7,0x1c,0x30,0xdf,0xc4,0x04,0xb7,0xa4,0x96,0x70,0xc9,0x84, +0x8c,0xe8,0x6a,0xaf,0xc2,0xcc,0x56,0x37,0xdc,0x94,0x1e,0xf6,0xe2,0x59,0x88,0xd9, +0xe7,0xba,0xe8,0x4b,0xe4,0xee,0xd1,0x5c,0x65,0xac,0x54,0x73,0x5a,0xbf,0xd7,0xab, +0xd7,0x7a,0x36,0x84,0xfa,0xce,0x66,0xc3,0xbe,0x05,0xf6,0x81,0x94,0x94,0x99,0x81, +0x8b,0xe6,0x1f,0xda,0xea,0x07,0x8d,0x1d,0xea,0x3a,0x3c,0xd3,0x68,0x34,0x4d,0x7d, +0xa5,0x58,0xf2,0xc1,0xb8,0xfb,0x12,0xbd,0x2a,0x3b,0x8e,0x8e,0x95,0xd2,0x7c,0x38, +0x22,0x3d,0xb2,0xb5,0x96,0x1f,0x82,0x60,0xd2,0x6a,0x70,0x3b,0x3e,0xb0,0xaf,0x41, +0xf5,0xe5,0x8b,0x71,0xc6,0xa4,0xa8,0x98,0x32,0x5b,0x0b,0x4d,0x27,0x0f,0xfd,0xf1, +0x22,0x49,0xed,0xd1,0xd5,0x6c,0x6e,0x10,0xd9,0xbc,0x38,0x04,0xc4,0xfd,0x4e,0xef, +0xd7,0x85,0x40,0x4a,0xbb,0xa1,0xa3,0x3f,0x0c,0x33,0x21,0x9e,0xd1,0x3f,0xa8,0xad, +0xf2,0x51,0x3f,0xd6,0xfa,0x69,0x38,0x96,0x30,0xd9,0x5f,0x52,0x13,0x84,0x38,0x31, +0x23,0x92,0xd6,0x7c,0x34,0xa1,0xe3,0x05,0xa7,0xc9,0x90,0x55,0x79,0xb1,0xba,0xcd, +0xe4,0x0f,0x51,0x11,0xe8,0xfa,0xfa,0x74,0x99,0x5f,0xe6,0xa1,0x1e,0xbe,0x8f,0x97, +0x13,0x12,0xa2,0xbd,0xd5,0x31,0x57,0xc1,0x06,0x19,0x88,0xab,0xc5,0xdd,0xc5,0xd1, +0xd1,0xfd,0xb4,0x24,0xdf,0xdc,0x96,0xf1,0x88,0x73,0xce,0x09,0x46,0xdf,0xd5,0x8e, +0x04,0xbc,0xbe,0x8b,0x8f,0x35,0x62,0x0c,0x8f,0xa6,0x5a,0x93,0x00,0x00,0x00,0x05, +0xa3,0x25,0x2c,0x99,0xdd,0xfd,0x89,0xe3,0x19,0xa6,0xf8,0xd3,0xa3,0x95,0x3f,0x69, +0x05,0xca,0x60,0x67,0xda,0x34,0xf6,0xa9,0x03,0x00,0x77,0xe3,0xec,0xb8,0xde,0x0c, +0xbe,0x38,0x7a,0x44,0x90,0x5a,0xa2,0x5d,0xf5,0x3a,0x2c,0x0e,0x29,0x4e,0x04,0x1f, +0xd4,0xd5,0x79,0x56,0x7e,0xd6,0x4f,0x15,0xa4,0xad,0x9c,0x49,0xc9,0x5d,0x70,0x2b, +0xbb,0x2a,0x6c,0x06,0x69,0xb9,0x4c,0xb5,0x04,0x06,0x97,0x52,0xaa,0x5b,0xf5,0x63, +0x85,0x19,0x8c,0x03,0x3a,0xb8,0x64,0x88,0x3a,0x9a,0x36,0x81,0xa1,0x7f,0xc7,0xaf, +0x79,0x16,0xcc,0x12,0xbc,0xb3,0xca,0x53,0x62,0xf9,0x1f,0x19,0xde,0xa9,0xf2,0xe5, +0x04,0x9f,0xc6,0xee,0xb2,0x49,0x5b,0x89,0x60,0xe6,0xb4,0xac,0x3a,0x04,0xfc,0xe0, +0x3b,0x46,0x7b,0x5a,0xf1,0x5e,0xfa,0xac,0xd4,0x78,0x2d,0xfe,0x0d,0x74,0x75,0x3a, +0x7e,0x99,0x4d,0x24,0xfd,0x53,0xe1,0x61,0x4f,0xd1,0xea,0x55,0x4f,0xaa,0xb7,0x91, + +}; +#endif /* WOLFPKCS11_LMS */ + +#ifdef WOLFPKCS11_XMSS +/* XMSS-SHA2_10_256 known-answer vector (RFC 8391). */ +static const CK_BYTE xmss_kat_pub[68] = { +0x00,0x00,0x00,0x01,0xd7,0x0b,0xb1,0x4d,0x46,0xa9,0x21,0xa2,0x97,0x03,0x87,0x3e, +0x05,0xfb,0x5c,0xa2,0x2f,0xfe,0x53,0xe0,0xf1,0x7b,0x56,0x62,0xd4,0x7c,0x25,0xdf, +0x2c,0xe7,0x2a,0x35,0x56,0x9c,0x82,0x31,0xc8,0x0c,0x2f,0x37,0x1c,0x49,0x95,0xe4, +0x1e,0x7a,0x4a,0x4f,0x51,0x07,0x25,0xd1,0xae,0x2c,0xaf,0xfd,0x2d,0xaf,0xf2,0xe3, +0x9e,0x10,0x34,0x36, +}; +static const CK_BYTE xmss_kat_sig[2500] = { +0x00,0x00,0x00,0x00,0x9e,0xf8,0xb9,0xac,0xb8,0xfe,0xdd,0xc9,0x3f,0x08,0x19,0xf9, +0x55,0x88,0x6e,0x1d,0x1e,0x47,0xc5,0xab,0x37,0x37,0xa5,0xa7,0xcb,0xea,0x23,0x9f, +0x1c,0x06,0xdb,0x62,0x86,0x0e,0xde,0xc6,0x86,0xb7,0xa0,0xd9,0x5f,0x1a,0xf3,0x76, +0x01,0x8f,0xc3,0x83,0xce,0x9c,0xc5,0x0b,0x0c,0x43,0x0d,0x71,0x9f,0xd2,0x92,0x13, +0x23,0x88,0xe1,0xad,0xb1,0x3a,0x74,0x22,0xff,0xbb,0x27,0x27,0xd4,0x69,0x27,0x2a, +0x73,0x95,0xa8,0xe2,0xdd,0xef,0x11,0x77,0xa7,0xbd,0xa4,0x8a,0xae,0x06,0x86,0xf3, +0x94,0x2b,0x5d,0x9b,0x60,0x88,0x91,0x3a,0x4e,0x32,0xea,0xdb,0x34,0x80,0x8a,0x71, +0x79,0x63,0x89,0xb8,0x93,0x04,0x6d,0xbc,0x98,0x25,0xa5,0x43,0x13,0x34,0x96,0xb6, +0xae,0x66,0x33,0xbf,0x91,0xde,0xad,0x75,0xa4,0xd4,0x30,0x0b,0xe9,0x8e,0x7d,0xe2, +0x15,0x61,0x2a,0x03,0x8f,0xa1,0x25,0xb9,0x2f,0x1e,0xd8,0xc0,0x32,0x16,0x3a,0x78, +0x5f,0xea,0xed,0x79,0x36,0xaf,0x16,0x5b,0xaa,0x29,0x2e,0x39,0x12,0xf5,0x57,0x42, +0x32,0xce,0x70,0x00,0xf7,0xfc,0x51,0x90,0xb5,0x3b,0x51,0xee,0xb2,0x31,0x3f,0xcf, +0xc7,0x7e,0x13,0xe1,0xb8,0xc9,0x7f,0xb4,0xa5,0x89,0x20,0x1f,0x04,0xad,0xe6,0x09, +0x12,0x94,0x48,0x7a,0xa5,0x1a,0x78,0x3f,0x30,0x0d,0x44,0xf6,0xec,0x2c,0x9d,0x34, +0x5a,0x10,0xbd,0xf9,0xb2,0x96,0xda,0x19,0x25,0xb2,0x9a,0x30,0x07,0x37,0x78,0x6e, +0xd1,0x51,0x2e,0x90,0xfd,0xc1,0xd3,0xe0,0xee,0x38,0x4a,0x82,0x87,0x05,0xe4,0x7d, +0x45,0x4c,0x50,0xab,0xb6,0x4b,0x49,0xc5,0x1f,0x08,0x9a,0x26,0xac,0x1c,0xee,0xc6, +0xf5,0xc5,0x4a,0xf9,0xef,0xe6,0x12,0xfb,0xa1,0xc7,0x2e,0x3a,0x00,0xfe,0xad,0x45, +0x4f,0xb7,0x5d,0xdf,0xe9,0x7f,0x0c,0x7c,0x27,0x7f,0x93,0x61,0x76,0x12,0x29,0x89, +0x73,0x44,0x31,0xc3,0x6d,0xe5,0x6c,0x1c,0x5c,0xb7,0x0d,0x45,0xdb,0xe0,0x42,0x4f, +0xff,0xc8,0xa7,0x0d,0xbc,0x1c,0x0d,0x8b,0xde,0xde,0x29,0x40,0xc2,0x72,0x05,0xde, +0x87,0x50,0xfa,0x00,0x58,0x0c,0x67,0x82,0xb1,0x36,0x33,0x1b,0x35,0xe2,0xdc,0x0d, +0xb1,0x8f,0x6c,0x0b,0x76,0xd6,0x99,0x9d,0x52,0xaa,0x84,0x07,0x35,0x3f,0x1d,0x31, +0x60,0x81,0xb4,0xad,0xe2,0x17,0x5a,0x9d,0x46,0x54,0x87,0x43,0x2e,0x6e,0x0e,0xa3, +0x99,0xa9,0x63,0xe4,0xf6,0x49,0xb0,0x98,0x34,0x2d,0x52,0x6b,0xc9,0x62,0x11,0xac, +0x6b,0x59,0x38,0x2f,0x45,0x11,0xc6,0xdb,0x29,0xe1,0xea,0x4d,0x44,0x0f,0x88,0x5d, +0x63,0x24,0x73,0x72,0x46,0x22,0x06,0xa9,0xea,0xbb,0xeb,0x69,0x30,0x3f,0xd7,0x95, +0xcf,0x41,0x4b,0x8f,0x10,0x59,0xb6,0x74,0x2e,0x09,0x8e,0xc6,0x94,0x2a,0x39,0x4b, +0x0e,0x00,0x6f,0x01,0xe2,0x75,0x0b,0xc1,0x37,0xdf,0x99,0x7d,0x11,0xad,0x79,0xdc, +0x05,0xac,0xae,0xc7,0xd0,0xc6,0x25,0x40,0xb0,0xfd,0x5a,0xc7,0x0a,0xde,0x19,0x36, +0x14,0x3d,0x72,0x7a,0xa3,0xd1,0x54,0xeb,0x0f,0xab,0x96,0x74,0x56,0x5f,0x23,0xa5, +0x9d,0xbc,0x9d,0xf9,0x80,0x3a,0x88,0xb8,0xfb,0xf2,0xbc,0x11,0x26,0x8a,0x3e,0x0e, +0xda,0xaf,0xe8,0x50,0xc9,0x65,0x88,0xbf,0xb6,0xee,0xcf,0xb7,0x1f,0x28,0xf1,0x33, +0x22,0xc4,0xe7,0xd4,0x2b,0x24,0xac,0xa8,0x7f,0x9a,0x40,0xdd,0xf2,0x3d,0x00,0x2f, +0xf9,0x98,0x96,0x95,0x3a,0x25,0xae,0x77,0x95,0x5f,0x9e,0xb9,0x16,0x7e,0xe9,0x85, +0x24,0xb7,0xb4,0x18,0x00,0xc4,0xae,0x79,0xab,0x64,0x34,0xe3,0x2b,0x56,0xf5,0xa2, +0x55,0x4c,0x4b,0xe8,0x5a,0x69,0x90,0x75,0x74,0x9f,0x24,0xd6,0x7e,0xcd,0xda,0xe2, +0xfb,0x9e,0xc0,0x22,0xcb,0x6d,0x59,0xb5,0x9a,0x97,0x35,0x1a,0x7c,0xbc,0xfc,0x87, +0x19,0x13,0x13,0x3e,0x08,0x37,0xb3,0x61,0x91,0x1b,0x99,0xb4,0x68,0xfd,0x20,0xc5, +0x7f,0xdc,0x2c,0x32,0x90,0xc3,0x1b,0xed,0x2c,0x45,0x73,0xf3,0x75,0xc2,0xb8,0xb2, +0x49,0x7c,0x51,0xd1,0x44,0x20,0x1c,0x92,0x05,0xc6,0x27,0x1e,0xa2,0x54,0x15,0x31, +0x09,0x99,0xb6,0x09,0x1c,0xac,0x9b,0xda,0xa6,0x59,0x16,0x6b,0xa5,0xe4,0xaa,0x9d, +0xcf,0xc5,0xfd,0x7e,0x8a,0xa5,0x88,0xbf,0x1f,0x69,0x1c,0x76,0x17,0x21,0x4a,0x86, +0x83,0x69,0x2a,0x4c,0xdc,0x3b,0xc1,0xc9,0xaf,0x02,0x8c,0x24,0x1a,0x1a,0x6e,0xa8, +0xcd,0x63,0xb2,0xf6,0xa1,0x02,0x81,0xd3,0x7e,0x94,0xef,0x0a,0xa2,0x0b,0xfc,0xa9, +0x0b,0xd0,0xc9,0xdc,0x84,0xee,0x68,0x63,0xd2,0xed,0x59,0x8d,0xa2,0x2b,0xf3,0x88, +0xc3,0x8c,0xc3,0x85,0x5b,0x3e,0x87,0xe6,0x90,0xc6,0x1f,0x22,0xfe,0xe1,0x38,0xea, +0x5a,0x31,0x82,0xf3,0xcd,0xae,0x9e,0x9c,0x4e,0xe9,0xef,0x13,0x98,0xb6,0x96,0x9e, +0xa6,0xc2,0x22,0x03,0x70,0xe1,0x69,0x20,0xdd,0xc8,0x8a,0xa3,0x67,0x27,0xc5,0x13, +0xfc,0x4c,0x6f,0x6b,0xa1,0xc7,0x44,0x72,0xd3,0x21,0x63,0x3e,0x2c,0x81,0xdc,0xec, +0x09,0x2b,0x5d,0xf5,0x76,0x1a,0xc2,0x3e,0x2e,0x58,0xa4,0x25,0x50,0x49,0x9f,0xa3, +0x92,0xce,0x4e,0x90,0xc1,0x6a,0xf8,0x85,0xa9,0x46,0xe8,0x5c,0x88,0xe6,0x76,0x91, +0x24,0x58,0x29,0x3d,0x98,0x33,0x8c,0x2f,0x0d,0x8a,0x14,0x82,0xc6,0x6a,0x04,0xdd, +0x45,0x21,0x77,0x2d,0x6a,0xd8,0x2d,0x6b,0xfd,0x0a,0x91,0xc2,0x33,0x97,0x48,0x9d, +0x61,0x73,0x77,0xcb,0xec,0xac,0x6a,0x0d,0x94,0xfa,0xe5,0xe1,0x3e,0xd3,0x74,0xfd, +0x43,0xf4,0x9f,0xa4,0x62,0x42,0xc8,0x19,0x4f,0xbe,0x53,0x97,0xf5,0xfe,0xe7,0x65, +0x2d,0x88,0x0c,0x35,0xb9,0xce,0xe2,0x8c,0x04,0x12,0xf3,0x90,0x89,0xe7,0x3e,0x0d, +0x70,0x1c,0x7e,0x53,0x80,0xc7,0x94,0x8e,0x32,0x15,0x5b,0xbe,0xb5,0x16,0xdb,0x86, +0xc4,0xdd,0xaf,0xe3,0x63,0x25,0xae,0x84,0x01,0xdd,0xcb,0x0e,0x60,0x7b,0x86,0xbf, +0x55,0xb2,0xb3,0x1b,0xd6,0x57,0xc9,0x70,0x98,0xac,0xd0,0x8f,0x14,0x5f,0x45,0x1b, +0x02,0x26,0x00,0xf0,0x67,0x09,0x79,0xce,0xf7,0x31,0x1b,0x2f,0xac,0x51,0x55,0xf0, +0xc4,0x4a,0x38,0x9e,0x96,0xad,0x6d,0x82,0xbb,0x8b,0xe6,0x9b,0x99,0xbe,0xec,0xe2, +0x3f,0x9c,0x3c,0x9d,0xb4,0x93,0x40,0x55,0x22,0xb4,0x5b,0xdc,0x24,0xc6,0xb5,0xe9, +0x5d,0x3f,0x1e,0x62,0x39,0x37,0x96,0x2f,0x42,0x32,0x1e,0xd8,0xff,0x4e,0xb7,0x48, +0x28,0xcd,0x1c,0xad,0x70,0x6c,0x89,0x79,0x9b,0x18,0xb5,0x34,0xc7,0xc5,0x26,0xca, +0x78,0x19,0x85,0xd7,0xa7,0xd2,0x6c,0xfd,0x54,0xa8,0x8d,0xd9,0xa6,0x79,0x4e,0xa8, +0x1d,0x97,0x66,0x9e,0x72,0x0b,0x74,0xc3,0x29,0x60,0x74,0xa0,0xa9,0xe1,0x59,0x9e, +0x2b,0x63,0xcb,0x04,0x3e,0xca,0x98,0xbd,0x46,0xaf,0x4d,0x32,0x59,0x51,0x85,0x52, +0x9d,0xdd,0xc1,0xdc,0xbc,0x0b,0xbe,0x8c,0x47,0x6f,0x9b,0x5d,0x18,0xc1,0xb1,0xbe, +0x07,0x0d,0x91,0x2b,0x47,0x28,0xc7,0xc8,0x02,0x71,0xf7,0xe2,0xb2,0x6d,0x9e,0x29, +0x5a,0xbd,0x41,0x4b,0x68,0xaa,0xc5,0x8f,0x3d,0xda,0xda,0x21,0x84,0xbe,0xf6,0xa0, +0xec,0xf9,0xee,0xc8,0x8a,0xa1,0xa5,0xbe,0xbf,0x81,0xe4,0x51,0xac,0xa4,0xa0,0x39, +0xc5,0xbf,0x2e,0xaa,0x7d,0x72,0xb3,0x29,0x59,0xc2,0x63,0x46,0xe4,0xf4,0xd7,0xe4, +0x64,0xdf,0x02,0x67,0xf3,0x52,0x93,0xee,0x77,0x52,0xe9,0x31,0xa8,0xed,0x37,0xd7, +0xaf,0xa6,0x63,0x5c,0x0b,0x75,0xc3,0x45,0xb9,0xb7,0xa2,0x6d,0x0e,0x6d,0x58,0xf4, +0xb8,0xeb,0x25,0x70,0x44,0x23,0xb4,0x6c,0xbc,0x7d,0x7b,0x18,0x1a,0x1c,0xb7,0xb1, +0x99,0x40,0xb4,0x4e,0x6e,0x78,0x73,0xe4,0xa4,0xc6,0x46,0x07,0x1e,0xd9,0x77,0x86, +0x15,0x4b,0xdc,0x79,0x4f,0xd1,0xa7,0x5c,0x2c,0xbb,0xa9,0x9b,0x8f,0x27,0x26,0xc2, +0x50,0xf9,0x6e,0x46,0x41,0x8e,0x79,0x0f,0xcf,0x6e,0x3e,0x20,0xea,0x29,0xb9,0xec, +0x19,0x56,0xe6,0x01,0x4a,0x6d,0x6b,0x1f,0xb2,0xa1,0x62,0x61,0xbb,0x6d,0x56,0xfc, +0x09,0x77,0xc0,0xfe,0xd0,0xf6,0x79,0xd5,0xfb,0x61,0xe6,0xbc,0x76,0xc7,0xd7,0x18, +0xa8,0x24,0xda,0xec,0xf2,0xf4,0x2c,0xed,0xb8,0xcf,0xdf,0x16,0xc2,0x13,0xb4,0x21, +0x05,0x8f,0xa7,0x77,0x60,0x1b,0xeb,0x7f,0x7e,0xa2,0x79,0x44,0xae,0x06,0x80,0xd9, +0xb2,0xa1,0xd2,0xa7,0x14,0x19,0x90,0x6d,0x64,0xef,0x65,0x1a,0xf8,0x64,0x08,0xae, +0x48,0xc0,0x6f,0x08,0x12,0x43,0xe4,0x35,0xb6,0x52,0x20,0x2b,0xf3,0xda,0x03,0x5b, +0x5f,0x3d,0xd4,0x99,0xb7,0xb8,0x4d,0x72,0x97,0x7d,0x8c,0x21,0x77,0xde,0x61,0x5c, +0xd6,0x40,0x6a,0xe6,0xaa,0xfe,0xe6,0x9f,0x36,0xce,0x3b,0xfa,0xa0,0xe3,0x16,0xfc, +0xd7,0xee,0x32,0x15,0x34,0xad,0x71,0xe9,0xdd,0xdc,0x1b,0xeb,0xb6,0xc7,0xb1,0x95, +0x2a,0x68,0x88,0x10,0xb6,0x61,0xf6,0xd4,0xaf,0x8f,0xc0,0x92,0x73,0x18,0x5b,0x87, +0xbb,0x39,0x62,0xf0,0x6d,0x7e,0x69,0x38,0xce,0x5e,0x42,0x26,0x26,0x2e,0x02,0xae, +0x2d,0x4e,0xe3,0xde,0x0b,0xfe,0xb3,0x14,0x97,0xd8,0xcd,0xc1,0x86,0x63,0x10,0xcc, +0x95,0x12,0x8a,0x61,0xa3,0xa1,0x73,0xd5,0x96,0x8e,0x30,0xeb,0xef,0x82,0x5f,0x3d, +0xca,0x82,0x7a,0xb7,0x77,0xdc,0xac,0xac,0x97,0xcf,0xad,0xff,0x25,0xcd,0x4e,0x8f, +0xde,0xdf,0xa0,0xae,0xed,0xc0,0x6e,0x23,0x21,0xfb,0x89,0xdb,0x07,0x28,0xee,0xe9, +0xbd,0xff,0x82,0xb4,0x2a,0x4f,0xd1,0xfd,0x83,0x25,0x35,0x08,0x21,0xd1,0xef,0x47, +0x5f,0x41,0x06,0xf5,0x7e,0xad,0x57,0x5d,0x52,0x13,0x17,0xc0,0x14,0x3c,0xe9,0x90, +0x72,0xf0,0x32,0x25,0x7e,0x86,0x62,0x4b,0xce,0x3e,0x57,0x9e,0x36,0x18,0x58,0x7d, +0xea,0x24,0xde,0x9e,0xf0,0x09,0x87,0xfa,0x0f,0x4d,0x81,0xab,0xdc,0xdf,0x03,0xee, +0x83,0xd1,0xf9,0x85,0x0a,0x49,0x65,0x75,0xcd,0x84,0x08,0xf3,0x2e,0xd2,0x07,0x06, +0xf2,0x8c,0x4b,0x96,0x4f,0x79,0x97,0x31,0x16,0xd9,0x5b,0xe4,0x38,0x6b,0xed,0x94, +0xe9,0x18,0x6a,0x99,0xf4,0x38,0x23,0x30,0xe5,0xac,0xca,0x3e,0xe4,0x7f,0x93,0x63, +0xbd,0x74,0xa5,0x6f,0x99,0x92,0xb3,0x6b,0xed,0x45,0xd4,0x7e,0xe2,0x59,0x1e,0x19, +0xe8,0x3b,0xf5,0x73,0xe5,0x49,0xe7,0x8e,0xca,0x8a,0x43,0x1a,0xa7,0x0f,0x8d,0x7a, +0x0e,0x06,0xb9,0x15,0xe0,0xbc,0x11,0x0c,0x9b,0x00,0xcd,0xe6,0x0a,0xb1,0x5d,0x3d, +0x68,0x96,0xe1,0x42,0x97,0xff,0xd2,0xbb,0x93,0x32,0x03,0xd9,0x84,0xd1,0xdc,0x2b, +0x42,0xe8,0xef,0x1c,0x89,0x32,0x3e,0x4c,0x83,0x2d,0x98,0x04,0x00,0x9a,0x4b,0xad, +0x37,0x77,0xc9,0xea,0x0d,0xe2,0xd1,0x50,0x1a,0x92,0xf6,0x55,0xac,0x25,0xc2,0xaa, +0x08,0x02,0x88,0x1b,0x36,0xf2,0x2c,0x5c,0x95,0x1b,0x26,0x6c,0x11,0xf9,0x51,0xad, +0x49,0x02,0x65,0x33,0xe7,0xb5,0x61,0x40,0xb7,0x5e,0x96,0x65,0xe7,0x33,0xad,0x39, +0x06,0x36,0xa2,0x6e,0x1d,0x48,0x15,0x52,0x24,0xdc,0x1e,0xbb,0xd1,0xa3,0xbf,0x6b, +0xb6,0x56,0x9d,0x79,0x0c,0xce,0xe9,0xab,0xee,0x36,0xc0,0x0b,0xce,0xd4,0xed,0xeb, +0x7d,0x52,0x9a,0x3d,0x8a,0x71,0xd1,0xa0,0xa0,0x1f,0xc9,0x13,0x98,0xea,0xad,0x27, +0x2b,0x50,0xfd,0x54,0xbe,0xe1,0x72,0x4b,0xc7,0xc8,0x60,0xda,0xcb,0x76,0x5a,0x14, +0x12,0x1e,0xe6,0xad,0xfa,0xb1,0xc0,0xe8,0xfe,0x3c,0x40,0xfb,0xb4,0xb4,0x56,0x04, +0x66,0x22,0x24,0x01,0x13,0x84,0xc6,0x36,0x82,0x71,0x81,0x31,0xde,0x46,0x1e,0x61, +0xdd,0xa6,0xb4,0xee,0x8c,0x4e,0xc1,0xeb,0x0f,0xe2,0x2e,0x8a,0x6a,0xd4,0xf5,0x20, +0x35,0x34,0x0a,0xfd,0x9b,0x85,0x4a,0x6b,0xf9,0xfb,0x3b,0xad,0xf7,0xf1,0x02,0x96, +0xbf,0x00,0xe1,0xe3,0x35,0xfb,0x63,0xb9,0xa0,0x7f,0xf4,0xd6,0x70,0x4a,0x2e,0x47, +0x34,0x85,0xfa,0xc5,0xab,0xb3,0x07,0xe9,0x94,0x6f,0x11,0x97,0xad,0xdb,0x88,0x96, +0x3c,0x65,0xd4,0x6c,0x01,0x32,0x1b,0xbe,0x7d,0xa9,0x10,0x27,0x68,0x71,0x7c,0x23, +0xbb,0x78,0x26,0xd0,0x0c,0xe9,0xae,0x76,0x6b,0x46,0xba,0xeb,0x26,0x2b,0xea,0x54, +0xe3,0xff,0x89,0x03,0x9c,0xdf,0x3b,0xb0,0xa7,0xb5,0x48,0x44,0xa7,0x23,0xab,0x2b, +0xb1,0x7d,0x09,0x05,0x91,0x3a,0x3d,0xc6,0xd7,0x8a,0x16,0x72,0x1a,0x8f,0xce,0x99, +0xd0,0x7a,0xbe,0x67,0x06,0xf4,0x8f,0xf1,0x69,0x40,0xe1,0xe5,0xe1,0xb9,0x91,0x2b, +0x23,0x98,0x99,0xfc,0x91,0xe1,0x0f,0xac,0xcf,0x51,0x2b,0xfc,0xc3,0x0f,0xdd,0x2a, +0x97,0x6d,0xe5,0x1f,0x3e,0x5a,0x33,0x70,0xec,0x6d,0x99,0xdf,0x8f,0x26,0xed,0xf3, +0x45,0xee,0x11,0x16,0xe6,0x8f,0x5f,0xbf,0x20,0xb8,0xca,0x89,0x5b,0x29,0x76,0xec, +0x57,0xb7,0x5b,0xe7,0x72,0x86,0x2d,0xb3,0xd7,0x99,0xcd,0x9f,0xec,0x7b,0x53,0x92, +0x4b,0x87,0x59,0x43,0xec,0xdd,0x19,0x0d,0xd7,0xc0,0x22,0xa8,0x44,0x3e,0xc8,0x7a, +0x99,0xa8,0x4f,0xa8,0x25,0xf2,0xc0,0x2c,0xa5,0x98,0xcf,0xbe,0xff,0x5f,0x79,0x1a, +0x5e,0x4b,0xc0,0xdc,0x17,0x2d,0x29,0xab,0x6a,0xe3,0xfd,0xcc,0x70,0x70,0x75,0xbd, +0x2d,0x52,0x2b,0x9a,0x1d,0x3b,0x8f,0xe4,0xb7,0x2a,0x9e,0x98,0x39,0x17,0x46,0x32, +0xc7,0xee,0x53,0x33,0x36,0x80,0xb9,0xa5,0x18,0xf0,0xb3,0x54,0xc0,0xbb,0x71,0x78, +0x0e,0x63,0xee,0xe0,0x0c,0x26,0x62,0x29,0xca,0x70,0xf9,0x99,0x24,0x17,0x3c,0xc7, +0x34,0xa5,0x59,0x72,0x14,0x1e,0xf1,0xb2,0x26,0x39,0x3c,0x7e,0xf9,0x66,0x77,0xe8, +0x6f,0x4f,0x74,0x98,0x18,0xd3,0xa7,0x82,0x8b,0xc8,0x1c,0x94,0xc9,0x7b,0xa5,0xc0, +0x2b,0x74,0x96,0x75,0x3b,0xe2,0xc8,0x72,0x54,0xfb,0x87,0xe5,0x4a,0x3e,0x7a,0x75, +0xf8,0xba,0x73,0x69,0xa4,0x26,0x2d,0x44,0xd2,0xc5,0x49,0xd9,0xc5,0xa7,0xe9,0xda, +0x72,0x5b,0x52,0x33,0xd4,0x09,0x78,0x1e,0x6e,0x39,0x17,0xf3,0xcd,0xfe,0x02,0x4b, +0x61,0xbe,0xb2,0x0c,0x94,0xf9,0x62,0xc9,0x8b,0x54,0x2a,0xe2,0x3c,0x28,0x12,0xcb, +0x62,0xd3,0x45,0x22,0xcf,0x15,0x6b,0x71,0x5d,0xbf,0x6f,0xda,0xed,0x41,0xf7,0xd1, +0xa3,0xd7,0x20,0x8b,0xe0,0x93,0x48,0x97,0x83,0x35,0x3d,0xd3,0xb5,0x09,0x51,0xa8, +0x3e,0xcb,0xb9,0x56,0x02,0x31,0xb9,0xda,0x29,0xfb,0xb0,0x94,0x0a,0xeb,0xde,0xf2, +0x99,0xd0,0xec,0x75,0x56,0xd1,0xc9,0x98,0x7c,0x02,0x2d,0x55,0xa1,0x0f,0x81,0x5d, +0x06,0x46,0xf2,0xd8,0xc8,0x64,0x06,0xb7,0x91,0x60,0xde,0xe3,0xba,0x1b,0xb0,0x24, +0xc3,0xce,0xb7,0x8e,0x44,0x1f,0x5b,0x22,0x70,0x47,0xa8,0x74,0xda,0x66,0x25,0x46, +0xce,0x91,0xf5,0x9d,0x20,0xb9,0xe2,0xc9,0xd4,0xc6,0xed,0x05,0xd3,0xd5,0x5c,0x99, +0x94,0x86,0x76,0x4f,0x41,0x0b,0x96,0x35,0xf2,0x50,0xfe,0x10,0x04,0xcb,0xe6,0x3a, +0x11,0xc2,0xcd,0x5a,0xfd,0xbf,0x2f,0xf9,0xe6,0x3d,0xf4,0x72,0xc2,0xdf,0xcf,0xb6, +0x1c,0x54,0x64,0x07,0xb8,0x33,0x04,0xe3,0xd2,0x43,0x76,0xf9,0x37,0x27,0x9e,0x5b, +0xb4,0xf4,0xc2,0x31,0x8e,0x83,0x8c,0x2a,0x2f,0x31,0x70,0x04,0x15,0xdc,0xb8,0xe2, +0x28,0x61,0xc7,0x56,0x05,0x22,0x69,0x96,0x08,0x9e,0x92,0xd3,0xc9,0x59,0x62,0x6e, +0xa4,0xea,0x66,0xb9,0x91,0x1a,0x6f,0xec,0x07,0x93,0x33,0x08,0x2a,0x6b,0x1d,0x48, +0xf5,0x9a,0xde,0xfb,0x8b,0x92,0xa1,0x78,0x12,0x31,0x3e,0xf7,0xdd,0x78,0xaa,0x0b, +0x0f,0xc0,0x0e,0x11,0x03,0xbb,0x2a,0xd5,0x0e,0x2f,0x3a,0x0a,0x23,0xf3,0x3b,0x72, +0x85,0x62,0xb7,0xbc,0xae,0xdc,0x9a,0xe3,0x8a,0x76,0x21,0x13,0x94,0x74,0xd7,0xf2, +0x5c,0xa6,0xd4,0x58, +}; + +/* XMSSMT-SHA2_20/2_256 known-answer vector (RFC 8391). */ +static const CK_BYTE xmssmt_kat_pub[68] = { +0x00,0x00,0x00,0x01,0x37,0xb2,0xd3,0x48,0x2b,0xac,0xbf,0x7f,0x69,0xea,0x7c,0x08, +0x1f,0x5d,0x6c,0xaf,0x97,0x6c,0xe7,0x80,0x4d,0x19,0x03,0xee,0xc4,0x7f,0xd4,0x4e, +0x00,0xf2,0x4c,0xf5,0x49,0x2e,0x7c,0x5e,0x17,0xf3,0x0b,0x53,0x50,0x72,0x89,0x48, +0x43,0x58,0xec,0xe3,0xdf,0x27,0x74,0x43,0xc0,0x8f,0x27,0x18,0x7b,0xb2,0xcd,0xa7, +0x43,0x54,0xd1,0xcb, +}; +static const CK_BYTE xmssmt_kat_sig[4963] = { +0x00,0x00,0x00,0x46,0x4b,0xbe,0xe0,0x3f,0x66,0x56,0xcb,0xca,0xc0,0xe0,0x43,0x52, +0xfd,0x7a,0x93,0xc7,0xda,0x47,0xe7,0x94,0x68,0x64,0x01,0xb5,0x6e,0xd1,0xee,0x5e, +0xa7,0x17,0xe4,0x33,0x8a,0x43,0x26,0x3a,0x91,0xd0,0xf6,0x8f,0xc9,0xb8,0x71,0x8d, +0x81,0x20,0xd3,0xaf,0x93,0x75,0xc4,0x06,0x6b,0x09,0x7e,0x72,0x1c,0xed,0x6e,0xa0, +0x3a,0xcf,0xb2,0x6b,0x03,0x2b,0x1e,0x46,0x0f,0xfd,0xb0,0x5d,0x94,0x57,0x4f,0x6a, +0x33,0x6f,0x73,0x65,0x3b,0xf2,0x51,0x14,0xa7,0x3c,0xfd,0xa6,0x15,0x7e,0xe2,0x19, +0xbb,0x39,0x3a,0x65,0x18,0x32,0x2f,0x22,0xf5,0x55,0x02,0xe2,0x40,0x40,0x92,0x45, +0xb0,0x38,0x17,0xde,0xc6,0xc7,0x01,0x41,0x9f,0x38,0x11,0x9a,0x61,0x86,0x55,0xc2, +0xb4,0xfe,0x8d,0x40,0x93,0xe7,0xc5,0x4f,0xf1,0xa2,0x54,0x40,0xa2,0xdf,0x42,0xe1, +0x77,0x06,0xa2,0x3f,0x3b,0x68,0xfc,0x1f,0xcc,0x57,0xa0,0x13,0x60,0x65,0xc6,0x24, +0xc9,0x3e,0x5b,0x0e,0xe6,0x75,0x8d,0xe3,0xca,0xad,0x70,0x82,0xae,0x9f,0x5c,0xe8, +0x1e,0xcd,0x29,0x8e,0xa8,0x25,0xdb,0x8f,0x4f,0x8e,0xb5,0x1d,0x27,0x32,0xe4,0x2e, +0x4c,0x1e,0xf0,0xbf,0xa5,0xc4,0xa6,0xb8,0x5d,0x48,0x06,0x7d,0xca,0x96,0xdf,0x76, +0x83,0xcf,0x89,0x85,0x97,0xa8,0x32,0xb1,0x1e,0x97,0x4c,0x34,0xad,0x13,0xd3,0xd0, +0xa0,0xe6,0x95,0x66,0x34,0x9b,0x6b,0x6b,0x83,0x63,0xa1,0x0b,0x47,0x9a,0xea,0x62, +0x94,0xf2,0x79,0x77,0x68,0xbc,0x27,0x1c,0xbd,0xb5,0x38,0x24,0x27,0x57,0x30,0xaa, +0x9b,0x91,0xa1,0x40,0xfa,0x7b,0xb2,0x3d,0x63,0x3b,0x35,0x76,0x05,0x44,0xa1,0x8f, +0xdd,0x82,0x9c,0x31,0x3b,0x64,0xac,0x66,0x9a,0x02,0xfa,0x3a,0xea,0x48,0xa3,0x89, +0xe0,0x61,0x10,0x9f,0xde,0xfc,0x01,0xac,0x77,0xed,0x51,0x69,0x31,0x9c,0x4a,0x59, +0x1a,0x0b,0xb3,0xdd,0x05,0xd6,0x71,0xb8,0x39,0x8b,0x0c,0xd9,0x61,0xe5,0x2d,0x59, +0x0b,0x1f,0xe1,0x08,0xa4,0x50,0x19,0x6c,0x5f,0xb2,0xd5,0x00,0xe4,0xbd,0xb8,0xe7, +0xad,0x70,0xd3,0xc7,0xad,0xf4,0xd0,0x90,0x40,0x77,0xf2,0xc7,0x9f,0xde,0x5f,0xea, +0xa9,0x72,0x97,0x13,0x52,0xa4,0xcf,0x11,0x6b,0x73,0xe2,0x48,0x03,0xfc,0x15,0xe7, +0x00,0x3b,0xe8,0xaf,0x12,0x66,0x88,0x02,0xfe,0xd2,0xe6,0xdd,0x82,0xa3,0x33,0x1e, +0xfb,0xe1,0xf1,0xe7,0x6e,0xa4,0xd7,0x32,0x69,0xd7,0xd8,0xa4,0x75,0x84,0xe3,0x2e, +0x3e,0xe2,0x13,0x24,0x9b,0xc5,0xa4,0xc0,0xd4,0x15,0x9d,0x7c,0x23,0x8d,0x2c,0x9a, +0x3b,0x39,0xee,0x99,0x6e,0x1d,0x8a,0x78,0x6b,0xb3,0x17,0xe3,0x9d,0x1c,0x27,0xc4, +0xe6,0x57,0x81,0x91,0xf9,0xe7,0x06,0x4a,0x89,0xea,0x9e,0x78,0x33,0x65,0x44,0xf3, +0xa4,0xe4,0x8e,0x48,0x9b,0xdb,0x7c,0xd5,0x61,0x36,0x51,0x38,0x42,0xdc,0x36,0x8c, +0xd2,0xf1,0x63,0x96,0x02,0xbf,0x97,0x4a,0xed,0x79,0x9c,0xd0,0xee,0x6f,0xbf,0xb8, +0xd7,0x2c,0x51,0xed,0x31,0x7d,0x8a,0xcc,0x63,0xf0,0x6a,0xc0,0x42,0xee,0xe7,0x91, +0xf0,0xc0,0x8e,0xc9,0xf4,0xb0,0xbe,0xba,0x6d,0x71,0x05,0x79,0x37,0x33,0xa2,0xa9, +0xba,0x1d,0x11,0x4a,0xcd,0x40,0x39,0x79,0x7f,0x35,0xbf,0x0e,0xf9,0xa4,0x9c,0x6c, +0xf6,0x3e,0x5b,0x95,0xbf,0xc3,0x4e,0x5c,0x83,0x20,0x81,0x49,0x71,0x5e,0x29,0x56, +0x15,0x27,0xb7,0xd6,0xa0,0x83,0xa0,0xc3,0xed,0x2f,0x2a,0xaf,0xc7,0xee,0x09,0x6e, +0xa4,0x46,0x8c,0xfe,0x0e,0x75,0xb4,0x9e,0xe2,0x19,0x84,0xd5,0x59,0x1c,0x50,0xb2, +0x7f,0xbf,0x38,0x29,0x63,0xf4,0x63,0x1e,0xe7,0x34,0xc7,0x8e,0xe2,0xf5,0x71,0x82, +0x62,0x3c,0x9d,0x90,0x52,0x04,0x1b,0xab,0xb7,0xe2,0xe0,0x42,0x69,0x5f,0xda,0xf8, +0xc5,0xc4,0x56,0xd5,0x5e,0xc9,0xf8,0x44,0xe8,0xce,0x33,0x44,0x78,0x14,0x60,0x8f, +0x7f,0xc5,0x19,0xff,0xca,0xef,0x53,0x13,0x9d,0x7e,0xa8,0x5c,0x5f,0x61,0x2f,0xdf, +0xe3,0xd7,0x2e,0x61,0xc6,0xb9,0xf0,0x71,0x9f,0xeb,0xdf,0x2a,0x1b,0x5e,0x3a,0x78, +0x10,0xcf,0x05,0xde,0x8c,0xf5,0xec,0x6b,0x5f,0xaf,0x97,0xef,0xf8,0xa5,0xb0,0x14, +0xd2,0x6a,0xc6,0x4e,0x06,0x86,0xad,0x83,0x31,0x66,0xbe,0xf6,0x2d,0xd5,0x4b,0x74, +0xc4,0x97,0xa4,0xef,0xf6,0x05,0xde,0x7b,0xfc,0x0e,0x16,0xd9,0xcb,0x8d,0x50,0xb5, +0xbb,0x36,0xf6,0x5f,0x27,0x07,0xa7,0x94,0xc5,0x1d,0xb6,0x4c,0x91,0xe5,0x0f,0x25, +0xad,0xde,0x28,0xb3,0xc4,0x8e,0x47,0x6c,0x21,0xbd,0x00,0x0d,0x8b,0x09,0x50,0x77, +0xa5,0x2b,0xa6,0x0d,0xc7,0x10,0xe9,0x84,0x85,0x7f,0xc4,0x5b,0x2e,0xaf,0x62,0xe8, +0x5a,0xe6,0x45,0xae,0x2a,0x6c,0xcf,0xeb,0xd1,0xdf,0x03,0x4c,0x68,0x1b,0x85,0x20, +0x56,0x79,0x0a,0xa4,0x6d,0x48,0xce,0xb6,0xd0,0xe6,0xa1,0xc6,0xf0,0x54,0xd9,0xaa, +0xd0,0x24,0x39,0xca,0xc3,0x8c,0x83,0x6a,0x32,0x8b,0xca,0x23,0x5a,0x80,0x8c,0x97, +0xc7,0x89,0x03,0x71,0x46,0x21,0x22,0xe3,0xe5,0xda,0xf5,0x3f,0xe2,0x2b,0x13,0x67, +0xef,0x45,0xb9,0xc3,0x61,0xd5,0xd9,0x63,0x23,0x7b,0x01,0x79,0xb5,0xc1,0x87,0x77, +0xf4,0xe7,0xe8,0xb6,0xce,0x64,0x85,0xb0,0x91,0x42,0x6e,0xb1,0x0a,0x5c,0x21,0x7e, +0x8e,0xab,0xce,0x17,0xfc,0x09,0x7f,0x94,0xc6,0x7f,0xa9,0x5c,0x8f,0x4e,0x98,0x3a, +0xcf,0xd6,0x8a,0xd8,0x9a,0x9e,0xb4,0xfd,0xa6,0x84,0xfd,0xf8,0x7c,0xba,0x88,0xe2, +0xbd,0x9b,0x87,0x63,0x4c,0x9b,0x57,0x5a,0x8e,0xe5,0xd3,0xfc,0x92,0xe5,0xd2,0x23, +0x76,0x55,0x9e,0xda,0xb0,0x38,0xa0,0xb8,0x78,0x42,0xb4,0x1f,0xf8,0x01,0x7f,0x35, +0x56,0xe3,0x37,0xbb,0x04,0xdd,0x6f,0x3d,0xab,0x82,0x1b,0xfc,0x8c,0xb1,0x56,0x79, +0x58,0xb2,0xa6,0x9b,0xb2,0x48,0xff,0x2a,0x2a,0x31,0x75,0x38,0x7b,0x04,0x5e,0x38, +0x0f,0xea,0x0f,0xb3,0x53,0x61,0x0f,0x0c,0x72,0xc1,0x9e,0x24,0x6d,0xf2,0x2f,0xa5, +0xf9,0x02,0x8e,0x23,0x0c,0xc6,0x6e,0x44,0xae,0xe5,0x8e,0xa7,0x8c,0xaf,0xa8,0x1d, +0x47,0xb6,0xef,0xf1,0x68,0x3a,0xa0,0xe6,0xc0,0x3c,0x93,0xc3,0xa5,0x08,0x46,0xf7, +0x99,0x5b,0xb5,0x18,0x3c,0xda,0xe3,0xff,0x89,0x40,0xe8,0x18,0x1f,0xaa,0x34,0x20, +0x95,0x51,0x95,0xf0,0x36,0xd4,0xd6,0x22,0x64,0x37,0xff,0x13,0x26,0x06,0xf9,0x51, +0xa5,0x2c,0x99,0x95,0xc9,0xba,0xdc,0x51,0xf7,0x59,0x02,0x3a,0xd5,0xff,0x9a,0x39, +0x80,0xf6,0xab,0x0f,0xf8,0xf7,0x46,0x97,0x4f,0x19,0xb0,0xeb,0xfd,0x37,0xe7,0x23, +0x6f,0x69,0x98,0x5a,0x0b,0x2d,0xd8,0x5e,0x61,0x93,0xa2,0x62,0xe8,0x1b,0xee,0x3b, +0x33,0x6d,0x92,0xb7,0x4a,0x8b,0x2d,0x98,0xac,0xfd,0xfd,0xf9,0x62,0x80,0xd9,0x92, +0xf8,0xd1,0x5b,0x84,0x99,0x2d,0x2d,0x3c,0x6a,0xe4,0xe2,0xc6,0xde,0xf2,0xb9,0x18, +0x24,0x01,0x27,0xf5,0x41,0xcd,0xd6,0x9e,0xb9,0x2c,0x6d,0x15,0xb9,0x4c,0x6b,0x34, +0xe9,0x06,0x91,0x93,0xc9,0x04,0xfc,0x42,0x8c,0x67,0x92,0xde,0x63,0x16,0xf1,0xd5, +0x3b,0xed,0x94,0x12,0x49,0x60,0xa4,0x02,0x72,0xd8,0xc0,0x70,0x72,0xb5,0x97,0xff, +0xf9,0xc1,0x40,0xf3,0x3b,0x86,0xfc,0x37,0x90,0x1f,0xdb,0x33,0x21,0x3b,0x75,0x4f, +0x52,0x37,0x51,0x14,0x12,0xa1,0xee,0x21,0x27,0x60,0xa1,0x3f,0x0f,0xb6,0x5f,0xdc, +0xde,0xa9,0x6e,0x13,0xf3,0x39,0x45,0x8e,0x14,0xdc,0xc7,0xe1,0x90,0x9c,0x4a,0x4b, +0x2b,0x30,0xc4,0xc2,0x4f,0x55,0x42,0xf1,0x1b,0x08,0xcb,0x92,0xde,0x6b,0x7a,0xa6, +0xcd,0x8e,0x4f,0x66,0x19,0x42,0x05,0xc8,0x03,0xbc,0xf4,0x99,0xe8,0x51,0x5d,0x5f, +0x9d,0x23,0xef,0x68,0x27,0xc6,0xe9,0x67,0x89,0x4a,0xaf,0x49,0xce,0xda,0x4a,0xd8, +0xee,0x01,0xf9,0xb8,0x08,0x3b,0x57,0xe7,0x59,0x18,0xd0,0xda,0x24,0x62,0xba,0x3f, +0x87,0xfa,0x8d,0x41,0x94,0x29,0xf7,0x60,0xc3,0x9e,0xc9,0xa2,0xfe,0xb9,0x59,0xf6, +0x0f,0x68,0xd8,0xe2,0x86,0xd3,0x48,0x71,0xfb,0x11,0x49,0xc6,0x8d,0xdc,0xd8,0x0f, +0xc5,0xeb,0x12,0x3e,0x11,0xcf,0x28,0x1b,0x54,0xd1,0xea,0x7d,0x93,0x02,0xf6,0x3d, +0xd2,0x43,0x4f,0x1b,0xb5,0x2e,0xf2,0x62,0xfa,0x23,0xd8,0x1c,0xf4,0xbf,0x45,0x3d, +0x8a,0xa2,0x6a,0x1d,0x7f,0x94,0xae,0x79,0x43,0x0b,0xc6,0x0f,0x62,0x67,0x93,0xa8, +0x79,0xee,0xbb,0x98,0x8c,0x3f,0x26,0xf2,0x4c,0xce,0x7c,0x82,0x79,0x9d,0x79,0x1b, +0x7d,0xac,0xc0,0xf1,0xe1,0x23,0x23,0x9f,0x80,0x86,0x5c,0xe2,0x45,0x42,0x3a,0x2c, +0x32,0x0d,0x83,0xe6,0xa7,0x59,0xa1,0x60,0x4f,0x9d,0x75,0xc9,0x1b,0xc3,0x8d,0x81, +0x15,0x24,0x0b,0x53,0x63,0x71,0x27,0xde,0xa9,0x71,0x08,0x5f,0xac,0xab,0xd5,0x43, +0xf6,0xd4,0x82,0x94,0x75,0x51,0xfb,0xa9,0x3c,0x98,0x65,0x3a,0x2b,0x81,0x66,0x66, +0x79,0x3f,0x19,0x8d,0x66,0xf4,0x27,0x6a,0x27,0xb9,0xb8,0x1c,0xc5,0x1f,0xee,0x57, +0xc7,0x41,0x08,0x58,0xc6,0x5e,0x3b,0xbc,0xca,0x9a,0xa2,0x0a,0xa1,0xfa,0xe7,0x8e, +0x7f,0xaf,0x97,0xc0,0x04,0xef,0xb9,0xb4,0xe6,0xba,0x4d,0x4d,0x72,0x8b,0x9c,0x17, +0x4a,0x10,0x63,0x32,0xd4,0xc6,0x27,0x6d,0xb9,0x88,0xce,0xa6,0x5e,0x5a,0xcf,0x29, +0xaa,0x4a,0x87,0xd1,0x56,0x77,0x83,0x49,0xbc,0x09,0x33,0x01,0x59,0xf1,0xe4,0xef, +0xf4,0x1f,0xf8,0x88,0x12,0xf1,0x87,0x51,0x15,0x1a,0x87,0xbc,0xfe,0xe6,0xf7,0x3d, +0x81,0xa2,0xa8,0xf9,0x01,0x38,0xb8,0xc0,0x3a,0x32,0x46,0x8e,0x26,0x66,0x4c,0x96, +0x1d,0x83,0xd2,0xb5,0x89,0x4a,0x7b,0x47,0x0f,0x36,0xce,0x75,0xaa,0xcf,0x37,0xca, +0x66,0xc9,0xda,0xbc,0x67,0x2e,0x14,0xe1,0x06,0x80,0xca,0x03,0xe5,0xa3,0xa3,0x6b, +0xea,0xb6,0x38,0xb1,0x95,0x00,0xea,0x70,0x3c,0xa0,0x10,0x7f,0xac,0x9a,0x7e,0xad, +0xd6,0x2c,0xec,0xb7,0x4b,0x1b,0xd8,0xdd,0x66,0xc2,0x18,0xfb,0x41,0x9d,0xaf,0xea, +0x45,0x37,0xca,0x08,0x8b,0x4b,0x36,0x0f,0xf6,0xad,0xf0,0x58,0x81,0x32,0xe6,0x06, +0xb3,0xcd,0x10,0x03,0x7b,0x44,0x35,0x16,0x9b,0x5a,0x4e,0x9b,0xb1,0x73,0xe3,0x2f, +0x99,0xb1,0x5b,0x6e,0x00,0x9f,0x0a,0xbc,0x39,0x40,0x7e,0x92,0xe0,0xe1,0xf2,0x33, +0x9e,0x42,0x0c,0xcf,0xe7,0xf7,0x4a,0x7b,0xd6,0x4f,0x2c,0x42,0x82,0x70,0xcc,0xb2, +0x2e,0x71,0x5e,0x10,0xc3,0x1d,0x5d,0xed,0x20,0xcf,0x62,0xf8,0xc5,0xfd,0x22,0x63, +0x7d,0xf9,0xac,0xcb,0x44,0x49,0xf3,0x6c,0x70,0x52,0xcb,0x78,0xd4,0x2f,0x70,0x3c, +0xf9,0xbf,0x71,0x48,0xf6,0x7a,0x0b,0x97,0xb4,0x5b,0xa1,0xe9,0xa0,0x86,0x93,0x95, +0x83,0x49,0x3f,0xe4,0x47,0x85,0x51,0x77,0xbc,0xd5,0xf1,0x68,0x3d,0xf1,0x92,0x83, +0x3c,0xcd,0x83,0x76,0x4e,0x36,0xcb,0x3e,0x79,0x5c,0xb1,0x56,0xcf,0x84,0x06,0x11, +0xa8,0x47,0x7d,0x42,0x37,0x39,0x15,0xcd,0x16,0xd4,0x11,0x6b,0x53,0x04,0x50,0x58, +0xd6,0xe1,0xa6,0xe4,0x45,0xa4,0x72,0x72,0x29,0x23,0x7d,0x8e,0x77,0x33,0x28,0x2b, +0x39,0x6a,0xfa,0x34,0xdd,0xe0,0x17,0x7d,0x2b,0xcc,0xa5,0xb4,0xd1,0xa2,0xc6,0x3f, +0xd8,0x8b,0xfa,0xd7,0xae,0xd7,0x92,0x67,0xb9,0x82,0x36,0x83,0xde,0x12,0x29,0x75, +0x33,0x26,0x0e,0x88,0xb8,0x83,0x96,0x87,0x3b,0x49,0xae,0x9c,0x7d,0x5c,0xa9,0x31, +0x35,0xe9,0x91,0x60,0x61,0x64,0x8c,0xd6,0xbb,0x9d,0x01,0xbb,0x74,0xf1,0x33,0x97, +0x1e,0x0f,0x9c,0xc2,0x94,0xdb,0xf9,0x69,0x97,0x90,0x18,0x36,0xb8,0x29,0x79,0xc5, +0x86,0xd4,0x54,0x7a,0x5b,0x9f,0x43,0xbf,0xda,0x81,0x32,0xcd,0x4a,0x20,0x2a,0xde, +0xaf,0xda,0x69,0x35,0xeb,0xc1,0xd3,0xf2,0xb3,0xb3,0x04,0xe7,0x69,0xbe,0xc2,0xe2, +0x2f,0x48,0x91,0xa0,0xb6,0xf0,0x0a,0x06,0x36,0x6d,0xc1,0x3b,0x1d,0x01,0xff,0xa9, +0xa8,0x1d,0x4a,0xeb,0xde,0x4e,0xac,0xd1,0xbe,0xe4,0x7b,0x0a,0xa9,0x73,0x55,0x42, +0x60,0xe4,0x48,0xa8,0x3e,0xd2,0xd2,0x8d,0xe5,0x2e,0x26,0x84,0x4a,0xcc,0xdf,0x18, +0xf7,0x4b,0xcc,0x07,0x0b,0xc1,0x5f,0x13,0xc8,0xac,0x4d,0xfe,0x27,0x0f,0x40,0xe7, +0x69,0x36,0x54,0x5d,0xa7,0xac,0xf6,0xa1,0xb9,0xe7,0x34,0x78,0x3f,0x3d,0x51,0x6b, +0xee,0xac,0xae,0xdc,0x28,0x2b,0x5c,0xa0,0xc6,0x57,0x40,0xa5,0xdb,0xa5,0x11,0x9e, +0x79,0xb0,0x06,0x8b,0xd2,0xb9,0xfe,0xe0,0x34,0x66,0xaf,0x78,0x96,0xce,0x59,0x16, +0xa4,0xad,0x17,0x10,0x15,0x69,0x6a,0x9e,0xd6,0x79,0xf2,0x65,0x1c,0xcc,0x1b,0x4c, +0x5b,0xa7,0x04,0x7b,0xf8,0x91,0x2a,0xaa,0x73,0x25,0x6a,0xc3,0x29,0x86,0xbc,0xa6, +0xc6,0x4d,0xd4,0x7b,0x6c,0x71,0x76,0x86,0x78,0x82,0x11,0xdc,0x58,0xa8,0x34,0xb3, +0x00,0x3c,0xb4,0x8f,0xaf,0xd2,0xec,0xde,0x1c,0x97,0x66,0x60,0x76,0x8a,0x16,0x2d, +0x6c,0xe3,0x06,0xfd,0xb3,0x49,0x6a,0x7c,0x4d,0xa1,0x34,0xe8,0x66,0x7b,0xa8,0x2b, +0x88,0x4e,0xcb,0x0d,0xec,0xda,0xf7,0x44,0x00,0x71,0x82,0x9b,0xc0,0xc9,0xe3,0x86, +0x14,0x1a,0xf4,0x03,0x19,0x35,0xf3,0x13,0xc2,0xc3,0xc8,0x24,0x82,0xa2,0x0b,0xf9, +0x77,0x99,0x3e,0x81,0xd7,0x54,0x39,0xa6,0xec,0x71,0x39,0xbf,0x1a,0x41,0x72,0x19, +0x30,0xf2,0xe3,0x40,0x1b,0xbb,0xad,0x6d,0x3a,0x79,0x82,0x7c,0x9f,0x22,0xe1,0xd3, +0x0b,0x12,0xc3,0x6f,0xdc,0xe4,0x30,0x71,0xfe,0x31,0x32,0xc2,0x57,0x7e,0xf3,0x7c, +0x59,0x56,0xbb,0xd3,0x20,0xdd,0x0a,0x58,0xab,0x44,0x02,0xd5,0xda,0x5a,0x5c,0xba, +0x04,0x20,0x95,0xf1,0xbc,0x75,0x47,0xca,0x14,0x26,0xb4,0xbe,0x55,0x43,0x27,0x78, +0x36,0x50,0x7d,0xf9,0x72,0xda,0xf0,0xde,0xb6,0xb9,0xe1,0xa2,0x2d,0xc1,0x0c,0x59, +0x86,0xd3,0x7b,0x19,0x28,0x85,0xb7,0x37,0xb2,0xa2,0x3d,0x36,0x81,0xdc,0xbb,0xd5, +0xbf,0xc9,0x81,0xd6,0xad,0x36,0xcf,0xbf,0x0d,0x1d,0xa0,0xf7,0x87,0xd4,0xbc,0x24, +0xe2,0xb9,0x0b,0xfe,0xde,0x99,0x3f,0xdd,0xd9,0x57,0x5f,0xd0,0x34,0x7f,0xde,0xf9, +0xad,0x92,0x8d,0x08,0x4f,0x66,0xd0,0xe4,0xf0,0x31,0x97,0x6c,0x7d,0xbf,0xc5,0xce, +0x59,0x64,0x23,0x68,0x36,0x52,0x33,0xf5,0xb2,0x37,0x2a,0xc4,0xe2,0x91,0xda,0xff, +0x43,0xb2,0x10,0xe3,0x54,0x4a,0xaf,0x71,0xcc,0x57,0x43,0x0b,0xc5,0x04,0x6b,0x6d, +0x37,0xc2,0x9c,0x00,0xcd,0x4b,0xe6,0x17,0xc6,0xc1,0x9e,0x41,0x3b,0x6e,0x8d,0x74, +0x52,0x0f,0x36,0xce,0xc1,0xc7,0xe1,0xcf,0xf2,0x81,0x33,0xec,0xe3,0x28,0x8c,0x5e, +0xb7,0x6d,0x2b,0xcf,0x1e,0x45,0xb2,0x2e,0x79,0xa5,0xfa,0xab,0xc9,0x83,0x7c,0x76, +0xf0,0x3d,0xf0,0xc7,0x4c,0x35,0xd8,0xbe,0x0f,0x5b,0xe3,0xba,0xfd,0x18,0xef,0x46, +0x0f,0xc0,0xba,0x6a,0xff,0xfb,0xd4,0xce,0x82,0x26,0xac,0x62,0xb3,0xf5,0x71,0xbe, +0xdd,0x00,0xf1,0x22,0xf0,0x0e,0x7e,0xf7,0xe8,0x9d,0x2e,0x9d,0x82,0xfe,0x32,0x69, +0xc7,0x5f,0xba,0xe3,0x97,0xd0,0xf6,0x13,0x21,0x85,0x78,0xd6,0x77,0xa2,0x31,0x7f, +0xa3,0x8f,0x2a,0xbb,0xbe,0xbf,0x7f,0x28,0x11,0x00,0x7e,0x63,0xd1,0x2d,0x2e,0xc6, +0x04,0x1d,0xeb,0x1e,0x96,0x60,0xd4,0xa0,0x0c,0xfd,0x9d,0xa8,0x4c,0xd5,0xf9,0xa3, +0xfb,0x16,0xed,0x74,0xad,0xdb,0x48,0x8c,0x72,0x6f,0x56,0x79,0x58,0xaf,0x76,0x1d, +0x54,0x1f,0x72,0x47,0x00,0xf8,0x1f,0x64,0x20,0x5f,0x43,0x7c,0xb9,0xb1,0x03,0x94, +0x2d,0xd7,0x54,0x16,0xf8,0x55,0x19,0xe0,0xd7,0x76,0xb2,0x85,0x88,0x91,0x94,0xa3, +0x05,0xa8,0xab,0x9e,0x4c,0x42,0xa8,0xb8,0xbc,0xdc,0x9a,0xc7,0xea,0x79,0x41,0xf4, +0x4d,0x3f,0x8a,0x13,0x84,0x03,0x76,0x17,0xee,0x07,0xd5,0x00,0xee,0x68,0x51,0xec, +0xf3,0x0d,0xd6,0x29,0x4f,0x51,0x56,0x0c,0xce,0x1c,0x53,0x1d,0x63,0x66,0x87,0xd4, +0x58,0x93,0xf8,0xd2,0x2e,0x5b,0x80,0x19,0x59,0xd7,0xc3,0x08,0x19,0x54,0x28,0xe5, +0x67,0x1b,0x8b,0x60,0x69,0x96,0xbd,0x39,0xc4,0x17,0x31,0xc8,0xcc,0x5d,0x16,0xf2, +0x43,0xc3,0x4d,0x92,0x45,0xd4,0x6f,0x51,0xf9,0xbc,0x32,0x40,0x66,0xc8,0xc9,0xca, +0x88,0x60,0x9b,0xcc,0x96,0x4e,0x1b,0x2c,0x1b,0x77,0xd1,0x38,0xc8,0x45,0x47,0x7c, +0x48,0xd1,0xce,0x46,0x0c,0x58,0x7a,0x04,0x57,0x93,0xdd,0x2a,0x18,0x35,0xb4,0x6d, +0xc0,0xb3,0xe8,0xb5,0xd0,0x99,0x5d,0x78,0x63,0x10,0x70,0x58,0x6a,0x8f,0xb1,0x25, +0xaa,0x7a,0x7a,0x42,0x82,0xad,0x37,0x28,0x40,0xd4,0x37,0x34,0x62,0x59,0x65,0xd0, +0x33,0xbc,0x22,0xed,0xf9,0x14,0x49,0x52,0x98,0x06,0xcd,0xac,0x78,0x75,0x01,0xd7, +0x7a,0x21,0x38,0xae,0xd6,0xf6,0x61,0xa4,0x16,0x6f,0x04,0xce,0xf1,0x0e,0x3b,0x14, +0x56,0x47,0xb4,0x0a,0x48,0x65,0x2a,0x44,0x8e,0xbe,0xf1,0x59,0x6d,0x17,0x1f,0x73, +0x5e,0x19,0x21,0xd3,0x7b,0x03,0xc6,0x1f,0xef,0x38,0x45,0x5c,0xd6,0x4e,0x8c,0x7a, +0xc0,0x35,0x40,0x9d,0xb3,0xc1,0x0c,0xbd,0x78,0x8a,0x58,0x50,0xef,0xf4,0xd1,0x38, +0xca,0xdc,0x8b,0x05,0x67,0x01,0xf6,0x97,0xbb,0x4b,0xa6,0xea,0x47,0x00,0x54,0xa3, +0xe4,0x90,0xd2,0x5a,0x07,0xfb,0x8e,0x32,0xdd,0xc0,0x62,0xf0,0x2a,0x57,0xd9,0xad, +0x27,0x24,0xbf,0x53,0xc2,0x16,0xc1,0xd8,0xd5,0x61,0x0d,0x53,0xea,0x79,0x0a,0xb4, +0x85,0x98,0x65,0xb6,0xc2,0x31,0xb6,0xac,0x75,0x5f,0x76,0xa5,0x2c,0x5b,0xf4,0x83, +0x9c,0x37,0xe5,0x06,0x8c,0xa4,0x72,0x83,0x66,0x70,0x69,0x22,0x7b,0x04,0x70,0xb3, +0xbf,0xd3,0x21,0xc5,0x9c,0xa2,0xd9,0xe2,0xc6,0x59,0xbe,0xe9,0x61,0x3e,0xb6,0x8a, +0x37,0x2d,0x3b,0x8c,0xca,0x35,0x7d,0x41,0x28,0xc2,0x82,0xbd,0x3a,0x58,0x46,0xd6, +0x58,0x32,0x29,0xfd,0x61,0x29,0x71,0x9c,0x0c,0xe4,0xd9,0x79,0xf4,0x94,0xa9,0xfd, +0x91,0xea,0xaa,0xd7,0x6c,0xe1,0x34,0x56,0x39,0xc1,0x82,0x5c,0x2b,0x51,0x82,0xed, +0x4c,0x1e,0xad,0xd0,0x53,0xa0,0x99,0x89,0x66,0x5c,0xe6,0x24,0xef,0xa6,0xd5,0x24, +0x8c,0xf3,0x31,0x5e,0xd3,0xfe,0x1b,0x26,0xd6,0xf0,0x9d,0x1f,0xd8,0x65,0x31,0x01, +0x6d,0x0d,0x96,0x1d,0x26,0xdc,0x4b,0xd0,0xd2,0x35,0x2c,0xc2,0x48,0x0e,0x3e,0x21, +0x6d,0x49,0x18,0x97,0xb1,0xdf,0x0f,0xe0,0x48,0x98,0xba,0x9a,0xd5,0x63,0x49,0x9e, +0xc8,0x4c,0x9c,0x33,0x62,0x54,0xf6,0x86,0x7e,0x5b,0x88,0xb8,0xf0,0x82,0xb7,0xd5, +0xd2,0x2b,0x22,0x25,0x6e,0xbf,0x28,0x1d,0x48,0xd7,0xd9,0xf6,0x2d,0x20,0x9f,0x28, +0x36,0x76,0xe0,0x9e,0x79,0x44,0xa6,0x68,0xbb,0xb0,0x4b,0x37,0xef,0xc9,0x34,0xe9, +0xf7,0x29,0x64,0xc7,0xe8,0x08,0x91,0x9f,0xc1,0x52,0x32,0x77,0x6d,0x36,0xf7,0x82, +0xfc,0x0b,0x97,0x65,0x4f,0xf7,0x4c,0x68,0xa7,0x51,0x4d,0xad,0x53,0x2e,0xf9,0xe6, +0x42,0xd8,0x49,0xed,0x0f,0xbb,0x90,0xe9,0x6f,0x1c,0x8f,0xc2,0x84,0x74,0xa0,0x4e, +0x9b,0x5e,0x66,0xf6,0xe8,0x1c,0xb1,0xea,0x6f,0x3b,0x3b,0xc0,0x44,0x88,0xec,0xd8, +0x86,0xbd,0x34,0xb3,0x49,0x08,0x5a,0xc4,0xe8,0x29,0x46,0xfb,0xd0,0x8f,0x62,0x23, +0x7a,0x66,0x34,0x95,0x43,0xd5,0x9a,0x1c,0x4c,0xb9,0x74,0xaa,0x16,0x1c,0xcf,0x8b, +0xf4,0x66,0x0a,0x78,0x80,0xfa,0x1a,0xd4,0xb2,0x48,0x67,0x16,0x3c,0x24,0xb0,0xff, +0xcc,0xdf,0xd8,0x1c,0xd2,0x30,0xd9,0xf0,0xa8,0x37,0xcc,0x3c,0x3e,0x24,0x7f,0xa7, +0x62,0x16,0x41,0x68,0x4c,0x64,0x32,0xac,0xbf,0xa9,0xfa,0x31,0xb1,0x4e,0x61,0x3c, +0xc2,0xd1,0xa5,0xd7,0x56,0xdf,0xb0,0xdc,0x97,0x68,0x6f,0xe2,0xd4,0x72,0xaa,0xd1, +0xd5,0xf5,0x09,0xba,0x15,0x3e,0x10,0xa6,0x62,0x69,0x3d,0xac,0x6c,0x2d,0x4b,0x85, +0x71,0x19,0xda,0x30,0x2e,0x4d,0x23,0x9e,0xfe,0xf0,0x1d,0xc3,0xf2,0x58,0xf9,0x08, +0xa5,0x95,0x67,0xe0,0x30,0x93,0x89,0xab,0xcd,0x48,0xbe,0x72,0xaa,0x4b,0x4e,0x64, +0xe5,0xc6,0xc1,0x43,0xa8,0x82,0x09,0x83,0xae,0x37,0x14,0x1c,0x7c,0x68,0x91,0x29, +0xba,0x8e,0x04,0x71,0xad,0xaa,0x05,0xe3,0x7d,0x7b,0x1b,0xdf,0xfe,0x04,0x09,0x20, +0x5c,0xd9,0xce,0x94,0x7c,0xcc,0xcb,0xfe,0xfe,0x08,0x13,0x2a,0xe9,0xe9,0x68,0x5b, +0x32,0x05,0x86,0x67,0xd0,0x03,0x00,0xf4,0x04,0xe9,0xd2,0x56,0xe1,0xa8,0xd1,0x65, +0x10,0x55,0x9c,0xd0,0x4a,0xfe,0x8a,0x03,0x7d,0x23,0xfc,0xf6,0xb6,0x9c,0x13,0x37, +0xb8,0xdf,0xee,0xe2,0x7e,0xb8,0x1b,0xd7,0x96,0x1a,0x6a,0x54,0xeb,0x17,0xeb,0x2b, +0xaf,0x29,0x7c,0x5c,0x65,0xce,0x84,0x9b,0xa4,0x5d,0xe8,0xaf,0x95,0x69,0x57,0xf9, +0x52,0x13,0x8d,0x1b,0xaf,0xd7,0x0e,0x49,0x40,0x86,0xb6,0xe6,0x95,0xcf,0x2b,0x25, +0x37,0x95,0x44,0x7f,0xdd,0x8e,0x53,0x46,0xe9,0x60,0xce,0xa9,0xf2,0xfa,0x4e,0x4a, +0xb5,0x15,0xb0,0x5f,0x24,0x2e,0x79,0xe3,0x45,0x0c,0xae,0xda,0x5e,0x49,0x10,0xd1, +0x1a,0x7c,0xd8,0x8d,0x55,0xcd,0x3b,0xf5,0x0b,0x5e,0xc4,0x53,0x4e,0x85,0xbd,0xed, +0x35,0x2b,0x2e,0xdb,0x9e,0xad,0x9b,0x86,0x82,0x95,0xbd,0x3e,0xcd,0x0d,0x51,0x9f, +0x2f,0x5c,0x0a,0xb5,0xc6,0x69,0xba,0xe2,0x10,0x60,0x9c,0x09,0xc3,0x11,0xc5,0x72, +0xf6,0xcc,0x65,0x38,0x9e,0xea,0x04,0x69,0x7f,0x0f,0xee,0xe0,0xba,0x1a,0x53,0xf9, +0x21,0xb3,0xf0,0x95,0xec,0xfe,0x53,0xfc,0xdb,0xe9,0xcc,0xe4,0xd9,0xd0,0xf3,0x59, +0xc7,0x77,0x65,0xac,0xf7,0x77,0xab,0xb7,0x5f,0xde,0x45,0x2f,0x8a,0x02,0x32,0x6c, +0xcc,0xe8,0x87,0xbe,0x48,0x5d,0xc6,0x4d,0x4e,0x76,0x1c,0x59,0x80,0x15,0xd6,0xf4, +0x1f,0x03,0x7d,0x3b,0x4f,0x4d,0x1c,0xd4,0x25,0xe0,0x80,0x42,0x80,0x65,0x1f,0x7e, +0xe1,0xcd,0x36,0x21,0x5d,0x82,0x86,0x08,0xe1,0x57,0xd9,0xa8,0x20,0x42,0x36,0x84, +0x4c,0xd6,0x06,0x5b,0xa3,0x55,0x0d,0x4c,0x4e,0x34,0x55,0xca,0x16,0x18,0x01,0x4b, +0xf5,0x1d,0x0f,0x17,0xf0,0x5a,0x00,0xae,0x90,0x20,0x29,0xf3,0x4e,0x95,0xed,0x83, +0xba,0x5e,0x0d,0xea,0x4b,0xec,0x35,0x0a,0x52,0x83,0xd0,0xf7,0xe2,0xff,0x57,0x4b, +0x2a,0x1d,0x16,0x56,0xfc,0xa4,0xfb,0x58,0x76,0x38,0xf0,0x85,0x91,0xa5,0xa8,0xec, +0x25,0x60,0x86,0xd2,0x40,0xa6,0x21,0x16,0x19,0x58,0x25,0xcb,0x73,0x86,0x66,0xe8, +0x3d,0xc7,0x52,0xd6,0xa2,0x78,0x24,0x9e,0xbf,0x25,0x7b,0x3c,0x4d,0xce,0x0a,0x38, +0xc2,0x17,0xcf,0x37,0x26,0xbf,0x78,0xf3,0x84,0x00,0xaf,0xb3,0x8d,0x21,0x3b,0xfa, +0xda,0x70,0x40,0x78,0x30,0xb0,0xce,0x6a,0xae,0x7d,0xc1,0x68,0x0e,0x3b,0x1d,0x05, +0x41,0x5c,0x4a,0x53,0x09,0xf5,0x56,0xe9,0x77,0x3d,0xa3,0x74,0x59,0x74,0x60,0x6a, +0xd7,0xf1,0x26,0x04,0x85,0xa9,0xef,0x09,0x0e,0xd0,0xd9,0x24,0xaa,0xaf,0x20,0xa3, +0x98,0xf6,0xec,0xb2,0x1d,0x47,0xd7,0xa5,0x6b,0xd8,0x29,0xea,0x7f,0x03,0x70,0x73, +0x3f,0xa8,0xf7,0xef,0x5c,0xc8,0x5e,0x35,0x4a,0xbf,0xb6,0xb0,0x4c,0x0b,0xae,0x57, +0xa1,0x29,0x79,0x89,0xfc,0x8f,0x4c,0x24,0x28,0x6a,0x18,0x20,0x4e,0x6a,0x03,0x71, +0x90,0x74,0xef,0xdc,0xed,0x84,0x33,0xe5,0xeb,0x1f,0xa2,0x1e,0x51,0x7b,0x18,0xb6, +0xec,0xce,0xc4,0x39,0x96,0x6b,0xe1,0xaf,0x10,0x6d,0x88,0x43,0x15,0x3d,0xc1,0x31, +0x9f,0xd4,0xfc,0xcc,0x5f,0x69,0x23,0x83,0x9c,0xf9,0xc5,0x1e,0x6d,0xdd,0x33,0x98, +0x64,0xfa,0xe8,0x93,0x5d,0xbe,0xfa,0x95,0x81,0x33,0x7c,0xc3,0x63,0x62,0xea,0xf8, +0x58,0x07,0xdd,0x29,0x8f,0xcc,0x48,0x71,0x94,0x31,0x1a,0x77,0x54,0xc1,0x6f,0x09, +0xd9,0xc3,0x5e,0x4e,0x86,0x3c,0xcf,0x62,0xf0,0xd5,0x7a,0x42,0x80,0x31,0x44,0xb7, +0x68,0xa1,0x26,0x58,0x9f,0xe0,0x63,0x1e,0x48,0xda,0x1c,0x9e,0xbf,0x5f,0x57,0xbb, +0xe4,0x4f,0xe2,0x23,0xbd,0x7c,0xc3,0x90,0xae,0x94,0xdf,0x85,0x23,0xfa,0xf6,0xf4, +0xb3,0x63,0xdb,0xcf,0x15,0xf0,0xf8,0x6c,0xf2,0xd8,0x1e,0x01,0x3e,0xee,0x83,0xd1, +0x7d,0x29,0x40,0x90,0x28,0xdc,0xd6,0xf8,0x55,0xf4,0x0a,0xbc,0x23,0xc7,0xd8,0x25, +0x79,0xe7,0x0a,0xd6,0xb6,0xba,0x5c,0x3a,0x72,0xbe,0x39,0x7c,0x71,0x24,0x8d,0xfb, +0x0c,0x95,0x6d,0xaf,0x18,0x81,0x8a,0x5e,0x38,0xf2,0xfa,0xc3,0x82,0x3d,0x86,0x37, +0xae,0x46,0x30,0xcd,0x61,0x07,0xee,0x02,0x08,0x64,0x09,0x08,0x8b,0x25,0x8a,0xf5, +0x29,0x21,0xba,0xc9,0xd3,0x1a,0xaa,0x18,0x86,0x9b,0x7d,0x65,0x1a,0x4d,0x27,0xc6, +0x4e,0x55,0x4d,0xf5,0x73,0x03,0x6f,0x52,0x01,0xe1,0xc2,0x02,0x2f,0x79,0xf5,0x9a, +0x5e,0x84,0x0f,0x4e,0x2d,0x0b,0x35,0xf3,0x6e,0x7c,0xc5,0x48,0x97,0xf8,0xcd,0x53, +0x61,0xd6,0xb0,0xea,0x79,0xb4,0xc8,0xf8,0x65,0xa9,0x5c,0xd7,0x61,0xd6,0x6e,0x3a, +0xf7,0x7a,0x60,0x31,0x64,0x82,0x52,0xa7,0x59,0xe1,0x25,0xc6,0x5e,0xef,0x9f,0xbb, +0x65,0xb4,0x62,0x63,0x18,0x28,0x33,0xb9,0xad,0x48,0x0c,0xae,0xdf,0x5b,0x58,0x0d, +0xb2,0x8a,0xef,0xd2,0x1d,0x56,0x10,0x38,0x02,0x66,0xcc,0x6e,0xbf,0x07,0xce,0x50, +0x79,0x13,0xf0,0x1b,0x2d,0x84,0x33,0x93,0x3a,0xe7,0x10,0xb5,0x94,0x7c,0xf7,0x2e, +0x77,0xc4,0xab,0x3a,0xc5,0x92,0x38,0xa1,0xe9,0x57,0x1b,0x94,0x1c,0xf1,0xa0,0x38, +0x1c,0xcd,0xe1,0x7e,0x07,0x02,0xbe,0x08,0x66,0xb9,0xe2,0xb9,0xf9,0xff,0x6d,0xcd, +0x9c,0xa9,0x61,0x97,0xe1,0x02,0xc9,0x35,0x9e,0x25,0x9c,0x84,0xcc,0x67,0x5c,0x27, +0x8e,0x7d,0x82,0x89,0x19,0xbd,0x05,0x1c,0xaf,0xf0,0xb1,0xed,0x08,0x93,0xd9,0x70, +0xe0,0xb5,0x52,0x69,0xb0,0x1f,0xb4,0xdd,0x0b,0xd2,0xcf,0x75,0x99,0x24,0x5d,0xae, +0xe4,0x35,0xaa,0xaa,0x1c,0x01,0x4f,0xe4,0x65,0x6b,0x4c,0x46,0x32,0xec,0x76,0x09, +0x2a,0xed,0xcd,0xfd,0xde,0xdf,0x93,0xc6,0x63,0x64,0x6a,0x39,0xfe,0xee,0xe2,0x9e, +0x41,0x1d,0xc7,0x69,0xdb,0xdb,0x00,0xc3,0x9d,0xac,0x69,0xec,0x42,0xa7,0x1b,0x0e, +0x85,0x78,0xfc,0x49,0x96,0xa1,0x09,0x1c,0xdd,0x13,0x75,0x8f,0x2e,0xa8,0x26,0xd4, +0x77,0xb0,0x7e,0x6a,0xcf,0x97,0x6f,0xf7,0x22,0x6c,0xdf,0x88,0x09,0xef,0xe0,0x9f, +0x16,0x7b,0x63,0x2f,0x0b,0x6e,0xd7,0x62,0x07,0xff,0x99,0x0c,0x7f,0x81,0x48,0x0e, +0x56,0x98,0x2c,0x0d,0xd4,0x95,0xe4,0xb2,0xd4,0x43,0x25,0x2a,0x9d,0x1b,0x29,0x3f, +0x6c,0x42,0xe5,0x60,0xd6,0xcc,0x30,0x71,0xb9,0x3b,0xd3,0xe7,0xea,0xff,0x52,0x74, +0x8c,0x08,0x31,0x4f,0x38,0xf5,0x9c,0xfb,0x84,0xf1,0xa6,0xd9,0x29,0x74,0x8e,0x38, +0x0b,0xed,0x78,0x83,0x1a,0xa3,0x9b,0x62,0x12,0xfa,0x4f,0x90,0x73,0x2a,0xe2,0x3d, +0x00,0x2c,0xc4,0x39,0xad,0x46,0x8e,0x8c,0x23,0x96,0x6e,0x62,0xb4,0x52,0x31,0x66, +0x4c,0x88,0xf4,0xce,0xc5,0xa7,0x9b,0x72,0xcc,0x52,0xbd,0xd7,0x54,0x2d,0xeb,0xb6, +0xa5,0xd4,0xce,0xaa,0xba,0xd1,0xc3,0x5c,0xbd,0x59,0x7b,0x39,0x6d,0x49,0x79,0xde, +0x64,0x2e,0x45,0x52,0x00,0x5a,0xb8,0x76,0x00,0x77,0x59,0x21,0xa7,0xe8,0x5f,0x63, +0x6b,0x5c,0x3e,0x93,0x13,0x5f,0x7d,0x7c,0x20,0x7f,0x5e,0x55,0xfc,0xc7,0x34,0x83, +0xba,0xf7,0x94,0xbf,0x94,0x37,0x20,0xfb,0x09,0x4d,0x70,0x42,0x86,0x41,0x9e,0x06, +0x1a,0x30,0x8b,0xb7,0x61,0x4f,0x0f,0xa3,0xc4,0xb9,0xe1,0x0c,0xe4,0x02,0x0b,0x24, +0xcf,0x40,0xd2,0x9e,0x9a,0xdf,0x71,0xe1,0xe9,0x0c,0x47,0x7d,0xe1,0x6f,0x4a,0x52, +0x4e,0x94,0xf0,0xb3,0x23,0x3b,0xdb,0x2c,0x0c,0xd7,0x5e,0x5b,0x71,0x35,0xdd,0xb5, +0xb6,0xe2,0xf3,0x6a,0x5c,0xa1,0xe8,0x56,0xb4,0x68,0x75,0xfc,0x3e,0xec,0x04,0xdd, +0x1e,0xac,0xb5,0xa7,0xf2,0xb4,0xb2,0x5d,0x1b,0x86,0x0a,0xe2,0x7f,0xfc,0xbe,0xdb, +0x9d,0x13,0xe8,0xcd,0xc9,0x5d,0x57,0x67,0x72,0xb1,0x77,0xc5,0x5b,0x9e,0x64,0xc5, +0xa7,0x89,0x3d,0xc3,0x0e,0x4c,0xa1,0x99,0x32,0xab,0x31,0x84,0x25,0x50,0x1a,0x17, +0x3b,0x70,0x01,0xd6,0xdb,0x6d,0xa8,0xde,0x9c,0x20,0x16,0xb8,0x74,0x94,0x06,0x84, +0x13,0xb6,0xec,0x2b,0x2c,0x6f,0x8f,0x4f,0x86,0x65,0x15,0x4b,0x79,0x70,0xc9,0xc3, +0x6b,0xc8,0x99,0xbf,0xc9,0x37,0xd4,0xab,0xf3,0x13,0xba,0x25,0x72,0x22,0xdf,0xc8, +0x73,0x32,0xec,0xef,0x40,0xe1,0x1a,0x8b,0x3e,0x44,0xd5,0x7d,0xcf,0x2a,0x0f,0x08, +0x9c,0xd0,0xf9,0x72,0x8a,0xe6,0x88,0x53,0x06,0x92,0xe0,0xd4,0x6a,0xb4,0x85,0x71, +0x90,0xf2,0xb0,0xb2,0x33,0x4d,0x87,0x9c,0x12,0xac,0xe6,0x89,0x69,0x8e,0x21,0xf4, +0x24,0x37,0x69,0x27,0x34,0x1f,0x43,0x61,0x0f,0x2b,0x46,0x4f,0x4f,0xc8,0x6a,0x66, +0x71,0xf3,0x44,0x46,0x68,0x86,0x2e,0x11,0x2e,0xb9,0x03,0x04,0x90,0x7e,0xd2,0x3a, +0x07,0x16,0x34,0x37,0x2d,0xb0,0x5d,0x8d,0x9f,0x75,0x01,0x10,0xbd,0xce,0x9b,0xe1, +0x66,0xea,0x76,0x39,0x72,0x6f,0xe6,0x0c,0x4d,0x96,0xa7,0x0d,0x67,0xae,0x1c,0x6c, +0x81,0x42,0xe3,0x81,0xe8,0xc9,0xae,0xa8,0x50,0x73,0x7b,0x9e,0x10,0x09,0x10,0x03, +0xf1,0x72,0x33,0x43,0xa9,0x44,0xce,0x84,0xba,0x39,0x0b,0x6d,0x87,0xb7,0x69,0x1c, +0x3c,0x5a,0x71,0x3b,0xd1,0x76,0xa9,0xbb,0xf2,0xd5,0xe7,0x86,0x22,0x03,0xb5,0x34, +0x60,0x89,0x5c,0xb2,0xa1,0xd2,0xe4,0x32,0x1f,0xc4,0x5f,0xb6,0x84,0x2f,0x7b,0x4a, +0x45,0xe4,0x6d,0x2f,0x2c,0x6c,0xfe,0xf7,0x36,0x18,0x3f,0x4f,0xcb,0x30,0x07,0x8c, +0x93,0x0f,0x09,0x31,0x2a,0x6b,0x9c,0xae,0x64,0x5d,0x12,0x0e,0xa3,0xc2,0x4a,0xf1, +0xb4,0xcd,0x85,0x6d,0x34,0xaf,0x46,0x3d,0x41,0xd3,0x17,0x67,0xe0,0x1b,0xf5,0x4e, +0xba,0xb9,0xea,0x8c,0x6e,0x94,0xef,0xcb,0x46,0x5b,0xad,0x57,0x84,0x90,0xfb,0xa1, +0xae,0x50,0x08,0xe2,0xd6,0x2c,0xfb,0xc4,0x47,0xcb,0x51,0x84,0xbd,0xbf,0x41,0x2b, +0x81,0x31,0x1a,0xdb,0xf5,0x4b,0x8d,0x5c,0x9a,0xc9,0xcc,0x0f,0x75,0x1c,0x1a,0xc5, +0xcd,0xc2,0xec,0x31,0x8a,0x95,0xfe,0xe0,0xeb,0x93,0x3c,0x58,0xce,0xf3,0xbc,0xdb, +0x3e,0x4b,0x66,0x41,0x04,0xe1,0x94,0x17,0x0d,0x49,0xec,0x07,0x93,0xc5,0xed,0xd9, +0xce,0x42,0x23,0x7b,0x5d,0xc2,0x10,0x23,0x4b,0x00,0xe7,0x88,0x4a,0xee,0x0a,0x66, +0x1b,0x40,0xd3,0xde,0x42,0x64,0x1b,0x43,0x5c,0x6b,0x90,0xe0,0xe8,0x68,0x5f,0x57, +0xbe,0x1f,0x77,0x81,0x30,0x2c,0xfd,0xcd,0x41,0xb7,0x36,0x11,0xe6,0x9b,0xbf,0x71, +0x47,0xfb,0xa6,0x69,0x1d,0xc2,0xdd,0xb5,0xc5,0xad,0xe3,0xef,0xe0,0xfe,0x67,0xef, +0xf3,0x64,0x25,0x6a,0xd1,0x10,0xd7,0xe7,0xbb,0xdb,0x67,0x05,0x7a,0xec,0x55,0x80, +0xa0,0x8b,0x5f,0x24,0xb3,0x97,0x28,0xcf,0x95,0xe3,0xe0,0x96,0x02,0xfe,0x4b,0x64, +0xe4,0xf9,0x53,0x8b,0xf1,0x04,0x27,0x53,0xe1,0xc3,0x8d,0x01,0x8d,0x08,0xa9,0xf7, +0x8e,0x62,0x1c, +}; +#endif /* WOLFPKCS11_XMSS */ + +#endif /* WOLFPKCS11_TESTS_HBS_KAT_H */ diff --git a/tests/hbs_persistence_test.c b/tests/hbs_persistence_test.c new file mode 100644 index 00000000..14d0f020 --- /dev/null +++ b/tests/hbs_persistence_test.c @@ -0,0 +1,463 @@ +/* hbs_persistence_test.c + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfPKCS11. + * + * wolfPKCS11 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfPKCS11 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 + * + * Token-object persistence test for verify-only LMS/HSS and XMSS/XMSS^MT + * public keys: import a raw public key as a token object, finalize and + * re-initialize the library (forcing a reload from disk), then find the key + * again and confirm it still verifies a known-good signature. + * + * For the current verify-only feature a public key is an ordinary token + * object with no special state, so this only exercises the generic store / + * reload path. It is deliberately kept as groundwork for the future + * sign-capable builds: once private keys carry persisted one-time signature + * state, this test grows to cover that state surviving a reload, which is the + * part where HBS persistence becomes genuinely feature-specific. + */ + +#ifdef HAVE_CONFIG_H + #include +#endif + +#ifndef WOLFSSL_USER_SETTINGS + #include +#endif +#include +#include + +#ifndef WOLFPKCS11_USER_SETTINGS + #include +#endif +#include + +#ifndef HAVE_PKCS11_STATIC +#include +#endif + +#include +#include + +#if (defined(WOLFPKCS11_LMS) || defined(WOLFPKCS11_XMSS)) && \ + !defined(WOLFPKCS11_NO_STORE) + +#include "hbs_kat.h" + +#ifndef WOLFPKCS11_DLL_FILENAME + #ifdef __MACH__ + #define WOLFPKCS11_DLL_FILENAME "./src/.libs/libwolfpkcs11.dylib" + #else + #define WOLFPKCS11_DLL_FILENAME "./src/.libs/libwolfpkcs11.so" + #endif +#endif + +#define CHECK_CKR(rv, msg) \ + do { \ + if ((rv) != CKR_OK) { \ + fprintf(stderr, "\n%s:%d - %s: %lx - FAIL\n", \ + __FILE__, __LINE__, msg, (unsigned long)(rv)); \ + } \ + } \ + while (0) + +#ifndef HAVE_PKCS11_STATIC +static void* dlib; +#endif +static CK_FUNCTION_LIST* funcList; +static CK_SLOT_ID slot = 0; +static const char* tokenName = "wolfpkcs11"; +static byte* soPin = (byte*)"password123456"; +static int soPinLen = 14; +static byte* userPin = (byte*)"wolfpkcs11-test"; +static int userPinLen = 15; + +static CK_OBJECT_CLASS pubKeyClass = CKO_PUBLIC_KEY; +static CK_BBOOL ckTrue = CK_TRUE; + +static CK_RV pkcs11_init(void) +{ + CK_RV ret; + CK_C_INITIALIZE_ARGS args; + CK_SLOT_ID slotList[16]; + CK_ULONG slotCount = sizeof(slotList) / sizeof(slotList[0]); + +#ifndef HAVE_PKCS11_STATIC + CK_C_GetFunctionList func; + + dlib = dlopen(WOLFPKCS11_DLL_FILENAME, RTLD_NOW | RTLD_LOCAL); + if (dlib == NULL) { + fprintf(stderr, "dlopen error: %s\n", dlerror()); + return -1; + } + func = (CK_C_GetFunctionList)dlsym(dlib, "C_GetFunctionList"); + if (func == NULL) { + fprintf(stderr, "Failed to get function list function\n"); + dlclose(dlib); + return -1; + } + ret = func(&funcList); + if (ret != CKR_OK) { + fprintf(stderr, "Failed to get function list: %lx\n", + (unsigned long)ret); + dlclose(dlib); + return ret; + } +#else + ret = C_GetFunctionList(&funcList); + if (ret != CKR_OK) { + fprintf(stderr, "Failed to get function list: %lx\n", + (unsigned long)ret); + return ret; + } +#endif + + XMEMSET(&args, 0, sizeof(args)); + args.flags = CKF_OS_LOCKING_OK; + ret = funcList->C_Initialize(&args); + CHECK_CKR(ret, "Initialize"); + + if (ret == CKR_OK) { + ret = funcList->C_GetSlotList(CK_TRUE, slotList, &slotCount); + CHECK_CKR(ret, "Get Slot List"); + } + if (ret == CKR_OK) { + if (slotCount > 0) + slot = slotList[0]; + else { + fprintf(stderr, "No slots available\n"); + ret = CKR_GENERAL_ERROR; + } + } + return ret; +} + +static void pkcs11_final(void) +{ + funcList->C_Finalize(NULL); +#ifndef HAVE_PKCS11_STATIC + if (dlib != NULL) { + dlclose(dlib); + dlib = NULL; + } +#endif +} + +static CK_RV pkcs11_init_token(void) +{ + CK_RV ret; + unsigned char label[32]; + + XMEMSET(label, ' ', sizeof(label)); + XMEMCPY(label, tokenName, strlen(tokenName)); + ret = funcList->C_InitToken(slot, soPin, soPinLen, label); + CHECK_CKR(ret, "Init Token"); + return ret; +} + +static CK_RV pkcs11_set_user_pin(void) +{ + CK_RV ret; + CK_SESSION_HANDLE session; + int flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + + ret = funcList->C_OpenSession(slot, flags, NULL, NULL, &session); + CHECK_CKR(ret, "Open Session for PIN setup"); + if (ret == CKR_OK) { + ret = funcList->C_Login(session, CKU_SO, soPin, soPinLen); + CHECK_CKR(ret, "Login as SO"); + if (ret == CKR_OK) { + ret = funcList->C_InitPIN(session, userPin, userPinLen); + CHECK_CKR(ret, "Init User PIN"); + } + funcList->C_Logout(session); + funcList->C_CloseSession(session); + } + return ret; +} + +static CK_RV pkcs11_open_session(CK_SESSION_HANDLE* session) +{ + CK_RV ret; + int flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; + + ret = funcList->C_OpenSession(slot, flags, NULL, NULL, session); + CHECK_CKR(ret, "Open Session"); + if (ret == CKR_OK) { + ret = funcList->C_Login(*session, CKU_USER, userPin, userPinLen); + CHECK_CKR(ret, "Login"); + } + return ret; +} + +/* Create a token public-key object holding a raw HBS public key. */ +static CK_RV create_token_pubkey(CK_SESSION_HANDLE session, CK_KEY_TYPE keyType, + CK_BYTE* id, CK_ULONG idLen, const CK_BYTE* pub, CK_ULONG pubLen, + CK_OBJECT_HANDLE* obj) +{ + CK_RV ret; + CK_ATTRIBUTE tmpl[] = { + { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_TOKEN, &ckTrue, sizeof(ckTrue) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_ID, id, idLen }, + { CKA_VALUE, (CK_BYTE*)pub, pubLen }, + }; + + ret = funcList->C_CreateObject(session, tmpl, + sizeof(tmpl) / sizeof(*tmpl), obj); + CHECK_CKR(ret, "Create token public key"); + return ret; +} + +/* Find the token public key previously created with the given CKA_ID. */ +static CK_RV find_token_pubkey(CK_SESSION_HANDLE session, CK_BYTE* id, + CK_ULONG idLen, CK_OBJECT_HANDLE* obj) +{ + CK_RV ret; + CK_ULONG count = 0; + CK_ATTRIBUTE tmpl[] = { + { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, + { CKA_ID, id, idLen }, + }; + + ret = funcList->C_FindObjectsInit(session, tmpl, + sizeof(tmpl) / sizeof(*tmpl)); + CHECK_CKR(ret, "FindObjectsInit"); + if (ret == CKR_OK) { + ret = funcList->C_FindObjects(session, obj, 1, &count); + CHECK_CKR(ret, "FindObjects"); + funcList->C_FindObjectsFinal(session); + } + if (ret == CKR_OK && count != 1) { + fprintf(stderr, "\nExpected 1 persisted key, found %lu - FAIL\n", + (unsigned long)count); + ret = CKR_GENERAL_ERROR; + } + return ret; +} + +/* Verify a known-good signature, then a one-byte-flipped copy that must be + * rejected with CKR_SIGNATURE_INVALID. */ +static CK_RV verify_good_and_tampered(CK_SESSION_HANDLE session, + CK_OBJECT_HANDLE obj, CK_MECHANISM_TYPE mechType, const CK_BYTE* sig, + CK_ULONG sigLen) +{ + CK_RV ret; + CK_MECHANISM mech; + CK_BYTE* badSig; + + badSig = (CK_BYTE*)XMALLOC(sigLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (badSig == NULL) + return CKR_HOST_MEMORY; + + mech.mechanism = mechType; + mech.pParameter = NULL; + mech.ulParameterLen = 0; + + ret = funcList->C_VerifyInit(session, &mech, obj); + CHECK_CKR(ret, "VerifyInit (persisted key)"); + if (ret == CKR_OK) { + ret = funcList->C_Verify(session, hbs_kat_msg, HBS_KAT_MSG_LEN, + (CK_BYTE*)sig, sigLen); + CHECK_CKR(ret, "Verify good signature (persisted key)"); + } + if (ret == CKR_OK) { + XMEMCPY(badSig, sig, sigLen); + badSig[sigLen / 2] ^= 0x01; + ret = funcList->C_VerifyInit(session, &mech, obj); + CHECK_CKR(ret, "VerifyInit (tampered)"); + } + if (ret == CKR_OK) { + CK_RV vret = funcList->C_Verify(session, hbs_kat_msg, HBS_KAT_MSG_LEN, + badSig, sigLen); + if (vret != CKR_SIGNATURE_INVALID) { + fprintf(stderr, "\nTampered signature not rejected: %lx - FAIL\n", + (unsigned long)vret); + ret = CKR_GENERAL_ERROR; + } + } + XFREE(badSig, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return ret; +} + +/* One scheme, one phase: phase 1 creates the token public key and verifies; + * phase 2 finds the persisted key and re-verifies. */ +static CK_RV scheme_roundtrip(CK_SESSION_HANDLE session, const char* name, + CK_KEY_TYPE keyType, CK_MECHANISM_TYPE mechType, CK_BYTE* id, + CK_ULONG idLen, const CK_BYTE* pub, CK_ULONG pubLen, const CK_BYTE* sig, + CK_ULONG sigLen, int phase) +{ + CK_RV ret; + CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE; + + if (phase == 1) { + printf(" [%s] creating token public key and verifying...\n", name); + ret = create_token_pubkey(session, keyType, id, idLen, pub, pubLen, + &obj); + if (ret == CKR_OK) + ret = verify_good_and_tampered(session, obj, mechType, sig, sigLen); + } + else { + printf(" [%s] finding persisted key and re-verifying...\n", name); + ret = find_token_pubkey(session, id, idLen, &obj); + if (ret == CKR_OK) + ret = verify_good_and_tampered(session, obj, mechType, sig, sigLen); + } + return ret; +} + +#ifdef WOLFPKCS11_LMS +static CK_BYTE hssId[] = "hbs-persist-hss"; +#endif +#ifdef WOLFPKCS11_XMSS +static CK_BYTE xmssId[] = "hbs-persist-xmss"; +static CK_BYTE xmssmtId[] = "hbs-persist-xmssmt"; +#endif + +/* Run every enabled scheme through the given phase (1 = before reinit, + * 2 = after reinit). */ +static CK_RV run_phase(CK_SESSION_HANDLE session, int phase) +{ + CK_RV ret = CKR_OK; + +#ifdef WOLFPKCS11_LMS + if (ret == CKR_OK) + ret = scheme_roundtrip(session, "HSS", CKK_HSS, CKM_HSS, + hssId, sizeof(hssId) - 1, hss_kat_pub, sizeof(hss_kat_pub), + hss_kat_sig, sizeof(hss_kat_sig), phase); +#endif +#ifdef WOLFPKCS11_XMSS + if (ret == CKR_OK) + ret = scheme_roundtrip(session, "XMSS", CKK_XMSS, CKM_XMSS, + xmssId, sizeof(xmssId) - 1, xmss_kat_pub, sizeof(xmss_kat_pub), + xmss_kat_sig, sizeof(xmss_kat_sig), phase); + if (ret == CKR_OK) + ret = scheme_roundtrip(session, "XMSSMT", CKK_XMSSMT, + CKM_XMSSMT, xmssmtId, sizeof(xmssmtId) - 1, xmssmt_kat_pub, + sizeof(xmssmt_kat_pub), xmssmt_kat_sig, sizeof(xmssmt_kat_sig), + phase); +#endif + return ret; +} + +/* Remove the on-disk store artifacts this test creates so repeated runs stay + * self-contained. remove() on an absent file is a harmless no-op, so removing + * the superset of possible object/key files (ids 0..2 across the enabled + * schemes) is safe regardless of which schemes are compiled in. */ +static void cleanup_test_files(const char* dir) +{ + char path[512]; + int i; + + if (dir == NULL) + return; + + snprintf(path, sizeof(path), "%s/wp11_token_0000000000000001", dir); + (void)remove(path); + for (i = 0; i <= 2; i++) { + snprintf(path, sizeof(path), + "%s/wp11_obj_0000000000000001_%016lx", dir, (unsigned long)i); + (void)remove(path); + snprintf(path, sizeof(path), + "%s/wp11_hsskey_pub_0000000000000001_%016lx", dir, (unsigned long)i); + (void)remove(path); + snprintf(path, sizeof(path), + "%s/wp11_xmsskey_pub_0000000000000001_%016lx", dir, (unsigned long)i); + (void)remove(path); + } +} + +static CK_RV hbs_persistence_test(void) +{ + CK_RV ret; + CK_SESSION_HANDLE session = CK_INVALID_HANDLE; + + /* Phase 1: fresh token, create token public keys, verify. */ + ret = pkcs11_init(); + if (ret != CKR_OK) + return ret; + if (ret == CKR_OK) + ret = pkcs11_init_token(); + if (ret == CKR_OK) + ret = pkcs11_set_user_pin(); + if (ret == CKR_OK) + ret = pkcs11_open_session(&session); + if (ret == CKR_OK) + ret = run_phase(session, 1); + if (session != CK_INVALID_HANDLE) { + funcList->C_Logout(session); + funcList->C_CloseSession(session); + session = CK_INVALID_HANDLE; + } + pkcs11_final(); + if (ret != CKR_OK) + return ret; + + /* Phase 2: re-initialize (reload from disk), find keys, re-verify. */ + printf("--- re-initializing library (reload from disk) ---\n"); + ret = pkcs11_init(); + if (ret != CKR_OK) + return ret; + if (ret == CKR_OK) + ret = pkcs11_open_session(&session); + if (ret == CKR_OK) + ret = run_phase(session, 2); + if (session != CK_INVALID_HANDLE) { + funcList->C_Logout(session); + funcList->C_CloseSession(session); + } + pkcs11_final(); + return ret; +} +#endif /* (WOLFPKCS11_LMS || WOLFPKCS11_XMSS) && !WOLFPKCS11_NO_STORE */ + +int main(int argc, char* argv[]) +{ + (void)argc; + (void)argv; +#if (defined(WOLFPKCS11_LMS) || defined(WOLFPKCS11_XMSS)) && \ + !defined(WOLFPKCS11_NO_STORE) + { + CK_RV ret; + +#ifndef WOLFPKCS11_NO_ENV + if (!XGETENV("WOLFPKCS11_TOKEN_PATH")) { + XSETENV("WOLFPKCS11_TOKEN_PATH", "./store/hbs", 1); + } +#endif + + printf("wolfPKCS11 HBS public-key persistence test\n"); + printf("==========================================\n\n"); + + ret = hbs_persistence_test(); +#ifndef WOLFPKCS11_NO_ENV + cleanup_test_files(XGETENV("WOLFPKCS11_TOKEN_PATH")); +#endif + if (ret == CKR_OK) { + printf("\nAll tests passed!\n"); + return 0; + } + printf("\nTest failed with error: %lx\n", (unsigned long)ret); + return 1; + } +#else + printf("LMS/XMSS or key store not compiled in!\n"); + return 77; +#endif +} diff --git a/tests/include.am b/tests/include.am index 52a42e00..5af7cbba 100644 --- a/tests/include.am +++ b/tests/include.am @@ -245,6 +245,11 @@ noinst_PROGRAMS += tests/concurrent_destroy_object_test tests_concurrent_destroy_object_test_SOURCES = tests/concurrent_destroy_object_test.c tests_concurrent_destroy_object_test_LDADD = +check_PROGRAMS += tests/hbs_persistence_test +noinst_PROGRAMS += tests/hbs_persistence_test +tests_hbs_persistence_test_SOURCES = tests/hbs_persistence_test.c +tests_hbs_persistence_test_LDADD = + if BUILD_STATIC tests_pkcs11test_LDADD += src/libwolfpkcs11.la tests_pkcs11mtt_LDADD += src/libwolfpkcs11.la @@ -295,6 +300,7 @@ tests_mlkem_secret_scrub_test_LDADD += src/libwolfpkcs11.la tests_logout_token_key_zero_test_LDADD += src/libwolfpkcs11.la tests_tpm_decode_bounds_test_LDADD += src/libwolfpkcs11.la tests_concurrent_destroy_object_test_LDADD += src/libwolfpkcs11.la +tests_hbs_persistence_test_LDADD += src/libwolfpkcs11.la else tests_object_id_uniqueness_test_LDADD += src/libwolfpkcs11.la tests_empty_pin_store_test_LDADD += src/libwolfpkcs11.la @@ -337,9 +343,11 @@ tests_mlkem_secret_scrub_test_LDADD += src/libwolfpkcs11.la tests_logout_token_key_zero_test_LDADD += src/libwolfpkcs11.la tests_tpm_decode_bounds_test_LDADD += src/libwolfpkcs11.la tests_concurrent_destroy_object_test_LDADD += src/libwolfpkcs11.la +tests_hbs_persistence_test_LDADD += src/libwolfpkcs11.la endif EXTRA_DIST += tests/unit.h \ tests/testdata.h \ tests/pkcs11_test_util.h \ + tests/hbs_kat.h \ tests/README.md diff --git a/tests/pkcs11v3test.c b/tests/pkcs11v3test.c index d444a357..12e8d7c6 100644 --- a/tests/pkcs11v3test.c +++ b/tests/pkcs11v3test.c @@ -87,13 +87,14 @@ static byte* userPin = (byte*)"wolfpkcs11-test"; static int userPinLen; #ifdef WOLFPKCS11_PKCS11_V3_2 -#if defined(WOLFPKCS11_MLDSA) || defined(WOLFPKCS11_MLKEM) +#if defined(WOLFPKCS11_MLDSA) || defined(WOLFPKCS11_MLKEM) || \ + defined(WOLFPKCS11_LMS) || defined(WOLFPKCS11_XMSS) static CK_BBOOL ckTrue = CK_TRUE; static CK_OBJECT_CLASS privKeyClass = CKO_PRIVATE_KEY; static CK_OBJECT_CLASS pubKeyClass = CKO_PUBLIC_KEY; -#endif /* WOLFPKCS11_MLDSA || WOLFPKCS11_MLKEM */ +#endif /* MLDSA || MLKEM || LMS || XMSS */ #ifdef WOLFPKCS11_MLDSA static CK_KEY_TYPE mldsaKeyType = CKK_ML_DSA; @@ -2901,6 +2902,910 @@ static void pkcs11_close_session(int flags, void* args) } } +#if defined(WOLFPKCS11_LMS) || defined(WOLFPKCS11_XMSS) +/* ---- Stateful hash-based signature verify (LMS/HSS, XMSS/XMSS^MT) ---- + * Known-answer verification tests. The public keys, signatures and message + * are defined in hbs_kat.h (shared with hbs_persistence_test.c); this + * verify-only feature imports the raw public key and checks the signature. */ +#include "hbs_kat.h" + +/* Import a raw HBS public key, verify a known-good signature (expect OK), + * flip one signature byte (expect CKR_SIGNATURE_INVALID), verify a + * wrong-length signature (expect CKR_SIGNATURE_INVALID, not a function + * failure), confirm C_CopyObject on the key is rejected, and confirm a second + * C_VerifyInit with no intervening C_Verify returns CKR_OPERATION_ACTIVE. */ +static CK_RV hbs_verify_kat(CK_SESSION_HANDLE session, CK_KEY_TYPE keyType, + CK_MECHANISM_TYPE mechType, const CK_BYTE* pub, CK_ULONG pubLen, + const CK_BYTE* sig, CK_ULONG sigLen) +{ + CK_RV ret; + CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE; + CK_MECHANISM mech; + CK_BYTE* badSig; + CK_ATTRIBUTE tmpl[] = { + { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_VALUE, (CK_BYTE*)pub, pubLen }, + }; + + badSig = (CK_BYTE*)XMALLOC(sigLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (badSig == NULL) + return CKR_HOST_MEMORY; + + mech.mechanism = mechType; + mech.pParameter = NULL; + mech.ulParameterLen = 0; + + ret = funcList->C_CreateObject(session, tmpl, + sizeof(tmpl) / sizeof(*tmpl), &obj); + CHECK_CKR(ret, "HBS public key import"); + if (ret == CKR_OK) { + ret = funcList->C_VerifyInit(session, &mech, obj); + CHECK_CKR(ret, "HBS C_VerifyInit"); + } + if (ret == CKR_OK) { + ret = funcList->C_Verify(session, hbs_kat_msg, HBS_KAT_MSG_LEN, + (CK_BYTE*)sig, sigLen); + CHECK_CKR(ret, "HBS C_Verify (valid signature)"); + } + if (ret == CKR_OK) { + XMEMCPY(badSig, sig, sigLen); + badSig[sigLen / 2] ^= 0x01; + ret = funcList->C_VerifyInit(session, &mech, obj); + CHECK_CKR(ret, "HBS C_VerifyInit (tampered)"); + } + if (ret == CKR_OK) { + ret = funcList->C_Verify(session, hbs_kat_msg, HBS_KAT_MSG_LEN, + badSig, sigLen); + CHECK_CKR_FAIL(ret, CKR_SIGNATURE_INVALID, + "HBS tampered-signature verify"); + } + if (ret == CKR_OK) { + /* A wrong-length signature must be reported as an invalid signature, + * not a function failure. */ + ret = funcList->C_VerifyInit(session, &mech, obj); + CHECK_CKR(ret, "HBS C_VerifyInit (wrong length)"); + } + if (ret == CKR_OK) { + ret = funcList->C_Verify(session, hbs_kat_msg, HBS_KAT_MSG_LEN, + (CK_BYTE*)sig, sigLen - 1); + CHECK_CKR_FAIL(ret, CKR_SIGNATURE_INVALID, + "HBS wrong-length-signature verify"); + } + if (ret == CKR_OK) { + /* Copy of a stateful HBS key is not supported; C_CopyObject must + * fail and create no object. */ + CK_OBJECT_HANDLE copy = CK_INVALID_HANDLE; + CK_ATTRIBUTE copyTmpl[] = { + { CKA_LABEL, (CK_BYTE*)"hbs-copy", 8 }, + }; + CK_RV copyRet = funcList->C_CopyObject(session, obj, copyTmpl, 1, + ©); + CHECK_COND(copyRet != CKR_OK, ret, "HBS C_CopyObject rejected"); + if (copy != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, copy); + } + if (ret == CKR_OK) { + /* A second C_VerifyInit with no intervening C_Verify must return + * CKR_OPERATION_ACTIVE rather than silently resetting the operation. */ + ret = funcList->C_VerifyInit(session, &mech, obj); + CHECK_CKR(ret, "HBS C_VerifyInit (active-guard first)"); + } + if (ret == CKR_OK) { + ret = funcList->C_VerifyInit(session, &mech, obj); + CHECK_CKR_FAIL(ret, CKR_OPERATION_ACTIVE, + "HBS second C_VerifyInit rejected"); + } + if (ret == CKR_OK) { + /* The first operation is still active; drain it so teardown is clean. */ + ret = funcList->C_Verify(session, hbs_kat_msg, HBS_KAT_MSG_LEN, + (CK_BYTE*)sig, sigLen); + CHECK_CKR(ret, "HBS C_Verify (drain active op)"); + } + + if (obj != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, obj); + XFREE(badSig, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return ret; +} + +/* A stateful-HBS private-key import attempt must be rejected. */ +static CK_RV hbs_priv_import_rejected(CK_SESSION_HANDLE session, + CK_KEY_TYPE keyType, const CK_BYTE* pub, CK_ULONG pubLen) +{ + CK_RV ret; + CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE; + CK_ATTRIBUTE tmpl[] = { + { CKA_CLASS, &privKeyClass, sizeof(privKeyClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_VALUE, (CK_BYTE*)pub, pubLen }, + }; + + ret = funcList->C_CreateObject(session, tmpl, + sizeof(tmpl) / sizeof(*tmpl), &obj); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_VALUE_INVALID, + "HBS private-key import rejected"); + if (obj != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, obj); + return ret; +} + +/* Keygen must be rejected in a verify-only build (mechanism not implemented). */ +static CK_RV hbs_keygen_rejected(CK_SESSION_HANDLE session, + CK_MECHANISM_TYPE kgMech) +{ + CK_RV ret; + CK_MECHANISM mech; + CK_OBJECT_HANDLE pub = CK_INVALID_HANDLE, priv = CK_INVALID_HANDLE; + CK_ATTRIBUTE pubTmpl[] = { { CKA_VERIFY, &ckTrue, sizeof(ckTrue) } }; + CK_ATTRIBUTE privTmpl[] = { { CKA_SIGN, &ckTrue, sizeof(ckTrue) } }; + + mech.mechanism = kgMech; + mech.pParameter = NULL; + mech.ulParameterLen = 0; + ret = funcList->C_GenerateKeyPair(session, &mech, pubTmpl, 1, + privTmpl, 1, &pub, &priv); + CHECK_CKR_FAIL(ret, CKR_MECHANISM_INVALID, + "HBS keygen rejected in verify-only build"); + return ret; +} + +/* Import a raw public key and read CKA_VALUE back; it must round-trip byte + * for byte (verify-only export path). */ +static CK_RV hbs_getattr_value(CK_SESSION_HANDLE session, CK_KEY_TYPE keyType, + const CK_BYTE* pub, CK_ULONG pubLen) +{ + CK_RV ret; + CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE; + CK_BYTE* out; + CK_ATTRIBUTE valTmpl[] = { { CKA_VALUE, NULL, 0 } }; + CK_ATTRIBUTE tmpl[] = { + { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_VALUE, (CK_BYTE*)pub, pubLen }, + }; + + /* Size the read buffer to the key so every parameter set round-trips, + * including SHA-512 sets whose public key exceeds a small fixed buffer. */ + out = (CK_BYTE*)malloc(pubLen); + if (out == NULL) + return CKR_HOST_MEMORY; + + ret = funcList->C_CreateObject(session, tmpl, + sizeof(tmpl) / sizeof(*tmpl), &obj); + CHECK_CKR(ret, "HBS getattr key import"); + /* Query length only first. */ + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, obj, valTmpl, 1); + CHECK_CKR(ret, "HBS CKA_VALUE length query"); + } + if (ret == CKR_OK && valTmpl[0].ulValueLen != pubLen) { + ret = CKR_GENERAL_ERROR; + CHECK_CKR(ret, "HBS CKA_VALUE length mismatch"); + } + if (ret == CKR_OK) { + valTmpl[0].pValue = out; + valTmpl[0].ulValueLen = pubLen; + ret = funcList->C_GetAttributeValue(session, obj, valTmpl, 1); + CHECK_CKR(ret, "HBS CKA_VALUE read"); + } + if (ret == CKR_OK && + (valTmpl[0].ulValueLen != pubLen || + XMEMCMP(out, pub, pubLen) != 0)) { + ret = CKR_GENERAL_ERROR; + CHECK_CKR(ret, "HBS CKA_VALUE round-trip"); + } + + if (obj != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, obj); + free(out); + return ret; +} + +/* GetMechanismInfo for an HBS verify mechanism must advertise CKF_VERIFY and + * must not claim CKF_SIGN (verify-only build). */ +static CK_RV hbs_mech_info(CK_MECHANISM_TYPE mechType) +{ + CK_RV ret; + CK_MECHANISM_INFO info; + + XMEMSET(&info, 0, sizeof(info)); + ret = funcList->C_GetMechanismInfo(slot, mechType, &info); + CHECK_CKR(ret, "HBS C_GetMechanismInfo"); + if (ret == CKR_OK && (info.flags & CKF_VERIFY) == 0) { + ret = CKR_GENERAL_ERROR; + CHECK_CKR(ret, "HBS mech info missing CKF_VERIFY"); + } + if (ret == CKR_OK && (info.flags & CKF_SIGN) != 0) { + ret = CKR_GENERAL_ERROR; + CHECK_CKR(ret, "HBS mech info unexpectedly claims CKF_SIGN"); + } + return ret; +} + +/* A public key created without CKA_VALUE is an incomplete template and must be + * rejected rather than yielding an unusable object. */ +static CK_RV hbs_empty_template_rejected(CK_SESSION_HANDLE session, + CK_KEY_TYPE keyType) +{ + CK_RV ret; + CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE; + CK_ATTRIBUTE tmpl[] = { + { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + }; + + ret = funcList->C_CreateObject(session, tmpl, + sizeof(tmpl) / sizeof(*tmpl), &obj); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_VALUE_INVALID, + "HBS empty-template public key rejected"); + if (obj != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, obj); + return ret; +} + +/* A truncated (wrong-length) raw public key must be rejected as a bad + * attribute value, not surfaced as an internal failure. */ +static CK_RV hbs_bad_pubkey_len(CK_SESSION_HANDLE session, CK_KEY_TYPE keyType, + const CK_BYTE* pub, CK_ULONG pubLen) +{ + CK_RV ret; + CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE; + CK_ATTRIBUTE tmpl[] = { + { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_VALUE, (CK_BYTE*)pub, pubLen - 1 }, + }; + + ret = funcList->C_CreateObject(session, tmpl, + sizeof(tmpl) / sizeof(*tmpl), &obj); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_VALUE_INVALID, + "HBS truncated public key rejected"); + if (obj != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, obj); + return ret; +} +#endif /* WOLFPKCS11_LMS || WOLFPKCS11_XMSS */ + + +#ifdef WOLFPKCS11_LMS + +static CK_RV test_hss_verify_kat(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + return hbs_verify_kat(session, CKK_HSS, CKM_HSS, + hss_kat_pub, sizeof(hss_kat_pub), hss_kat_sig, sizeof(hss_kat_sig)); +} + +static CK_RV test_hss_priv_import_rejected(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + return hbs_priv_import_rejected(session, CKK_HSS, + hss_kat_pub, sizeof(hss_kat_pub)); +} + +static CK_RV test_hss_verify_only_no_keygen(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + return hbs_keygen_rejected(session, CKM_HSS_KEY_PAIR_GEN); +} + +static CK_RV test_hss_getattr_value(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + return hbs_getattr_value(session, CKK_HSS, + hss_kat_pub, sizeof(hss_kat_pub)); +} + +/* Read the LMS parameter attributes derived from the imported public key. + * hss_kat_pub is a single-level (L1) tree with LMS type H5 and LMOTS W4. */ +static CK_RV test_hss_getattr_params(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE; + CK_ULONG levels = 0; + CK_LMS_TYPE lmsType = 0; + CK_LMOTS_TYPE lmotsType = 0; + CK_KEY_TYPE hssKeyType = CKK_HSS; + CK_ATTRIBUTE tmpl[] = { + { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, + { CKA_KEY_TYPE, &hssKeyType, sizeof(hssKeyType) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_VALUE, (CK_BYTE*)hss_kat_pub, sizeof(hss_kat_pub) }, + }; + CK_ATTRIBUTE q[] = { + { CKA_HSS_LEVELS, &levels, sizeof(levels) }, + { CKA_HSS_LMS_TYPE, &lmsType, sizeof(lmsType) }, + { CKA_HSS_LMOTS_TYPE, &lmotsType, sizeof(lmotsType) }, + }; + + ret = funcList->C_CreateObject(session, tmpl, + sizeof(tmpl) / sizeof(*tmpl), &obj); + CHECK_CKR(ret, "HSS params key import"); + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, obj, q, + sizeof(q) / sizeof(*q)); + CHECK_CKR(ret, "HSS params C_GetAttributeValue"); + } + if (ret == CKR_OK && levels != 1) { + ret = CKR_GENERAL_ERROR; + CHECK_CKR(ret, "HSS CKA_HSS_LEVELS value"); + } + if (ret == CKR_OK && lmsType != CKL_LMS_SHA256_M32_H5) { + ret = CKR_GENERAL_ERROR; + CHECK_CKR(ret, "HSS CKA_HSS_LMS_TYPE value"); + } + if (ret == CKR_OK && lmotsType != CKL_LMOTS_SHA256_N32_W4) { + ret = CKR_GENERAL_ERROR; + CHECK_CKR(ret, "HSS CKA_HSS_LMOTS_TYPE value"); + } + + if (obj != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, obj); + return ret; +} + +/* Read the array-form HSS attributes and the keys-remaining state. hss_kat_pub + * is a single-level (L1) tree, so each array has one entry equal to the scalar + * top-level type; CKA_HSS_KEYS_REMAINING is a private-key/state property and is + * unavailable on a verify-only public key. */ +static CK_RV test_hss_getattr_array_params(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE; + CK_ULONG lmsTypes[8]; + CK_ULONG lmotsTypes[8]; + CK_ULONG keysRemaining = 0; + CK_KEY_TYPE hssKeyType = CKK_HSS; + CK_ATTRIBUTE tmpl[] = { + { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, + { CKA_KEY_TYPE, &hssKeyType, sizeof(hssKeyType) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_VALUE, (CK_BYTE*)hss_kat_pub, sizeof(hss_kat_pub) }, + }; + CK_ATTRIBUTE qArrays[] = { + { CKA_HSS_LMS_TYPES, lmsTypes, sizeof(lmsTypes) }, + { CKA_HSS_LMOTS_TYPES, lmotsTypes, sizeof(lmotsTypes) }, + }; + CK_ATTRIBUTE qRemaining[] = { + { CKA_HSS_KEYS_REMAINING, &keysRemaining, sizeof(keysRemaining) }, + }; + + ret = funcList->C_CreateObject(session, tmpl, + sizeof(tmpl) / sizeof(*tmpl), &obj); + CHECK_CKR(ret, "HSS array-params key import"); + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, obj, qArrays, + sizeof(qArrays) / sizeof(*qArrays)); + CHECK_CKR(ret, "HSS array C_GetAttributeValue"); + } + /* L1 tree: one CK_ULONG entry each, equal to the top-level H5 / W4 types. */ + if (ret == CKR_OK && (qArrays[0].ulValueLen != sizeof(CK_ULONG) || + lmsTypes[0] != CKL_LMS_SHA256_M32_H5)) { + ret = CKR_GENERAL_ERROR; + CHECK_CKR(ret, "HSS CKA_HSS_LMS_TYPES value"); + } + if (ret == CKR_OK && (qArrays[1].ulValueLen != sizeof(CK_ULONG) || + lmotsTypes[0] != CKL_LMOTS_SHA256_N32_W4)) { + ret = CKR_GENERAL_ERROR; + CHECK_CKR(ret, "HSS CKA_HSS_LMOTS_TYPES value"); + } + if (ret == CKR_OK) { + /* Unavailable attribute: reported through ulValueLen, so the call's + * return code is not asserted here. */ + (void)funcList->C_GetAttributeValue(session, obj, qRemaining, 1); + if (qRemaining[0].ulValueLen != CK_UNAVAILABLE_INFORMATION) { + ret = CKR_GENERAL_ERROR; + CHECK_CKR(ret, "HSS CKA_HSS_KEYS_REMAINING unavailable"); + } + } + + if (obj != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, obj); + return ret; +} + +static CK_RV test_hss_mech_info(void* args) +{ + (void)args; + return hbs_mech_info(CKM_HSS); +} + +static CK_RV test_hss_empty_template_rejected(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + return hbs_empty_template_rejected(session, CKK_HSS); +} + +static CK_RV test_hss_bad_pubkey_len(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + return hbs_bad_pubkey_len(session, CKK_HSS, + hss_kat_pub, sizeof(hss_kat_pub)); +} + +/* A structurally invalid public key of the correct length (here an unknown + * top-level LMS type) must be rejected as a bad attribute value, not surface as + * a function failure. Complements test_hss_bad_pubkey_len (wrong length). */ +static CK_RV test_hss_bad_pubkey_value(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE; + CK_KEY_TYPE keyType = CKK_HSS; + CK_BYTE badPub[sizeof(hss_kat_pub)]; + CK_ATTRIBUTE tmpl[] = { + { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_VALUE, badPub, sizeof(badPub) }, + }; + + /* Corrupt the top-level LMS type (bytes 4..7) to an unknown value. */ + XMEMCPY(badPub, hss_kat_pub, sizeof(badPub)); + badPub[4] = 0xFF; + badPub[5] = 0xFF; + badPub[6] = 0xFF; + badPub[7] = 0xFF; + + ret = funcList->C_CreateObject(session, tmpl, + sizeof(tmpl) / sizeof(*tmpl), &obj); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_VALUE_INVALID, + "HSS structurally invalid public key rejected"); + if (obj != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, obj); + return ret; +} + +/* Supplying the correct CKA_HSS_* parameter attributes on import must succeed; + * supplying a wrong one must be rejected. hss_kat_pub is L1/H5/W4. */ +static CK_RV test_hss_paramset_validate(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE; + CK_KEY_TYPE keyType = CKK_HSS; + CK_ULONG levels = 1; + CK_LMS_TYPE lmsType = CKL_LMS_SHA256_M32_H5; + CK_LMOTS_TYPE lmotsType = CKL_LMOTS_SHA256_N32_W4; + CK_LMS_TYPE badLmsType = CKL_LMS_SHA256_M32_H10; + CK_ATTRIBUTE good[] = { + { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_HSS_LEVELS, &levels, sizeof(levels) }, + { CKA_HSS_LMS_TYPE, &lmsType, sizeof(lmsType) }, + { CKA_HSS_LMOTS_TYPE, &lmotsType, sizeof(lmotsType) }, + { CKA_VALUE, (CK_BYTE*)hss_kat_pub, sizeof(hss_kat_pub) }, + }; + CK_ATTRIBUTE bad[] = { + { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_HSS_LMS_TYPE, &badLmsType, sizeof(badLmsType) }, + { CKA_VALUE, (CK_BYTE*)hss_kat_pub, sizeof(hss_kat_pub) }, + }; + + ret = funcList->C_CreateObject(session, good, + sizeof(good) / sizeof(*good), &obj); + CHECK_CKR(ret, "HSS import with matching CKA_HSS_* params"); + if (obj != CK_INVALID_HANDLE) { + funcList->C_DestroyObject(session, obj); + obj = CK_INVALID_HANDLE; + } + if (ret == CKR_OK) { + ret = funcList->C_CreateObject(session, bad, + sizeof(bad) / sizeof(*bad), &obj); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_VALUE_INVALID, + "HSS import with mismatching CKA_HSS_LMS_TYPE rejected"); + if (obj != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, obj); + } + return ret; +} + +/* CKA_PARAMETER_SET carries the XMSS/XMSS^MT OID and does not apply to HSS + * (CKK_HSS) keys, which use the CKA_HSS_* attributes instead. Supplying it on + * an HSS object -- both on import and via C_SetAttributeValue -- must be + * rejected rather than silently accepted as a no-op. */ +static CK_RV test_hss_paramset_rejected(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE; + CK_KEY_TYPE keyType = CKK_HSS; + CK_ULONG paramSet = 1; + CK_ATTRIBUTE setTmpl[] = { + { CKA_PARAMETER_SET, ¶mSet, sizeof(paramSet) }, + }; + CK_ATTRIBUTE badImport[] = { + { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_PARAMETER_SET, ¶mSet, sizeof(paramSet) }, + { CKA_VALUE, (CK_BYTE*)hss_kat_pub, sizeof(hss_kat_pub) }, + }; + CK_ATTRIBUTE goodImport[] = { + { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_VALUE, (CK_BYTE*)hss_kat_pub, sizeof(hss_kat_pub) }, + }; + + /* CKA_PARAMETER_SET in the import template must be rejected. */ + ret = funcList->C_CreateObject(session, badImport, + sizeof(badImport) / sizeof(*badImport), &obj); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_VALUE_INVALID, + "HSS import with CKA_PARAMETER_SET rejected"); + if (obj != CK_INVALID_HANDLE) { + funcList->C_DestroyObject(session, obj); + obj = CK_INVALID_HANDLE; + } + + /* Setting CKA_PARAMETER_SET on a valid HSS object must be rejected too. */ + if (ret == CKR_OK) { + ret = funcList->C_CreateObject(session, goodImport, + sizeof(goodImport) / sizeof(*goodImport), &obj); + CHECK_CKR(ret, "HSS import for CKA_PARAMETER_SET set-attr test"); + } + if (ret == CKR_OK) { + ret = funcList->C_SetAttributeValue(session, obj, setTmpl, 1); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_VALUE_INVALID, + "HSS C_SetAttributeValue CKA_PARAMETER_SET rejected"); + } + + if (obj != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, obj); + return ret; +} + +/* A failed re-import via C_SetAttributeValue (a bad CKA_VALUE) must leave the + * existing key intact: the object still verifies its original signature. This + * exercises the atomic temporary-key swap in WP11_Object_SetHssKey. */ +static CK_RV test_hss_reimport_atomic(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE; + CK_MECHANISM mech; + CK_KEY_TYPE keyType = CKK_HSS; + CK_ATTRIBUTE tmpl[] = { + { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_VALUE, (CK_BYTE*)hss_kat_pub, sizeof(hss_kat_pub) }, + }; + /* A truncated public key is an invalid re-import value. */ + CK_ATTRIBUTE badVal[] = { + { CKA_VALUE, (CK_BYTE*)hss_kat_pub, sizeof(hss_kat_pub) - 1 }, + }; + + mech.mechanism = CKM_HSS; + mech.pParameter = NULL; + mech.ulParameterLen = 0; + + ret = funcList->C_CreateObject(session, tmpl, + sizeof(tmpl) / sizeof(*tmpl), &obj); + CHECK_CKR(ret, "HSS key import for re-import test"); + if (ret == CKR_OK) { + ret = funcList->C_SetAttributeValue(session, obj, badVal, 1); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_VALUE_INVALID, + "HSS re-import of invalid CKA_VALUE rejected"); + } + if (ret == CKR_OK) { + /* The failed re-import must leave the original key usable. */ + ret = funcList->C_VerifyInit(session, &mech, obj); + CHECK_CKR(ret, "HSS C_VerifyInit after failed re-import"); + } + if (ret == CKR_OK) { + ret = funcList->C_Verify(session, hbs_kat_msg, HBS_KAT_MSG_LEN, + (CK_BYTE*)hss_kat_sig, sizeof(hss_kat_sig)); + CHECK_CKR(ret, "HSS verify after failed re-import"); + } + + if (obj != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, obj); + return ret; +} + +#ifdef WOLFPKCS11_XMSS +/* CKM_HSS must reject a key whose type is not CKK_HSS. Pair it with an XMSS + * public key so C_VerifyInit's HSS mechanism/key-type guard is exercised + * directly (the cross-scheme counterpart of test_xmss_wrong_mech_keytype). */ +static CK_RV test_hss_wrong_mech_keytype(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE; + CK_MECHANISM mech; + CK_KEY_TYPE xmssKeyType = CKK_XMSS; + CK_ATTRIBUTE tmpl[] = { + { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, + { CKA_KEY_TYPE, &xmssKeyType, sizeof(xmssKeyType) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_VALUE, (CK_BYTE*)xmss_kat_pub, sizeof(xmss_kat_pub) }, + }; + + mech.mechanism = CKM_HSS; + mech.pParameter = NULL; + mech.ulParameterLen = 0; + + ret = funcList->C_CreateObject(session, tmpl, + sizeof(tmpl) / sizeof(*tmpl), &obj); + CHECK_CKR(ret, "XMSS key import for HSS wrong-mech test"); + if (ret == CKR_OK) { + ret = funcList->C_VerifyInit(session, &mech, obj); + CHECK_CKR_FAIL(ret, CKR_KEY_TYPE_INCONSISTENT, + "CKM_HSS mechanism rejects XMSS key"); + } + + if (obj != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, obj); + return ret; +} +#endif /* WOLFPKCS11_XMSS */ +#endif /* WOLFPKCS11_LMS */ + + +#ifdef WOLFPKCS11_XMSS + +static CK_RV test_xmss_verify_kat(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + return hbs_verify_kat(session, CKK_XMSS, CKM_XMSS, + xmss_kat_pub, sizeof(xmss_kat_pub), xmss_kat_sig, sizeof(xmss_kat_sig)); +} + +static CK_RV test_xmssmt_verify_kat(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + return hbs_verify_kat(session, CKK_XMSSMT, CKM_XMSSMT, + xmssmt_kat_pub, sizeof(xmssmt_kat_pub), + xmssmt_kat_sig, sizeof(xmssmt_kat_sig)); +} + +static CK_RV test_xmss_priv_import_rejected(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + return hbs_priv_import_rejected(session, CKK_XMSS, + xmss_kat_pub, sizeof(xmss_kat_pub)); +} + +static CK_RV test_xmss_verify_only_no_keygen(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + return hbs_keygen_rejected(session, CKM_XMSS_KEY_PAIR_GEN); +} + +static CK_RV test_xmss_getattr_value(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + return hbs_getattr_value(session, CKK_XMSS, + xmss_kat_pub, sizeof(xmss_kat_pub)); +} + +static CK_RV test_xmssmt_getattr_value(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + return hbs_getattr_value(session, CKK_XMSSMT, + xmssmt_kat_pub, sizeof(xmssmt_kat_pub)); +} + +static CK_RV test_xmss_mech_info(void* args) +{ + (void)args; + return hbs_mech_info(CKM_XMSS); +} + +static CK_RV test_xmssmt_mech_info(void* args) +{ + (void)args; + return hbs_mech_info(CKM_XMSSMT); +} + +static CK_RV test_xmss_empty_template_rejected(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + return hbs_empty_template_rejected(session, CKK_XMSS); +} + +static CK_RV test_xmss_bad_pubkey_len(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + return hbs_bad_pubkey_len(session, CKK_XMSS, + xmss_kat_pub, sizeof(xmss_kat_pub)); +} + +/* A structurally invalid XMSS public key of the correct length (here an unknown + * parameter-set OID in the leading bytes) must be rejected as a bad attribute + * value, not a function failure. Complements test_xmss_bad_pubkey_len. */ +static CK_RV test_xmss_bad_pubkey_value(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE; + CK_KEY_TYPE keyType = CKK_XMSS; + CK_BYTE badPub[sizeof(xmss_kat_pub)]; + CK_ATTRIBUTE tmpl[] = { + { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_VALUE, badPub, sizeof(badPub) }, + }; + + /* Corrupt the leading parameter-set OID to an unknown value; length stays + * correct so this exercises the structural-rejection path. */ + XMEMCPY(badPub, xmss_kat_pub, sizeof(badPub)); + badPub[0] = 0xFF; + badPub[1] = 0xFF; + badPub[2] = 0xFF; + badPub[3] = 0xFF; + + ret = funcList->C_CreateObject(session, tmpl, + sizeof(tmpl) / sizeof(*tmpl), &obj); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_VALUE_INVALID, + "XMSS structurally invalid public key rejected"); + if (obj != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, obj); + return ret; +} + +/* A key created as CKK_XMSS must be rejected by the XMSS^MT mechanism: + * C_VerifyInit enforces the mechanism/key-type pairing. See + * test_hss_wrong_mech_keytype for the HSS counterpart. */ +static CK_RV test_xmss_wrong_mech_keytype(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE; + CK_MECHANISM mech; + CK_KEY_TYPE xmssKeyType = CKK_XMSS; + CK_ATTRIBUTE tmpl[] = { + { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, + { CKA_KEY_TYPE, &xmssKeyType, sizeof(xmssKeyType) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_VALUE, (CK_BYTE*)xmss_kat_pub, sizeof(xmss_kat_pub) }, + }; + + mech.mechanism = CKM_XMSSMT; + mech.pParameter = NULL; + mech.ulParameterLen = 0; + + ret = funcList->C_CreateObject(session, tmpl, + sizeof(tmpl) / sizeof(*tmpl), &obj); + CHECK_CKR(ret, "XMSS key import for wrong-mech test"); + if (ret == CKR_OK) { + ret = funcList->C_VerifyInit(session, &mech, obj); + CHECK_CKR_FAIL(ret, CKR_KEY_TYPE_INCONSISTENT, + "XMSSMT mechanism rejects XMSS key"); + } + + if (obj != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, obj); + return ret; +} + +/* CKA_PARAMETER_SET (the XMSS OID) on import must match the public key: the + * matching OID succeeds and round-trips on read-back; a wrong OID is rejected. + * xmss_kat_pub carries OID 0x00000001 in its leading bytes. */ +static CK_RV test_xmss_paramset(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE; + CK_KEY_TYPE keyType = CKK_XMSS; + CK_ULONG oid = 1; + CK_ULONG badOid = 2; + CK_ULONG readOid = 0; + CK_ATTRIBUTE q[] = { { CKA_PARAMETER_SET, &readOid, sizeof(readOid) } }; + CK_ATTRIBUTE good[] = { + { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_PARAMETER_SET, &oid, sizeof(oid) }, + { CKA_VALUE, (CK_BYTE*)xmss_kat_pub, sizeof(xmss_kat_pub) }, + }; + CK_ATTRIBUTE bad[] = { + { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_PARAMETER_SET, &badOid, sizeof(badOid) }, + { CKA_VALUE, (CK_BYTE*)xmss_kat_pub, sizeof(xmss_kat_pub) }, + }; + + ret = funcList->C_CreateObject(session, good, + sizeof(good) / sizeof(*good), &obj); + CHECK_CKR(ret, "XMSS import with matching CKA_PARAMETER_SET"); + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, obj, q, 1); + CHECK_CKR(ret, "XMSS CKA_PARAMETER_SET read-back"); + } + if (ret == CKR_OK && (q[0].ulValueLen != sizeof(readOid) || readOid != 1)) { + ret = CKR_GENERAL_ERROR; + CHECK_CKR(ret, "XMSS CKA_PARAMETER_SET value"); + } + if (obj != CK_INVALID_HANDLE) { + funcList->C_DestroyObject(session, obj); + obj = CK_INVALID_HANDLE; + } + if (ret == CKR_OK) { + ret = funcList->C_CreateObject(session, bad, + sizeof(bad) / sizeof(*bad), &obj); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_VALUE_INVALID, + "XMSS import with mismatching CKA_PARAMETER_SET rejected"); + if (obj != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, obj); + } + return ret; +} + +/* CKA_PARAMETER_SET on an existing XMSS object is derived from the key, not an + * independently settable value. A C_SetAttributeValue supplying a wrong OID + * (with or without CKA_VALUE) must be rejected rather than silently accepted, + * and the key-derived value must be left unchanged. The import path validates + * the OID against the key, so a lone CKA_PARAMETER_SET (no CKA_VALUE) is + * rejected too. xmss_kat_pub carries OID 1. */ +static CK_RV test_xmss_paramset_setattr_rejected(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE; + CK_KEY_TYPE keyType = CKK_XMSS; + CK_ULONG badOid = 2; + CK_ULONG readOid = 0; + CK_ATTRIBUTE q[] = { { CKA_PARAMETER_SET, &readOid, sizeof(readOid) } }; + CK_ATTRIBUTE importTmpl[] = { + { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_VALUE, (CK_BYTE*)xmss_kat_pub, sizeof(xmss_kat_pub) }, + }; + CK_ATTRIBUTE setBadOnly[] = { + { CKA_PARAMETER_SET, &badOid, sizeof(badOid) }, + }; + CK_ATTRIBUTE setBadWithVal[] = { + { CKA_PARAMETER_SET, &badOid, sizeof(badOid) }, + { CKA_VALUE, (CK_BYTE*)xmss_kat_pub, sizeof(xmss_kat_pub) }, + }; + + ret = funcList->C_CreateObject(session, importTmpl, + sizeof(importTmpl) / sizeof(*importTmpl), &obj); + CHECK_CKR(ret, "XMSS import for set-attr test"); + + /* A wrong OID via C_SetAttributeValue must be rejected, not a no-op. */ + if (ret == CKR_OK) { + ret = funcList->C_SetAttributeValue(session, obj, setBadOnly, 1); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_VALUE_INVALID, + "XMSS set wrong CKA_PARAMETER_SET rejected"); + } + if (ret == CKR_OK) { + ret = funcList->C_SetAttributeValue(session, obj, setBadWithVal, 2); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_VALUE_INVALID, + "XMSS set wrong CKA_PARAMETER_SET + value rejected"); + } + /* The key-derived OID must be unchanged by the rejected sets. */ + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, obj, q, 1); + CHECK_CKR(ret, "XMSS CKA_PARAMETER_SET read-back after rejected set"); + } + if (ret == CKR_OK && (q[0].ulValueLen != sizeof(readOid) || readOid != 1)) { + ret = CKR_GENERAL_ERROR; + CHECK_CKR(ret, "XMSS CKA_PARAMETER_SET unchanged after rejected set"); + } + + if (obj != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, obj); + return ret; +} +#endif /* WOLFPKCS11_XMSS */ + + static TEST_FUNC testFunc[] = { PKCS11TEST_FUNC_NO_INIT_DECL(test_get_interface_list), PKCS11TEST_FUNC_NO_INIT_DECL(test_get_interface), @@ -2936,6 +3841,40 @@ static TEST_FUNC testFunc[] = { PKCS11TEST_FUNC_SESS_DECL(test_mlkem_encap_decap_not_permitted), PKCS11TEST_FUNC_SESS_DECL(test_copy_object_mlkem_key), #endif +#ifdef WOLFPKCS11_LMS + PKCS11TEST_FUNC_SESS_DECL(test_hss_verify_kat), + PKCS11TEST_FUNC_SESS_DECL(test_hss_priv_import_rejected), + PKCS11TEST_FUNC_SESS_DECL(test_hss_verify_only_no_keygen), + PKCS11TEST_FUNC_SESS_DECL(test_hss_getattr_value), + PKCS11TEST_FUNC_SESS_DECL(test_hss_getattr_params), + PKCS11TEST_FUNC_SESS_DECL(test_hss_getattr_array_params), + PKCS11TEST_FUNC_SESS_DECL(test_hss_mech_info), + PKCS11TEST_FUNC_SESS_DECL(test_hss_empty_template_rejected), + PKCS11TEST_FUNC_SESS_DECL(test_hss_bad_pubkey_len), + PKCS11TEST_FUNC_SESS_DECL(test_hss_bad_pubkey_value), + PKCS11TEST_FUNC_SESS_DECL(test_hss_paramset_validate), + PKCS11TEST_FUNC_SESS_DECL(test_hss_paramset_rejected), + PKCS11TEST_FUNC_SESS_DECL(test_hss_reimport_atomic), +#endif +#ifdef WOLFPKCS11_XMSS + PKCS11TEST_FUNC_SESS_DECL(test_xmss_verify_kat), + PKCS11TEST_FUNC_SESS_DECL(test_xmssmt_verify_kat), + PKCS11TEST_FUNC_SESS_DECL(test_xmss_priv_import_rejected), + PKCS11TEST_FUNC_SESS_DECL(test_xmss_verify_only_no_keygen), + PKCS11TEST_FUNC_SESS_DECL(test_xmss_getattr_value), + PKCS11TEST_FUNC_SESS_DECL(test_xmssmt_getattr_value), + PKCS11TEST_FUNC_SESS_DECL(test_xmss_mech_info), + PKCS11TEST_FUNC_SESS_DECL(test_xmssmt_mech_info), + PKCS11TEST_FUNC_SESS_DECL(test_xmss_empty_template_rejected), + PKCS11TEST_FUNC_SESS_DECL(test_xmss_bad_pubkey_len), + PKCS11TEST_FUNC_SESS_DECL(test_xmss_bad_pubkey_value), + PKCS11TEST_FUNC_SESS_DECL(test_xmss_wrong_mech_keytype), + PKCS11TEST_FUNC_SESS_DECL(test_xmss_paramset), + PKCS11TEST_FUNC_SESS_DECL(test_xmss_paramset_setattr_rejected), +#endif +#if defined(WOLFPKCS11_LMS) && defined(WOLFPKCS11_XMSS) + PKCS11TEST_FUNC_SESS_DECL(test_hss_wrong_mech_keytype), +#endif #endif }; static int testFuncCnt = sizeof(testFunc) / sizeof(*testFunc); diff --git a/wolfpkcs11/internal.h b/wolfpkcs11/internal.h index 0e72be16..4c6f2a10 100644 --- a/wolfpkcs11/internal.h +++ b/wolfpkcs11/internal.h @@ -36,6 +36,14 @@ #include #endif +#ifdef WOLFPKCS11_LMS +#include +#endif + +#ifdef WOLFPKCS11_XMSS +#include +#endif + #include #include @@ -117,6 +125,14 @@ C_EXTRA_FLAGS="-DWOLFSSL_PUBLIC_MP -DWC_RSA_DIRECT" #error Compiling with ML-KEM requires ML-KEM support in wolfSSL. #endif +#if defined(WOLFPKCS11_LMS) && !defined(WOLFSSL_HAVE_LMS) +#error Compiling with LMS/HSS requires LMS support in wolfSSL (--enable-lms). +#endif + +#if defined(WOLFPKCS11_XMSS) && !defined(WOLFSSL_HAVE_XMSS) +#error Compiling with XMSS requires XMSS support in wolfSSL (--enable-xmss). +#endif + /* We need the next two for NSS, just for storage, even if we have no algos */ #ifndef WC_MD5_DIGEST_SIZE #define WC_MD5_DIGEST_SIZE 16 @@ -277,6 +293,11 @@ C_EXTRA_FLAGS="-DWOLFSSL_PUBLIC_MP -DWC_RSA_DIRECT" #define WP11_INIT_TLS_MAC_VERIFY 0x0071 #define WP11_INIT_MLDSA_SIGN 0x0080 #define WP11_INIT_MLDSA_VERIFY 0x0081 +/* Stateful hash-based signature verify operations. Sign flags (0x0090, + * 0x00A0) are reserved for the sign-capable builds. XMSS and XMSS^MT share + * one verify flag; the mechanism→key-type check distinguishes them. */ +#define WP11_INIT_HSS_VERIFY 0x0091 +#define WP11_INIT_XMSS_VERIFY 0x00A1 /* Operation categories for CKR_OPERATION_ACTIVE checks */ #define WP11_OP_ENCRYPT 0 @@ -589,6 +610,22 @@ WP11_LOCAL int WP11_Mldsa_Verify(unsigned char* sig, word32 sigLen, unsigned cha word32 dataLen, int* stat, WP11_Object* pub, WP11_Session* session); +#ifdef WOLFPKCS11_LMS +WP11_LOCAL int WP11_Object_SetHssKey(WP11_Object* object, unsigned char** data, + CK_ULONG* len); +WP11_LOCAL int WP11_Hss_Verify(unsigned char* sig, word32 sigLen, + unsigned char* data, word32 dataLen, int* stat, + WP11_Object* pub); +#endif + +#ifdef WOLFPKCS11_XMSS +WP11_LOCAL int WP11_Object_SetXmssKey(WP11_Object* object, unsigned char** data, + CK_ULONG* len); +WP11_LOCAL int WP11_Xmss_Verify(unsigned char* sig, word32 sigLen, + unsigned char* data, word32 dataLen, int* stat, + WP11_Object* pub); +#endif + WP11_LOCAL int WP11_Dh_GenerateKeyPair(WP11_Object* pub, WP11_Object* priv, WP11_Slot* slot); WP11_LOCAL int WP11_Dh_Derive(unsigned char* pub, word32 pubLen, unsigned char* key, diff --git a/wolfpkcs11/pkcs11.h b/wolfpkcs11/pkcs11.h index 33397388..87668905 100644 --- a/wolfpkcs11/pkcs11.h +++ b/wolfpkcs11/pkcs11.h @@ -178,6 +178,9 @@ extern "C" { #define CKK_AES 0x0000001FUL #define CKK_DES3 0x00000015UL /* not supported */ #define CKK_HKDF 0x00000042UL +#define CKK_HSS 0x00000046UL +#define CKK_XMSS 0x00000047UL +#define CKK_XMSSMT 0x00000048UL #define CKK_ML_KEM 0x00000049UL #define CKK_ML_DSA 0x0000004AUL @@ -264,6 +267,13 @@ extern "C" { /* KEM */ #define CKA_ENCAPSULATE 0x00000633UL #define CKA_DECAPSULATE 0x00000634UL +/* LMS/HSS (RFC 8554) */ +#define CKA_HSS_LEVELS 0x00000617UL +#define CKA_HSS_LMS_TYPE 0x00000618UL +#define CKA_HSS_LMOTS_TYPE 0x00000619UL +#define CKA_HSS_LMS_TYPES 0x0000061AUL +#define CKA_HSS_LMOTS_TYPES 0x0000061BUL +#define CKA_HSS_KEYS_REMAINING 0x0000061CUL #ifdef WOLFPKCS11_NSS #define CKA_NSS_EMAIL (CKA_NSS + 2) @@ -367,6 +377,14 @@ extern "C" { #define CKM_ML_DSA_KEY_PAIR_GEN 0x0000001CUL #define CKM_ML_DSA 0x0000001DUL #define CKM_HASH_ML_DSA 0x0000001FUL +/* Stateful hash-based signature mechanisms (RFC 8554 HSS, RFC 8391 XMSS / + * XMSS^MT). */ +#define CKM_HSS_KEY_PAIR_GEN 0x00004032UL +#define CKM_HSS 0x00004033UL +#define CKM_XMSS_KEY_PAIR_GEN 0x00004034UL +#define CKM_XMSSMT_KEY_PAIR_GEN 0x00004035UL +#define CKM_XMSS 0x00004036UL +#define CKM_XMSSMT 0x00004037UL #ifdef WOLFPKCS11_NSS #define CKM_NSS_TLS_PRF_GENERAL_SHA256 (CKM_NSS + 21) @@ -879,6 +897,32 @@ typedef CK_ULONG CK_ML_KEM_PARAMETER_SET_TYPE; #define CKP_ML_KEM_768 0x00000002UL #define CKP_ML_KEM_1024 0x00000003UL +/* HSS / LMS / LMOTS algorithm identifiers (RFC 8554). The HSS key parameters + * are carried by the CKA_HSS_LEVELS / CKA_HSS_LMS_TYPE(S) / CKA_HSS_LMOTS_TYPE(S) + * key attributes (PKCS#11 v3.3 HSS profile). */ +typedef CK_ULONG CK_HSS_LEVELS; +typedef CK_ULONG CK_LMS_TYPE; +typedef CK_ULONG CK_LMOTS_TYPE; + +/* RFC 8554 LMS typecodes (subset supported by wolfSSL) */ +#define CKL_LMS_SHA256_M32_H5 0x00000005UL +#define CKL_LMS_SHA256_M32_H10 0x00000006UL +#define CKL_LMS_SHA256_M32_H15 0x00000007UL +#define CKL_LMS_SHA256_M32_H20 0x00000008UL +#define CKL_LMS_SHA256_M32_H25 0x00000009UL + +/* RFC 8554 LMOTS typecodes (subset supported by wolfSSL) */ +#define CKL_LMOTS_SHA256_N32_W1 0x00000001UL +#define CKL_LMOTS_SHA256_N32_W2 0x00000002UL +#define CKL_LMOTS_SHA256_N32_W4 0x00000003UL +#define CKL_LMOTS_SHA256_N32_W8 0x00000004UL + +/* XMSS / XMSS^MT parameter-set identifier types (PKCS#11 v3.3). The value is + * the numeric algorithm OID (per NIST SP800-208), also carried in the leading + * 4 bytes of the public key. */ +typedef CK_ULONG CK_XMSS_PARAMETER_SET_TYPE; +typedef CK_ULONG CK_XMSSMT_PARAMETER_SET_TYPE; + /* Function list types. */ typedef struct CK_FUNCTION_LIST CK_FUNCTION_LIST; diff --git a/wolfpkcs11/store.h b/wolfpkcs11/store.h index 12bf120e..183c65a6 100644 --- a/wolfpkcs11/store.h +++ b/wolfpkcs11/store.h @@ -40,6 +40,12 @@ #define WOLFPKCS11_STORE_MLDSAKEY_PUB 0x0D #define WOLFPKCS11_STORE_MLKEMKEY_PRIV 0x0E #define WOLFPKCS11_STORE_MLKEMKEY_PUB 0x0F +/* Stateful hash-based signature keys. The private-key storage types (0x10 for + * HSS, 0x12 for XMSS) are reserved for the future sign-capable builds so each + * priv/pub pair stays adjacent and ordered private-before-public like the + * other algorithms above. */ +#define WOLFPKCS11_STORE_HSSKEY_PUB 0x11 +#define WOLFPKCS11_STORE_XMSSKEY_PUB 0x13 /* * Opens access to location to read/write token data.