From a0e1fcebfb3d250a003ad5d17dca62a3e03eea09 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Tue, 24 Mar 2026 16:31:31 +0100 Subject: [PATCH 001/167] Re-enable hostap tests and remove some flaky tests ALL should not include NULL ciphersuites. Those need to be enabled explicitly. --- .../tests | 17 --------- .../tests | 13 ------- .github/workflows/hostap-vm.yml | 36 +++++++++---------- scripts/openssl.test | 4 +-- src/internal.c | 1 + 5 files changed, 21 insertions(+), 50 deletions(-) diff --git a/.github/workflows/hostap-files/configs/07c9f183ea744ac04585fb6dd10220c75a5e2e74/tests b/.github/workflows/hostap-files/configs/07c9f183ea744ac04585fb6dd10220c75a5e2e74/tests index 5ebaee3ba5..2ece8719ef 100644 --- a/.github/workflows/hostap-files/configs/07c9f183ea744ac04585fb6dd10220c75a5e2e74/tests +++ b/.github/workflows/hostap-files/configs/07c9f183ea744ac04585fb6dd10220c75a5e2e74/tests @@ -248,9 +248,6 @@ ap_wpa2_eap_tls_check_cert_subject_neg ap_wpa2_eap_tls_diff_ca_trust2 ap_wpa2_eap_tls_domain_mismatch_cn ap_wpa2_eap_tls_domain_suffix_mismatch_cn -ap_wpa2_eap_tls_intermediate_ca_ocsp_multi_missing_resp -ap_wpa2_eap_tls_intermediate_ca_ocsp_revoked_sha1 -ap_wpa2_eap_tls_intermediate_ca_ocsp_sha1 ap_wpa2_eap_tls_neg_incorrect_trust_root ap_wpa2_eap_tls_ocsp_multi ap_wpa2_eap_tls_ocsp_multi_revoked @@ -649,9 +646,6 @@ dpp_config_dpp_gen_secp521r1 dpp_config_dpp_gen_secp521r1_prime256v1 dpp_config_dpp_gen_secp521r1_secp384r1 dpp_config_dpp_gen_secp521r1_secp521r1 -dpp_config_dpp_override_prime256v1 -dpp_config_dpp_override_secp384r1 -dpp_config_dpp_override_secp521r1 dpp_config_error_legacy_invalid_psk dpp_config_error_legacy_no_pass dpp_config_error_legacy_no_pass_for_sae @@ -691,7 +685,6 @@ dpp_config_no_discovery dpp_config_no_discovery_ssid dpp_config_no_signed_connector dpp_config_no_wi_fi_tech -dpp_config_override_objects dpp_config_root_not_an_object dpp_config_save dpp_config_save2 @@ -748,12 +741,6 @@ dpp_hostapd_configurator_enrollee_v1 dpp_hostapd_configurator_fragmentation dpp_hostapd_configurator_override_objects dpp_hostapd_configurator_responder -dpp_hostapd_enrollee_fragmentation -dpp_hostapd_enrollee_gas_errors -dpp_hostapd_enrollee_gas_proto -dpp_hostapd_enrollee_gas_timeout -dpp_hostapd_enrollee_gas_timeout_comeback -dpp_hostapd_enrollee_gas_tx_status_errors dpp_intro_mismatch dpp_invalid_configurator_key dpp_invalid_legacy_params @@ -906,10 +893,6 @@ dpp_qr_code_auth_incompatible_roles2 dpp_qr_code_auth_incompatible_roles_failure dpp_qr_code_auth_incompatible_roles_failure2 dpp_qr_code_auth_incompatible_roles_failure3 -dpp_qr_code_auth_initiator_either_1 -dpp_qr_code_auth_initiator_either_2 -dpp_qr_code_auth_initiator_either_3 -dpp_qr_code_auth_initiator_enrollee dpp_qr_code_auth_mutual dpp_qr_code_auth_mutual2 dpp_qr_code_auth_mutual_bp_256 diff --git a/.github/workflows/hostap-files/configs/b607d2723e927a3446d89aed813f1aa6068186bb/tests b/.github/workflows/hostap-files/configs/b607d2723e927a3446d89aed813f1aa6068186bb/tests index ff99618815..3caefd947a 100644 --- a/.github/workflows/hostap-files/configs/b607d2723e927a3446d89aed813f1aa6068186bb/tests +++ b/.github/workflows/hostap-files/configs/b607d2723e927a3446d89aed813f1aa6068186bb/tests @@ -347,7 +347,6 @@ ap_wpa2_eap_tls_ocsp_server_signed ap_wpa2_eap_tls_ocsp_invalid_data ap_wpa2_eap_tls_ocsp_invalid ap_wpa2_eap_tls_ocsp_unknown_sign -ap_wpa2_eap_tls_intermediate_ca ap_wpa2_eap_tls_ocsp_multi_revoked ap_wpa2_eap_tls_domain_suffix_match_cn_full ap_wpa2_eap_tls_domain_match_cn @@ -461,9 +460,6 @@ dpp_qr_code_auth_mutual_not_used dpp_qr_code_auth_mutual_curve_mismatch dpp_qr_code_auth_hostapd_mutual2 dpp_qr_code_listen_continue -dpp_qr_code_auth_initiator_enrollee -dpp_qr_code_auth_initiator_either_2 -dpp_qr_code_auth_initiator_either_3 dpp_config_legacy dpp_config_legacy_psk_hex dpp_config_fragmentation @@ -475,9 +471,6 @@ dpp_config_dpp_gen_secp521r1 dpp_config_dpp_gen_expiry dpp_config_dpp_gen_expired_key dpp_config_dpp_gen_3rd_party -dpp_config_dpp_override_prime256v1 -dpp_config_dpp_override_secp384r1 -dpp_config_override_objects dpp_config_signed_connector_error_no_dot_1 dpp_config_signed_connector_error_no_dot_2 dpp_config_signed_connector_error_unexpected_signature_len @@ -579,12 +572,6 @@ dpp_pkex_nak_curve_change2 dpp_hostapd_configurator dpp_hostapd_configurator_responder dpp_hostapd_configurator_fragmentation -dpp_hostapd_enrollee_fragmentation -dpp_hostapd_enrollee_gas_timeout -dpp_hostapd_enrollee_gas_timeout_comeback -dpp_hostapd_enrollee_gas_errors -dpp_hostapd_enrollee_gas_proto -dpp_hostapd_enrollee_gas_tx_status_errors dpp_hostapd_configurator_override_objects dpp_own_config dpp_own_config_group_id diff --git a/.github/workflows/hostap-vm.yml b/.github/workflows/hostap-vm.yml index 56052f9ea4..bd2241a89e 100644 --- a/.github/workflows/hostap-vm.yml +++ b/.github/workflows/hostap-vm.yml @@ -2,14 +2,10 @@ name: hostap and wpa-supplicant Tests # START OF COMMON SECTION on: - workflow_dispatch: # Allows people to run it manually if they want but - # disables it from running automatically when broken -# To restore this to an auto test delete the above workflow_dispatch line and -# comments and uncomment the below lines for push and pull_request -# push: -# branches: [ 'master', 'main', 'release/**' ] -# pull_request: -# branches: [ '*' ] + push: + branches: [ 'master', 'main', 'release/**' ] + pull_request: + branches: [ '*' ] concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -232,16 +228,6 @@ jobs: working-directory: hostap run: git checkout ${{ matrix.config.hostap_ref }} - - name: Update certs - working-directory: hostap/tests/hwsim/auth_serv - run: | - ./update.sh - ./sha512-generate.sh - # Force regeneration of rsa3072-ca.key to get rsa3072-generate.sh to - # correctly update all the certs - rm rsa3072-ca.key - ./rsa3072-generate.sh - - if: ${{ matrix.config.osp_ref }} name: Checkout OSP uses: actions/checkout@v4 @@ -259,6 +245,20 @@ jobs: patch -p1 < $f done + - name: Update certs + working-directory: hostap/tests/hwsim/auth_serv + run: | + mkdir -p rootCA/newcerts + ./update.sh + ./ec-generate.sh + ./ec2-generate.sh + ./sha512-generate.sh + # Force regeneration of rsa3072-ca.key to get rsa3072-generate.sh to + # correctly update all the certs + rm rsa3072-ca.key + ./rsa3072-generate.sh + ./ica-generate.sh + - name: Apply extra patches working-directory: hostap run: | diff --git a/scripts/openssl.test b/scripts/openssl.test index b41d4499af..b0a323f679 100755 --- a/scripts/openssl.test +++ b/scripts/openssl.test @@ -263,9 +263,9 @@ start_wolfssl_server() { echo -e "\n# Trying to start $wolfssl_suite wolfSSL server on port $server_port..." echo "#" - echo "# $WOLFSSL_SERVER -p $server_port -g -v d -x -i $psk $crl -l ALL \"$wolfssl_cert\" \"$wolfssl_key\" \"$wolfssl_caCert\"" + echo "# $WOLFSSL_SERVER -p $server_port -g -v d -x -i $psk $crl -l ALL:eNULL \"$wolfssl_cert\" \"$wolfssl_key\" \"$wolfssl_caCert\"" # shellcheck disable=SC2086 - $WOLFSSL_SERVER -p "$server_port" -g -v d -x -i $psk $crl -l ALL "$wolfssl_cert" "$wolfssl_key" "$wolfssl_caCert" & + $WOLFSSL_SERVER -p "$server_port" -g -v d -x -i $psk $crl -l ALL:eNULL "$wolfssl_cert" "$wolfssl_key" "$wolfssl_caCert" & server_pid=$! # wait to see if server successfully starts before continuing sleep 0.1 diff --git a/src/internal.c b/src/internal.c index c0d9680d2c..1acfe41769 100644 --- a/src/internal.c +++ b/src/internal.c @@ -28751,6 +28751,7 @@ static int ParseCipherList(Suites* suites, haveRSA, 1, 1, !haveRSA, 1, haveRSA, !haveRSA, 0, 0, 1, 1, 1, side ); + suites->setSuites = 1; return 1; /* wolfSSL default */ } From 97f1e44721ddc9416678f464e1451e5788c7e681 Mon Sep 17 00:00:00 2001 From: Lealem Amedie Date: Mon, 6 Apr 2026 10:03:17 -0600 Subject: [PATCH 002/167] Add Ed25519/Ed448 cases to oid2nid() oidKeyType switch --- src/ssl.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/ssl.c b/src/ssl.c index 58cd6701c0..ede7863b2f 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -17765,6 +17765,14 @@ word32 nid2oid(int nid, int grp) case WC_NID_X9_62_id_ecPublicKey: return ECDSAk; #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + case WC_NID_ED25519: + return ED25519k; + #endif /* HAVE_ED25519 */ + #ifdef HAVE_ED448 + case WC_NID_ED448: + return ED448k; + #endif /* HAVE_ED448 */ } break; @@ -18145,6 +18153,14 @@ int oid2nid(word32 oid, int grp) case ECDSAk: return WC_NID_X9_62_id_ecPublicKey; #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + case ED25519k: + return WC_NID_ED25519; + #endif /* HAVE_ED25519 */ + #ifdef HAVE_ED448 + case ED448k: + return WC_NID_ED448; + #endif /* HAVE_ED448 */ } break; From 89dac98b95c86599d37709d0934572115ecde46b Mon Sep 17 00:00:00 2001 From: Lealem Amedie Date: Mon, 6 Apr 2026 12:28:28 -0600 Subject: [PATCH 003/167] fix d2iTryAltDhKey short-circuiting the d2i probe chain When wc_DhKeyDecode() rejected the input, d2iTryAltDhKey() returned 0 after freeing the DH object. d2i_evp_pkey_try() treats any value >= 0 as success, so a non-DH input would stop the probe chain at the DH step and never reach the Falcon, Dilithium, Ed25519, or Ed448 probes that follow. d2i_PUBKEY()/d2i_PrivateKey() consequently returned NULL for any key type past DH in the chain. --- wolfcrypt/src/evp_pk.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/wolfcrypt/src/evp_pk.c b/wolfcrypt/src/evp_pk.c index bf0b3cf6af..51fffc6be8 100644 --- a/wolfcrypt/src/evp_pk.c +++ b/wolfcrypt/src/evp_pk.c @@ -404,24 +404,23 @@ static int d2iTryAltDhKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, key = (DhKey*)dhObj->internal; /* Try decoding data as a DH public key. */ if (wc_DhKeyDecode(mem, &keyIdx, key, (word32)memSz) != 0) { - ret = 0; + wolfSSL_DH_free(dhObj); + return WOLFSSL_FATAL_ERROR; } - if (ret == 1) { - /* DH key has data and is external to DH object. */ - elements = ELEMENT_P | ELEMENT_G | ELEMENT_Q | ELEMENT_PUB; - if (priv) { - elements |= ELEMENT_PRV; - } - if (SetDhExternal_ex(dhObj, elements) != WOLFSSL_SUCCESS ) { - ret = 0; - } + /* DH key has data and is external to DH object. */ + elements = ELEMENT_P | ELEMENT_G | ELEMENT_Q | ELEMENT_PUB; + if (priv) { + elements |= ELEMENT_PRV; + } + if (SetDhExternal_ex(dhObj, elements) != WOLFSSL_SUCCESS ) { + ret = 0; } if (ret == 1) { /* Create an EVP PKEY object. */ ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_DH); } if (ret == 1) { - /* Put RSA key object into EVP PKEY object. */ + /* Put DH key object into EVP PKEY object. */ (*out)->ownDh = 1; (*out)->dh = dhObj; } From d385ae9c296999d7c57fb4ce8a6d62672f847e4d Mon Sep 17 00:00:00 2001 From: Lealem Amedie Date: Mon, 6 Apr 2026 12:32:25 -0600 Subject: [PATCH 004/167] add Ed25519 and Ed448 support to the EVP_PKEY layer - Add WC_EVP_PKEY_ED25519 / WC_EVP_PKEY_ED448 type constants and matching EVP_PKEY_ED25519 / EVP_PKEY_ED448 OpenSSL aliases. - Extend WOLFSSL_EVP_PKEY with ed25519/ed448 fields and ownership bits, and free them in wolfSSL_EVP_PKEY_free(). - Add d2i probe functions that accept both SubjectPublicKeyInfo / PKCS#8 PrivateKeyInfo encodings and raw 32/57-byte key material, and hook them into the d2i_evp_pkey_try() chain. - Map the Ed25519/Ed448 signature OIDs in the relevant lookups and teach the PEM key-format dispatch and SSL_CTX_use_PrivateKey switch about the new types. --- src/pk.c | 20 ++++ src/ssl.c | 16 +++ src/ssl_load.c | 12 ++ wolfcrypt/src/evp.c | 26 ++++ wolfcrypt/src/evp_pk.c | 262 ++++++++++++++++++++++++++++++++++++++++- wolfssl/openssl/evp.h | 6 + wolfssl/ssl.h | 12 ++ 7 files changed, 353 insertions(+), 1 deletion(-) diff --git a/src/pk.c b/src/pk.c index 1aaf40d065..4544baaf10 100644 --- a/src/pk.c +++ b/src/pk.c @@ -6262,6 +6262,16 @@ WOLFSSL_EVP_PKEY* wolfSSL_PEM_read_bio_PrivateKey(WOLFSSL_BIO* bio, case DHk: type = WC_EVP_PKEY_DH; break; + #ifdef HAVE_ED25519 + case ED25519k: + type = WC_EVP_PKEY_ED25519; + break; + #endif + #ifdef HAVE_ED448 + case ED448k: + type = WC_EVP_PKEY_ED448; + break; + #endif default: type = WOLFSSL_FATAL_ERROR; break; @@ -6409,6 +6419,16 @@ WOLFSSL_EVP_PKEY* wolfSSL_PEM_read_PrivateKey(XFILE fp, WOLFSSL_EVP_PKEY **key, case DHk: type = WC_EVP_PKEY_DH; break; + #ifdef HAVE_ED25519 + case ED25519k: + type = WC_EVP_PKEY_ED25519; + break; + #endif + #ifdef HAVE_ED448 + case ED448k: + type = WC_EVP_PKEY_ED448; + break; + #endif default: type = WOLFSSL_FATAL_ERROR; break; diff --git a/src/ssl.c b/src/ssl.c index ede7863b2f..47b13a8513 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -17747,6 +17747,14 @@ word32 nid2oid(int nid, int grp) return CTC_SHA3_512wECDSA; #endif #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + case WC_NID_ED25519: + return CTC_ED25519; + #endif /* HAVE_ED25519 */ + #ifdef HAVE_ED448 + case WC_NID_ED448: + return CTC_ED448; + #endif /* HAVE_ED448 */ } break; @@ -18131,6 +18139,14 @@ int oid2nid(word32 oid, int grp) return WC_NID_ecdsa_with_SHA3_512; #endif #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + case CTC_ED25519: + return WC_NID_ED25519; + #endif /* HAVE_ED25519 */ + #ifdef HAVE_ED448 + case CTC_ED448: + return WC_NID_ED448; + #endif /* HAVE_ED448 */ } break; diff --git a/src/ssl_load.c b/src/ssl_load.c index 0a0fb9e467..d77ccb31d6 100644 --- a/src/ssl_load.c +++ b/src/ssl_load.c @@ -5256,6 +5256,18 @@ int wolfSSL_CTX_use_PrivateKey(WOLFSSL_CTX *ctx, WOLFSSL_EVP_PKEY *pkey) WOLFSSL_MSG("populating ECC key"); ret = ECC_populate_EVP_PKEY(pkey, pkey->ecc); break; + #endif + #ifdef HAVE_ED25519 + case WC_EVP_PKEY_ED25519: + /* DER is already stored in pkey->pkey.ptr by d2i_evp_pkey. */ + WOLFSSL_MSG("populating Ed25519 key"); + break; + #endif + #ifdef HAVE_ED448 + case WC_EVP_PKEY_ED448: + /* DER is already stored in pkey->pkey.ptr by d2i_evp_pkey. */ + WOLFSSL_MSG("populating Ed448 key"); + break; #endif default: ret = 0; diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index b802958a9e..f8f0a264b2 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -41,6 +41,12 @@ #include #include #include +#ifdef HAVE_ED25519 +#include +#endif +#ifdef HAVE_ED448 +#include +#endif static const struct s_ent { const enum wc_HashType macType; @@ -11679,6 +11685,26 @@ void wolfSSL_EVP_PKEY_free(WOLFSSL_EVP_PKEY* key) break; #endif /* ! NO_DH ... */ + #ifdef HAVE_ED25519 + case WC_EVP_PKEY_ED25519: + if (key->ed25519 != NULL && key->ownEd25519 == 1) { + wc_ed25519_free(key->ed25519); + XFREE(key->ed25519, key->heap, DYNAMIC_TYPE_ED25519); + key->ed25519 = NULL; + } + break; + #endif /* HAVE_ED25519 */ + + #ifdef HAVE_ED448 + case WC_EVP_PKEY_ED448: + if (key->ed448 != NULL && key->ownEd448 == 1) { + wc_ed448_free(key->ed448); + XFREE(key->ed448, key->heap, DYNAMIC_TYPE_ED448); + key->ed448 = NULL; + } + break; + #endif /* HAVE_ED448 */ + #ifdef HAVE_HKDF case WC_EVP_PKEY_HKDF: XFREE(key->hkdfSalt, NULL, DYNAMIC_TYPE_SALT); diff --git a/wolfcrypt/src/evp_pk.c b/wolfcrypt/src/evp_pk.c index 51fffc6be8..1a2a14729a 100644 --- a/wolfcrypt/src/evp_pk.c +++ b/wolfcrypt/src/evp_pk.c @@ -231,6 +231,157 @@ static int d2iTryEccKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, } #endif /* HAVE_ECC && OPENSSL_EXTRA */ +#ifdef HAVE_ED25519 +/** + * Try to make an Ed25519 EVP PKEY from data. + * + * @param [in, out] out On in, an EVP PKEY or NULL. + * On out, an EVP PKEY or NULL. + * @param [in] mem Memory containing key data. + * @param [in] memSz Size of key data in bytes. + * @param [in] priv 1 means private key, 0 means public key. + * @return 1 on success. + * @return 0 otherwise. + */ +static int d2iTryEd25519Key(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, + long memSz, int priv) +{ + ed25519_key* edKey = NULL; + word32 keyIdx = 0; + int isEdKey; + int ret = 1; + + edKey = (ed25519_key*)XMALLOC(sizeof(ed25519_key), NULL, + DYNAMIC_TYPE_ED25519); + if (edKey == NULL) { + return 0; + } + if (wc_ed25519_init(edKey) != 0) { + XFREE(edKey, NULL, DYNAMIC_TYPE_ED25519); + return 0; + } + + /* Try decoding data as an Ed25519 private/public key. The input may be + * either a DER-encoded SubjectPublicKeyInfo / PKCS#8 PrivateKeyInfo + * (the normal d2i_PUBKEY input) or a raw key (as passed from + * CopyDecodedToX509 where dCert->publicKey is the raw bytes from the + * SPKI BIT STRING). Try the structured form first, then fall back to + * the raw import. */ + if (priv) { + isEdKey = (wc_Ed25519PrivateKeyDecode(mem, &keyIdx, edKey, + (word32)memSz) == 0); + if (!isEdKey && memSz == ED25519_KEY_SIZE) { + keyIdx = (word32)memSz; + isEdKey = (wc_ed25519_import_private_only(mem, (word32)memSz, + edKey) == 0); + } + } + else { + isEdKey = (wc_Ed25519PublicKeyDecode(mem, &keyIdx, edKey, + (word32)memSz) == 0); + if (!isEdKey && memSz == ED25519_PUB_KEY_SIZE) { + keyIdx = (word32)memSz; + isEdKey = (wc_ed25519_import_public(mem, (word32)memSz, edKey) + == 0); + } + } + + if (!isEdKey) { + wc_ed25519_free(edKey); + XFREE(edKey, NULL, DYNAMIC_TYPE_ED25519); + return WOLFSSL_FATAL_ERROR; + } + + /* Create an EVP PKEY object holding the DER bytes. */ + ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_ED25519); + if (ret == 1) { + (*out)->ownEd25519 = 1; + (*out)->ed25519 = edKey; + } + else { + wc_ed25519_free(edKey); + XFREE(edKey, NULL, DYNAMIC_TYPE_ED25519); + } + + return ret; +} +#endif /* HAVE_ED25519 */ + +#ifdef HAVE_ED448 +/** + * Try to make an Ed448 EVP PKEY from data. + * + * @param [in, out] out On in, an EVP PKEY or NULL. + * On out, an EVP PKEY or NULL. + * @param [in] mem Memory containing key data. + * @param [in] memSz Size of key data in bytes. + * @param [in] priv 1 means private key, 0 means public key. + * @return 1 on success. + * @return 0 otherwise. + */ +static int d2iTryEd448Key(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, + long memSz, int priv) +{ + ed448_key* edKey = NULL; + word32 keyIdx = 0; + int isEdKey; + int ret = 1; + + edKey = (ed448_key*)XMALLOC(sizeof(ed448_key), NULL, DYNAMIC_TYPE_ED448); + if (edKey == NULL) { + return 0; + } + if (wc_ed448_init(edKey) != 0) { + XFREE(edKey, NULL, DYNAMIC_TYPE_ED448); + return 0; + } + + /* Try decoding data as an Ed448 private/public key. The input may be + * either a DER-encoded SubjectPublicKeyInfo / PKCS#8 PrivateKeyInfo + * (the normal d2i_PUBKEY input) or a raw key (as passed from + * CopyDecodedToX509 where dCert->publicKey is the raw bytes from the + * SPKI BIT STRING). Try the structured form first, then fall back to + * the raw import. */ + if (priv) { + isEdKey = (wc_Ed448PrivateKeyDecode(mem, &keyIdx, edKey, + (word32)memSz) == 0); + if (!isEdKey && memSz == ED448_KEY_SIZE) { + keyIdx = (word32)memSz; + isEdKey = (wc_ed448_import_private_only(mem, (word32)memSz, + edKey) == 0); + } + } + else { + isEdKey = (wc_Ed448PublicKeyDecode(mem, &keyIdx, edKey, + (word32)memSz) == 0); + if (!isEdKey && memSz == ED448_PUB_KEY_SIZE) { + keyIdx = (word32)memSz; + isEdKey = (wc_ed448_import_public(mem, (word32)memSz, edKey) + == 0); + } + } + + if (!isEdKey) { + wc_ed448_free(edKey); + XFREE(edKey, NULL, DYNAMIC_TYPE_ED448); + return WOLFSSL_FATAL_ERROR; + } + + /* Create an EVP PKEY object holding the DER bytes. */ + ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_ED448); + if (ret == 1) { + (*out)->ownEd448 = 1; + (*out)->ed448 = edKey; + } + else { + wc_ed448_free(edKey); + XFREE(edKey, NULL, DYNAMIC_TYPE_ED448); + } + + return ret; +} +#endif /* HAVE_ED448 */ + #if !defined(NO_DSA) /** * Try to make a DSA EVP PKEY from data. @@ -686,6 +837,18 @@ static WOLFSSL_EVP_PKEY* d2i_evp_pkey_try(WOLFSSL_EVP_PKEY** out, #endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */ #endif /* !NO_DH && OPENSSL_EXTRA && WOLFSSL_DH_EXTRA */ +#ifdef HAVE_ED25519 + if (d2iTryEd25519Key(&pkey, *in, inSz, priv) >= 0) { + ; + } + else +#endif /* HAVE_ED25519 */ +#ifdef HAVE_ED448 + if (d2iTryEd448Key(&pkey, *in, inSz, priv) >= 0) { + ; + } + else +#endif /* HAVE_ED448 */ #ifdef HAVE_FALCON if (d2iTryFalconKey(&pkey, *in, inSz, priv) >= 0) { ; @@ -917,7 +1080,14 @@ static WOLFSSL_EVP_PKEY* d2i_evp_pkey(int type, WOLFSSL_EVP_PKEY** out, ) || (type == WC_EVP_PKEY_EC && algId != ECDSAk) || (type == WC_EVP_PKEY_DSA && algId != DSAk) || - (type == WC_EVP_PKEY_DH && algId != DHk)) { + (type == WC_EVP_PKEY_DH && algId != DHk) + #ifdef HAVE_ED25519 + || (type == WC_EVP_PKEY_ED25519 && algId != ED25519k) + #endif + #ifdef HAVE_ED448 + || (type == WC_EVP_PKEY_ED448 && algId != ED448k) + #endif + ) { WOLFSSL_MSG("PKCS8 does not match EVP key type"); return NULL; } @@ -1022,6 +1192,96 @@ static WOLFSSL_EVP_PKEY* d2i_evp_pkey(int type, WOLFSSL_EVP_PKEY** out, #endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */ #endif /* HAVE_DH */ #endif /* WOLFSSL_QT || OPENSSL_ALL || WOLFSSL_OPENSSH */ +#ifdef HAVE_ED25519 + case WC_EVP_PKEY_ED25519: + { + ed25519_key* edKey; + word32 keyIdx = 0; + int isEdKey; + + edKey = (ed25519_key*)XMALLOC(sizeof(ed25519_key), NULL, + DYNAMIC_TYPE_ED25519); + if (edKey == NULL) { + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + if (wc_ed25519_init(edKey) != 0) { + XFREE(edKey, NULL, DYNAMIC_TYPE_ED25519); + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + if (priv) { + isEdKey = (wc_Ed25519PrivateKeyDecode(p, &keyIdx, edKey, + (word32)local->pkey_sz) == 0); + if (!isEdKey && local->pkey_sz == ED25519_KEY_SIZE) { + isEdKey = (wc_ed25519_import_private_only(p, + (word32)local->pkey_sz, edKey) == 0); + } + } + else { + isEdKey = (wc_Ed25519PublicKeyDecode(p, &keyIdx, edKey, + (word32)local->pkey_sz) == 0); + if (!isEdKey && local->pkey_sz == ED25519_PUB_KEY_SIZE) { + isEdKey = (wc_ed25519_import_public(p, + (word32)local->pkey_sz, edKey) == 0); + } + } + if (!isEdKey) { + wc_ed25519_free(edKey); + XFREE(edKey, NULL, DYNAMIC_TYPE_ED25519); + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + local->ownEd25519 = 1; + local->ed25519 = edKey; + break; + } +#endif /* HAVE_ED25519 */ +#ifdef HAVE_ED448 + case WC_EVP_PKEY_ED448: + { + ed448_key* edKey; + word32 keyIdx = 0; + int isEdKey; + + edKey = (ed448_key*)XMALLOC(sizeof(ed448_key), NULL, + DYNAMIC_TYPE_ED448); + if (edKey == NULL) { + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + if (wc_ed448_init(edKey) != 0) { + XFREE(edKey, NULL, DYNAMIC_TYPE_ED448); + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + if (priv) { + isEdKey = (wc_Ed448PrivateKeyDecode(p, &keyIdx, edKey, + (word32)local->pkey_sz) == 0); + if (!isEdKey && local->pkey_sz == ED448_KEY_SIZE) { + isEdKey = (wc_ed448_import_private_only(p, + (word32)local->pkey_sz, edKey) == 0); + } + } + else { + isEdKey = (wc_Ed448PublicKeyDecode(p, &keyIdx, edKey, + (word32)local->pkey_sz) == 0); + if (!isEdKey && local->pkey_sz == ED448_PUB_KEY_SIZE) { + isEdKey = (wc_ed448_import_public(p, + (word32)local->pkey_sz, edKey) == 0); + } + } + if (!isEdKey) { + wc_ed448_free(edKey); + XFREE(edKey, NULL, DYNAMIC_TYPE_ED448); + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + local->ownEd448 = 1; + local->ed448 = edKey; + break; + } +#endif /* HAVE_ED448 */ default: WOLFSSL_MSG("Unsupported key type"); wolfSSL_EVP_PKEY_free(local); diff --git a/wolfssl/openssl/evp.h b/wolfssl/openssl/evp.h index f4ee44cd00..b8dfcb340c 100644 --- a/wolfssl/openssl/evp.h +++ b/wolfssl/openssl/evp.h @@ -450,6 +450,12 @@ enum { WC_EVP_PKEY_HKDF = WC_NID_hkdf, WC_EVP_PKEY_FALCON = 300, /* Randomly picked value. */ WC_EVP_PKEY_DILITHIUM = 301, /* Randomly picked value. */ +#ifdef HAVE_ED25519 + WC_EVP_PKEY_ED25519 = WC_NID_ED25519, +#endif +#ifdef HAVE_ED448 + WC_EVP_PKEY_ED448 = WC_NID_ED448, +#endif WC_AES_128_CFB1_TYPE = 24, WC_AES_192_CFB1_TYPE = 25, WC_AES_256_CFB1_TYPE = 26, diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index df5e272365..81160a57dc 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -602,6 +602,12 @@ struct WOLFSSL_EVP_PKEY { #ifndef NO_DH WOLFSSL_DH* dh; #endif + #ifdef HAVE_ED25519 + struct ed25519_key* ed25519; + #endif + #ifdef HAVE_ED448 + struct ed448_key* ed448; + #endif WC_RNG rng; #ifdef HAVE_HKDF const WOLFSSL_EVP_MD* hkdfMd; @@ -627,6 +633,12 @@ struct WOLFSSL_EVP_PKEY { WC_BITFIELD ownEcc:1; /* if struct owns ECC and should free it */ WC_BITFIELD ownDsa:1; /* if struct owns DSA and should free it */ WC_BITFIELD ownRsa:1; /* if struct owns RSA and should free it */ +#ifdef HAVE_ED25519 + WC_BITFIELD ownEd25519:1; /* if struct owns Ed25519 and should free it */ +#endif +#ifdef HAVE_ED448 + WC_BITFIELD ownEd448:1; /* if struct owns Ed448 and should free it */ +#endif }; From c01c43448d97be0af6023fc41e9f8f75250342b6 Mon Sep 17 00:00:00 2001 From: Lealem Amedie Date: Mon, 6 Apr 2026 13:05:16 -0600 Subject: [PATCH 005/167] Add testing for the new ED paths in EVP_PKEY layer --- tests/api/test_evp_pkey.c | 132 ++++++++++++++++++++++++++++++++++++++ tests/api/test_evp_pkey.h | 8 ++- wolfssl/openssl/evp.h | 6 ++ 3 files changed, 145 insertions(+), 1 deletion(-) diff --git a/tests/api/test_evp_pkey.c b/tests/api/test_evp_pkey.c index 931f2b3804..81416c5c10 100644 --- a/tests/api/test_evp_pkey.c +++ b/tests/api/test_evp_pkey.c @@ -2357,3 +2357,135 @@ int test_wolfSSL_EVP_PKEY_print_public(void) return EXPECT_RESULT(); } +int test_wolfSSL_EVP_PKEY_ed25519(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && defined(HAVE_ED25519) + WOLFSSL_EVP_PKEY* pkey = NULL; + const unsigned char* p; + + static const unsigned char rawPub[32] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f + }; + + static const unsigned char spkiPub[] = { + 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21, 0x00, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f + }; + + /* Exercise the WC_EVP_PKEY_ED25519 case in d2i_evp_pkey() + * including the algId match for the PKCS#8 wrapper. */ + p = server_ed25519_key; + ExpectNotNull(pkey = wolfSSL_d2i_PrivateKey(EVP_PKEY_ED25519, NULL, + &p, (long)sizeof_server_ed25519_key)); + ExpectIntEQ(wolfSSL_EVP_PKEY_id(pkey), EVP_PKEY_ED25519); + wolfSSL_EVP_PKEY_free(pkey); + pkey = NULL; + + p = spkiPub; + ExpectNotNull(pkey = wolfSSL_d2i_PUBKEY(NULL, &p, (long)sizeof(spkiPub))); + ExpectIntEQ(wolfSSL_EVP_PKEY_id(pkey), EVP_PKEY_ED25519); + wolfSSL_EVP_PKEY_free(pkey); + pkey = NULL; + + /* Exercise d2iTryEd25519Key's raw fallback where the caller passes + * the raw bytes from the SPKI BIT STRING rather than a wrapped SPKI. */ + p = rawPub; + ExpectNotNull(pkey = wolfSSL_d2i_PUBKEY(NULL, &p, (long)sizeof(rawPub))); + ExpectIntEQ(wolfSSL_EVP_PKEY_id(pkey), EVP_PKEY_ED25519); + wolfSSL_EVP_PKEY_free(pkey); + pkey = NULL; + + { + static const unsigned char junk[16] = { 0 }; + const unsigned char* jp = junk; + ExpectNull(wolfSSL_d2i_PUBKEY(NULL, &jp, (long)sizeof(junk))); + } +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_CTX_use_PrivateKey_ed25519(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && defined(HAVE_ED25519) && \ + !defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL_EVP_PKEY* pkey = NULL; + const unsigned char* p; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); + + /* Load the matching Ed25519 server cert */ + ExpectIntEQ(wolfSSL_CTX_use_certificate_buffer(ctx, server_ed25519_cert, + (long)sizeof_server_ed25519_cert, WOLFSSL_FILETYPE_ASN1), + WOLFSSL_SUCCESS); + + /* Decode the Ed25519 private key as a WOLFSSL_EVP_PKEY */ + p = server_ed25519_key; + ExpectNotNull(pkey = wolfSSL_d2i_PrivateKey(EVP_PKEY_ED25519, NULL, + &p, (long)sizeof_server_ed25519_key)); + ExpectIntEQ(wolfSSL_EVP_PKEY_id(pkey), EVP_PKEY_ED25519); + + /* Load the pkey and check for success */ + ExpectIntEQ(wolfSSL_CTX_use_PrivateKey(ctx, pkey), WOLFSSL_SUCCESS); + + wolfSSL_EVP_PKEY_free(pkey); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_EVP_PKEY_ed448(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && defined(HAVE_ED448) + WOLFSSL_EVP_PKEY* pkey = NULL; + const unsigned char* p; + /* 57 arbitrary bytes used as a "raw Ed448 public key". */ + static const unsigned char rawPub[57] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38 + }; + + static const unsigned char spkiPub[] = { + 0x30, 0x43, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x71, 0x03, 0x3a, 0x00, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38 + }; + + /* SPKI path. */ + p = spkiPub; + ExpectNotNull(pkey = wolfSSL_d2i_PUBKEY(NULL, &p, (long)sizeof(spkiPub))); + ExpectIntEQ(wolfSSL_EVP_PKEY_id(pkey), EVP_PKEY_ED448); + wolfSSL_EVP_PKEY_free(pkey); + pkey = NULL; + + /* Raw 57-byte fallback path. */ + p = rawPub; + ExpectNotNull(pkey = wolfSSL_d2i_PUBKEY(NULL, &p, (long)sizeof(rawPub))); + ExpectIntEQ(wolfSSL_EVP_PKEY_id(pkey), EVP_PKEY_ED448); + wolfSSL_EVP_PKEY_free(pkey); + pkey = NULL; +#endif + return EXPECT_RESULT(); +} + diff --git a/tests/api/test_evp_pkey.h b/tests/api/test_evp_pkey.h index e11d5b9c8c..2f60056d3e 100644 --- a/tests/api/test_evp_pkey.h +++ b/tests/api/test_evp_pkey.h @@ -60,6 +60,9 @@ int test_wolfSSL_EVP_MD_ecc_signing(void); int test_wolfSSL_EVP_PKEY_encrypt(void); int test_wolfSSL_EVP_PKEY_derive(void); int test_wolfSSL_EVP_PKEY_print_public(void); +int test_wolfSSL_EVP_PKEY_ed25519(void); +int test_wolfSSL_CTX_use_PrivateKey_ed25519(void); +int test_wolfSSL_EVP_PKEY_ed448(void); #define TEST_EVP_PKEY_DECLS \ TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_PKEY_CTX_new_id), \ @@ -97,6 +100,9 @@ int test_wolfSSL_EVP_PKEY_print_public(void); TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_MD_ecc_signing), \ TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_PKEY_encrypt), \ TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_PKEY_derive), \ - TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_PKEY_print_public) + TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_PKEY_print_public), \ + TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_PKEY_ed25519), \ + TEST_DECL_GROUP("evp_pkey", test_wolfSSL_CTX_use_PrivateKey_ed25519), \ + TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_PKEY_ed448) #endif /* WOLFCRYPT_TEST_EVP_PKEY_H */ diff --git a/wolfssl/openssl/evp.h b/wolfssl/openssl/evp.h index b8dfcb340c..dc41bd11a4 100644 --- a/wolfssl/openssl/evp.h +++ b/wolfssl/openssl/evp.h @@ -523,6 +523,12 @@ enum { #define EVP_PKEY_HKDF WC_EVP_PKEY_HKDF #define EVP_PKEY_FALCON WC_EVP_PKEY_FALCON #define EVP_PKEY_DILITHIUM WC_EVP_PKEY_DILITHIUM +#ifdef HAVE_ED25519 +#define EVP_PKEY_ED25519 WC_EVP_PKEY_ED25519 +#endif +#ifdef HAVE_ED448 +#define EVP_PKEY_ED448 WC_EVP_PKEY_ED448 +#endif #define AES_128_CFB1_TYPE WC_AES_128_CFB1_TYPE #define AES_192_CFB1_TYPE WC_AES_192_CFB1_TYPE #define AES_256_CFB1_TYPE WC_AES_256_CFB1_TYPE From 8e263292ebd34ecaaf8c0d8b816404f3b34beb3c Mon Sep 17 00:00:00 2001 From: Lealem Amedie Date: Mon, 6 Apr 2026 14:03:24 -0600 Subject: [PATCH 006/167] Address Copilot feedback --- tests/api/test_evp_pkey.c | 61 +++++++++++++++++++++++---------------- wolfcrypt/src/evp_pk.c | 60 ++++++++++++++++++++++++-------------- 2 files changed, 74 insertions(+), 47 deletions(-) diff --git a/tests/api/test_evp_pkey.c b/tests/api/test_evp_pkey.c index 81416c5c10..eee753125e 100644 --- a/tests/api/test_evp_pkey.c +++ b/tests/api/test_evp_pkey.c @@ -2364,19 +2364,25 @@ int test_wolfSSL_EVP_PKEY_ed25519(void) WOLFSSL_EVP_PKEY* pkey = NULL; const unsigned char* p; + /* Known-valid Ed25519 public key matching server_ed25519_key. The bytes + * are the raw 32-byte BIT STRING contents from + * ./certs/ed25519/server-ed25519-key.der so the import succeeds even + * under strict point-validation. */ static const unsigned char rawPub[32] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f + 0x23, 0xaa, 0x4d, 0x60, 0x50, 0xe0, 0x13, 0xd3, + 0x3a, 0xed, 0xab, 0xf6, 0xa9, 0xcc, 0x4a, 0xfe, + 0xd7, 0x4d, 0x2f, 0xd2, 0x5b, 0x1a, 0x10, 0x05, + 0xef, 0x5a, 0x41, 0x25, 0xce, 0x1b, 0x53, 0x78 }; + /* SPKI wrapper around the same known-valid public key (the full + * contents of ./certs/ed25519/server-ed25519-key.der). */ static const unsigned char spkiPub[] = { 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21, 0x00, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f + 0x23, 0xaa, 0x4d, 0x60, 0x50, 0xe0, 0x13, 0xd3, + 0x3a, 0xed, 0xab, 0xf6, 0xa9, 0xcc, 0x4a, 0xfe, + 0xd7, 0x4d, 0x2f, 0xd2, 0x5b, 0x1a, 0x10, 0x05, + 0xef, 0x5a, 0x41, 0x25, 0xce, 0x1b, 0x53, 0x78 }; /* Exercise the WC_EVP_PKEY_ED25519 case in d2i_evp_pkey() @@ -2448,28 +2454,33 @@ int test_wolfSSL_EVP_PKEY_ed448(void) #if defined(OPENSSL_EXTRA) && defined(HAVE_ED448) WOLFSSL_EVP_PKEY* pkey = NULL; const unsigned char* p; - /* 57 arbitrary bytes used as a "raw Ed448 public key". */ + + /* Known-valid Ed448 public key: the raw 57-byte BIT STRING contents + * from ./certs/ed448/server-ed448-key.der so the import succeeds even + * under strict point-validation. */ static const unsigned char rawPub[57] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x38 + 0x54, 0x81, 0x39, 0x01, 0xeb, 0x37, 0xd9, 0xa9, + 0x07, 0xcd, 0x01, 0xbc, 0x9d, 0x70, 0x16, 0xc2, + 0x2c, 0x2b, 0x75, 0x5b, 0x63, 0xdb, 0xee, 0x3a, + 0x2d, 0x44, 0x92, 0x46, 0xb4, 0x7b, 0x07, 0x03, + 0x4f, 0xa2, 0xae, 0x86, 0x86, 0xdc, 0x8b, 0x4b, + 0x2c, 0x7f, 0xe8, 0x6b, 0x14, 0x8d, 0x58, 0xdd, + 0x6d, 0xe7, 0x6f, 0x3a, 0x05, 0x95, 0xa8, 0xef, + 0x00 }; + /* SPKI wrapper around the same known-valid public key (the full + * contents of ./certs/ed448/server-ed448-key.der). */ static const unsigned char spkiPub[] = { 0x30, 0x43, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x71, 0x03, 0x3a, 0x00, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x38 + 0x54, 0x81, 0x39, 0x01, 0xeb, 0x37, 0xd9, 0xa9, + 0x07, 0xcd, 0x01, 0xbc, 0x9d, 0x70, 0x16, 0xc2, + 0x2c, 0x2b, 0x75, 0x5b, 0x63, 0xdb, 0xee, 0x3a, + 0x2d, 0x44, 0x92, 0x46, 0xb4, 0x7b, 0x07, 0x03, + 0x4f, 0xa2, 0xae, 0x86, 0x86, 0xdc, 0x8b, 0x4b, + 0x2c, 0x7f, 0xe8, 0x6b, 0x14, 0x8d, 0x58, 0xdd, + 0x6d, 0xe7, 0x6f, 0x3a, 0x05, 0x95, 0xa8, 0xef, + 0x00 }; /* SPKI path. */ diff --git a/wolfcrypt/src/evp_pk.c b/wolfcrypt/src/evp_pk.c index 1a2a14729a..e0dff16cf8 100644 --- a/wolfcrypt/src/evp_pk.c +++ b/wolfcrypt/src/evp_pk.c @@ -241,7 +241,8 @@ static int d2iTryEccKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, * @param [in] memSz Size of key data in bytes. * @param [in] priv 1 means private key, 0 means public key. * @return 1 on success. - * @return 0 otherwise. + * @return 0 on allocation/initialization failure + * @return WOLFSSL_FATAL_ERROR if the input is not an Ed25519 key. */ static int d2iTryEd25519Key(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, long memSz, int priv) @@ -250,14 +251,19 @@ static int d2iTryEd25519Key(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, word32 keyIdx = 0; int isEdKey; int ret = 1; + void* heap = NULL; - edKey = (ed25519_key*)XMALLOC(sizeof(ed25519_key), NULL, + if (*out != NULL) { + heap = (*out)->heap; + } + + edKey = (ed25519_key*)XMALLOC(sizeof(ed25519_key), heap, DYNAMIC_TYPE_ED25519); if (edKey == NULL) { return 0; } - if (wc_ed25519_init(edKey) != 0) { - XFREE(edKey, NULL, DYNAMIC_TYPE_ED25519); + if (wc_ed25519_init_ex(edKey, heap, INVALID_DEVID) != 0) { + XFREE(edKey, heap, DYNAMIC_TYPE_ED25519); return 0; } @@ -288,11 +294,13 @@ static int d2iTryEd25519Key(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, if (!isEdKey) { wc_ed25519_free(edKey); - XFREE(edKey, NULL, DYNAMIC_TYPE_ED25519); + XFREE(edKey, heap, DYNAMIC_TYPE_ED25519); return WOLFSSL_FATAL_ERROR; } - /* Create an EVP PKEY object holding the DER bytes. */ + /* Create an EVP PKEY object holding the input bytes. These are the + * SPKI / PKCS#8 DER on the structured path, or the raw 32-byte key + * on the raw fallback path. */ ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_ED25519); if (ret == 1) { (*out)->ownEd25519 = 1; @@ -300,7 +308,7 @@ static int d2iTryEd25519Key(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, } else { wc_ed25519_free(edKey); - XFREE(edKey, NULL, DYNAMIC_TYPE_ED25519); + XFREE(edKey, heap, DYNAMIC_TYPE_ED25519); } return ret; @@ -317,7 +325,8 @@ static int d2iTryEd25519Key(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, * @param [in] memSz Size of key data in bytes. * @param [in] priv 1 means private key, 0 means public key. * @return 1 on success. - * @return 0 otherwise. + * @return 0 on allocation/initialization failure. + * @return WOLFSSL_FATAL_ERROR if the input is not an Ed448 key. */ static int d2iTryEd448Key(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, long memSz, int priv) @@ -326,13 +335,18 @@ static int d2iTryEd448Key(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, word32 keyIdx = 0; int isEdKey; int ret = 1; + void* heap = NULL; - edKey = (ed448_key*)XMALLOC(sizeof(ed448_key), NULL, DYNAMIC_TYPE_ED448); + if (*out != NULL) { + heap = (*out)->heap; + } + + edKey = (ed448_key*)XMALLOC(sizeof(ed448_key), heap, DYNAMIC_TYPE_ED448); if (edKey == NULL) { return 0; } - if (wc_ed448_init(edKey) != 0) { - XFREE(edKey, NULL, DYNAMIC_TYPE_ED448); + if (wc_ed448_init_ex(edKey, heap, INVALID_DEVID) != 0) { + XFREE(edKey, heap, DYNAMIC_TYPE_ED448); return 0; } @@ -363,11 +377,13 @@ static int d2iTryEd448Key(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, if (!isEdKey) { wc_ed448_free(edKey); - XFREE(edKey, NULL, DYNAMIC_TYPE_ED448); + XFREE(edKey, heap, DYNAMIC_TYPE_ED448); return WOLFSSL_FATAL_ERROR; } - /* Create an EVP PKEY object holding the DER bytes. */ + /* Create an EVP PKEY object holding the input bytes. These are the + * SPKI / PKCS#8 DER on the structured path, or the raw 57-byte key + * on the raw fallback path. */ ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_ED448); if (ret == 1) { (*out)->ownEd448 = 1; @@ -375,7 +391,7 @@ static int d2iTryEd448Key(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, } else { wc_ed448_free(edKey); - XFREE(edKey, NULL, DYNAMIC_TYPE_ED448); + XFREE(edKey, heap, DYNAMIC_TYPE_ED448); } return ret; @@ -1199,14 +1215,14 @@ static WOLFSSL_EVP_PKEY* d2i_evp_pkey(int type, WOLFSSL_EVP_PKEY** out, word32 keyIdx = 0; int isEdKey; - edKey = (ed25519_key*)XMALLOC(sizeof(ed25519_key), NULL, + edKey = (ed25519_key*)XMALLOC(sizeof(ed25519_key), local->heap, DYNAMIC_TYPE_ED25519); if (edKey == NULL) { wolfSSL_EVP_PKEY_free(local); return NULL; } - if (wc_ed25519_init(edKey) != 0) { - XFREE(edKey, NULL, DYNAMIC_TYPE_ED25519); + if (wc_ed25519_init_ex(edKey, local->heap, INVALID_DEVID) != 0) { + XFREE(edKey, local->heap, DYNAMIC_TYPE_ED25519); wolfSSL_EVP_PKEY_free(local); return NULL; } @@ -1228,7 +1244,7 @@ static WOLFSSL_EVP_PKEY* d2i_evp_pkey(int type, WOLFSSL_EVP_PKEY** out, } if (!isEdKey) { wc_ed25519_free(edKey); - XFREE(edKey, NULL, DYNAMIC_TYPE_ED25519); + XFREE(edKey, local->heap, DYNAMIC_TYPE_ED25519); wolfSSL_EVP_PKEY_free(local); return NULL; } @@ -1244,14 +1260,14 @@ static WOLFSSL_EVP_PKEY* d2i_evp_pkey(int type, WOLFSSL_EVP_PKEY** out, word32 keyIdx = 0; int isEdKey; - edKey = (ed448_key*)XMALLOC(sizeof(ed448_key), NULL, + edKey = (ed448_key*)XMALLOC(sizeof(ed448_key), local->heap, DYNAMIC_TYPE_ED448); if (edKey == NULL) { wolfSSL_EVP_PKEY_free(local); return NULL; } - if (wc_ed448_init(edKey) != 0) { - XFREE(edKey, NULL, DYNAMIC_TYPE_ED448); + if (wc_ed448_init_ex(edKey, local->heap, INVALID_DEVID) != 0) { + XFREE(edKey, local->heap, DYNAMIC_TYPE_ED448); wolfSSL_EVP_PKEY_free(local); return NULL; } @@ -1273,7 +1289,7 @@ static WOLFSSL_EVP_PKEY* d2i_evp_pkey(int type, WOLFSSL_EVP_PKEY** out, } if (!isEdKey) { wc_ed448_free(edKey); - XFREE(edKey, NULL, DYNAMIC_TYPE_ED448); + XFREE(edKey, local->heap, DYNAMIC_TYPE_ED448); wolfSSL_EVP_PKEY_free(local); return NULL; } From b9ca065c9586c9c3931c177201bf0f276a29ad56 Mon Sep 17 00:00:00 2001 From: sebastian-carpenter Date: Fri, 27 Mar 2026 10:56:50 -0600 Subject: [PATCH 007/167] increase TLS ECH inner hello lengths to word32 --- src/tls.c | 8 +++++--- src/tls13.c | 4 ++-- wolfssl/internal.h | 4 ++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/tls.c b/src/tls.c index 09e6c92174..4096dc6bfc 100644 --- a/src/tls.c +++ b/src/tls.c @@ -13696,7 +13696,7 @@ static int TLSX_ECH_Write(WOLFSSL_ECH* ech, byte msgType, byte* writeBuf, writeBuf_p += ech->encLen; } /* innerClientHelloLen */ - c16toa(ech->innerClientHelloLen, writeBuf_p); + c16toa((word16)ech->innerClientHelloLen, writeBuf_p); writeBuf_p += 2; /* set payload offset for when we finalize */ ech->outerClientPayload = writeBuf_p; @@ -14155,7 +14155,7 @@ static int TLSX_ECH_ExpandOuterExtensions(WOLFSSL* ssl, WOLFSSL_ECH* ech, if (ret == 0) { XFREE(ech->innerClientHello, heap, DYNAMIC_TYPE_TMP_BUFFER); ech->innerClientHello = newInnerCh; - ech->innerClientHelloLen = (word16)newInnerChLen; + ech->innerClientHelloLen = newInnerChLen; newInnerCh = NULL; } @@ -14269,6 +14269,7 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size, word32 offset = 0; word16 len; word16 tmpVal16; + word16 lenCh; WOLFSSL_MSG("TLSX_ECH_Parse"); if (ssl->options.disableECH) { @@ -14385,7 +14386,8 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size, readBuf_p += len; offset += len; /* read payload (encrypted CH) len */ - ato16(readBuf_p, &ech->innerClientHelloLen); + ato16(readBuf_p, &lenCh); + ech->innerClientHelloLen = lenCh; readBuf_p += 2; offset += 2; /* Check payload is no bigger than remaining bytes. */ diff --git a/src/tls13.c b/src/tls13.c index e46a518f71..2cd0c2b220 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -4759,8 +4759,8 @@ int SendTls13ClientHello(WOLFSSL* ssl) args->ech->type = 0; /* set innerClientHelloLen to ClientHelloInner + padding + tag */ args->ech->paddingLen = 31 - ((args->length - 1) % 32); - args->ech->innerClientHelloLen = (word16)(args->length + - args->ech->paddingLen + args->ech->hpke->Nt); + args->ech->innerClientHelloLen = args->length + + args->ech->paddingLen + args->ech->hpke->Nt; /* set the length back to before we computed ClientHelloInner size */ args->length = (word32)args->preXLength; } diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 5e512f76eb..2cfb968370 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -3131,9 +3131,9 @@ typedef struct WOLFSSL_ECH { byte* outerClientPayload; byte* confBuf; EchCipherSuite cipherSuite; - word16 aadLen; + word32 aadLen; + word32 innerClientHelloLen; word16 paddingLen; - word16 innerClientHelloLen; word16 kemId; word16 encLen; EchState state; From 48a0d410b8c6b9a18981ced8856b23a8c34e91c0 Mon Sep 17 00:00:00 2001 From: sebastian-carpenter Date: Fri, 27 Mar 2026 11:37:28 -0600 Subject: [PATCH 008/167] improve GetMsgHash error checks --- src/tls13.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/tls13.c b/src/tls13.c index 2cd0c2b220..f9d1e66bde 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -3933,10 +3933,14 @@ static int EchCalcAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz, if (isHrr) { /* the transcript hash of ClientHelloInner1 */ - hashSz = GetMsgHash(ssl, clientHelloInnerHash); - if (hashSz > 0) { + ret = GetMsgHash(ssl, clientHelloInnerHash); + if (ret > 0) { + hashSz = ret; ret = 0; } + else if (ret == 0) { + ret = HASH_TYPE_E; + } /* restart ECH transcript hash, similar to RestartHandshakeHash but * don't add a cookie */ @@ -3976,6 +3980,9 @@ static int EchCalcAcceptance(WOLFSSL* ssl, byte* label, word16 labelSz, if (ret > 0) { ret = 0; } + else if (ret == 0) { + ret = HASH_TYPE_E; + } } /* pick the right type and size based on mac_algorithm */ @@ -8648,6 +8655,8 @@ int CreateSigData(WOLFSSL* ssl, byte* sigData, word16* sigDataSz, ret = GetMsgHash(ssl, &sigData[idx]); if (ret < 0) return ret; + if (ret == 0) + return HASH_TYPE_E; *sigDataSz = (word16)(idx + ret); ret = 0; From 690b086edfffcaa74a81f40239a3afa0b100af1e Mon Sep 17 00:00:00 2001 From: sebastian-carpenter Date: Fri, 27 Mar 2026 13:21:56 -0600 Subject: [PATCH 009/167] add null check --- src/tls13.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tls13.c b/src/tls13.c index f9d1e66bde..e892f58de7 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -5701,6 +5701,9 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, /* check for acceptConfirmation */ if (ssl->echConfigs != NULL && !ssl->options.disableECH) { args->echX = TLSX_Find(ssl->extensions, TLSX_ECH); + if (args->echX == NULL || args->echX->data == NULL) + return WOLFSSL_FATAL_ERROR; + /* account for hrr extension instead of server random */ if (args->extMsgType == hello_retry_request) { args->acceptOffset = From cae12b7ffb7475414c7e36779c7cb4e51947a0aa Mon Sep 17 00:00:00 2001 From: sebastian-carpenter Date: Fri, 27 Mar 2026 13:22:28 -0600 Subject: [PATCH 010/167] mirror arg requirements from wc_HpkeContextSealBase --- wolfcrypt/src/hpke.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wolfcrypt/src/hpke.c b/wolfcrypt/src/hpke.c index 8f16f66f70..52f2ad8fd7 100644 --- a/wolfcrypt/src/hpke.c +++ b/wolfcrypt/src/hpke.c @@ -1175,7 +1175,8 @@ int wc_HpkeContextOpenBase(Hpke* hpke, HpkeBaseContext* context, byte* aad, int ret; byte nonce[HPKE_Nn_MAX]; WC_DECLARE_VAR(aes, Aes, 1, 0); - if (hpke == NULL || context == NULL || ciphertext == NULL || out == NULL) { + if (hpke == NULL || context == NULL || (aad == NULL && aadSz > 0) || + ciphertext == NULL || out == NULL) { return BAD_FUNC_ARG; } From c887dc47a3b4606fceb447eae6ccd8bd3359ec68 Mon Sep 17 00:00:00 2001 From: sebastian-carpenter Date: Fri, 27 Mar 2026 13:50:30 -0600 Subject: [PATCH 011/167] fixing bad state for ech->type --- src/tls13.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/tls13.c b/src/tls13.c index e892f58de7..24e47095ff 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -4909,8 +4909,10 @@ int SendTls13ClientHello(WOLFSSL* ssl) args->ech->innerClientHello = (byte*)XMALLOC(args->ech->innerClientHelloLen - args->ech->hpke->Nt, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); - if (args->ech->innerClientHello == NULL) + if (args->ech->innerClientHello == NULL) { + args->ech->type = ECH_TYPE_OUTER; return MEMORY_E; + } /* set the padding bytes to 0 */ XMEMSET(args->ech->innerClientHello + args->ech->innerClientHelloLen - args->ech->hpke->Nt - args->ech->paddingLen, 0, @@ -4933,8 +4935,10 @@ int SendTls13ClientHello(WOLFSSL* ssl) /* change the outer client random */ ret = wc_RNG_GenerateBlock(ssl->rng, args->output + args->clientRandomOffset, RAN_LEN); - if (ret != 0) + if (ret != 0) { + args->ech->type = ECH_TYPE_OUTER; return ret; + } /* copy the new client random */ XMEMCPY(ssl->arrays->clientRandom, args->output + args->clientRandomOffset, RAN_LEN); @@ -4943,10 +4947,10 @@ int SendTls13ClientHello(WOLFSSL* ssl) ret = TLSX_WriteRequest(ssl, args->ech->innerClientHello + args->idx - (RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ), client_hello, &args->length); + /* set the type to outer */ + args->ech->type = ECH_TYPE_OUTER; if (ret != 0) return ret; - /* set the type to outer */ - args->ech->type = 0; } #endif From 38a6d7564104433b4537ce9841571fe8185851eb Mon Sep 17 00:00:00 2001 From: sebastian-carpenter Date: Fri, 27 Mar 2026 14:19:58 -0600 Subject: [PATCH 012/167] faster key length validation when setting configs --- src/ssl_ech.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ssl_ech.c b/src/ssl_ech.c index eb9b9a6a5a..bb456cc456 100644 --- a/src/ssl_ech.c +++ b/src/ssl_ech.c @@ -548,7 +548,8 @@ int SetEchConfigsEx(WOLFSSL_EchConfig** outputConfigs, void* heap, echConfig += 2; /* hpke public_key */ - if (hpkePubkeyLen > HPKE_Npk_MAX || hpkePubkeyLen == 0) { + if (hpkePubkeyLen > HPKE_Npk_MAX || + hpkePubkeyLen != wc_HpkeKemGetEncLen(workingConfig->kemId)) { ret = BUFFER_E; break; } From c8fff0a36cf09f3fb6ae43a72a34e2f5f8302974 Mon Sep 17 00:00:00 2001 From: sebastian-carpenter Date: Mon, 30 Mar 2026 13:36:50 -0600 Subject: [PATCH 013/167] hpke testing - broke api testing into a different function --- wolfcrypt/src/hpke.c | 8 +- wolfcrypt/test/test.c | 345 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 324 insertions(+), 29 deletions(-) diff --git a/wolfcrypt/src/hpke.c b/wolfcrypt/src/hpke.c index 52f2ad8fd7..0c1037325d 100644 --- a/wolfcrypt/src/hpke.c +++ b/wolfcrypt/src/hpke.c @@ -917,7 +917,7 @@ int wc_HpkeInitSealContext(Hpke* hpke, HpkeBaseContext* context, void* ephemeralKey, void* receiverKey, byte* info, word32 infoSz) { if (hpke == NULL || context == NULL || ephemeralKey == NULL || - receiverKey == NULL || (info == NULL && infoSz > 0)) { + receiverKey == NULL || (info == NULL && infoSz != 0)) { return BAD_FUNC_ARG; } @@ -935,7 +935,7 @@ int wc_HpkeContextSealBase(Hpke* hpke, HpkeBaseContext* context, int ret; byte nonce[HPKE_Nn_MAX]; WC_DECLARE_VAR(aes, Aes, 1, 0); - if (hpke == NULL || context == NULL || (aad == NULL && aadSz > 0) || + if (hpke == NULL || context == NULL || (aad == NULL && aadSz != 0) || plaintext == NULL || out == NULL) { return BAD_FUNC_ARG; } @@ -1160,7 +1160,7 @@ int wc_HpkeInitOpenContext(Hpke* hpke, HpkeBaseContext* context, word32 infoSz) { if (hpke == NULL || context == NULL || receiverKey == NULL || pubKey == NULL - || (info == NULL && infoSz > 0)) { + || (info == NULL && infoSz != 0)) { return BAD_FUNC_ARG; } @@ -1175,7 +1175,7 @@ int wc_HpkeContextOpenBase(Hpke* hpke, HpkeBaseContext* context, byte* aad, int ret; byte nonce[HPKE_Nn_MAX]; WC_DECLARE_VAR(aes, Aes, 1, 0); - if (hpke == NULL || context == NULL || (aad == NULL && aadSz > 0) || + if (hpke == NULL || context == NULL || (aad == NULL && aadSz != 0) || ciphertext == NULL || out == NULL) { return BAD_FUNC_ARG; } diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index ff297d7142..03ffadd9a0 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -32177,6 +32177,317 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t x963kdf_test(void) defined(HAVE_CURVE448)) && \ defined(HAVE_AESGCM) +#if defined(HAVE_ECC) && defined(WOLFSSL_AES_128) && \ + (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && !defined(NO_SHA256) +static wc_test_ret_t hpke_test_api(Hpke* hpke) +{ + wc_test_ret_t ret = 0; + int rngRet = 0; + WC_RNG rng[1]; + const char* start_text = "this is a test"; + const char* info_text = "info"; + const char* aad_text = "aad"; + byte ciphertext[MAX_HPKE_LABEL_SZ]; + byte plaintext[MAX_HPKE_LABEL_SZ]; + void* receiverKey = NULL; + void* ephemeralKey = NULL; +#ifdef WOLFSSL_SMALL_STACK + byte *pubKey = NULL; /* public key */ + word16 pubKeySz = (word16)HPKE_Npk_MAX; +#else + byte pubKey[HPKE_Npk_MAX]; /* public key */ + word16 pubKeySz = (word16)sizeof(pubKey); +#endif + + rngRet = ret = wc_InitRng(rng); + + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + +#ifdef WOLFSSL_SMALL_STACK + if (ret == 0) { + pubKey = (byte *)XMALLOC(pubKeySz, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER); + if (pubKey == NULL) + ret = WC_TEST_RET_ENC_EC(MEMORY_E); + } +#endif + + /* Negative test case with NULL argument */ + if (ret == 0) { + ret = wc_HpkeGenerateKeyPair(NULL, &receiverKey, rng); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + if (ret == 0) { + ret = wc_HpkeGenerateKeyPair(hpke, NULL, rng); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + if (ret == 0) { + ret = wc_HpkeGenerateKeyPair(hpke, &receiverKey, NULL); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + + /* generate the keys */ + if (ret == 0) { + ret = wc_HpkeGenerateKeyPair(hpke, &ephemeralKey, rng); + if (ret != 0) + ret = WC_TEST_RET_ENC_EC(ret); + } + + if (ret == 0) { + ret = wc_HpkeGenerateKeyPair(hpke, &receiverKey, rng); + if (ret != 0) + ret = WC_TEST_RET_ENC_EC(ret); + } + + /* Negative test case with NULL argument */ + if (ret == 0) { + ret = wc_HpkeSealBase(NULL, ephemeralKey, receiverKey, + (byte*)info_text, (word32)XSTRLEN(info_text), + (byte*)aad_text, (word32)XSTRLEN(aad_text), + (byte*)start_text, (word32)XSTRLEN(start_text), + ciphertext); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + if (ret == 0) { + ret = wc_HpkeSealBase(hpke, NULL, receiverKey, + (byte*)info_text, (word32)XSTRLEN(info_text), + (byte*)aad_text, (word32)XSTRLEN(aad_text), + (byte*)start_text, (word32)XSTRLEN(start_text), + ciphertext); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + if (ret == 0) { + ret = wc_HpkeSealBase(hpke, ephemeralKey, NULL, + (byte*)info_text, (word32)XSTRLEN(info_text), + (byte*)aad_text, (word32)XSTRLEN(aad_text), + (byte*)start_text, (word32)XSTRLEN(start_text), + ciphertext); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + if (ret == 0) { + ret = wc_HpkeSealBase(hpke, ephemeralKey, receiverKey, + (byte*)NULL, (word32)XSTRLEN(info_text), + (byte*)aad_text, (word32)XSTRLEN(aad_text), + (byte*)start_text, (word32)XSTRLEN(start_text), + ciphertext); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + if (ret == 0) { + ret = wc_HpkeSealBase(hpke, ephemeralKey, receiverKey, + (byte*)info_text, (word32)XSTRLEN(info_text), + (byte*)NULL, (word32)XSTRLEN(aad_text), + (byte*)start_text, (word32)XSTRLEN(start_text), + ciphertext); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + if (ret == 0) { + ret = wc_HpkeSealBase(hpke, ephemeralKey, receiverKey, + (byte*)info_text, (word32)XSTRLEN(info_text), + (byte*)aad_text, (word32)XSTRLEN(aad_text), + (byte*)NULL, (word32)XSTRLEN(start_text), + ciphertext); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + if (ret == 0) { + ret = wc_HpkeSealBase(hpke, ephemeralKey, receiverKey, + (byte*)info_text, (word32)XSTRLEN(info_text), + (byte*)aad_text, (word32)XSTRLEN(aad_text), + (byte*)start_text, (word32)XSTRLEN(start_text), + NULL); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + + /* seal */ + if (ret == 0) { + ret = wc_HpkeSealBase(hpke, ephemeralKey, receiverKey, + (byte*)info_text, (word32)XSTRLEN(info_text), + (byte*)aad_text, (word32)XSTRLEN(aad_text), + (byte*)start_text, (word32)XSTRLEN(start_text), + ciphertext); + if (ret != 0) + ret = WC_TEST_RET_ENC_EC(ret); + } + + /* Negative test case with NULL argument */ + if (ret == 0) { + ret = wc_HpkeSerializePublicKey(NULL, ephemeralKey, pubKey, &pubKeySz); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + if (ret == 0) { + ret = wc_HpkeSerializePublicKey(hpke, NULL, pubKey, &pubKeySz); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + if (ret == 0) { + ret = wc_HpkeSerializePublicKey(hpke, ephemeralKey, NULL, &pubKeySz); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + if (ret == 0) { + ret = wc_HpkeSerializePublicKey(hpke, ephemeralKey, pubKey, NULL); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + + /* export ephemeral key */ + if (ret == 0) { + ret = wc_HpkeSerializePublicKey(hpke, ephemeralKey, pubKey, &pubKeySz); + if (ret != 0) + ret = WC_TEST_RET_ENC_EC(ret); + } + + /* Negative test case with NULL argument */ + if (ret == 0) { + ret = wc_HpkeOpenBase(NULL, receiverKey, pubKey, pubKeySz, + (byte*)info_text, (word32)XSTRLEN(info_text), + (byte*)aad_text, (word32)XSTRLEN(aad_text), + ciphertext, (word32)XSTRLEN(start_text), + plaintext); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + if (ret == 0) { + ret = wc_HpkeOpenBase(hpke, NULL, pubKey, pubKeySz, + (byte*)info_text, (word32)XSTRLEN(info_text), + (byte*)aad_text, (word32)XSTRLEN(aad_text), + ciphertext, (word32)XSTRLEN(start_text), + plaintext); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + if (ret == 0) { + ret = wc_HpkeOpenBase(hpke, receiverKey, NULL, pubKeySz, + (byte*)info_text, (word32)XSTRLEN(info_text), + (byte*)aad_text, (word32)XSTRLEN(aad_text), + ciphertext, (word32)XSTRLEN(start_text), + plaintext); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + if (ret == 0) { + ret = wc_HpkeOpenBase(hpke, receiverKey, pubKey, pubKeySz, + (byte*)NULL, (word32)XSTRLEN(info_text), + (byte*)aad_text, (word32)XSTRLEN(aad_text), + ciphertext, (word32)XSTRLEN(start_text), + plaintext); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + if (ret == 0) { + ret = wc_HpkeOpenBase(hpke, receiverKey, pubKey, pubKeySz, + (byte*)info_text, (word32)XSTRLEN(info_text), + (byte*)NULL, (word32)XSTRLEN(aad_text), + ciphertext, (word32)XSTRLEN(start_text), + plaintext); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + if (ret == 0) { + ret = wc_HpkeOpenBase(hpke, receiverKey, pubKey, pubKeySz, + (byte*)info_text, (word32)XSTRLEN(info_text), + (byte*)aad_text, (word32)XSTRLEN(aad_text), + NULL, (word32)XSTRLEN(start_text), + plaintext); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + if (ret == 0) { + ret = wc_HpkeOpenBase(hpke, receiverKey, pubKey, pubKeySz, + (byte*)info_text, (word32)XSTRLEN(info_text), + (byte*)aad_text, (word32)XSTRLEN(aad_text), + ciphertext, (word32)XSTRLEN(start_text), + NULL); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + + /* open with exported ephemeral key */ + if (ret == 0) { + ret = wc_HpkeOpenBase(hpke, receiverKey, pubKey, pubKeySz, + (byte*)info_text, (word32)XSTRLEN(info_text), + (byte*)aad_text, (word32)XSTRLEN(aad_text), + ciphertext, (word32)XSTRLEN(start_text), + plaintext); + if (ret != 0) + ret = WC_TEST_RET_ENC_EC(ret); + } + + if (ret == 0) { + ret = XMEMCMP(plaintext, start_text, XSTRLEN(start_text)); + if (ret != 0) + ret = WC_TEST_RET_ENC_NC; + } + + if (ephemeralKey != NULL) + wc_HpkeFreeKey(hpke, hpke->kem, ephemeralKey, hpke->heap); + + if (receiverKey != NULL) + wc_HpkeFreeKey(hpke, hpke->kem, receiverKey, hpke->heap); + + WC_FREE_VAR_EX(pubKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + + if (rngRet == 0) + wc_FreeRng(rng); + + return ret; +} +#endif /* HAVE_ECC && WOLFSSL_AES_128 && (!NO_ECC256 || HAVE_ALL_CURVES) && + !NO_SHA256 */ + static wc_test_ret_t hpke_test_single(Hpke* hpke) { wc_test_ret_t ret = 0; @@ -32259,31 +32570,6 @@ static wc_test_ret_t hpke_test_single(Hpke* hpke) ret = WC_TEST_RET_ENC_NC; } - /* Negative test case with NULL argument */ - if (ret == 0) { - ret = wc_HpkeGenerateKeyPair(NULL, &receiverKey, rng); - if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) - ret = WC_TEST_RET_ENC_EC(ret); - else - ret = 0; - } - - if (ret == 0) { - ret = wc_HpkeGenerateKeyPair(hpke, NULL, rng); - if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) - ret = WC_TEST_RET_ENC_EC(ret); - else - ret = 0; - } - - if (ret == 0) { - ret = wc_HpkeGenerateKeyPair(hpke, &receiverKey, NULL); - if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) - ret = WC_TEST_RET_ENC_EC(ret); - else - ret = 0; - } - if (ephemeralKey != NULL) wc_HpkeFreeKey(hpke, hpke->kem, ephemeralKey, hpke->heap); @@ -32406,6 +32692,15 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hpke_test(void) #if defined(HAVE_ECC) && defined(WOLFSSL_AES_128) #if (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && !defined(NO_SHA256) + /* p256 but this will only test the api */ + ret = wc_HpkeInit(hpke, DHKEM_P256_HKDF_SHA256, HKDF_SHA256, + HPKE_AES_128_GCM, NULL); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + ret = hpke_test_api(hpke); + if (ret != 0) + return ret; + /* p256 */ ret = wc_HpkeInit(hpke, DHKEM_P256_HKDF_SHA256, HKDF_SHA256, HPKE_AES_128_GCM, NULL); From b9e1fafc4a4b259a0b29364aeee6ca8ab31cfc7a Mon Sep 17 00:00:00 2001 From: sebastian-carpenter Date: Tue, 7 Apr 2026 11:40:03 -0600 Subject: [PATCH 014/167] key cannot be 0 length --- src/ssl_ech.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ssl_ech.c b/src/ssl_ech.c index bb456cc456..643affbbd0 100644 --- a/src/ssl_ech.c +++ b/src/ssl_ech.c @@ -548,7 +548,7 @@ int SetEchConfigsEx(WOLFSSL_EchConfig** outputConfigs, void* heap, echConfig += 2; /* hpke public_key */ - if (hpkePubkeyLen > HPKE_Npk_MAX || + if (hpkePubkeyLen == 0 || hpkePubkeyLen > HPKE_Npk_MAX || hpkePubkeyLen != wc_HpkeKemGetEncLen(workingConfig->kemId)) { ret = BUFFER_E; break; From 7336ed7cee5e02f7d0cc35c470c200f0f6bdcee7 Mon Sep 17 00:00:00 2001 From: Anthony Hu Date: Tue, 24 Mar 2026 15:12:25 -0400 Subject: [PATCH 015/167] Fixes ZD 19760 Before this fix, the certificates were not getting into the certificate manager. This makes sure they are going in. --- src/ssl_api_cert.c | 8 ++ src/x509_str.c | 63 +++++++++++++ tests/api/test_ossl_x509_str.c | 166 +++++++++++++++++++++++---------- tests/api/test_ossl_x509_str.h | 4 +- wolfssl/internal.h | 1 + 5 files changed, 191 insertions(+), 51 deletions(-) diff --git a/src/ssl_api_cert.c b/src/ssl_api_cert.c index f54edcd8e4..73e598c75a 100644 --- a/src/ssl_api_cert.c +++ b/src/ssl_api_cert.c @@ -1536,6 +1536,14 @@ void wolfSSL_CTX_set_cert_store(WOLFSSL_CTX* ctx, WOLFSSL_X509_STORE* str) ctx->x509_store_pt = str; /* Context has ownership and free it with context free. */ ctx->cm->x509_store_p = ctx->x509_store_pt; + +#ifdef OPENSSL_EXTRA + /* Non-self-signed certs (intermediates) added via + * X509_STORE_add_cert only go into store->certs, not the + * CertManager. Push them into the CM now so that all + * verification paths can find them. */ + X509StorePushCertsToCM(str); +#endif } } diff --git a/src/x509_str.c b/src/x509_str.c index 90113caede..aa74267c4d 100644 --- a/src/x509_str.c +++ b/src/x509_str.c @@ -1598,6 +1598,69 @@ static int X509StoreAddCa(WOLFSSL_X509_STORE* store, return result; } +/* Push certificates from the store's X509 stacks (certs and trusted) into the + * CertManager, then free and NULL the stacks to signal that this store is now + * owned by an SSL_CTX. + * + * This is needed when an X509_STORE is attached to an SSL_CTX via + * SSL_CTX_set_cert_store: self-signed CAs are already in the CM (added by + * X509StoreAddCa during X509_STORE_add_cert), but non-self-signed intermediates + * are only in store->certs and must be explicitly added to the CM so that all + * verification paths (including CertManagerVerify) can find them. */ +WOLFSSL_LOCAL int X509StorePushCertsToCM(WOLFSSL_X509_STORE* store) +{ + int i; + int num; + int ret; + int anyFail = 0; + WOLFSSL_X509* x509; + + WOLFSSL_ENTER("X509StorePushCertsToCM"); + + if (store == NULL || store->cm == NULL) + return WOLFSSL_SUCCESS; + + /* Push non-self-signed intermediates from store->certs into the CM. */ + if (store->certs != NULL) { + num = wolfSSL_sk_X509_num(store->certs); + for (i = 0; i < num; i++) { + x509 = wolfSSL_sk_X509_value(store->certs, i); + if (x509 != NULL) { + ret = X509StoreAddCa(store, x509, WOLFSSL_USER_CA); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("X509StorePushCertsToCM: failed to add cert"); + anyFail = 1; + } + } + } + /* Free and NULL to mark store as CTX-owned. Future add_cert calls + * will go directly to the CertManager. */ + wolfSSL_sk_X509_pop_free(store->certs, NULL); + store->certs = NULL; + } + + /* Push trusted certs too. Self-signed CAs are typically already in the CM + * (added during X509_STORE_add_cert), but AddCA handles duplicates. */ + if (store->trusted != NULL) { + num = wolfSSL_sk_X509_num(store->trusted); + for (i = 0; i < num; i++) { + x509 = wolfSSL_sk_X509_value(store->trusted, i); + if (x509 != NULL) { + ret = X509StoreAddCa(store, x509, WOLFSSL_USER_CA); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("X509StorePushCertsToCM: failed to add " + "trusted cert"); + anyFail = 1; + } + } + } + wolfSSL_sk_X509_pop_free(store->trusted, NULL); + store->trusted = NULL; + } + + return anyFail ? WOLFSSL_FATAL_ERROR : WOLFSSL_SUCCESS; +} + int wolfSSL_X509_STORE_add_cert(WOLFSSL_X509_STORE* store, WOLFSSL_X509* x509) { int result = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR); diff --git a/tests/api/test_ossl_x509_str.c b/tests/api/test_ossl_x509_str.c index 99b82877c3..f9e2dd8318 100644 --- a/tests/api/test_ossl_x509_str.c +++ b/tests/api/test_ossl_x509_str.c @@ -1074,56 +1074,6 @@ int test_X509_STORE_InvalidCa(void) ExpectIntEQ(X509_STORE_CTX_init(ctx, str, cert, untrusted), 1); ExpectIntEQ(X509_verify_cert(ctx), 1); ExpectIntEQ(last_errcode, X509_V_ERR_INVALID_CA); - /* Defense in depth: ctx->error must not be clobbered back to X509_V_OK - * by the later successful verification of the intermediate against the - * trusted root. The worst-seen error must persist. */ - ExpectIntEQ(X509_STORE_CTX_get_error(ctx), X509_V_ERR_INVALID_CA); - - X509_free(cert); - X509_STORE_free(str); - X509_STORE_CTX_free(ctx); - sk_X509_pop_free(untrusted, NULL); -#endif - return EXPECT_RESULT(); -} - -int test_X509_STORE_InvalidCa_NoCallback(void) -{ - EXPECT_DECLS; -#if defined(OPENSSL_ALL) && !defined(NO_RSA) && !defined(NO_FILESYSTEM) - const char* filename = "./certs/intermediate/ca_false_intermediate/" - "test_int_not_cacert.pem"; - const char* srvfile = "./certs/intermediate/ca_false_intermediate/" - "test_sign_bynoca_srv.pem"; - X509_STORE_CTX* ctx = NULL; - X509_STORE* str = NULL; - XFILE fp = XBADFILE; - X509* cert = NULL; - STACK_OF(X509)* untrusted = NULL; - - ExpectTrue((fp = XFOPEN(srvfile, "rb")) - != XBADFILE); - ExpectNotNull(cert = PEM_read_X509(fp, 0, 0, 0 )); - if (fp != XBADFILE) { - XFCLOSE(fp); - fp = XBADFILE; - } - - ExpectNotNull(str = X509_STORE_new()); - ExpectNotNull(ctx = X509_STORE_CTX_new()); - ExpectNotNull(untrusted = sk_X509_new_null()); - - /* Create cert chain stack with an intermediate that is CA:FALSE. */ - ExpectIntEQ(test_X509_STORE_untrusted_load_cert_to_stack(filename, - untrusted), TEST_SUCCESS); - - ExpectIntEQ(X509_STORE_load_locations(str, - "./certs/intermediate/ca_false_intermediate/test_ca.pem", - NULL), 1); - ExpectIntEQ(X509_STORE_CTX_init(ctx, str, cert, untrusted), 1); - /* No verify callback: verification must fail on CA:FALSE issuer. */ - ExpectIntNE(X509_verify_cert(ctx), 1); - ExpectIntEQ(X509_STORE_CTX_get_error(ctx), X509_V_ERR_INVALID_CA); X509_free(cert); X509_STORE_free(str); @@ -1843,3 +1793,119 @@ int test_X509_STORE_No_SSL_CTX(void) #endif return EXPECT_RESULT(); } + +/* Test that SSL_CTX_set_cert_store propagates certificates (including + * non-self-signed intermediates) into the CertManager, and that certs + * added to the store after set_cert_store also reach the CertManager. + * Regression test for ZD 19760 / GitHub PR #8708. + */ +int test_wolfSSL_CTX_set_cert_store(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && !defined(NO_FILESYSTEM) && \ + !defined(NO_WOLFSSL_CLIENT) + SSL_CTX* ctx = NULL; + X509_STORE* store = NULL; + X509* rootCa = NULL; + X509* intCa = NULL; + X509* int2Ca = NULL; + X509_STORE_CTX* storeCtx = NULL; + X509* svrCert = NULL; + + const char caCert[] = "./certs/ca-cert.pem"; + const char intCaCert[] = "./certs/intermediate/ca-int-cert.pem"; + const char int2CaCert[] = "./certs/intermediate/ca-int2-cert.pem"; + const char svrIntCert[] = "./certs/intermediate/server-int-cert.pem"; + + /* --- Part 1: Add certs to store BEFORE set_cert_store --- + * Non-self-signed intermediates should be pushed into the CertManager + * when set_cert_store is called. */ + ExpectNotNull(store = X509_STORE_new()); + ExpectNotNull(rootCa = wolfSSL_X509_load_certificate_file(caCert, + SSL_FILETYPE_PEM)); + ExpectNotNull(intCa = wolfSSL_X509_load_certificate_file(intCaCert, + SSL_FILETYPE_PEM)); + ExpectNotNull(int2Ca = wolfSSL_X509_load_certificate_file(int2CaCert, + SSL_FILETYPE_PEM)); + + ExpectIntEQ(X509_STORE_add_cert(store, rootCa), SSL_SUCCESS); + ExpectIntEQ(X509_STORE_add_cert(store, intCa), SSL_SUCCESS); + ExpectIntEQ(X509_STORE_add_cert(store, int2Ca), SSL_SUCCESS); + + ExpectNotNull(ctx = SSL_CTX_new(TLS_client_method())); + + /* This should push intermediates from store->certs into the CM */ + SSL_CTX_set_cert_store(ctx, store); + + /* After set_cert_store, store->certs and store->trusted should be NULLed + * to signal CTX ownership */ + if (EXPECT_SUCCESS()) { + ExpectNull(store->certs); + ExpectNull(store->trusted); + } + + /* Verify using CertManagerVerify - this only checks the CM, not the + * store's certs stack, so it proves the intermediates were pushed */ + ExpectIntEQ(wolfSSL_CertManagerVerify(wolfSSL_CTX_GetCertManager(ctx), + svrIntCert, SSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + + /* Also verify using X509_verify_cert for completeness */ + ExpectNotNull(svrCert = wolfSSL_X509_load_certificate_file(svrIntCert, + SSL_FILETYPE_PEM)); + ExpectNotNull(storeCtx = X509_STORE_CTX_new()); + if (EXPECT_SUCCESS()) { + ExpectIntEQ(X509_STORE_CTX_init(storeCtx, + SSL_CTX_get_cert_store(ctx), svrCert, NULL), SSL_SUCCESS); + ExpectIntEQ(X509_verify_cert(storeCtx), SSL_SUCCESS); + } + + X509_STORE_CTX_free(storeCtx); + storeCtx = NULL; + X509_free(svrCert); + svrCert = NULL; + SSL_CTX_free(ctx); + ctx = NULL; + /* store is freed by SSL_CTX_free */ + store = NULL; + + X509_free(rootCa); + rootCa = NULL; + X509_free(intCa); + intCa = NULL; + X509_free(int2Ca); + int2Ca = NULL; + + /* --- Part 2: Add certs to store AFTER set_cert_store --- + * When store->certs is NULL (CTX-owned), X509_STORE_add_cert should + * route non-self-signed certs directly to the CertManager. */ + ExpectNotNull(store = X509_STORE_new()); + ExpectNotNull(ctx = SSL_CTX_new(TLS_client_method())); + + /* Attach empty store first */ + SSL_CTX_set_cert_store(ctx, store); + + /* Now add certs after ownership transfer */ + ExpectNotNull(rootCa = wolfSSL_X509_load_certificate_file(caCert, + SSL_FILETYPE_PEM)); + ExpectNotNull(intCa = wolfSSL_X509_load_certificate_file(intCaCert, + SSL_FILETYPE_PEM)); + ExpectNotNull(int2Ca = wolfSSL_X509_load_certificate_file(int2CaCert, + SSL_FILETYPE_PEM)); + + ExpectIntEQ(X509_STORE_add_cert(store, rootCa), SSL_SUCCESS); + ExpectIntEQ(X509_STORE_add_cert(store, intCa), SSL_SUCCESS); + ExpectIntEQ(X509_STORE_add_cert(store, int2Ca), SSL_SUCCESS); + + /* Verify that certs added after set_cert_store are in the CM */ + ExpectIntEQ(wolfSSL_CertManagerVerify(wolfSSL_CTX_GetCertManager(ctx), + svrIntCert, SSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + + SSL_CTX_free(ctx); + /* store freed by SSL_CTX_free */ + X509_free(rootCa); + X509_free(intCa); + X509_free(int2Ca); +#endif + return EXPECT_RESULT(); +} + diff --git a/tests/api/test_ossl_x509_str.h b/tests/api/test_ossl_x509_str.h index 6737046453..a3fe8bfebd 100644 --- a/tests/api/test_ossl_x509_str.h +++ b/tests/api/test_ossl_x509_str.h @@ -42,6 +42,7 @@ int test_wolfSSL_X509_STORE_get1_certs(void); int test_wolfSSL_X509_STORE_set_get_crl(void); int test_wolfSSL_X509_CA_num(void); int test_X509_STORE_No_SSL_CTX(void); +int test_wolfSSL_CTX_set_cert_store(void); #define TEST_OSSL_X509_STORE_DECLS \ TEST_DECL_GROUP("ossl_x509_store", test_wolfSSL_X509_STORE_CTX_set_time), \ @@ -65,6 +66,7 @@ int test_X509_STORE_No_SSL_CTX(void); TEST_DECL_GROUP("ossl_x509_store", test_wolfSSL_X509_STORE_get1_certs), \ TEST_DECL_GROUP("ossl_x509_store", test_wolfSSL_X509_STORE_set_get_crl), \ TEST_DECL_GROUP("ossl_x509_store", test_wolfSSL_X509_CA_num), \ - TEST_DECL_GROUP("ossl_x509_store", test_X509_STORE_No_SSL_CTX) + TEST_DECL_GROUP("ossl_x509_store", test_X509_STORE_No_SSL_CTX), \ + TEST_DECL_GROUP("ossl_x509_store", test_wolfSSL_CTX_set_cert_store) #endif /* WOLFCRYPT_TEST_OSSL_X509_STR_H */ diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 5e512f76eb..ae13cdb552 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -2730,6 +2730,7 @@ WOLFSSL_LOCAL void CleanupStoreCtxCallback(WOLFSSL_X509_STORE_CTX* store, #endif /* !defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH) */ WOLFSSL_LOCAL int X509StoreLoadCertBuffer(WOLFSSL_X509_STORE *str, byte *buf, word32 bufLen, int type); +WOLFSSL_LOCAL int X509StorePushCertsToCM(WOLFSSL_X509_STORE* store); #endif /* !defined NO_CERTS */ /* wolfSSL Sock Addr */ From ce226a8ad7fc974c8c05a9c76f9c453ed179b855 Mon Sep 17 00:00:00 2001 From: Anthony Hu Date: Fri, 10 Apr 2026 12:15:04 -0400 Subject: [PATCH 016/167] Fix bad merge in tests --- tests/api/test_ossl_x509_str.c | 50 ++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/tests/api/test_ossl_x509_str.c b/tests/api/test_ossl_x509_str.c index f9e2dd8318..6beaa37d1e 100644 --- a/tests/api/test_ossl_x509_str.c +++ b/tests/api/test_ossl_x509_str.c @@ -1074,6 +1074,56 @@ int test_X509_STORE_InvalidCa(void) ExpectIntEQ(X509_STORE_CTX_init(ctx, str, cert, untrusted), 1); ExpectIntEQ(X509_verify_cert(ctx), 1); ExpectIntEQ(last_errcode, X509_V_ERR_INVALID_CA); + /* Defense in depth: ctx->error must not be clobbered back to X509_V_OK + * by the later successful verification of the intermediate against the + * trusted root. The worst-seen error must persist. */ + ExpectIntEQ(X509_STORE_CTX_get_error(ctx), X509_V_ERR_INVALID_CA); + + X509_free(cert); + X509_STORE_free(str); + X509_STORE_CTX_free(ctx); + sk_X509_pop_free(untrusted, NULL); +#endif + return EXPECT_RESULT(); +} + +int test_X509_STORE_InvalidCa_NoCallback(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_ALL) && !defined(NO_RSA) && !defined(NO_FILESYSTEM) + const char* filename = "./certs/intermediate/ca_false_intermediate/" + "test_int_not_cacert.pem"; + const char* srvfile = "./certs/intermediate/ca_false_intermediate/" + "test_sign_bynoca_srv.pem"; + X509_STORE_CTX* ctx = NULL; + X509_STORE* str = NULL; + XFILE fp = XBADFILE; + X509* cert = NULL; + STACK_OF(X509)* untrusted = NULL; + + ExpectTrue((fp = XFOPEN(srvfile, "rb")) + != XBADFILE); + ExpectNotNull(cert = PEM_read_X509(fp, 0, 0, 0 )); + if (fp != XBADFILE) { + XFCLOSE(fp); + fp = XBADFILE; + } + + ExpectNotNull(str = X509_STORE_new()); + ExpectNotNull(ctx = X509_STORE_CTX_new()); + ExpectNotNull(untrusted = sk_X509_new_null()); + + /* Create cert chain stack with an intermediate that is CA:FALSE. */ + ExpectIntEQ(test_X509_STORE_untrusted_load_cert_to_stack(filename, + untrusted), TEST_SUCCESS); + + ExpectIntEQ(X509_STORE_load_locations(str, + "./certs/intermediate/ca_false_intermediate/test_ca.pem", + NULL), 1); + ExpectIntEQ(X509_STORE_CTX_init(ctx, str, cert, untrusted), 1); + /* No verify callback: verification must fail on CA:FALSE issuer. */ + ExpectIntNE(X509_verify_cert(ctx), 1); + ExpectIntEQ(X509_STORE_CTX_get_error(ctx), X509_V_ERR_INVALID_CA); X509_free(cert); X509_STORE_free(str); From e69639c4b25ae5862634f5793944f1a81e4df74a Mon Sep 17 00:00:00 2001 From: sebastian-carpenter Date: Fri, 10 Apr 2026 14:31:14 -0600 Subject: [PATCH 017/167] small fixes: test for overflow more consistency in setting ech->type simpler hpke check when parsing ech config --- src/ssl_ech.c | 6 +++--- src/tls13.c | 9 +++++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/ssl_ech.c b/src/ssl_ech.c index 643affbbd0..1f864bc15b 100644 --- a/src/ssl_ech.c +++ b/src/ssl_ech.c @@ -547,9 +547,9 @@ int SetEchConfigsEx(WOLFSSL_EchConfig** outputConfigs, void* heap, ato16(echConfig, &hpkePubkeyLen); echConfig += 2; - /* hpke public_key */ - if (hpkePubkeyLen == 0 || hpkePubkeyLen > HPKE_Npk_MAX || - hpkePubkeyLen != wc_HpkeKemGetEncLen(workingConfig->kemId)) { + /* hpke public_key + * KEM support will be checked along with the ciphersuites */ + if (hpkePubkeyLen != wc_HpkeKemGetEncLen(workingConfig->kemId)) { ret = BUFFER_E; break; } diff --git a/src/tls13.c b/src/tls13.c index 24e47095ff..aa38a4fe5d 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -3801,6 +3801,7 @@ int EchConfigGetSupportedCipherSuite(WOLFSSL_EchConfig* config) int i = 0; if (!wc_HpkeKemIsSupported(config->kemId)) { + WOLFSSL_MSG("ECH config: KEM not supported"); return WOLFSSL_FATAL_ERROR; } @@ -3811,6 +3812,7 @@ int EchConfigGetSupportedCipherSuite(WOLFSSL_EchConfig* config) } } + WOLFSSL_MSG("ECH config: KDF or AEAD not supported"); return WOLFSSL_FATAL_ERROR; } @@ -4759,15 +4761,18 @@ int SendTls13ClientHello(WOLFSSL* ssl) /* get size for inner */ ret = TLSX_GetRequestSize(ssl, client_hello, &args->length); + + /* set the type to outer */ + args->ech->type = ECH_TYPE_OUTER; if (ret != 0) return ret; - /* set the type to outer */ - args->ech->type = 0; /* set innerClientHelloLen to ClientHelloInner + padding + tag */ args->ech->paddingLen = 31 - ((args->length - 1) % 32); args->ech->innerClientHelloLen = args->length + args->ech->paddingLen + args->ech->hpke->Nt; + if (args->ech->innerClientHelloLen > 0xFFFF) + return BUFFER_E; /* set the length back to before we computed ClientHelloInner size */ args->length = (word32)args->preXLength; } From ed0220107d5dae94d6b8958a6f438913b48f20a7 Mon Sep 17 00:00:00 2001 From: sebastian-carpenter Date: Fri, 10 Apr 2026 14:42:03 -0600 Subject: [PATCH 018/167] hpke testing: negative testing for hpke api's rejection tests for hpke --- wolfcrypt/test/test.c | 604 ++++++++++++++++++++++++++++++------------ 1 file changed, 441 insertions(+), 163 deletions(-) diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 03ffadd9a0..0a275b2849 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -32177,20 +32177,24 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t x963kdf_test(void) defined(HAVE_CURVE448)) && \ defined(HAVE_AESGCM) -#if defined(HAVE_ECC) && defined(WOLFSSL_AES_128) && \ - (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && !defined(NO_SHA256) -static wc_test_ret_t hpke_test_api(Hpke* hpke) +/* test null/bad arguments for wc_HpkeInit, a one-shot seal/open round-trip + * with wc_HpkeSealBase/wc_HpkeOpenBase, and auth failure cases (wrong info, + * wrong AAD, tampered ciphertext, wrong receiver key) */ +static wc_test_ret_t hpke_test_single(Hpke* hpke, int kem, int kdf, int aead) { wc_test_ret_t ret = 0; int rngRet = 0; WC_RNG rng[1]; const char* start_text = "this is a test"; const char* info_text = "info"; + const char* alt_info_text = "different info"; const char* aad_text = "aad"; + const char* alt_aad_text = "different aad"; byte ciphertext[MAX_HPKE_LABEL_SZ]; byte plaintext[MAX_HPKE_LABEL_SZ]; void* receiverKey = NULL; void* ephemeralKey = NULL; + void* wrongKey = NULL; #ifdef WOLFSSL_SMALL_STACK byte *pubKey = NULL; /* public key */ word16 pubKeySz = (word16)HPKE_Npk_MAX; @@ -32199,15 +32203,34 @@ static wc_test_ret_t hpke_test_api(Hpke* hpke) word16 pubKeySz = (word16)sizeof(pubKey); #endif - rngRet = ret = wc_InitRng(rng); + /* NULL hpke */ + ret = wc_HpkeInit(NULL, kem, kdf, aead, NULL); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + return WC_TEST_RET_ENC_EC(ret); + /* bad kem */ + ret = wc_HpkeInit(hpke, 0, kdf, aead, NULL); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + return WC_TEST_RET_ENC_EC(ret); + /* bad kdf */ + ret = wc_HpkeInit(hpke, kem, 0, aead, NULL); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + return WC_TEST_RET_ENC_EC(ret); + /* bad aead */ + ret = wc_HpkeInit(hpke, kem, kdf, 0, NULL); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + return WC_TEST_RET_ENC_EC(ret); + /* valid init */ + ret = wc_HpkeInit(hpke, kem, kdf, aead, NULL); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + rngRet = ret = wc_InitRng(rng); if (ret != 0) return WC_TEST_RET_ENC_EC(ret); #ifdef WOLFSSL_SMALL_STACK if (ret == 0) { - pubKey = (byte *)XMALLOC(pubKeySz, HEAP_HINT, - DYNAMIC_TYPE_TMP_BUFFER); + pubKey = (byte *)XMALLOC(pubKeySz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); if (pubKey == NULL) ret = WC_TEST_RET_ENC_EC(MEMORY_E); } @@ -32410,6 +32433,17 @@ static wc_test_ret_t hpke_test_api(Hpke* hpke) else ret = 0; } + if (ret == 0) { + ret = wc_HpkeOpenBase(hpke, receiverKey, pubKey, 0, + (byte*)info_text, (word32)XSTRLEN(info_text), + (byte*)aad_text, (word32)XSTRLEN(aad_text), + ciphertext, (word32)XSTRLEN(start_text), + plaintext); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } if (ret == 0) { ret = wc_HpkeOpenBase(hpke, receiverKey, pubKey, pubKeySz, (byte*)NULL, (word32)XSTRLEN(info_text), @@ -32455,102 +32489,57 @@ static wc_test_ret_t hpke_test_api(Hpke* hpke) ret = 0; } - /* open with exported ephemeral key */ + /* wrong info */ + if (ret == 0) { + ret = wc_HpkeOpenBase(hpke, receiverKey, pubKey, pubKeySz, + (byte*)alt_info_text, (word32)XSTRLEN(alt_info_text), + (byte*)aad_text, (word32)XSTRLEN(aad_text), + ciphertext, (word32)XSTRLEN(start_text), plaintext); + if (ret == 0) + ret = WC_TEST_RET_ENC_NC; + else + ret = 0; + } + /* wrong AAD */ if (ret == 0) { ret = wc_HpkeOpenBase(hpke, receiverKey, pubKey, pubKeySz, (byte*)info_text, (word32)XSTRLEN(info_text), - (byte*)aad_text, (word32)XSTRLEN(aad_text), - ciphertext, (word32)XSTRLEN(start_text), - plaintext); - if (ret != 0) - ret = WC_TEST_RET_ENC_EC(ret); - } - - if (ret == 0) { - ret = XMEMCMP(plaintext, start_text, XSTRLEN(start_text)); - if (ret != 0) + (byte*)alt_aad_text, (word32)XSTRLEN(alt_aad_text), + ciphertext, (word32)XSTRLEN(start_text), plaintext); + if (ret == 0) ret = WC_TEST_RET_ENC_NC; + else + ret = 0; } - - if (ephemeralKey != NULL) - wc_HpkeFreeKey(hpke, hpke->kem, ephemeralKey, hpke->heap); - - if (receiverKey != NULL) - wc_HpkeFreeKey(hpke, hpke->kem, receiverKey, hpke->heap); - - WC_FREE_VAR_EX(pubKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - - if (rngRet == 0) - wc_FreeRng(rng); - - return ret; -} -#endif /* HAVE_ECC && WOLFSSL_AES_128 && (!NO_ECC256 || HAVE_ALL_CURVES) && - !NO_SHA256 */ - -static wc_test_ret_t hpke_test_single(Hpke* hpke) -{ - wc_test_ret_t ret = 0; - int rngRet = 0; - WC_RNG rng[1]; - const char* start_text = "this is a test"; - const char* info_text = "info"; - const char* aad_text = "aad"; - byte ciphertext[MAX_HPKE_LABEL_SZ]; - byte plaintext[MAX_HPKE_LABEL_SZ]; - void* receiverKey = NULL; - void* ephemeralKey = NULL; -#ifdef WOLFSSL_SMALL_STACK - byte *pubKey = NULL; /* public key */ - word16 pubKeySz = (word16)HPKE_Npk_MAX; -#else - byte pubKey[HPKE_Npk_MAX]; /* public key */ - word16 pubKeySz = (word16)sizeof(pubKey); -#endif - - rngRet = ret = wc_InitRng(rng); - - if (ret != 0) - return WC_TEST_RET_ENC_EC(ret); - -#ifdef WOLFSSL_SMALL_STACK + /* tampered ciphertext */ if (ret == 0) { - pubKey = (byte *)XMALLOC(pubKeySz, HEAP_HINT, - DYNAMIC_TYPE_TMP_BUFFER); - if (pubKey == NULL) - ret = WC_TEST_RET_ENC_EC(MEMORY_E); - } -#endif - - /* generate the keys */ - if (ret == 0) { - ret = wc_HpkeGenerateKeyPair(hpke, &ephemeralKey, rng); - if (ret != 0) - ret = WC_TEST_RET_ENC_EC(ret); - } - - if (ret == 0) { - ret = wc_HpkeGenerateKeyPair(hpke, &receiverKey, rng); - if (ret != 0) - ret = WC_TEST_RET_ENC_EC(ret); - } - - /* seal */ - if (ret == 0) { - ret = wc_HpkeSealBase(hpke, ephemeralKey, receiverKey, + ciphertext[0] ^= 0xFF; + ret = wc_HpkeOpenBase(hpke, receiverKey, pubKey, pubKeySz, (byte*)info_text, (word32)XSTRLEN(info_text), (byte*)aad_text, (word32)XSTRLEN(aad_text), - (byte*)start_text, (word32)XSTRLEN(start_text), - ciphertext); - if (ret != 0) - ret = WC_TEST_RET_ENC_EC(ret); + ciphertext, (word32)XSTRLEN(start_text), plaintext); + ciphertext[0] ^= 0xFF; + if (ret == 0) + ret = WC_TEST_RET_ENC_NC; + else + ret = 0; } - - /* export ephemeral key */ + /* wrong receiver key */ + if (ret == 0) + ret = wc_HpkeGenerateKeyPair(hpke, &wrongKey, rng); if (ret == 0) { - ret = wc_HpkeSerializePublicKey(hpke, ephemeralKey, pubKey, &pubKeySz); - if (ret != 0) - ret = WC_TEST_RET_ENC_EC(ret); + ret = wc_HpkeOpenBase(hpke, wrongKey, pubKey, pubKeySz, + (byte*)info_text, (word32)XSTRLEN(info_text), + (byte*)aad_text, (word32)XSTRLEN(aad_text), + ciphertext, (word32)XSTRLEN(start_text), plaintext); + if (ret == 0) + ret = WC_TEST_RET_ENC_NC; + else + ret = 0; + } + if (wrongKey != NULL) { + wc_HpkeFreeKey(hpke, hpke->kem, wrongKey, hpke->heap); + wrongKey = NULL; } /* open with exported ephemeral key */ @@ -32572,7 +32561,6 @@ static wc_test_ret_t hpke_test_single(Hpke* hpke) if (ephemeralKey != NULL) wc_HpkeFreeKey(hpke, hpke->kem, ephemeralKey, hpke->heap); - if (receiverKey != NULL) wc_HpkeFreeKey(hpke, hpke->kem, receiverKey, hpke->heap); @@ -32584,6 +32572,10 @@ static wc_test_ret_t hpke_test_single(Hpke* hpke) return ret; } +/* test null/bad arguments for the context-based HPKE API + * (wc_HpkeInitSealContext, wc_HpkeContextSealBase, wc_HpkeInitOpenContext, + * wc_HpkeContextOpenBase) and wc_HpkeDeserializePublicKey, a two-message + * seal/open round-trip, out-of-order open rejection, and seq overflow */ static wc_test_ret_t hpke_test_multi(Hpke* hpke) { wc_test_ret_t ret = 0; @@ -32596,91 +32588,411 @@ static wc_test_ret_t hpke_test_multi(Hpke* hpke) byte plaintext[MAX_HPKE_LABEL_SZ]; void* receiverKey = NULL; void* ephemeralKey = NULL; + void* deserializedKey = NULL; #ifdef WOLFSSL_SMALL_STACK HpkeBaseContext* context = NULL; - byte *pubKey = NULL; /* public key */ + byte* pubKey = NULL; word16 pubKeySz = (word16)HPKE_Npk_MAX; #else HpkeBaseContext context[1]; - byte pubKey[HPKE_Npk_MAX]; /* public key */ + byte pubKey[HPKE_Npk_MAX]; word16 pubKeySz = (word16)sizeof(pubKey); #endif + rngRet = ret = wc_InitRng(rng); if (ret != 0) - return ret; + return WC_TEST_RET_ENC_EC(ret); + #ifdef WOLFSSL_SMALL_STACK - pubKey = (byte *)XMALLOC(pubKeySz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + pubKey = (byte*)XMALLOC(pubKeySz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); if (pubKey == NULL) ret = MEMORY_E; - if (ret == 0) { + if (ret == 0) context = (HpkeBaseContext*)XMALLOC(sizeof(HpkeBaseContext), HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - } if (context == NULL) ret = MEMORY_E; #endif + /* generate the keys */ if (ret == 0) ret = wc_HpkeGenerateKeyPair(hpke, &ephemeralKey, rng); if (ret == 0) ret = wc_HpkeGenerateKeyPair(hpke, &receiverKey, rng); - /* setup seal context */ + + /* Negative test case with NULL argument */ + if (ret == 0) { + ret = wc_HpkeInitSealContext(NULL, context, ephemeralKey, receiverKey, + (byte*)info_text, (word32)XSTRLEN(info_text)); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + if (ret == 0) { + ret = wc_HpkeInitSealContext(hpke, NULL, ephemeralKey, receiverKey, + (byte*)info_text, (word32)XSTRLEN(info_text)); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + if (ret == 0) { + ret = wc_HpkeInitSealContext(hpke, context, NULL, receiverKey, + (byte*)info_text, (word32)XSTRLEN(info_text)); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + if (ret == 0) { + ret = wc_HpkeInitSealContext(hpke, context, ephemeralKey, NULL, + (byte*)info_text, (word32)XSTRLEN(info_text)); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + /* NULL info with non-zero infoSz */ + if (ret == 0) { + ret = wc_HpkeInitSealContext(hpke, context, ephemeralKey, receiverKey, + NULL, (word32)XSTRLEN(info_text)); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + /* infoSz too large to fit in labeled_ikm scratch buffer */ + if (ret == 0) { + /* prefer ciphertexts[0] to info_text for this test since static + * analysis may throw an error */ + ret = wc_HpkeInitSealContext(hpke, context, ephemeralKey, receiverKey, + ciphertexts[0], MAX_HPKE_LABEL_SZ); + if (ret != WC_NO_ERR_TRACE(BUFFER_E)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + + /* initialize a valid seal context for ContextSealBase tests */ if (ret == 0) { ret = wc_HpkeInitSealContext(hpke, context, ephemeralKey, receiverKey, (byte*)info_text, (word32)XSTRLEN(info_text)); + if (ret != 0) + ret = WC_TEST_RET_ENC_EC(ret); } + + /* Negative test case with NULL argument */ + if (ret == 0) { + ret = wc_HpkeContextSealBase(NULL, context, + (byte*)aad_text, (word32)XSTRLEN(aad_text), + (byte*)start_text, (word32)XSTRLEN(start_text), ciphertexts[0]); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + if (ret == 0) { + ret = wc_HpkeContextSealBase(hpke, NULL, + (byte*)aad_text, (word32)XSTRLEN(aad_text), + (byte*)start_text, (word32)XSTRLEN(start_text), ciphertexts[0]); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + /* NULL aad with non-zero aadSz */ + if (ret == 0) { + ret = wc_HpkeContextSealBase(hpke, context, + NULL, (word32)XSTRLEN(aad_text), + (byte*)start_text, (word32)XSTRLEN(start_text), ciphertexts[0]); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + if (ret == 0) { + ret = wc_HpkeContextSealBase(hpke, context, + (byte*)aad_text, (word32)XSTRLEN(aad_text), + NULL, (word32)XSTRLEN(start_text), ciphertexts[0]); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + if (ret == 0) { + ret = wc_HpkeContextSealBase(hpke, context, + (byte*)aad_text, (word32)XSTRLEN(aad_text), + (byte*)start_text, (word32)XSTRLEN(start_text), NULL); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + /* seal message 0 */ if (ret == 0) { ret = wc_HpkeContextSealBase(hpke, context, (byte*)aad_text, (word32)XSTRLEN(aad_text), - (byte*)start_text, (word32)XSTRLEN(start_text), - ciphertexts[context->seq]); + (byte*)start_text, (word32)XSTRLEN(start_text), ciphertexts[0]); + if (ret != 0) + ret = WC_TEST_RET_ENC_EC(ret); } /* seal message 1 */ if (ret == 0) { ret = wc_HpkeContextSealBase(hpke, context, (byte*)aad_text, (word32)XSTRLEN(aad_text), - (byte*)start_text, (word32)XSTRLEN(start_text), - ciphertexts[context->seq]); + (byte*)start_text, (word32)XSTRLEN(start_text), ciphertexts[1]); + if (ret != 0) + ret = WC_TEST_RET_ENC_EC(ret); } - /* export ephemeral key */ - if (ret == 0) + + /* Negative test case with NULL argument */ + if (ret == 0) { ret = wc_HpkeSerializePublicKey(hpke, ephemeralKey, pubKey, &pubKeySz); - /* setup open context */ + if (ret != 0) + ret = WC_TEST_RET_ENC_EC(ret); + } + if (ret == 0) { + ret = wc_HpkeDeserializePublicKey(NULL, &deserializedKey, pubKey, + pubKeySz); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + if (ret == 0) { + ret = wc_HpkeDeserializePublicKey(hpke, NULL, pubKey, pubKeySz); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + if (ret == 0) { + ret = wc_HpkeDeserializePublicKey(hpke, &deserializedKey, NULL, + pubKeySz); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + /* inSz = 0 is less than Npk → BUFFER_E */ + if (ret == 0) { + ret = wc_HpkeDeserializePublicKey(hpke, &deserializedKey, pubKey, 0); + if (ret != WC_NO_ERR_TRACE(BUFFER_E)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + /* deserialize result must re-serialize identically */ + if (ret == 0) { + ret = wc_HpkeDeserializePublicKey(hpke, &deserializedKey, pubKey, + pubKeySz); + if (ret != 0) + ret = WC_TEST_RET_ENC_EC(ret); + } + if (ret == 0) { + word16 reSz = (word16)sizeof(plaintext); + ret = wc_HpkeSerializePublicKey(hpke, deserializedKey, + plaintext, &reSz); + if (ret != 0) + ret = WC_TEST_RET_ENC_EC(ret); + else if (reSz != pubKeySz || XMEMCMP(plaintext, pubKey, pubKeySz) != 0) + ret = WC_TEST_RET_ENC_NC; + } + if (deserializedKey != NULL) { + wc_HpkeFreeKey(hpke, hpke->kem, deserializedKey, hpke->heap); + deserializedKey = NULL; + } + + /* Negative test case with NULL argument */ + if (ret == 0) { + ret = wc_HpkeInitOpenContext(NULL, context, receiverKey, pubKey, + pubKeySz, (byte*)info_text, (word32)XSTRLEN(info_text)); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + if (ret == 0) { + ret = wc_HpkeInitOpenContext(hpke, NULL, receiverKey, pubKey, + pubKeySz, (byte*)info_text, (word32)XSTRLEN(info_text)); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + if (ret == 0) { + ret = wc_HpkeInitOpenContext(hpke, context, NULL, pubKey, + pubKeySz, (byte*)info_text, (word32)XSTRLEN(info_text)); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + if (ret == 0) { + ret = wc_HpkeInitOpenContext(hpke, context, receiverKey, NULL, + pubKeySz, (byte*)info_text, (word32)XSTRLEN(info_text)); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + if (ret == 0) { + ret = wc_HpkeInitOpenContext(hpke, context, receiverKey, pubKey, + pubKeySz, NULL, (word32)XSTRLEN(info_text)); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + + /* initialize a valid open context for ContextOpenBase tests */ if (ret == 0) { ret = wc_HpkeInitOpenContext(hpke, context, receiverKey, pubKey, pubKeySz, (byte*)info_text, (word32)XSTRLEN(info_text)); + if (ret != 0) + ret = WC_TEST_RET_ENC_EC(ret); } + + /* Negative test case with NULL argument */ + if (ret == 0) { + ret = wc_HpkeContextOpenBase(NULL, context, + (byte*)aad_text, (word32)XSTRLEN(aad_text), + ciphertexts[0], (word32)XSTRLEN(start_text), plaintext); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + if (ret == 0) { + ret = wc_HpkeContextOpenBase(hpke, NULL, + (byte*)aad_text, (word32)XSTRLEN(aad_text), + ciphertexts[0], (word32)XSTRLEN(start_text), plaintext); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + /* NULL aad with non-zero aadSz */ + if (ret == 0) { + ret = wc_HpkeContextOpenBase(hpke, context, + NULL, (word32)XSTRLEN(aad_text), + ciphertexts[0], (word32)XSTRLEN(start_text), plaintext); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + if (ret == 0) { + ret = wc_HpkeContextOpenBase(hpke, context, + (byte*)aad_text, (word32)XSTRLEN(aad_text), + NULL, (word32)XSTRLEN(start_text), plaintext); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + if (ret == 0) { + ret = wc_HpkeContextOpenBase(hpke, context, + (byte*)aad_text, (word32)XSTRLEN(aad_text), + ciphertexts[0], (word32)XSTRLEN(start_text), NULL); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + + /* out-of-order open: try msg1 first */ + if (ret == 0) { + ret = wc_HpkeContextOpenBase(hpke, context, + (byte*)aad_text, (word32)XSTRLEN(aad_text), + ciphertexts[1], (word32)XSTRLEN(start_text), plaintext); + if (ret == 0) + ret = WC_TEST_RET_ENC_NC; + else + ret = 0; + } + /* open message 0 */ if (ret == 0) { - ret = wc_HpkeContextOpenBase(hpke, context, (byte*)aad_text, - (word32)XSTRLEN(aad_text), ciphertexts[context->seq], - (word32)XSTRLEN(start_text), plaintext); + ret = wc_HpkeContextOpenBase(hpke, context, + (byte*)aad_text, (word32)XSTRLEN(aad_text), + ciphertexts[0], (word32)XSTRLEN(start_text), plaintext); + if (ret != 0) + ret = WC_TEST_RET_ENC_EC(ret); } /* check message 0 */ - if (ret == 0) + if (ret == 0) { ret = XMEMCMP(plaintext, start_text, XSTRLEN(start_text)); + if (ret != 0) + ret = WC_TEST_RET_ENC_NC; + } /* open message 1 */ if (ret == 0) { - ret = wc_HpkeContextOpenBase(hpke, context, (byte*)aad_text, - (word32)XSTRLEN(aad_text), ciphertexts[context->seq], - (word32)XSTRLEN(start_text), plaintext); + ret = wc_HpkeContextOpenBase(hpke, context, + (byte*)aad_text, (word32)XSTRLEN(aad_text), + ciphertexts[1], (word32)XSTRLEN(start_text), plaintext); + if (ret != 0) + ret = WC_TEST_RET_ENC_EC(ret); } /* check message 1 */ - if (ret == 0) + if (ret == 0) { ret = XMEMCMP(plaintext, start_text, XSTRLEN(start_text)); + if (ret != 0) + ret = WC_TEST_RET_ENC_NC; + } + + /* seal context overflowed */ + if (ret == 0) { + ret = wc_HpkeInitSealContext(hpke, context, ephemeralKey, receiverKey, + (byte*)info_text, (word32)XSTRLEN(info_text)); + if (ret != 0) + ret = WC_TEST_RET_ENC_EC(ret); + } + if (ret == 0) { + context->seq = WC_MAX_SINT_OF(int); + ret = wc_HpkeContextSealBase(hpke, context, + (byte*)aad_text, (word32)XSTRLEN(aad_text), + (byte*)start_text, (word32)XSTRLEN(start_text), ciphertexts[0]); + if (ret != WC_NO_ERR_TRACE(SEQ_OVERFLOW_E)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + /* open context overflowed */ + if (ret == 0) { + ret = wc_HpkeInitOpenContext(hpke, context, receiverKey, pubKey, + pubKeySz, (byte*)info_text, (word32)XSTRLEN(info_text)); + if (ret != 0) + ret = WC_TEST_RET_ENC_EC(ret); + } + if (ret == 0) { + context->seq = WC_MAX_SINT_OF(int); + ret = wc_HpkeContextOpenBase(hpke, context, + (byte*)aad_text, (word32)XSTRLEN(aad_text), + ciphertexts[0], (word32)XSTRLEN(start_text), plaintext); + if (ret != WC_NO_ERR_TRACE(SEQ_OVERFLOW_E)) + ret = WC_TEST_RET_ENC_EC(ret); + else + ret = 0; + } + if (ephemeralKey != NULL) wc_HpkeFreeKey(hpke, hpke->kem, ephemeralKey, hpke->heap); if (receiverKey != NULL) wc_HpkeFreeKey(hpke, hpke->kem, receiverKey, hpke->heap); + #ifdef WOLFSSL_SMALL_STACK if (pubKey != NULL) XFREE(pubKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); if (context != NULL) XFREE(context, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); #endif + if (rngRet == 0) wc_FreeRng(rng); + return ret; } @@ -32692,21 +33004,9 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hpke_test(void) #if defined(HAVE_ECC) && defined(WOLFSSL_AES_128) #if (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && !defined(NO_SHA256) - /* p256 but this will only test the api */ - ret = wc_HpkeInit(hpke, DHKEM_P256_HKDF_SHA256, HKDF_SHA256, - HPKE_AES_128_GCM, NULL); - if (ret != 0) - return WC_TEST_RET_ENC_EC(ret); - ret = hpke_test_api(hpke); - if (ret != 0) - return ret; - /* p256 */ - ret = wc_HpkeInit(hpke, DHKEM_P256_HKDF_SHA256, HKDF_SHA256, - HPKE_AES_128_GCM, NULL); - if (ret != 0) - return WC_TEST_RET_ENC_EC(ret); - ret = hpke_test_single(hpke); + ret = hpke_test_single(hpke, DHKEM_P256_HKDF_SHA256, HKDF_SHA256, + HPKE_AES_128_GCM); if (ret != 0) return ret; ret = hpke_test_multi(hpke); @@ -32717,11 +33017,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hpke_test(void) #if (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && \ !defined(NO_SHA256) && defined(WOLFSSL_SHA512) /* p256 with sha512 kdf */ - ret = wc_HpkeInit(hpke, DHKEM_P256_HKDF_SHA256, HKDF_SHA512, - HPKE_AES_128_GCM, NULL); - if (ret != 0) - return WC_TEST_RET_ENC_EC(ret); - ret = hpke_test_single(hpke); + ret = hpke_test_single(hpke, DHKEM_P256_HKDF_SHA256, HKDF_SHA512, + HPKE_AES_128_GCM); if (ret != 0) return ret; ret = hpke_test_multi(hpke); @@ -32733,11 +33030,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hpke_test(void) #if (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && \ defined(WOLFSSL_SHA384) /* p384 */ - ret = wc_HpkeInit(hpke, DHKEM_P384_HKDF_SHA384, HKDF_SHA384, - HPKE_AES_128_GCM, NULL); - if (ret != 0) - return WC_TEST_RET_ENC_EC(ret); - ret = hpke_test_single(hpke); + ret = hpke_test_single(hpke, DHKEM_P384_HKDF_SHA384, HKDF_SHA384, + HPKE_AES_128_GCM); if (ret != 0) return ret; ret = hpke_test_multi(hpke); @@ -32748,11 +33042,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hpke_test(void) #if (defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)) && \ defined(WOLFSSL_SHA512) /* p521 */ - ret = wc_HpkeInit(hpke, DHKEM_P521_HKDF_SHA512, HKDF_SHA512, - HPKE_AES_128_GCM, NULL); - if (ret != 0) - return WC_TEST_RET_ENC_EC(ret); - ret = hpke_test_single(hpke); + ret = hpke_test_single(hpke, DHKEM_P521_HKDF_SHA512, HKDF_SHA512, + HPKE_AES_128_GCM); if (ret != 0) return ret; ret = hpke_test_multi(hpke); @@ -32763,11 +33054,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hpke_test(void) #if (defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)) && \ defined(WOLFSSL_SHA384) && defined(WOLFSSL_SHA512) /* p521 with sha384 kdf */ - ret = wc_HpkeInit(hpke, DHKEM_P521_HKDF_SHA512, HKDF_SHA384, - HPKE_AES_128_GCM, NULL); - if (ret != 0) - return WC_TEST_RET_ENC_EC(ret); - ret = hpke_test_single(hpke); + ret = hpke_test_single(hpke, DHKEM_P521_HKDF_SHA512, HKDF_SHA384, + HPKE_AES_128_GCM); if (ret != 0) return ret; ret = hpke_test_multi(hpke); @@ -32778,11 +33066,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hpke_test(void) #if defined(HAVE_CURVE25519) && !defined(NO_SHA256) && defined(WOLFSSL_AES_256) /* test with curve25519 and aes256 */ - ret = wc_HpkeInit(hpke, DHKEM_X25519_HKDF_SHA256, HKDF_SHA256, - HPKE_AES_256_GCM, NULL); - if (ret != 0) - return WC_TEST_RET_ENC_EC(ret); - ret = hpke_test_single(hpke); + ret = hpke_test_single(hpke, DHKEM_X25519_HKDF_SHA256, HKDF_SHA256, + HPKE_AES_256_GCM); if (ret != 0) return ret; ret = hpke_test_multi(hpke); @@ -32793,15 +33078,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hpke_test(void) #if defined(HAVE_CURVE448) && defined(WOLFSSL_SHA512) && \ defined(WOLFSSL_AES_256) - /* test with curve448 and aes256 */ - ret = wc_HpkeInit(hpke, DHKEM_X448_HKDF_SHA512, HKDF_SHA512, - HPKE_AES_256_GCM, NULL); - - /* HPKE does not support X448 yet, so expect failure */ - if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) - return WC_TEST_RET_ENC_EC(ret); - - ret = hpke_test_single(hpke); + ret = hpke_test_single(hpke, DHKEM_X448_HKDF_SHA512, HKDF_SHA512, + HPKE_AES_256_GCM); /* HPKE does not support X448 yet, so expect failure */ if (WC_TEST_RET_DEC_EC(ret) != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) From a4632ea508ae51bcab67b7a6a35905ebd01d0830 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Tue, 7 Apr 2026 14:42:09 +0200 Subject: [PATCH 019/167] Add BN_bn2binpad API and enable OpenVPN master CI testing --- .github/workflows/codespell.yml | 2 +- .github/workflows/openvpn.yml | 4 +-- src/ssl_bn.c | 50 +++++++++++++++++++++++++++++++++ tests/api/test_ossl_bn.c | 33 ++++++++++++++++++++++ wolfssl/openssl/bn.h | 7 +++-- 5 files changed, 90 insertions(+), 6 deletions(-) diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index ead4a2daf6..32351f8334 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -23,7 +23,7 @@ jobs: check_filenames: true check_hidden: true # Add comma separated list of words that occur multiple times that should be ignored (sorted alphabetically, case sensitive) - ignore_words_list: adin,aNULL,brunch,carryIn,chainG,ciph,cLen,cliKs,dout,haveA,inCreated,inOut,inout,larg,LEAPYEAR,Merget,optionA,parm,parms,repid,rIn,userA,ser,siz,te,Te,HSI,failT, + ignore_words_list: adin,aNULL,brunch,carryIn,chainG,ciph,cLen,cliKs,dout,haveA,inCreated,inOut,inout,larg,LEAPYEAR,Merget,optionA,parm,parms,repid,rIn,userA,ser,siz,te,Te,HSI,failT,toLen, # The exclude_file contains lines of code that should be ignored. This is useful for individual lines which have non-words that can safely be ignored. exclude_file: '.codespellexcludelines' # To skip files entirely from being processed, add it to the following list: diff --git a/.github/workflows/openvpn.yml b/.github/workflows/openvpn.yml index bc38257107..2f4974bb7a 100644 --- a/.github/workflows/openvpn.yml +++ b/.github/workflows/openvpn.yml @@ -42,9 +42,7 @@ jobs: strategy: fail-fast: false matrix: - # Pinned refs: avoid OpenVPN master until wolfSSL adds any new OpenSSL - # APIs it adopts (e.g. BN_bn2binpad). release/2.6 + latest stable tag. - ref: [ release/2.6, v2.6.19 ] + ref: [ master, release/2.6, v2.6.19 ] name: ${{ matrix.ref }} if: github.repository_owner == 'wolfssl' runs-on: ubuntu-24.04 diff --git a/src/ssl_bn.c b/src/ssl_bn.c index e3b758beb2..74d828da93 100644 --- a/src/ssl_bn.c +++ b/src/ssl_bn.c @@ -468,6 +468,56 @@ int wolfSSL_BN_bn2bin(const WOLFSSL_BIGNUM* bn, unsigned char* r) } +/* Encode a big number as a big-endian byte array, zero-padded to toLen bytes. + * + * Returns toLen on success, -1 on error (including when the number is too + * large to fit in toLen bytes). + * + * @param [in] bn Big number to encode. + * @param [out] r Buffer to place encoding into. Must be at least toLen + * bytes. + * @param [in] toLen Desired output length in bytes. + * @return toLen on success. + * @return -1 on error. + */ +int wolfSSL_BN_bn2binpad(const WOLFSSL_BIGNUM* bn, unsigned char* r, int toLen) +{ + int numBytes; + + WOLFSSL_ENTER("wolfSSL_BN_bn2binpad"); + + /* Validate parameters. */ + if (BN_IS_NULL(bn) || (r == NULL) || (toLen < 0)) { + WOLFSSL_MSG("NULL bn, r, or invalid toLen error"); + return WOLFSSL_FATAL_ERROR; + } + + /* Get the number of bytes needed to encode the big number. */ + numBytes = mp_unsigned_bin_size((mp_int*)bn->internal); + if (numBytes < 0) { + WOLFSSL_MSG("mp_unsigned_bin_size error"); + return WOLFSSL_FATAL_ERROR; + } + if (numBytes > toLen) { + WOLFSSL_MSG("BN too large for toLen"); + return WOLFSSL_FATAL_ERROR; + } + + /* Zero-pad leading bytes. */ + XMEMSET(r, 0, (size_t)(toLen - numBytes)); + + /* Encode the big number into the remaining bytes. */ + if (numBytes > 0 && + mp_to_unsigned_bin((mp_int*)bn->internal, r + toLen - numBytes) != + MP_OKAY) { + WOLFSSL_MSG("mp_to_unsigned_bin error"); + return WOLFSSL_FATAL_ERROR; + } + + return toLen; +} + + /* Return a big number with value of the decoding of the big-endian byte array. * * Returns ret when not NULL. diff --git a/tests/api/test_ossl_bn.c b/tests/api/test_ossl_bn.c index 3d9db919f2..61b036e545 100644 --- a/tests/api/test_ossl_bn.c +++ b/tests/api/test_ossl_bn.c @@ -323,6 +323,39 @@ int test_wolfSSL_BN_enc_dec(void) ExpectNotNull(BN_bin2bn(binNum, sizeof(binNum), b)); ExpectIntEQ(BN_cmp(a, b), -1); + /* BN_bn2binpad tests */ + { + unsigned char padOut[5]; + + /* Invalid parameters */ + ExpectIntEQ(BN_bn2binpad(NULL, padOut, sizeof(padOut)), -1); + ExpectIntEQ(BN_bn2binpad(&emptyBN, padOut, sizeof(padOut)), -1); + ExpectIntEQ(BN_bn2binpad(a, NULL, sizeof(padOut)), -1); + ExpectIntEQ(BN_bn2binpad(a, padOut, -1), -1); + /* toLen too small for the value */ + ExpectNotNull(BN_bin2bn(binNum, sizeof(binNum), b)); + ExpectIntEQ(BN_bn2binpad(b, padOut, 2), -1); + /* Normal case: a = 2, padded to 5 bytes */ + XMEMSET(padOut, 0xFF, sizeof(padOut)); + ExpectIntEQ(BN_bn2binpad(a, padOut, 5), 5); + ExpectIntEQ(padOut[0], 0x00); + ExpectIntEQ(padOut[1], 0x00); + ExpectIntEQ(padOut[2], 0x00); + ExpectIntEQ(padOut[3], 0x00); + ExpectIntEQ(padOut[4], 0x02); + /* Exact size (no padding needed) */ + ExpectIntEQ(BN_bn2binpad(a, padOut, 1), 1); + ExpectIntEQ(padOut[0], 0x02); + /* Zero value padded to 3 bytes */ + ExpectIntEQ(BN_set_word(a, 0), 1); + ExpectIntEQ(BN_bn2binpad(a, padOut, 3), 3); + ExpectIntEQ(padOut[0], 0x00); + ExpectIntEQ(padOut[1], 0x00); + ExpectIntEQ(padOut[2], 0x00); + /* Restore a = 2 for subsequent tests */ + ExpectIntEQ(BN_set_word(a, 2), 1); + } + ExpectNotNull(str = BN_bn2hex(a)); ExpectNotNull(BN_hex2bn(&b, str)); ExpectIntEQ(BN_cmp(a, b), 0); diff --git a/wolfssl/openssl/bn.h b/wolfssl/openssl/bn.h index 392aebac5f..7371f8a03a 100644 --- a/wolfssl/openssl/bn.h +++ b/wolfssl/openssl/bn.h @@ -135,6 +135,8 @@ WOLFSSL_API int wolfSSL_BN_cmp(const WOLFSSL_BIGNUM* a, const WOLFSSL_BIGNUM* b) WOLFSSL_API int wolfSSL_BN_ucmp(const WOLFSSL_BIGNUM* a, const WOLFSSL_BIGNUM* b); WOLFSSL_API int wolfSSL_BN_bn2bin(const WOLFSSL_BIGNUM* bn, unsigned char* r); +WOLFSSL_API int wolfSSL_BN_bn2binpad(const WOLFSSL_BIGNUM* bn, unsigned char* r, + int toLen); WOLFSSL_API WOLFSSL_BIGNUM* wolfSSL_BN_bin2bn(const unsigned char* str, int len, WOLFSSL_BIGNUM* ret); @@ -246,8 +248,9 @@ typedef WOLFSSL_BN_GENCB BN_GENCB; #define BN_cmp wolfSSL_BN_cmp #define BN_ucmp wolfSSL_BN_ucmp -#define BN_bn2bin wolfSSL_BN_bn2bin -#define BN_bin2bn wolfSSL_BN_bin2bn +#define BN_bn2bin wolfSSL_BN_bn2bin +#define BN_bn2binpad wolfSSL_BN_bn2binpad +#define BN_bin2bn wolfSSL_BN_bin2bn #define BN_mod wolfSSL_BN_mod #define BN_mod_exp wolfSSL_BN_mod_exp From 3e74f841d077131629818d7faa32e141630d1257 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Mon, 13 Apr 2026 15:50:26 +0200 Subject: [PATCH 020/167] Add tests for BN_bn2binpad with zero output length --- tests/api/test_ossl_bn.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/api/test_ossl_bn.c b/tests/api/test_ossl_bn.c index 61b036e545..c4872120f2 100644 --- a/tests/api/test_ossl_bn.c +++ b/tests/api/test_ossl_bn.c @@ -352,8 +352,11 @@ int test_wolfSSL_BN_enc_dec(void) ExpectIntEQ(padOut[0], 0x00); ExpectIntEQ(padOut[1], 0x00); ExpectIntEQ(padOut[2], 0x00); - /* Restore a = 2 for subsequent tests */ + /* toLen == 0 with zero-valued BN is valid */ + ExpectIntEQ(BN_bn2binpad(a, padOut, 0), 0); + /* toLen == 0 with non-zero BN is an error */ ExpectIntEQ(BN_set_word(a, 2), 1); + ExpectIntEQ(BN_bn2binpad(a, padOut, 0), -1); } ExpectNotNull(str = BN_bn2hex(a)); From dc9d16c10c496ceb575d29a1859fd25d8044d604 Mon Sep 17 00:00:00 2001 From: sebastian-carpenter Date: Mon, 13 Apr 2026 14:47:16 -0600 Subject: [PATCH 021/167] remove bad character --- wolfcrypt/test/test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 0a275b2849..586a890e7b 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -32776,7 +32776,7 @@ static wc_test_ret_t hpke_test_multi(Hpke* hpke) else ret = 0; } - /* inSz = 0 is less than Npk → BUFFER_E */ + /* inSz = 0 is less than Npk */ if (ret == 0) { ret = wc_HpkeDeserializePublicKey(hpke, &deserializedKey, pubKey, 0); if (ret != WC_NO_ERR_TRACE(BUFFER_E)) From 525714ca7c6df5f79eaab1266091cd318c494263 Mon Sep 17 00:00:00 2001 From: Anthony Hu Date: Mon, 13 Apr 2026 17:29:23 -0400 Subject: [PATCH 022/167] Fixup C++ Problem --- src/x509_str.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/x509_str.c b/src/x509_str.c index aa74267c4d..8d9536e7bf 100644 --- a/src/x509_str.c +++ b/src/x509_str.c @@ -1658,7 +1658,10 @@ WOLFSSL_LOCAL int X509StorePushCertsToCM(WOLFSSL_X509_STORE* store) store->trusted = NULL; } - return anyFail ? WOLFSSL_FATAL_ERROR : WOLFSSL_SUCCESS; + if (anyFail) { + return WOLFSSL_FATAL_ERROR; + } + return WOLFSSL_SUCCESS; } int wolfSSL_X509_STORE_add_cert(WOLFSSL_X509_STORE* store, WOLFSSL_X509* x509) From 373b45cd7a3f4688673e794e5f9fff96c0d1f628 Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Mon, 13 Apr 2026 14:53:22 -0700 Subject: [PATCH 023/167] Fix dangling secure_renegotiation pointer after TLSX_FreeAll ssl->secure_renegotiation caches a pointer into extension data owned by the ssl->extensions list. Three call sites free that list via TLSX_FreeAll without NULLing the cached pointer, leaving it dangling: - wolfSSL_clear() - FreeHandshakeResources() (TLSX_FreeAll branch) - wolfSSL_ResourceFree() After wolfSSL_clear(), calling wolfSSL_SSL_get_secure_renegotiation_support() reads the freed SecureRenegotiation struct. Confirmed heap-use-after-free under ASan with nginx, haproxy, and openssl-compat build profiles. NULL the pointer at all three sites. Add regression test covering the wolfSSL_clear path. --- src/internal.c | 9 +++++++++ src/ssl.c | 4 ++++ tests/api.c | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+) diff --git a/src/internal.c b/src/internal.c index 267c75a5d6..25acacf882 100644 --- a/src/internal.c +++ b/src/internal.c @@ -8952,6 +8952,11 @@ void wolfSSL_ResourceFree(WOLFSSL* ssl) #ifdef HAVE_TLS_EXTENSIONS #if !defined(NO_TLS) TLSX_FreeAll(ssl->extensions, ssl->heap); + ssl->extensions = NULL; + #if defined(HAVE_SECURE_RENEGOTIATION) \ + || defined(HAVE_SERVER_RENEGOTIATION_INFO) + ssl->secure_renegotiation = NULL; + #endif #endif /* !NO_TLS */ #ifdef HAVE_ALPN if (ssl->alpn_peer_requested != NULL) { @@ -9315,6 +9320,10 @@ void FreeHandshakeResources(WOLFSSL* ssl) /* Some extensions need to be kept for post-handshake querying. */ TLSX_FreeAll(ssl->extensions, ssl->heap); ssl->extensions = NULL; + #if defined(HAVE_SECURE_RENEGOTIATION) \ + || defined(HAVE_SERVER_RENEGOTIATION_INFO) + ssl->secure_renegotiation = NULL; + #endif #else #if !defined(NO_CERTS) && !defined(WOLFSSL_NO_SIGALG) TLSX_Remove(&ssl->extensions, TLSX_SIGNATURE_ALGORITHMS, ssl->heap); diff --git a/src/ssl.c b/src/ssl.c index 58cd6701c0..284b09c601 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -10051,6 +10051,10 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out, #if defined(HAVE_TLS_EXTENSIONS) && !defined(NO_TLS) TLSX_FreeAll(ssl->extensions, ssl->heap); ssl->extensions = NULL; + #if defined(HAVE_SECURE_RENEGOTIATION) \ + || defined(HAVE_SERVER_RENEGOTIATION_INFO) + ssl->secure_renegotiation = NULL; + #endif #endif if (ssl->keys.encryptionOn) { diff --git a/tests/api.c b/tests/api.c index 0e9cbe2982..e53ec70385 100644 --- a/tests/api.c +++ b/tests/api.c @@ -10203,6 +10203,38 @@ static int test_wolfSSL_wolfSSL_UseSecureRenegotiation(void) return EXPECT_RESULT(); } +/* TLSX_FreeAll frees the SecureRenegotiation struct but the cached pointer + * ssl->secure_renegotiation was not cleared, causing a use-after-free when + * queried after wolfSSL_clear(). */ +static int test_wolfSSL_clear_secure_renegotiation(void) +{ + EXPECT_DECLS; +#if (defined(HAVE_SECURE_RENEGOTIATION) || \ + defined(HAVE_SERVER_RENEGOTIATION_INFO)) && \ + (defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)) && \ + !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS) + WOLFSSL_CTX *ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()); + WOLFSSL *ssl = wolfSSL_new(ctx); + + ExpectNotNull(ctx); + ExpectNotNull(ssl); + + ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_UseSecureRenegotiation(ssl)); + ExpectNotNull(ssl->secure_renegotiation); + if (ssl->secure_renegotiation != NULL) + ssl->secure_renegotiation->enabled = 1; + + ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_clear(ssl)); + ExpectNull(ssl->secure_renegotiation); + ExpectIntEQ(WOLFSSL_FAILURE, + wolfSSL_SSL_get_secure_renegotiation_support(ssl)); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + /* Test reconnecting with a different ciphersuite after a renegotiation. */ static int test_wolfSSL_SCR_Reconnect(void) { @@ -35770,6 +35802,7 @@ TEST_CASE testCases[] = { TEST_DECL(test_TLSX_TCA_Find), TEST_DECL(test_TLSX_SNI_GetSize_overflow), TEST_DECL(test_wolfSSL_wolfSSL_UseSecureRenegotiation), + TEST_DECL(test_wolfSSL_clear_secure_renegotiation), TEST_DECL(test_wolfSSL_SCR_Reconnect), TEST_DECL(test_wolfSSL_SCR_check_enabled), TEST_DECL(test_tls_ext_duplicate), From ae1da8af4318c8d59103bd506bab2d20a6fe1a69 Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Mon, 13 Apr 2026 19:05:41 -0700 Subject: [PATCH 024/167] Add missing NULL checks in public API functions Add NULL and bounds validation to public API entry points that were missing basic argument checks. Fixes span ALPN, session cache, X509, SRP, PrivateKey ID/Label, and OBJ_obj2txt. --- src/ssl.c | 9 ++++++--- src/ssl_load.c | 28 ++++++++++++++++++++++++---- src/ssl_sess.c | 16 ++++++++++++++-- src/x509.c | 4 ++-- wolfcrypt/src/srp.c | 2 ++ 5 files changed, 48 insertions(+), 11 deletions(-) diff --git a/src/ssl.c b/src/ssl.c index 58cd6701c0..4e44a6360b 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -14545,7 +14545,10 @@ void* wolfSSL_GetHKDFExtractCtx(WOLFSSL* ssl) else if (a->type == WOLFSSL_GEN_DNS || a->type == WOLFSSL_GEN_EMAIL || a->type == WOLFSSL_GEN_URI) { bufSz = (int)XSTRLEN((const char*)a->obj); - XMEMCPY(buf, a->obj, min((word32)bufSz, (word32)bufLen)); + if (bufSz >= bufLen) { + bufSz = bufLen - 1; + } + XMEMCPY(buf, a->obj, (size_t)bufSz); } else if ((bufSz = wolfssl_obj2txt_numeric(buf, bufLen, a)) > 0) { if ((desc = oid_translate_num_to_str(buf))) { @@ -17498,7 +17501,7 @@ int wolfSSL_CTX_set_alpn_protos(WOLFSSL_CTX *ctx, const unsigned char *p, unsigned int p_len) { WOLFSSL_ENTER("wolfSSL_CTX_set_alpn_protos"); - if (ctx == NULL) + if (ctx == NULL || p == NULL) return BAD_FUNC_ARG; if (ctx->alpn_cli_protos != NULL) { XFREE((void*)ctx->alpn_cli_protos, ctx->heap, DYNAMIC_TYPE_OPENSSL); @@ -17552,7 +17555,7 @@ int wolfSSL_set_alpn_protos(WOLFSSL* ssl, WOLFSSL_ENTER("wolfSSL_set_alpn_protos"); - if (ssl == NULL || p_len <= 1) { + if (ssl == NULL || p_len <= 1 || p == NULL) { #if defined(WOLFSSL_ERROR_CODE_OPENSSL) /* 0 on success in OpenSSL, non-0 on failure in OpenSSL * the function reverses the return value convention. diff --git a/src/ssl_load.c b/src/ssl_load.c index 0a0fb9e467..9260aa2b9a 100644 --- a/src/ssl_load.c +++ b/src/ssl_load.c @@ -4159,6 +4159,10 @@ int wolfSSL_CTX_use_PrivateKey_Id(WOLFSSL_CTX* ctx, const unsigned char* id, WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey_Id"); + if (ctx == NULL || id == NULL || sz < 0) { + return 0; + } + /* Dispose of old private key and allocate and copy in id. */ FreeDer(&ctx->privateKey); if (AllocCopyDer(&ctx->privateKey, id, (word32)sz, PRIVATEKEY_TYPE, @@ -4227,10 +4231,16 @@ int wolfSSL_CTX_use_PrivateKey_Label(WOLFSSL_CTX* ctx, const char* label, int devId) { int ret = 1; - word32 sz = (word32)XSTRLEN(label) + 1; + word32 sz; WOLFSSL_ENTER("wolfSSL_CTX_use_PrivateKey_Label"); + if (ctx == NULL || label == NULL) { + return 0; + } + + sz = (word32)XSTRLEN(label) + 1; + /* Dispose of old private key and allocate and copy in label. */ FreeDer(&ctx->privateKey); if (AllocCopyDer(&ctx->privateKey, (const byte*)label, (word32)sz, @@ -4268,7 +4278,7 @@ int wolfSSL_CTX_use_AltPrivateKey_Id(WOLFSSL_CTX* ctx, const unsigned char* id, WOLFSSL_ENTER("wolfSSL_CTX_use_AltPrivateKey_Id"); - if ((ctx == NULL) || (id == NULL)) { + if ((ctx == NULL) || (id == NULL) || (sz < 0)) { ret = 0; } @@ -4561,6 +4571,10 @@ int wolfSSL_use_PrivateKey_Id(WOLFSSL* ssl, const unsigned char* id, { int ret = 1; + if (ssl == NULL || id == NULL || sz < 0) { + return 0; + } + /* Dispose of old private key if owned and allocate and copy in id. */ if (ssl->buffers.weOwnKey) { FreeDer(&ssl->buffers.key); @@ -4629,7 +4643,13 @@ int wolfSSL_use_PrivateKey_id(WOLFSSL* ssl, const unsigned char* id, int wolfSSL_use_PrivateKey_Label(WOLFSSL* ssl, const char* label, int devId) { int ret = 1; - word32 sz = (word32)XSTRLEN(label) + 1; + word32 sz; + + if (ssl == NULL || label == NULL) { + return 0; + } + + sz = (word32)XSTRLEN(label) + 1; /* Dispose of old private key if owned and allocate and copy in label. */ if (ssl->buffers.weOwnKey) { @@ -4672,7 +4692,7 @@ int wolfSSL_use_AltPrivateKey_Id(WOLFSSL* ssl, const unsigned char* id, long sz, { int ret = 1; - if ((ssl == NULL) || (id == NULL)) { + if ((ssl == NULL) || (id == NULL) || (sz < 0)) { ret = 0; } diff --git a/src/ssl_sess.c b/src/ssl_sess.c index d28d28976c..8cea6c7b30 100644 --- a/src/ssl_sess.c +++ b/src/ssl_sess.c @@ -430,10 +430,16 @@ int wolfSSL_memsave_session_cache(void* mem, int sz) { int i; cache_header_t cache_header; - SessionRow* row = (SessionRow*)((byte*)mem + sizeof(cache_header)); + SessionRow* row; WOLFSSL_ENTER("wolfSSL_memsave_session_cache"); + if (mem == NULL) { + return BAD_FUNC_ARG; + } + + row = (SessionRow*)((byte*)mem + sizeof(cache_header)); + if (sz < wolfSSL_get_session_cache_memsize()) { WOLFSSL_MSG("Memory buffer too small"); return BUFFER_E; @@ -520,10 +526,16 @@ int wolfSSL_memrestore_session_cache(const void* mem, int sz) { int i; cache_header_t cache_header; - SessionRow* row = (SessionRow*)((byte*)mem + sizeof(cache_header)); + SessionRow* row; WOLFSSL_ENTER("wolfSSL_memrestore_session_cache"); + if (mem == NULL) { + return BAD_FUNC_ARG; + } + + row = (SessionRow*)((byte*)mem + sizeof(cache_header)); + if (sz < wolfSSL_get_session_cache_memsize()) { WOLFSSL_MSG("Memory buffer too small"); return BUFFER_E; diff --git a/src/x509.c b/src/x509.c index 46dfd38ed4..82e3afb8f8 100644 --- a/src/x509.c +++ b/src/x509.c @@ -3277,8 +3277,8 @@ WOLFSSL_X509_EXTENSION* wolfSSL_X509V3_EXT_nconf(WOLFSSL_CONF *conf, WOLFSSL_ENTER("wolfSSL_X509V3_EXT_nconf"); - if (value == NULL) { - WOLFSSL_MSG("value NULL parameter"); + if (value == NULL || sName == NULL) { + WOLFSSL_MSG("NULL parameter"); return NULL; } diff --git a/wolfcrypt/src/srp.c b/wolfcrypt/src/srp.c index 2d8b4ec3e0..c8583ffbf9 100644 --- a/wolfcrypt/src/srp.c +++ b/wolfcrypt/src/srp.c @@ -378,6 +378,8 @@ int wc_SrpSetParams(Srp* srp, const byte* N, word32 nSz, if (srp->salt) { ForceZero(srp->salt, srp->saltSz); XFREE(srp->salt, srp->heap, DYNAMIC_TYPE_SRP); + srp->salt = NULL; + srp->saltSz = 0; } srp->salt = (byte*)XMALLOC(saltSz, srp->heap, DYNAMIC_TYPE_SRP); From 86c56de33fb2d54e2baf1e16e2636b6c9fc636a6 Mon Sep 17 00:00:00 2001 From: Lealem Amedie Date: Mon, 13 Apr 2026 21:32:54 -0600 Subject: [PATCH 025/167] Address peer review comments --- src/pk.c | 87 +++++++++++++++++ wolfcrypt/src/evp_pk.c | 186 ++++++++++-------------------------- wolfssl/wolfcrypt/ed25519.h | 7 ++ wolfssl/wolfcrypt/ed448.h | 7 ++ 4 files changed, 153 insertions(+), 134 deletions(-) diff --git a/src/pk.c b/src/pk.c index 4544baaf10..292c3a2d81 100644 --- a/src/pk.c +++ b/src/pk.c @@ -5501,6 +5501,50 @@ int wolfSSL_ED25519_verify(const unsigned char *msg, unsigned int msgSz, #endif /* OPENSSL_EXTRA && HAVE_ED25519 */ +#if (defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)) && \ + defined(HAVE_ED25519) +/* Allocate and initialize a new ed25519_key. + * + * @param [in] heap Heap hint for memory allocation. + * @param [in] devId Device identifier for crypto callbacks. + * @return Allocated and initialized ed25519_key on success. + * @return NULL on failure. + */ +ed25519_key* wolfSSL_ED25519_new(void* heap, int devId) +{ + ed25519_key* key; + + WOLFSSL_ENTER("wolfSSL_ED25519_new"); + + key = (ed25519_key*)XMALLOC(sizeof(ed25519_key), heap, + DYNAMIC_TYPE_ED25519); + if (key == NULL) { + WOLFSSL_ERROR_MSG("wolfSSL_ED25519_new malloc failure"); + } + else if (wc_ed25519_init_ex(key, heap, devId) != 0) { + WOLFSSL_ERROR_MSG("wolfSSL_ED25519_new init failure"); + XFREE(key, heap, DYNAMIC_TYPE_ED25519); + key = NULL; + } + + return key; +} + +/* Free an ed25519_key allocated with wolfSSL_ED25519_new. + * + * @param [in] key ed25519_key to free. May be NULL. + */ +void wolfSSL_ED25519_free(ed25519_key* key) +{ + if (key != NULL) { + void* heap = key->heap; + WOLFSSL_ENTER("wolfSSL_ED25519_free"); + wc_ed25519_free(key); + XFREE(key, heap, DYNAMIC_TYPE_ED25519); + } +} +#endif /* (OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL) && HAVE_ED25519 */ + /******************************************************************************* * END OF ED25519 API ******************************************************************************/ @@ -5954,6 +5998,49 @@ int wolfSSL_ED448_verify(const unsigned char *msg, unsigned int msgSz, } #endif /* OPENSSL_EXTRA && HAVE_ED448 */ +#if (defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)) && \ + defined(HAVE_ED448) +/* Allocate and initialize a new ed448_key. + * + * @param [in] heap Heap hint for memory allocation. + * @param [in] devId Device identifier for crypto callbacks. + * @return Allocated and initialized ed448_key on success. + * @return NULL on failure. + */ +ed448_key* wolfSSL_ED448_new(void* heap, int devId) +{ + ed448_key* key; + + WOLFSSL_ENTER("wolfSSL_ED448_new"); + + key = (ed448_key*)XMALLOC(sizeof(ed448_key), heap, DYNAMIC_TYPE_ED448); + if (key == NULL) { + WOLFSSL_ERROR_MSG("wolfSSL_ED448_new malloc failure"); + } + else if (wc_ed448_init_ex(key, heap, devId) != 0) { + WOLFSSL_ERROR_MSG("wolfSSL_ED448_new init failure"); + XFREE(key, heap, DYNAMIC_TYPE_ED448); + key = NULL; + } + + return key; +} + +/* Free an ed448_key allocated with wolfSSL_ED448_new. + * + * @param [in] key ed448_key to free. May be NULL. + */ +void wolfSSL_ED448_free(ed448_key* key) +{ + if (key != NULL) { + void* heap = key->heap; + WOLFSSL_ENTER("wolfSSL_ED448_free"); + wc_ed448_free(key); + XFREE(key, heap, DYNAMIC_TYPE_ED448); + } +} +#endif /* (OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL) && HAVE_ED448 */ + /******************************************************************************* * END OF ED448 API ******************************************************************************/ diff --git a/wolfcrypt/src/evp_pk.c b/wolfcrypt/src/evp_pk.c index e0dff16cf8..4a82d4931f 100644 --- a/wolfcrypt/src/evp_pk.c +++ b/wolfcrypt/src/evp_pk.c @@ -257,30 +257,21 @@ static int d2iTryEd25519Key(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, heap = (*out)->heap; } - edKey = (ed25519_key*)XMALLOC(sizeof(ed25519_key), heap, - DYNAMIC_TYPE_ED25519); + edKey = wolfSSL_ED25519_new(heap, INVALID_DEVID); if (edKey == NULL) { return 0; } - if (wc_ed25519_init_ex(edKey, heap, INVALID_DEVID) != 0) { - XFREE(edKey, heap, DYNAMIC_TYPE_ED25519); - return 0; - } - /* Try decoding data as an Ed25519 private/public key. The input may be - * either a DER-encoded SubjectPublicKeyInfo / PKCS#8 PrivateKeyInfo - * (the normal d2i_PUBKEY input) or a raw key (as passed from + /* Try decoding data as an Ed25519 private/public key. Private keys must + * be PKCS#8 PrivateKeyInfo DER (matching OpenSSL d2i_PrivateKey + * semantics). Public keys may be DER-encoded SubjectPublicKeyInfo (the + * normal d2i_PUBKEY input) or raw 32-byte key material (as passed from * CopyDecodedToX509 where dCert->publicKey is the raw bytes from the - * SPKI BIT STRING). Try the structured form first, then fall back to - * the raw import. */ + * SPKI BIT STRING); the structured form is tried first, then the raw + * import as fallback. */ if (priv) { isEdKey = (wc_Ed25519PrivateKeyDecode(mem, &keyIdx, edKey, (word32)memSz) == 0); - if (!isEdKey && memSz == ED25519_KEY_SIZE) { - keyIdx = (word32)memSz; - isEdKey = (wc_ed25519_import_private_only(mem, (word32)memSz, - edKey) == 0); - } } else { isEdKey = (wc_Ed25519PublicKeyDecode(mem, &keyIdx, edKey, @@ -293,22 +284,23 @@ static int d2iTryEd25519Key(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, } if (!isEdKey) { - wc_ed25519_free(edKey); - XFREE(edKey, heap, DYNAMIC_TYPE_ED25519); + wolfSSL_ED25519_free(edKey); return WOLFSSL_FATAL_ERROR; } /* Create an EVP PKEY object holding the input bytes. These are the * SPKI / PKCS#8 DER on the structured path, or the raw 32-byte key - * on the raw fallback path. */ - ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_ED25519); + * on the raw fallback path. If the caller already populated the EVP + * PKEY with the input bytes (pkey.ptr set), skip the allocate/copy. */ + if (*out == NULL || (*out)->pkey.ptr == NULL) { + ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_ED25519); + } if (ret == 1) { (*out)->ownEd25519 = 1; (*out)->ed25519 = edKey; } else { - wc_ed25519_free(edKey); - XFREE(edKey, heap, DYNAMIC_TYPE_ED25519); + wolfSSL_ED25519_free(edKey); } return ret; @@ -341,29 +333,21 @@ static int d2iTryEd448Key(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, heap = (*out)->heap; } - edKey = (ed448_key*)XMALLOC(sizeof(ed448_key), heap, DYNAMIC_TYPE_ED448); + edKey = wolfSSL_ED448_new(heap, INVALID_DEVID); if (edKey == NULL) { return 0; } - if (wc_ed448_init_ex(edKey, heap, INVALID_DEVID) != 0) { - XFREE(edKey, heap, DYNAMIC_TYPE_ED448); - return 0; - } - /* Try decoding data as an Ed448 private/public key. The input may be - * either a DER-encoded SubjectPublicKeyInfo / PKCS#8 PrivateKeyInfo - * (the normal d2i_PUBKEY input) or a raw key (as passed from + /* Try decoding data as an Ed448 private/public key. Private keys must + * be PKCS#8 PrivateKeyInfo DER (matching OpenSSL d2i_PrivateKey + * semantics). Public keys may be DER-encoded SubjectPublicKeyInfo (the + * normal d2i_PUBKEY input) or raw 57-byte key material (as passed from * CopyDecodedToX509 where dCert->publicKey is the raw bytes from the - * SPKI BIT STRING). Try the structured form first, then fall back to - * the raw import. */ + * SPKI BIT STRING); the structured form is tried first, then the raw + * import as fallback. */ if (priv) { isEdKey = (wc_Ed448PrivateKeyDecode(mem, &keyIdx, edKey, (word32)memSz) == 0); - if (!isEdKey && memSz == ED448_KEY_SIZE) { - keyIdx = (word32)memSz; - isEdKey = (wc_ed448_import_private_only(mem, (word32)memSz, - edKey) == 0); - } } else { isEdKey = (wc_Ed448PublicKeyDecode(mem, &keyIdx, edKey, @@ -376,22 +360,23 @@ static int d2iTryEd448Key(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, } if (!isEdKey) { - wc_ed448_free(edKey); - XFREE(edKey, heap, DYNAMIC_TYPE_ED448); + wolfSSL_ED448_free(edKey); return WOLFSSL_FATAL_ERROR; } /* Create an EVP PKEY object holding the input bytes. These are the * SPKI / PKCS#8 DER on the structured path, or the raw 57-byte key - * on the raw fallback path. */ - ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_ED448); + * on the raw fallback path. If the caller already populated the EVP + * PKEY with the input bytes (pkey.ptr set), skip the allocate/copy. */ + if (*out == NULL || (*out)->pkey.ptr == NULL) { + ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_ED448); + } if (ret == 1) { (*out)->ownEd448 = 1; (*out)->ed448 = edKey; } else { - wc_ed448_free(edKey); - XFREE(edKey, heap, DYNAMIC_TYPE_ED448); + wolfSSL_ED448_free(edKey); } return ret; @@ -556,7 +541,7 @@ static int d2iTryDhKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, static int d2iTryAltDhKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, long memSz, int priv) { - WOLFSSL_DH* dhObj; + WOLFSSL_DH* dhObj = NULL; word32 keyIdx = 0; DhKey* key = NULL; int elements; @@ -565,22 +550,25 @@ static int d2iTryAltDhKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, /* Create DH key object from data. */ dhObj = wolfSSL_DH_new(); if (dhObj == NULL) { - return 0; + ret = 0; } - key = (DhKey*)dhObj->internal; - /* Try decoding data as a DH public key. */ - if (wc_DhKeyDecode(mem, &keyIdx, key, (word32)memSz) != 0) { - wolfSSL_DH_free(dhObj); - return WOLFSSL_FATAL_ERROR; + if (ret == 1) { + key = (DhKey*)dhObj->internal; + /* Try decoding data as a DH public key. */ + if (wc_DhKeyDecode(mem, &keyIdx, key, (word32)memSz) != 0) { + ret = WOLFSSL_FATAL_ERROR; + } } - /* DH key has data and is external to DH object. */ - elements = ELEMENT_P | ELEMENT_G | ELEMENT_Q | ELEMENT_PUB; - if (priv) { - elements |= ELEMENT_PRV; - } - if (SetDhExternal_ex(dhObj, elements) != WOLFSSL_SUCCESS ) { - ret = 0; + if (ret == 1) { + /* DH key has data and is external to DH object. */ + elements = ELEMENT_P | ELEMENT_G | ELEMENT_Q | ELEMENT_PUB; + if (priv) { + elements |= ELEMENT_PRV; + } + if (SetDhExternal_ex(dhObj, elements) != WOLFSSL_SUCCESS) { + ret = 0; + } } if (ret == 1) { /* Create an EVP PKEY object. */ @@ -591,7 +579,7 @@ static int d2iTryAltDhKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, (*out)->ownDh = 1; (*out)->dh = dhObj; } - if (ret == 0) { + else if (dhObj != NULL) { wolfSSL_DH_free(dhObj); } @@ -1210,93 +1198,23 @@ static WOLFSSL_EVP_PKEY* d2i_evp_pkey(int type, WOLFSSL_EVP_PKEY** out, #endif /* WOLFSSL_QT || OPENSSL_ALL || WOLFSSL_OPENSSH */ #ifdef HAVE_ED25519 case WC_EVP_PKEY_ED25519: - { - ed25519_key* edKey; - word32 keyIdx = 0; - int isEdKey; - - edKey = (ed25519_key*)XMALLOC(sizeof(ed25519_key), local->heap, - DYNAMIC_TYPE_ED25519); - if (edKey == NULL) { + /* local->pkey.ptr already holds the input bytes, so + * d2iTryEd25519Key will skip the d2i_make_pkey allocate/copy + * and just decode into local->ed25519. */ + if (d2iTryEd25519Key(&local, p, local->pkey_sz, priv) != 1) { wolfSSL_EVP_PKEY_free(local); return NULL; } - if (wc_ed25519_init_ex(edKey, local->heap, INVALID_DEVID) != 0) { - XFREE(edKey, local->heap, DYNAMIC_TYPE_ED25519); - wolfSSL_EVP_PKEY_free(local); - return NULL; - } - if (priv) { - isEdKey = (wc_Ed25519PrivateKeyDecode(p, &keyIdx, edKey, - (word32)local->pkey_sz) == 0); - if (!isEdKey && local->pkey_sz == ED25519_KEY_SIZE) { - isEdKey = (wc_ed25519_import_private_only(p, - (word32)local->pkey_sz, edKey) == 0); - } - } - else { - isEdKey = (wc_Ed25519PublicKeyDecode(p, &keyIdx, edKey, - (word32)local->pkey_sz) == 0); - if (!isEdKey && local->pkey_sz == ED25519_PUB_KEY_SIZE) { - isEdKey = (wc_ed25519_import_public(p, - (word32)local->pkey_sz, edKey) == 0); - } - } - if (!isEdKey) { - wc_ed25519_free(edKey); - XFREE(edKey, local->heap, DYNAMIC_TYPE_ED25519); - wolfSSL_EVP_PKEY_free(local); - return NULL; - } - local->ownEd25519 = 1; - local->ed25519 = edKey; break; - } #endif /* HAVE_ED25519 */ #ifdef HAVE_ED448 case WC_EVP_PKEY_ED448: - { - ed448_key* edKey; - word32 keyIdx = 0; - int isEdKey; - - edKey = (ed448_key*)XMALLOC(sizeof(ed448_key), local->heap, - DYNAMIC_TYPE_ED448); - if (edKey == NULL) { + /* See WC_EVP_PKEY_ED25519 case above. */ + if (d2iTryEd448Key(&local, p, local->pkey_sz, priv) != 1) { wolfSSL_EVP_PKEY_free(local); return NULL; } - if (wc_ed448_init_ex(edKey, local->heap, INVALID_DEVID) != 0) { - XFREE(edKey, local->heap, DYNAMIC_TYPE_ED448); - wolfSSL_EVP_PKEY_free(local); - return NULL; - } - if (priv) { - isEdKey = (wc_Ed448PrivateKeyDecode(p, &keyIdx, edKey, - (word32)local->pkey_sz) == 0); - if (!isEdKey && local->pkey_sz == ED448_KEY_SIZE) { - isEdKey = (wc_ed448_import_private_only(p, - (word32)local->pkey_sz, edKey) == 0); - } - } - else { - isEdKey = (wc_Ed448PublicKeyDecode(p, &keyIdx, edKey, - (word32)local->pkey_sz) == 0); - if (!isEdKey && local->pkey_sz == ED448_PUB_KEY_SIZE) { - isEdKey = (wc_ed448_import_public(p, - (word32)local->pkey_sz, edKey) == 0); - } - } - if (!isEdKey) { - wc_ed448_free(edKey); - XFREE(edKey, local->heap, DYNAMIC_TYPE_ED448); - wolfSSL_EVP_PKEY_free(local); - return NULL; - } - local->ownEd448 = 1; - local->ed448 = edKey; break; - } #endif /* HAVE_ED448 */ default: WOLFSSL_MSG("Unsupported key type"); diff --git a/wolfssl/wolfcrypt/ed25519.h b/wolfssl/wolfcrypt/ed25519.h index 120c210a92..02858cc227 100644 --- a/wolfssl/wolfcrypt/ed25519.h +++ b/wolfssl/wolfcrypt/ed25519.h @@ -188,6 +188,13 @@ WOLFSSL_API int wc_ed25519_delete(ed25519_key* key, ed25519_key** key_p); #endif +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) +WOLFSSL_API +ed25519_key* wolfSSL_ED25519_new(void* heap, int devId); +WOLFSSL_API +void wolfSSL_ED25519_free(ed25519_key* key); +#endif + #ifdef HAVE_ED25519_KEY_IMPORT WOLFSSL_API int wc_ed25519_import_public(const byte* in, word32 inLen, ed25519_key* key); diff --git a/wolfssl/wolfcrypt/ed448.h b/wolfssl/wolfcrypt/ed448.h index e255fdacae..a72d8c0daf 100644 --- a/wolfssl/wolfcrypt/ed448.h +++ b/wolfssl/wolfcrypt/ed448.h @@ -164,6 +164,13 @@ int wc_ed448_init(ed448_key* key); WOLFSSL_API void wc_ed448_free(ed448_key* key); +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) +WOLFSSL_API +ed448_key* wolfSSL_ED448_new(void* heap, int devId); +WOLFSSL_API +void wolfSSL_ED448_free(ed448_key* key); +#endif + #ifdef HAVE_ED448_KEY_IMPORT WOLFSSL_API int wc_ed448_import_public(const byte* in, word32 inLen, ed448_key* key); From 8f73ae460dc1c33c3de825ab76404a98bb42491a Mon Sep 17 00:00:00 2001 From: Eric Blankenhorn Date: Fri, 10 Apr 2026 08:50:28 -0500 Subject: [PATCH 026/167] Fix TLSX_Parse to check dup ECH --- src/internal.c | 20 +++ src/tls.c | 3 + src/tls13.c | 8 +- tests/api.c | 222 ++++++++++++++++++++++++++++++ tests/api/test_tls13.c | 255 +++++++++++++++++++++++++++++++++++ tests/api/test_tls13.h | 4 + wolfcrypt/src/asn.c | 49 +++++-- wolfssl/error-ssl.h | 4 +- wolfssl/internal.h | 1 + wolfssl/wolfcrypt/settings.h | 10 ++ 10 files changed, 562 insertions(+), 14 deletions(-) diff --git a/src/internal.c b/src/internal.c index 267c75a5d6..53fb2ee052 100644 --- a/src/internal.c +++ b/src/internal.c @@ -21862,6 +21862,23 @@ int DoApplicationData(WOLFSSL* ssl, byte* input, word32* inOutIdx, int sniff) } #endif + /* Rate-limit empty application data records to prevent DoS */ + if (dataSz == 0) { + if (++ssl->options.emptyRecordCount >= WOLFSSL_MAX_EMPTY_RECORDS) { + WOLFSSL_MSG("Too many empty records"); +#ifdef WOLFSSL_EXTRA_ALERTS + if (sniff == NO_SNIFF) { + SendAlert(ssl, alert_fatal, unexpected_message); + } +#endif + WOLFSSL_ERROR_VERBOSE(EMPTY_RECORD_LIMIT_E); + return EMPTY_RECORD_LIMIT_E; + } + } + else { + ssl->options.emptyRecordCount = 0; + } + /* read data */ if (dataSz) { int rawSz = dataSz; /* keep raw size for idx adjustment */ @@ -27573,6 +27590,9 @@ const char* wolfSSL_ERR_reason_error_string(unsigned long e) case ALERT_COUNT_E: return "Alert Count exceeded error"; + case EMPTY_RECORD_LIMIT_E: + return "Too many empty records error"; + case EXT_MISSING: return "Required TLS extension missing"; diff --git a/src/tls.c b/src/tls.c index 02a0881352..d172699b3b 100644 --- a/src/tls.c +++ b/src/tls.c @@ -17043,6 +17043,9 @@ int TLSX_Parse(WOLFSSL* ssl, const byte* input, word16 length, byte msgType, #ifdef WOLFSSL_QUIC || (type == TLSX_KEY_QUIC_TP_PARAMS_DRAFT) #endif + #if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) + || (type == TLSX_ECH) + #endif #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_DUAL_ALG_CERTS) || (type == TLSX_CKS) #endif diff --git a/src/tls13.c b/src/tls13.c index b963ab0e3d..233a5b71a8 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -2638,9 +2638,10 @@ static int EncryptTls13(WOLFSSL* ssl, byte* output, const byte* input, #endif #ifdef WOLFSSL_CIPHER_TEXT_CHECK - if (ssl->specs.bulk_cipher_algorithm != wolfssl_cipher_null) { + if (ssl->specs.bulk_cipher_algorithm != wolfssl_cipher_null && + dataSz >= WOLFSSL_CIPHER_CHECK_SZ) { XMEMCPY(ssl->encrypt.sanityCheck, input, - min(dataSz, sizeof(ssl->encrypt.sanityCheck))); + sizeof(ssl->encrypt.sanityCheck)); } #endif @@ -2824,8 +2825,9 @@ static int EncryptTls13(WOLFSSL* ssl, byte* output, const byte* input, #ifdef WOLFSSL_CIPHER_TEXT_CHECK if (ssl->specs.bulk_cipher_algorithm != wolfssl_cipher_null && + dataSz >= WOLFSSL_CIPHER_CHECK_SZ && XMEMCMP(output, ssl->encrypt.sanityCheck, - min(dataSz, sizeof(ssl->encrypt.sanityCheck))) == 0) { + sizeof(ssl->encrypt.sanityCheck)) == 0) { WOLFSSL_MSG("EncryptTls13 sanity check failed! Glitch?"); return ENCRYPT_ERROR; diff --git a/tests/api.c b/tests/api.c index 0e9cbe2982..0e02c40676 100644 --- a/tests/api.c +++ b/tests/api.c @@ -21402,6 +21402,226 @@ static int test_MakeCertWithPathLen(void) return EXPECT_RESULT(); } +static int test_PathLenSelfIssued(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_CERT_REQ) && !defined(NO_ASN_TIME) && \ + defined(WOLFSSL_CERT_GEN) && defined(HAVE_ECC) && \ + defined(WOLFSSL_CERT_EXT) && !defined(NO_CERTS) && \ + (!defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH)) + Cert cert; + DecodedCert decodedCert; + byte rootDer[FOURK_BUF]; + byte icaDer[FOURK_BUF]; + byte entityDer[FOURK_BUF]; + int rootDerSz = 0; + int icaDerSz = 0; + int entityDerSz = 0; + WC_RNG rng; + ecc_key rootKey; + ecc_key icaKey; + ecc_key entityKey; + WOLFSSL_CERT_MANAGER* cm = NULL; + + XMEMSET(&rng, 0, sizeof(WC_RNG)); + XMEMSET(&rootKey, 0, sizeof(ecc_key)); + XMEMSET(&icaKey, 0, sizeof(ecc_key)); + XMEMSET(&entityKey, 0, sizeof(ecc_key)); + + ExpectIntEQ(wc_InitRng(&rng), 0); + ExpectIntEQ(wc_ecc_init(&rootKey), 0); + ExpectIntEQ(wc_ecc_init(&icaKey), 0); + ExpectIntEQ(wc_ecc_init(&entityKey), 0); + ExpectIntEQ(wc_ecc_make_key(&rng, 32, &rootKey), 0); + ExpectIntEQ(wc_ecc_make_key(&rng, 32, &icaKey), 0); + ExpectIntEQ(wc_ecc_make_key(&rng, 32, &entityKey), 0); + + /* Step 1: Create root CA with pathLen=0 */ + ExpectIntEQ(wc_InitCert(&cert), 0); + (void)XSTRNCPY(cert.subject.country, "US", CTC_NAME_SIZE); + (void)XSTRNCPY(cert.subject.state, "MT", CTC_NAME_SIZE); + (void)XSTRNCPY(cert.subject.locality, "Bozeman", CTC_NAME_SIZE); + (void)XSTRNCPY(cert.subject.org, "TestCA", CTC_NAME_SIZE); + (void)XSTRNCPY(cert.subject.unit, "Test", CTC_NAME_SIZE); + (void)XSTRNCPY(cert.subject.commonName, "TestRootCA", CTC_NAME_SIZE); + (void)XSTRNCPY(cert.subject.email, "root@test.com", CTC_NAME_SIZE); + cert.selfSigned = 1; + cert.isCA = 1; + cert.pathLen = 0; + cert.pathLenSet = 1; + cert.sigType = CTC_SHA256wECDSA; + cert.keyUsage = KEYUSE_KEY_CERT_SIGN | KEYUSE_CRL_SIGN; + ExpectIntEQ(wc_SetSubjectKeyIdFromPublicKey_ex(&cert, ECC_TYPE, &rootKey), + 0); + + ExpectIntGE(wc_MakeCert(&cert, rootDer, FOURK_BUF, NULL, &rootKey, &rng), + 0); + ExpectIntGE(rootDerSz = wc_SignCert(cert.bodySz, cert.sigType, rootDer, + FOURK_BUF, NULL, &rootKey, &rng), 0); + + /* Step 2: Create self-issued intermediate (same subject DN as root, + * different key, signed by root) - this should be blocked by pathLen=0 */ + ExpectIntEQ(wc_InitCert(&cert), 0); + cert.selfSigned = 0; + cert.isCA = 1; + cert.sigType = CTC_SHA256wECDSA; + cert.keyUsage = KEYUSE_KEY_CERT_SIGN | KEYUSE_CRL_SIGN; + /* Set both subject and issuer from the root cert so they match */ + ExpectIntEQ(wc_SetSubjectBuffer(&cert, rootDer, rootDerSz), 0); + ExpectIntEQ(wc_SetIssuerBuffer(&cert, rootDer, rootDerSz), 0); + ExpectIntEQ(wc_SetAuthKeyIdFromPublicKey_ex(&cert, ECC_TYPE, &rootKey), 0); + ExpectIntEQ(wc_SetSubjectKeyIdFromPublicKey_ex(&cert, ECC_TYPE, &icaKey), + 0); + + ExpectIntGE(wc_MakeCert(&cert, icaDer, FOURK_BUF, NULL, &icaKey, &rng), 0); + ExpectIntGE(icaDerSz = wc_SignCert(cert.bodySz, cert.sigType, icaDer, + FOURK_BUF, NULL, &rootKey, &rng), 0); + + /* Step 3: Create entity cert signed by the intermediate */ + ExpectIntEQ(wc_InitCert(&cert), 0); + cert.selfSigned = 0; + cert.isCA = 0; + cert.sigType = CTC_SHA256wECDSA; + (void)XSTRNCPY(cert.subject.country, "US", CTC_NAME_SIZE); + (void)XSTRNCPY(cert.subject.state, "MT", CTC_NAME_SIZE); + (void)XSTRNCPY(cert.subject.locality, "Bozeman", CTC_NAME_SIZE); + (void)XSTRNCPY(cert.subject.org, "TestEntity", CTC_NAME_SIZE); + (void)XSTRNCPY(cert.subject.commonName, "entity.test", CTC_NAME_SIZE); + ExpectIntEQ(wc_SetIssuerBuffer(&cert, icaDer, icaDerSz), 0); + ExpectIntEQ(wc_SetAuthKeyIdFromPublicKey_ex(&cert, ECC_TYPE, &icaKey), 0); + + ExpectIntGE(wc_MakeCert(&cert, entityDer, FOURK_BUF, NULL, &entityKey, + &rng), 0); + ExpectIntGE(entityDerSz = wc_SignCert(cert.bodySz, cert.sigType, entityDer, + FOURK_BUF, NULL, &icaKey, &rng), 0); + + /* Step 4: Load root CA into cert manager */ + ExpectNotNull(cm = wolfSSL_CertManagerNew()); + ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, rootDer, rootDerSz, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + + /* Step 5: Parse the self-issued intermediate as a chain cert. + * This simulates TLS chain verification where the intermediate is + * received as part of the certificate chain. + * Root CA has pathLen=0, so it should NOT be allowed to sign any + * intermediate CA (including self-issued ones). + * BUG: wolfSSL sets selfSigned=1 for this cert (issuer==subject DN), + * which causes the pathLen enforcement to be entirely skipped. */ + wc_InitDecodedCert(&decodedCert, icaDer, (word32)icaDerSz, NULL); + ExpectIntEQ(wc_ParseCert(&decodedCert, CHAIN_CERT_TYPE, VERIFY, + cm), WC_NO_ERR_TRACE(ASN_PATHLEN_INV_E)); + wc_FreeDecodedCert(&decodedCert); + + wolfSSL_CertManagerFree(cm); + wc_ecc_free(&entityKey); + wc_ecc_free(&icaKey); + wc_ecc_free(&rootKey); + wc_FreeRng(&rng); +#endif + return EXPECT_RESULT(); +} + +static int test_PathLenNoKeyUsage(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_CERT_REQ) && !defined(NO_ASN_TIME) && \ + defined(WOLFSSL_CERT_GEN) && defined(HAVE_ECC) && \ + defined(WOLFSSL_CERT_EXT) && !defined(NO_CERTS) && \ + (!defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH)) + Cert cert; + DecodedCert decodedCert; + byte rootDer[FOURK_BUF]; + byte icaDer[FOURK_BUF]; + int rootDerSz = 0; + int icaDerSz = 0; + WC_RNG rng; + ecc_key rootKey; + ecc_key icaKey; + WOLFSSL_CERT_MANAGER* cm = NULL; + + XMEMSET(&rng, 0, sizeof(WC_RNG)); + XMEMSET(&rootKey, 0, sizeof(ecc_key)); + XMEMSET(&icaKey, 0, sizeof(ecc_key)); + + ExpectIntEQ(wc_InitRng(&rng), 0); + ExpectIntEQ(wc_ecc_init(&rootKey), 0); + ExpectIntEQ(wc_ecc_init(&icaKey), 0); + ExpectIntEQ(wc_ecc_make_key(&rng, 32, &rootKey), 0); + ExpectIntEQ(wc_ecc_make_key(&rng, 32, &icaKey), 0); + + /* Step 1: Create root CA with pathLen=0 and KeyUsage */ + ExpectIntEQ(wc_InitCert(&cert), 0); + (void)XSTRNCPY(cert.subject.country, "US", CTC_NAME_SIZE); + (void)XSTRNCPY(cert.subject.state, "MT", CTC_NAME_SIZE); + (void)XSTRNCPY(cert.subject.locality, "Bozeman", CTC_NAME_SIZE); + (void)XSTRNCPY(cert.subject.org, "TestCA2", CTC_NAME_SIZE); + (void)XSTRNCPY(cert.subject.unit, "Test", CTC_NAME_SIZE); + (void)XSTRNCPY(cert.subject.commonName, "TestRootCA2", CTC_NAME_SIZE); + (void)XSTRNCPY(cert.subject.email, "root@test2.com", CTC_NAME_SIZE); + cert.selfSigned = 1; + cert.isCA = 1; + cert.pathLen = 0; + cert.pathLenSet = 1; + cert.sigType = CTC_SHA256wECDSA; + cert.keyUsage = KEYUSE_KEY_CERT_SIGN | KEYUSE_CRL_SIGN; + ExpectIntEQ(wc_SetSubjectKeyIdFromPublicKey_ex(&cert, ECC_TYPE, &rootKey), + 0); + + ExpectIntGE(wc_MakeCert(&cert, rootDer, FOURK_BUF, NULL, &rootKey, &rng), + 0); + ExpectIntGE(rootDerSz = wc_SignCert(cert.bodySz, cert.sigType, rootDer, + FOURK_BUF, NULL, &rootKey, &rng), 0); + + /* Step 2: Create intermediate CA WITHOUT KeyUsage extension. + * Per RFC 5280, when KeyUsage is absent all uses are valid. + * The root's pathLen=0 should still block this intermediate CA. + * BUG: pathLen check requires extKeyUsageSet which is false when + * KeyUsage is absent, so the check is skipped entirely. */ + ExpectIntEQ(wc_InitCert(&cert), 0); + cert.selfSigned = 0; + cert.isCA = 1; + cert.sigType = CTC_SHA256wECDSA; + /* Intentionally do NOT set keyUsage - test that pathLen is still enforced */ + cert.keyUsage = 0; + (void)XSTRNCPY(cert.subject.country, "US", CTC_NAME_SIZE); + (void)XSTRNCPY(cert.subject.state, "MT", CTC_NAME_SIZE); + (void)XSTRNCPY(cert.subject.locality, "Bozeman", CTC_NAME_SIZE); + (void)XSTRNCPY(cert.subject.org, "TestICA", CTC_NAME_SIZE); + (void)XSTRNCPY(cert.subject.unit, "Test", CTC_NAME_SIZE); + (void)XSTRNCPY(cert.subject.commonName, "TestICA-NoKU", CTC_NAME_SIZE); + (void)XSTRNCPY(cert.subject.email, "ica@test2.com", CTC_NAME_SIZE); + ExpectIntEQ(wc_SetIssuerBuffer(&cert, rootDer, rootDerSz), 0); + ExpectIntEQ(wc_SetAuthKeyIdFromPublicKey_ex(&cert, ECC_TYPE, &rootKey), 0); + ExpectIntEQ(wc_SetSubjectKeyIdFromPublicKey_ex(&cert, ECC_TYPE, &icaKey), + 0); + + ExpectIntGE(wc_MakeCert(&cert, icaDer, FOURK_BUF, NULL, &icaKey, &rng), 0); + ExpectIntGE(icaDerSz = wc_SignCert(cert.bodySz, cert.sigType, icaDer, + FOURK_BUF, NULL, &rootKey, &rng), 0); + + /* Step 3: Load root CA into cert manager */ + ExpectNotNull(cm = wolfSSL_CertManagerNew()); + ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, rootDer, rootDerSz, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + + /* Step 4: Parse the intermediate (no KeyUsage) as a chain cert. + * Root CA has pathLen=0, this intermediate CA should be rejected. + * The intermediate does NOT have the KeyUsage extension, but per + * RFC 5280 4.2.1.3 all key uses are valid when the extension is + * absent, so pathLen must still be enforced. */ + wc_InitDecodedCert(&decodedCert, icaDer, (word32)icaDerSz, NULL); + ExpectIntEQ(wc_ParseCert(&decodedCert, CHAIN_CERT_TYPE, VERIFY, + cm), WC_NO_ERR_TRACE(ASN_PATHLEN_INV_E)); + wc_FreeDecodedCert(&decodedCert); + + wolfSSL_CertManagerFree(cm); + wc_ecc_free(&icaKey); + wc_ecc_free(&rootKey); + wc_FreeRng(&rng); +#endif + return EXPECT_RESULT(); +} + static int test_MakeCertWith0Ser(void) { EXPECT_DECLS; @@ -35277,6 +35497,8 @@ TEST_CASE testCases[] = { TEST_DECL(test_wc_ParseCert), TEST_DECL(test_wc_ParseCert_Error), TEST_DECL(test_MakeCertWithPathLen), + TEST_DECL(test_PathLenSelfIssued), + TEST_DECL(test_PathLenNoKeyUsage), TEST_DECL(test_MakeCertWith0Ser), TEST_DECL(test_MakeCertWithCaFalse), #ifdef WOLFSSL_CERT_SIGN_CB diff --git a/tests/api/test_tls13.c b/tests/api/test_tls13.c index 6c4de12a10..6963f3f707 100644 --- a/tests/api/test_tls13.c +++ b/tests/api/test_tls13.c @@ -2922,6 +2922,108 @@ int test_tls13_duplicate_extension(void) } +#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) && \ + !defined(NO_WOLFSSL_SERVER) && !defined(NO_FILESYSTEM) && \ + (!defined(NO_RSA) || defined(HAVE_ECC)) +static int DupEchSend(WOLFSSL* ssl, char* buf, int sz, void* ctx) +{ + (void)ssl; + (void)buf; + (void)sz; + (void)ctx; + + return sz; +} +static int DupEchRecv(WOLFSSL* ssl, char* buf, int sz, void* ctx) +{ + WOLFSSL_BUFFER_INFO* msg = (WOLFSSL_BUFFER_INFO*)ctx; + int len = (int)msg->length; + + (void)ssl; + (void)sz; + + if (len > sz) + len = sz; + XMEMCPY(buf, msg->buffer, len); + msg->buffer += len; + msg->length -= len; + + return len; +} +#endif + +/* Test detection of duplicate ECH extension (type 0xfe0d) in ClientHello. + * ECH has a semaphore mapping in TLSX_ToSemaphore() and needs to be included + * in the duplicate-detection gate in TLSX_Parse(). RFC 8446 section 4.2 + * requires rejecting messages with duplicate extensions. + */ +int test_tls13_duplicate_ech_extension(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) && \ + !defined(NO_WOLFSSL_SERVER) && !defined(NO_FILESYSTEM) && \ + (!defined(NO_RSA) || defined(HAVE_ECC)) + /* TLS 1.3 ClientHello with two ECH extensions (type 0xfe0d). + * Extensions block contains: supported_versions + ECH + ECH (dup). */ + const unsigned char clientHelloDupEch[] = { + 0x16, 0x03, 0x03, 0x00, 0x40, 0x01, 0x00, 0x00, + 0x3c, 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x02, 0x13, 0x01, + 0x01, 0x00, 0x00, 0x11, 0x00, 0x2b, 0x00, 0x03, + 0x02, 0x03, 0x04, 0xfe, 0x0d, 0x00, 0x01, 0x00, + 0xfe, 0x0d, 0x00, 0x01, 0x00 + }; + WOLFSSL_BUFFER_INFO msg; + const char* testCertFile; + const char* testKeyFile; + WOLFSSL_CTX *ctx = NULL; + WOLFSSL *ssl = NULL; + +#ifndef NO_RSA + testCertFile = svrCertFile; + testKeyFile = svrKeyFile; +#elif defined(HAVE_ECC) + testCertFile = eccCertFile; + testKeyFile = eccKeyFile; +#endif + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_server_method())); + + ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx, testCertFile, + CERT_FILETYPE)); + ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, testKeyFile, + CERT_FILETYPE)); + + /* Read from 'msg'. */ + wolfSSL_SetIORecv(ctx, DupEchRecv); + /* No where to send to - dummy sender. */ + wolfSSL_SetIOSend(ctx, DupEchSend); + + ssl = wolfSSL_new(ctx); + ExpectNotNull(ssl); + + msg.buffer = (unsigned char*)clientHelloDupEch; + msg.length = (unsigned int)sizeof(clientHelloDupEch); + wolfSSL_SetIOReadCtx(ssl, &msg); + + ExpectIntNE(wolfSSL_accept(ssl), WOLFSSL_SUCCESS); + /* Can return duplicate ext error or socket error if the peer closed + * down while sending alert. */ + if (wolfSSL_get_error(ssl, 0) != WC_NO_ERR_TRACE(SOCKET_ERROR_E)) { + ExpectIntEQ(wolfSSL_get_error(ssl, 0), + WC_NO_ERR_TRACE(DUPLICATE_TLS_EXT_E)); + } + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + + int test_key_share_mismatch(void) { EXPECT_DECLS; @@ -3677,6 +3779,159 @@ int test_tls13_pqc_hybrid_truncated_keyshare(void) * (32 bytes) does not cause an unsigned integer underflow / OOB read in * SetTicket. Uses a full memio handshake, then injects a crafted * NewSessionTicket with a 5-byte ticket into the client's read path. */ +int test_tls13_empty_record_limit(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_TLS13) + struct test_memio_ctx test_ctx; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + int recSz; + int numRecs = WOLFSSL_MAX_EMPTY_RECORDS + 1; + byte rec[128]; /* buffer for one encrypted record */ + byte *allRecs = NULL; + int i; + char buf[64]; + + /* Test 1: Exceeding the empty record limit returns an error. */ + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0); + + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + /* Consume any post-handshake messages (e.g. NewSessionTicket). */ + wolfSSL_read(ssl_c, buf, sizeof(buf)); + test_memio_clear_buffer(&test_ctx, 0); + test_memio_clear_buffer(&test_ctx, 1); + + /* Get the size of an encrypted zero-length app data record. */ + recSz = BuildTls13Message(ssl_c, NULL, 0, NULL, 0, + application_data, 0, 1, 0); + ExpectIntGT(recSz, 0); + ExpectIntLE(recSz, (int)sizeof(rec)); + + /* Build all empty records into one contiguous buffer. */ + if (EXPECT_SUCCESS()) { + allRecs = (byte*)XMALLOC((size_t)(recSz * numRecs), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + ExpectNotNull(allRecs); + } + + for (i = 0; i < numRecs && EXPECT_SUCCESS(); i++) { + XMEMSET(rec, 0, sizeof(rec)); + ExpectIntEQ(BuildTls13Message(ssl_c, rec, (int)sizeof(rec), rec + + RECORD_HEADER_SZ, 0, application_data, 0, 0, 0), + recSz); + XMEMCPY(allRecs + i * recSz, rec, (size_t)recSz); + } + + /* Inject all records as a single message. */ + ExpectIntEQ(test_memio_inject_message(&test_ctx, 0, (const char*)allRecs, + recSz * numRecs), 0); + + /* The server's wolfSSL_read should fail with EMPTY_RECORD_LIMIT_E. */ + ExpectIntEQ(wolfSSL_read(ssl_s, buf, sizeof(buf)), + WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)); + ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR), + WC_NO_ERR_TRACE(EMPTY_RECORD_LIMIT_E)); + + XFREE(allRecs, NULL, DYNAMIC_TYPE_TMP_BUFFER); + allRecs = NULL; + wolfSSL_free(ssl_c); + ssl_c = NULL; + wolfSSL_free(ssl_s); + ssl_s = NULL; + wolfSSL_CTX_free(ctx_c); + ctx_c = NULL; + wolfSSL_CTX_free(ctx_s); + ctx_s = NULL; + + /* Test 2: Counter resets on non-empty record. + * Send (limit - 1) empty records, then 1 non-empty, then (limit - 1) + * more empty records. Should succeed without hitting the limit. */ + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0); + + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + wolfSSL_read(ssl_c, buf, sizeof(buf)); + test_memio_clear_buffer(&test_ctx, 0); + test_memio_clear_buffer(&test_ctx, 1); + + recSz = BuildTls13Message(ssl_c, NULL, 0, NULL, 0, + application_data, 0, 1, 0); + ExpectIntGT(recSz, 0); + + { + int emptyBefore = WOLFSSL_MAX_EMPTY_RECORDS - 1; + int emptyAfter = WOLFSSL_MAX_EMPTY_RECORDS - 1; + int dataRecSz; + byte dataRec[128]; + byte payload[1] = { 'a' }; + int totalSz; + + dataRecSz = BuildTls13Message(ssl_c, NULL, 0, NULL, 1, + application_data, 0, 1, 0); + ExpectIntGT(dataRecSz, 0); + + totalSz = recSz * (emptyBefore + emptyAfter) + dataRecSz; + if (EXPECT_SUCCESS()) { + allRecs = (byte*)XMALLOC((size_t)totalSz, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + ExpectNotNull(allRecs); + } + + /* Build (limit - 1) empty records */ + for (i = 0; i < emptyBefore && EXPECT_SUCCESS(); i++) { + XMEMSET(rec, 0, sizeof(rec)); + ExpectIntEQ(BuildTls13Message(ssl_c, rec, (int)sizeof(rec), + rec + RECORD_HEADER_SZ, 0, application_data, + 0, 0, 0), recSz); + XMEMCPY(allRecs + i * recSz, rec, (size_t)recSz); + } + + /* Build 1 non-empty record */ + if (EXPECT_SUCCESS()) { + XMEMSET(dataRec, 0, sizeof(dataRec)); + XMEMCPY(dataRec + RECORD_HEADER_SZ, payload, sizeof(payload)); + ExpectIntEQ(BuildTls13Message(ssl_c, dataRec, (int)sizeof(dataRec), + dataRec + RECORD_HEADER_SZ, 1, application_data, + 0, 0, 0), dataRecSz); + XMEMCPY(allRecs + emptyBefore * recSz, dataRec, + (size_t)dataRecSz); + } + + /* Build (limit - 1) more empty records */ + for (i = 0; i < emptyAfter && EXPECT_SUCCESS(); i++) { + XMEMSET(rec, 0, sizeof(rec)); + ExpectIntEQ(BuildTls13Message(ssl_c, rec, (int)sizeof(rec), + rec + RECORD_HEADER_SZ, 0, application_data, + 0, 0, 0), recSz); + XMEMCPY(allRecs + emptyBefore * recSz + dataRecSz + i * recSz, + rec, (size_t)recSz); + } + + ExpectIntEQ(test_memio_inject_message(&test_ctx, 0, + (const char*)allRecs, totalSz), 0); + } + + /* wolfSSL_read should return the 1-byte payload. The counter resets + * on the non-empty record so neither batch of (limit - 1) empties + * triggers the error. */ + ExpectIntEQ(wolfSSL_read(ssl_s, buf, sizeof(buf)), 1); + ExpectIntEQ(buf[0], 'a'); + + XFREE(allRecs, NULL, DYNAMIC_TYPE_TMP_BUFFER); + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + int test_tls13_short_session_ticket(void) { EXPECT_DECLS; diff --git a/tests/api/test_tls13.h b/tests/api/test_tls13.h index fd40bdc868..d116845edc 100644 --- a/tests/api/test_tls13.h +++ b/tests/api/test_tls13.h @@ -36,6 +36,7 @@ int test_tls13_ch2_different_cs(void); int test_tls13_sg_missing(void); int test_tls13_ks_missing(void); int test_tls13_duplicate_extension(void); +int test_tls13_duplicate_ech_extension(void); int test_key_share_mismatch(void); int test_tls13_middlebox_compat_empty_session_id(void); int test_tls13_plaintext_alert(void); @@ -44,6 +45,7 @@ int test_tls13_unknown_ext_rejected(void); int test_tls13_cert_req_sigalgs(void); int test_tls13_derive_keys_no_key(void); int test_tls13_pqc_hybrid_truncated_keyshare(void); +int test_tls13_empty_record_limit(void); int test_tls13_short_session_ticket(void); #define TEST_TLS13_DECLS \ @@ -59,6 +61,7 @@ int test_tls13_short_session_ticket(void); TEST_DECL_GROUP("tls13", test_tls13_sg_missing), \ TEST_DECL_GROUP("tls13", test_tls13_ks_missing), \ TEST_DECL_GROUP("tls13", test_tls13_duplicate_extension), \ + TEST_DECL_GROUP("tls13", test_tls13_duplicate_ech_extension), \ TEST_DECL_GROUP("tls13", test_key_share_mismatch), \ TEST_DECL_GROUP("tls13", test_tls13_middlebox_compat_empty_session_id), \ TEST_DECL_GROUP("tls13", test_tls13_plaintext_alert), \ @@ -66,6 +69,7 @@ int test_tls13_short_session_ticket(void); TEST_DECL_GROUP("tls13", test_tls13_cert_req_sigalgs), \ TEST_DECL_GROUP("tls13", test_tls13_derive_keys_no_key), \ TEST_DECL_GROUP("tls13", test_tls13_pqc_hybrid_truncated_keyshare), \ + TEST_DECL_GROUP("tls13", test_tls13_empty_record_limit), \ TEST_DECL_GROUP("tls13", test_tls13_short_session_ticket), \ TEST_DECL_GROUP("tls13", test_tls13_unknown_ext_rejected) diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index dc0c9ecfec..a150998a72 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -22425,16 +22425,24 @@ int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm, if (cert->pathLengthSet) cert->maxPathLen = cert->pathLength; - if (!cert->selfSigned) { - /* Need to perform a pathlen check on anything that will be used - * to sign certificates later on. Otherwise, pathLen doesn't - * mean anything. - * Nothing to check if we don't have the issuer of this cert. */ - if (type != CERT_TYPE && cert->isCA && cert->extKeyUsageSet && - (cert->extKeyUsage & KEYUSE_KEY_CERT_SIGN) != 0 && cert->ca) { + /* RFC 5280 6.1.4: Check issuer's pathLen constraint. + * Need to perform a pathlen check on anything that will be used + * to sign certificates later on. Otherwise, pathLen doesn't + * mean anything. + * Nothing to check if we don't have the issuer of this cert. + * + * Per RFC 5280, when the KeyUsage extension is absent, all key + * uses are implicitly valid (including keyCertSign), so pathLen + * enforcement must not be gated on KeyUsage presence. */ + if (type != CERT_TYPE && cert->isCA && cert->ca && + (!cert->extKeyUsageSet || + (cert->extKeyUsage & KEYUSE_KEY_CERT_SIGN) != 0)) { + if (!cert->selfSigned) { + /* RFC 5280 6.1.4(l): Non-self-issued cert decrements and + * checks the issuer's max_path_length. */ if (cert->ca->maxPathLen == 0) { - /* This cert CAN NOT be used as an intermediate cert. The - * issuer does not allow it. */ + /* This cert CAN NOT be used as an intermediate cert. + * The issuer does not allow it. */ cert->maxPathLen = 0; if (verify != NO_VERIFY) { WOLFSSL_MSG("\tNon-entity cert, maxPathLen is 0"); @@ -22444,7 +22452,28 @@ int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm, } } else { - cert->maxPathLen = (byte)min(cert->ca->maxPathLen - 1U, + cert->maxPathLen = (word16)min(cert->ca->maxPathLen - 1U, + cert->maxPathLen); + } + } + else { + /* RFC 5280 6.1.4(l): Self-issued certs do NOT decrement + * max_path_length, but the issuer's constraint still + * applies. A self-issued cert from a CA with maxPathLen=0 + * cannot act as an intermediate CA. */ + if (cert->ca->maxPathLen == 0) { + cert->maxPathLen = 0; + if (verify != NO_VERIFY) { + WOLFSSL_MSG("\tSelf-issued cert, maxPathLen is 0"); + WOLFSSL_MSG("\tmaxPathLen status: ERROR"); + WOLFSSL_ERROR_VERBOSE(ASN_PATHLEN_INV_E); + return ASN_PATHLEN_INV_E; + } + } + else { + /* Self-issued: honor issuer's constraint without + * decrementing. */ + cert->maxPathLen = (word16)min(cert->ca->maxPathLen, cert->maxPathLen); } } diff --git a/wolfssl/error-ssl.h b/wolfssl/error-ssl.h index 832ae9f440..4559a41f39 100644 --- a/wolfssl/error-ssl.h +++ b/wolfssl/error-ssl.h @@ -240,7 +240,9 @@ enum wolfSSL_ErrorCodes { SESSION_TICKET_NONCE_OVERFLOW = -517, /* Session ticket nonce overflow */ - WOLFSSL_LAST_E = -517 + EMPTY_RECORD_LIMIT_E = -518, /* Too many empty records received */ + + WOLFSSL_LAST_E = -518 /* codes -1000 to -1999 are reserved for wolfCrypt. */ }; diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 2450331aac..0234bb8f52 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -5216,6 +5216,7 @@ struct Options { byte asyncState; /* sub-state for enum asyncState */ byte buildMsgState; /* sub-state for enum buildMsgState */ byte alertCount; /* detect warning dos attempt */ + byte emptyRecordCount; /* detect empty record dos attempt */ #ifdef WOLFSSL_MULTICAST word16 mcastID; /* Multicast group ID */ #endif diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index b7552d1e52..334bc7c723 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -4143,6 +4143,16 @@ extern void uITRON4_free(void *p) ; #ifndef WOLFSSL_ALERT_COUNT_MAX #define WOLFSSL_ALERT_COUNT_MAX 5 #endif +#if WOLFSSL_ALERT_COUNT_MAX > 255 + #error "WOLFSSL_ALERT_COUNT_MAX must be <= 255 (stored in a byte)" +#endif + +#ifndef WOLFSSL_MAX_EMPTY_RECORDS + #define WOLFSSL_MAX_EMPTY_RECORDS 32 +#endif +#if WOLFSSL_MAX_EMPTY_RECORDS > 255 + #error "WOLFSSL_MAX_EMPTY_RECORDS must be <= 255 (stored in a byte)" +#endif /* Enable blinding by default for C-only, non-small curve25519 implementation */ #if defined(HAVE_CURVE25519) && !defined(CURVE25519_SMALL) && \ From 415c2889655cdeaff77acb2c829008c66c77f68e Mon Sep 17 00:00:00 2001 From: Eric Blankenhorn Date: Tue, 14 Apr 2026 08:14:55 -0500 Subject: [PATCH 027/167] Fix from review --- tests/api.c | 101 +++++++++++++++++++++++++++++++++++++++++ tests/api/test_tls13.c | 6 ++- 2 files changed, 106 insertions(+), 1 deletion(-) diff --git a/tests/api.c b/tests/api.c index 0e02c40676..0fb8ecdaaf 100644 --- a/tests/api.c +++ b/tests/api.c @@ -21521,6 +21521,106 @@ static int test_PathLenSelfIssued(void) return EXPECT_RESULT(); } +/* Verifies that a self-issued intermediate under a CA with pathLen > 0 is + * accepted AND that maxPathLen is propagated as min(ca->maxPathLen, + * cert->pathLength) without being decremented (RFC 5280 6.1.4(l)). + * Pins the `else` branch in asn.c so deletion or an accidental decrement + * (like the non-self-issued path) is detected. */ +static int test_PathLenSelfIssuedAllowed(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_CERT_REQ) && !defined(NO_ASN_TIME) && \ + defined(WOLFSSL_CERT_GEN) && defined(HAVE_ECC) && \ + defined(WOLFSSL_CERT_EXT) && !defined(NO_CERTS) && \ + (!defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH)) + Cert cert; + DecodedCert decodedCert; + byte rootDer[FOURK_BUF]; + byte icaDer[FOURK_BUF]; + int rootDerSz = 0; + int icaDerSz = 0; + WC_RNG rng; + ecc_key rootKey; + ecc_key icaKey; + WOLFSSL_CERT_MANAGER* cm = NULL; + + XMEMSET(&rng, 0, sizeof(WC_RNG)); + XMEMSET(&rootKey, 0, sizeof(ecc_key)); + XMEMSET(&icaKey, 0, sizeof(ecc_key)); + + ExpectIntEQ(wc_InitRng(&rng), 0); + ExpectIntEQ(wc_ecc_init(&rootKey), 0); + ExpectIntEQ(wc_ecc_init(&icaKey), 0); + ExpectIntEQ(wc_ecc_make_key(&rng, 32, &rootKey), 0); + ExpectIntEQ(wc_ecc_make_key(&rng, 32, &icaKey), 0); + + /* Step 1: Create root CA with pathLen=1 */ + ExpectIntEQ(wc_InitCert(&cert), 0); + (void)XSTRNCPY(cert.subject.country, "US", CTC_NAME_SIZE); + (void)XSTRNCPY(cert.subject.state, "MT", CTC_NAME_SIZE); + (void)XSTRNCPY(cert.subject.locality, "Bozeman", CTC_NAME_SIZE); + (void)XSTRNCPY(cert.subject.org, "TestCA3", CTC_NAME_SIZE); + (void)XSTRNCPY(cert.subject.unit, "Test", CTC_NAME_SIZE); + (void)XSTRNCPY(cert.subject.commonName, "TestRootCA3", CTC_NAME_SIZE); + (void)XSTRNCPY(cert.subject.email, "root@test3.com", CTC_NAME_SIZE); + cert.selfSigned = 1; + cert.isCA = 1; + cert.pathLen = 1; + cert.pathLenSet = 1; + cert.sigType = CTC_SHA256wECDSA; + cert.keyUsage = KEYUSE_KEY_CERT_SIGN | KEYUSE_CRL_SIGN; + ExpectIntEQ(wc_SetSubjectKeyIdFromPublicKey_ex(&cert, ECC_TYPE, &rootKey), + 0); + + ExpectIntGE(wc_MakeCert(&cert, rootDer, FOURK_BUF, NULL, &rootKey, &rng), + 0); + ExpectIntGE(rootDerSz = wc_SignCert(cert.bodySz, cert.sigType, rootDer, + FOURK_BUF, NULL, &rootKey, &rng), 0); + + /* Step 2: Create a self-issued intermediate with its OWN pathLen=5. + * The intentionally-larger pathLen lets the test distinguish: + * - Correct self-issued path: maxPathLen = min(1, 5) = 1 + * - Deleted else branch: maxPathLen stays at 5 (cert->pathLength) + * - Mutated to decrement: maxPathLen = min(0, 5) = 0 */ + ExpectIntEQ(wc_InitCert(&cert), 0); + cert.selfSigned = 0; + cert.isCA = 1; + cert.pathLen = 5; + cert.pathLenSet = 1; + cert.sigType = CTC_SHA256wECDSA; + cert.keyUsage = KEYUSE_KEY_CERT_SIGN | KEYUSE_CRL_SIGN; + /* Same subject/issuer DN as root -> self-issued */ + ExpectIntEQ(wc_SetSubjectBuffer(&cert, rootDer, rootDerSz), 0); + ExpectIntEQ(wc_SetIssuerBuffer(&cert, rootDer, rootDerSz), 0); + ExpectIntEQ(wc_SetAuthKeyIdFromPublicKey_ex(&cert, ECC_TYPE, &rootKey), 0); + ExpectIntEQ(wc_SetSubjectKeyIdFromPublicKey_ex(&cert, ECC_TYPE, &icaKey), + 0); + + ExpectIntGE(wc_MakeCert(&cert, icaDer, FOURK_BUF, NULL, &icaKey, &rng), 0); + ExpectIntGE(icaDerSz = wc_SignCert(cert.bodySz, cert.sigType, icaDer, + FOURK_BUF, NULL, &rootKey, &rng), 0); + + /* Step 3: Load root CA into cert manager */ + ExpectNotNull(cm = wolfSSL_CertManagerNew()); + ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, rootDer, rootDerSz, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + + /* Step 4: Parse the self-issued intermediate. Must be accepted AND + * maxPathLen must be exactly 1 (honors root's constraint without + * decrementing). */ + wc_InitDecodedCert(&decodedCert, icaDer, (word32)icaDerSz, NULL); + ExpectIntEQ(wc_ParseCert(&decodedCert, CHAIN_CERT_TYPE, VERIFY, cm), 0); + ExpectIntEQ(decodedCert.maxPathLen, 1); + wc_FreeDecodedCert(&decodedCert); + + wolfSSL_CertManagerFree(cm); + wc_ecc_free(&icaKey); + wc_ecc_free(&rootKey); + wc_FreeRng(&rng); +#endif + return EXPECT_RESULT(); +} + static int test_PathLenNoKeyUsage(void) { EXPECT_DECLS; @@ -35498,6 +35598,7 @@ TEST_CASE testCases[] = { TEST_DECL(test_wc_ParseCert_Error), TEST_DECL(test_MakeCertWithPathLen), TEST_DECL(test_PathLenSelfIssued), + TEST_DECL(test_PathLenSelfIssuedAllowed), TEST_DECL(test_PathLenNoKeyUsage), TEST_DECL(test_MakeCertWith0Ser), TEST_DECL(test_MakeCertWithCaFalse), diff --git a/tests/api/test_tls13.c b/tests/api/test_tls13.c index 6963f3f707..fd1167dc76 100644 --- a/tests/api/test_tls13.c +++ b/tests/api/test_tls13.c @@ -3787,7 +3787,11 @@ int test_tls13_empty_record_limit(void) WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; WOLFSSL *ssl_c = NULL, *ssl_s = NULL; int recSz; - int numRecs = WOLFSSL_MAX_EMPTY_RECORDS + 1; + /* Send exactly WOLFSSL_MAX_EMPTY_RECORDS to pin the boundary check. + * The Nth record increments the counter to N, and `N >= N` triggers + * the error. Sending one more would let a `>=` -> `>` mutation survive + * (the extra record would still trip the mutated check). */ + int numRecs = WOLFSSL_MAX_EMPTY_RECORDS; byte rec[128]; /* buffer for one encrypted record */ byte *allRecs = NULL; int i; From 0c0c426875b79b1835290fb529a0fe68ed86088b Mon Sep 17 00:00:00 2001 From: Eric Blankenhorn Date: Tue, 14 Apr 2026 09:35:29 -0500 Subject: [PATCH 028/167] Fix from review --- src/tls13.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tls13.c b/src/tls13.c index 233a5b71a8..1d932a56eb 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -2639,9 +2639,9 @@ static int EncryptTls13(WOLFSSL* ssl, byte* output, const byte* input, #ifdef WOLFSSL_CIPHER_TEXT_CHECK if (ssl->specs.bulk_cipher_algorithm != wolfssl_cipher_null && - dataSz >= WOLFSSL_CIPHER_CHECK_SZ) { + dataSz > 0) { XMEMCPY(ssl->encrypt.sanityCheck, input, - sizeof(ssl->encrypt.sanityCheck)); + min(dataSz, sizeof(ssl->encrypt.sanityCheck))); } #endif @@ -2825,9 +2825,9 @@ static int EncryptTls13(WOLFSSL* ssl, byte* output, const byte* input, #ifdef WOLFSSL_CIPHER_TEXT_CHECK if (ssl->specs.bulk_cipher_algorithm != wolfssl_cipher_null && - dataSz >= WOLFSSL_CIPHER_CHECK_SZ && + dataSz > 0 && XMEMCMP(output, ssl->encrypt.sanityCheck, - sizeof(ssl->encrypt.sanityCheck)) == 0) { + min(dataSz, sizeof(ssl->encrypt.sanityCheck))) == 0) { WOLFSSL_MSG("EncryptTls13 sanity check failed! Glitch?"); return ENCRYPT_ERROR; From 9a161a69f2246026da9d210fb5d364f661ed5f26 Mon Sep 17 00:00:00 2001 From: sebastian-carpenter Date: Wed, 15 Apr 2026 09:31:22 -0600 Subject: [PATCH 029/167] extra overflow clamp --- src/tls.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tls.c b/src/tls.c index 4096dc6bfc..0e030a725a 100644 --- a/src/tls.c +++ b/src/tls.c @@ -14091,6 +14091,9 @@ static int TLSX_ECH_ExpandOuterExtensions(WOLFSSL* ssl, WOLFSSL_ECH* ech, newInnerChLen = innerChLen - echOuterExtLen + extraSize - sessionIdLen + ssl->session->sessionIDSz; + if (newInnerChLen > 0xFFFF) { + return BUFFER_E; + } if (!foundEchOuter && sessionIdLen == ssl->session->sessionIDSz) { /* no extensions + no sessionID to copy */ From b96a83699ba12ba373a4b47f84b4a5d5fff6e649 Mon Sep 17 00:00:00 2001 From: Anthony Hu Date: Wed, 15 Apr 2026 11:47:56 -0400 Subject: [PATCH 030/167] Guarding fix --- tests/api/test_ossl_x509_str.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/api/test_ossl_x509_str.c b/tests/api/test_ossl_x509_str.c index 6beaa37d1e..370257d04a 100644 --- a/tests/api/test_ossl_x509_str.c +++ b/tests/api/test_ossl_x509_str.c @@ -1853,7 +1853,7 @@ int test_wolfSSL_CTX_set_cert_store(void) { EXPECT_DECLS; #if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && !defined(NO_FILESYSTEM) && \ - !defined(NO_WOLFSSL_CLIENT) + !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS) SSL_CTX* ctx = NULL; X509_STORE* store = NULL; X509* rootCa = NULL; From 36931c8b98876527c0095772928eb473a71917a5 Mon Sep 17 00:00:00 2001 From: Kareem Date: Mon, 6 Apr 2026 12:42:35 -0700 Subject: [PATCH 031/167] Ensure the SNI extension has at least OPAQUE16_LEN bytes in TLSX_SNI_GetFromBuffer. Thanks to Zou Dikai for the report. --- src/tls.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tls.c b/src/tls.c index 02a0881352..e9c198cec7 100644 --- a/src/tls.c +++ b/src/tls.c @@ -2800,6 +2800,9 @@ int TLSX_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz, } else { word16 listLen; + if (extLen < OPAQUE16_LEN) + return BUFFER_ERROR; + ato16(clientHello + offset, &listLen); offset += OPAQUE16_LEN; From d0a0c32204846009855debf36f365d668b0d723c Mon Sep 17 00:00:00 2001 From: Kareem Date: Mon, 6 Apr 2026 14:23:17 -0700 Subject: [PATCH 032/167] Prevent cert chain count from exceeding array max size when calling WriteCSRToBuffer. Thanks to Zou Dikai for the report. --- src/tls13.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/tls13.c b/src/tls13.c index b963ab0e3d..75321d8487 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -8882,7 +8882,7 @@ static word32 NextCert(byte* data, word32 length, word32* idx) * extIdx The index number of certificate status request data * for the certificate. * offset index offset - * returns Total number of bytes written. + * returns Total number of bytes written on success or negative value on error. */ static int WriteCSRToBuffer(WOLFSSL* ssl, DerBuffer** certExts, word16* extSz, word16 extSz_num) @@ -8897,6 +8897,9 @@ static int WriteCSRToBuffer(WOLFSSL* ssl, DerBuffer** certExts, word32 extIdx; DerBuffer* der; + if (extSz_num > MAX_CERT_EXTENSIONS) + return BAD_FUNC_ARG; + ext = TLSX_Find(ssl->extensions, TLSX_STATUS_REQUEST); csr = ext ? (CertificateStatusRequest*)ext->data : NULL; @@ -9148,8 +9151,11 @@ static int SendTls13Certificate(WOLFSSL* ssl) if (ret != 0) return ret; - ret = WriteCSRToBuffer(ssl, &ssl->buffers.certExts[0], &extSz[0], - 1 /* +1 for leaf */ + (word16)ssl->buffers.certChainCnt); + if ((word16)(1 + ssl->buffers.certChainCnt) > MAX_CERT_EXTENSIONS) + ret = BAD_FUNC_ARG; + if (ret == 0) + ret = WriteCSRToBuffer(ssl, &ssl->buffers.certExts[0], &extSz[0], + 1 /* +1 for leaf */ + (word16)ssl->buffers.certChainCnt); if (ret < 0) return ret; totalextSz += ret; From 5d0e050271f0b5e4dbce9b6915e3dd8cc2593b57 Mon Sep 17 00:00:00 2001 From: Kareem Date: Mon, 6 Apr 2026 15:17:30 -0700 Subject: [PATCH 033/167] Ensure ProcessChainOCSPRequest does not exceed the length of the cert chain. Thanks to Zou Dikai for the report. --- src/tls.c | 6 ++++++ src/tls13.c | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/tls.c b/src/tls.c index e9c198cec7..c727ed8f82 100644 --- a/src/tls.c +++ b/src/tls.c @@ -3614,6 +3614,12 @@ int ProcessChainOCSPRequest(WOLFSSL* ssl) if (chain && chain->buffer) { while (ret == 0 && pos + OPAQUE24_LEN < chain->length) { + if (i >= MAX_CERT_EXTENSIONS) { + WOLFSSL_MSG("OCSP request cert chain exceeds maximum length."); + ret = MAX_CERT_EXTENSIONS_ERR; + break; + } + c24to32(chain->buffer + pos, &der.length); pos += OPAQUE24_LEN; der.buffer = chain->buffer + pos; diff --git a/src/tls13.c b/src/tls13.c index 75321d8487..cbccb77bc5 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -8898,7 +8898,7 @@ static int WriteCSRToBuffer(WOLFSSL* ssl, DerBuffer** certExts, DerBuffer* der; if (extSz_num > MAX_CERT_EXTENSIONS) - return BAD_FUNC_ARG; + return MAX_CERT_EXTENSIONS_ERR; ext = TLSX_Find(ssl->extensions, TLSX_STATUS_REQUEST); csr = ext ? (CertificateStatusRequest*)ext->data : NULL; @@ -9152,7 +9152,7 @@ static int SendTls13Certificate(WOLFSSL* ssl) return ret; if ((word16)(1 + ssl->buffers.certChainCnt) > MAX_CERT_EXTENSIONS) - ret = BAD_FUNC_ARG; + ret = MAX_CERT_EXTENSIONS_ERR; if (ret == 0) ret = WriteCSRToBuffer(ssl, &ssl->buffers.certExts[0], &extSz[0], 1 /* +1 for leaf */ + (word16)ssl->buffers.certChainCnt); From 78abd541ec91cb6f4e2a7e9c6593bff0191a73ba Mon Sep 17 00:00:00 2001 From: Kareem Date: Mon, 6 Apr 2026 15:30:00 -0700 Subject: [PATCH 034/167] Enforce max size of responses array in SendCertificateStatus. Thanks to Zou Dikai for the report. --- src/internal.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/internal.c b/src/internal.c index a061851669..4bbb22ceba 100644 --- a/src/internal.c +++ b/src/internal.c @@ -25925,6 +25925,10 @@ int SendCertificateStatus(WOLFSSL* ssl) if (idx > chain->length) break; + if ((i + 1) >= MAX_CERT_EXTENSIONS) { + ret = MAX_CERT_EXTENSIONS_ERR; + break; + } ret = CreateOcspRequest(ssl, request, cert, der.buffer, der.length, &ctxOwnsRequest); if (ret == 0) { @@ -25953,6 +25957,11 @@ int SendCertificateStatus(WOLFSSL* ssl) else { while (ret == 0 && NULL != (request = ssl->ctx->chainOcspRequest[i])) { + if ((i + 1) >= MAX_CERT_EXTENSIONS) { + ret = MAX_CERT_EXTENSIONS_ERR; + break; + } + request->ssl = ssl; ret = CheckOcspRequest(SSL_CM(ssl)->ocsp_stapling, request, &responses[++i], ssl->heap); From d6c62cca60fd30cbb8878bfce8c497acc74a308d Mon Sep 17 00:00:00 2001 From: Kareem Date: Mon, 6 Apr 2026 15:47:33 -0700 Subject: [PATCH 035/167] In SSL sniffer, ensure the ClientHello extension length is sufficient to read the length before attempting the actual read. Thanks to Zou Dikai for the report. --- src/sniffer.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/sniffer.c b/src/sniffer.c index e8664721b1..daad3d297c 100644 --- a/src/sniffer.c +++ b/src/sniffer.c @@ -4195,6 +4195,9 @@ static int ProcessClientHello(const byte* input, int* sslBytes, { word16 listLen = 0, offset = 0; + if (extLen < OPAQUE16_LEN) + return BUFFER_ERROR; + ato16(input + offset, &listLen); offset += OPAQUE16_LEN; @@ -4228,6 +4231,9 @@ static int ProcessClientHello(const byte* input, int* sslBytes, #ifdef WOLFSSL_TLS13 case EXT_KEY_SHARE: { + if (extLen < OPAQUE16_LEN) + return BUFFER_ERROR; + word16 ksLen = (word16)((input[0] << 8) | input[1]); if (ksLen + OPAQUE16_LEN > extLen) { SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); @@ -4252,6 +4258,9 @@ static int ProcessClientHello(const byte* input, int* sslBytes, word32 ticketAge; const byte *identity, *binders; + if (extLen < OPAQUE16_LEN) + return BUFFER_ERROR; + idsLen = (word16)((input[idx] << 8) | input[idx+1]); if ((word32)idsLen + OPAQUE16_LEN + idx > (word32)extLen) { SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); From 74461e42509fcf42389b70376886c0ec0d784b51 Mon Sep 17 00:00:00 2001 From: Kareem Date: Mon, 6 Apr 2026 16:24:40 -0700 Subject: [PATCH 036/167] Code review feedback --- src/sniffer.c | 11 ++++++++--- src/tls.c | 4 +++- src/tls13.c | 2 +- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/sniffer.c b/src/sniffer.c index daad3d297c..c00915070b 100644 --- a/src/sniffer.c +++ b/src/sniffer.c @@ -4231,10 +4231,13 @@ static int ProcessClientHello(const byte* input, int* sslBytes, #ifdef WOLFSSL_TLS13 case EXT_KEY_SHARE: { - if (extLen < OPAQUE16_LEN) + word16 ksLen = 0; + if (extLen < OPAQUE16_LEN) { + SetError(BUFFER_ERROR_STR, error, session, FATAL_ERROR_STATE); return BUFFER_ERROR; + } - word16 ksLen = (word16)((input[0] << 8) | input[1]); + ksLen = (word16)((input[0] << 8) | input[1]); if (ksLen + OPAQUE16_LEN > extLen) { SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); return WOLFSSL_FATAL_ERROR; @@ -4258,8 +4261,10 @@ static int ProcessClientHello(const byte* input, int* sslBytes, word32 ticketAge; const byte *identity, *binders; - if (extLen < OPAQUE16_LEN) + if (extLen < OPAQUE16_LEN) { + SetError(BUFFER_ERROR_STR, error, session, FATAL_ERROR_STATE); return BUFFER_ERROR; + } idsLen = (word16)((input[idx] << 8) | input[idx+1]); if ((word32)idsLen + OPAQUE16_LEN + idx > (word32)extLen) { diff --git a/src/tls.c b/src/tls.c index c727ed8f82..0aab3463cf 100644 --- a/src/tls.c +++ b/src/tls.c @@ -3615,7 +3615,9 @@ int ProcessChainOCSPRequest(WOLFSSL* ssl) if (chain && chain->buffer) { while (ret == 0 && pos + OPAQUE24_LEN < chain->length) { if (i >= MAX_CERT_EXTENSIONS) { - WOLFSSL_MSG("OCSP request cert chain exceeds maximum length."); + WOLFSSL_ERROR_MSG_EX( + "OCSP request cert chain exceeds maximum length: " + "i=%d, MAX_CERT_EXTENSIONS=%d", i, MAX_CERT_EXTENSIONS); ret = MAX_CERT_EXTENSIONS_ERR; break; } diff --git a/src/tls13.c b/src/tls13.c index cbccb77bc5..12c610d894 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -9151,7 +9151,7 @@ static int SendTls13Certificate(WOLFSSL* ssl) if (ret != 0) return ret; - if ((word16)(1 + ssl->buffers.certChainCnt) > MAX_CERT_EXTENSIONS) + if ((1 + ssl->buffers.certChainCnt) > MAX_CERT_EXTENSIONS) ret = MAX_CERT_EXTENSIONS_ERR; if (ret == 0) ret = WriteCSRToBuffer(ssl, &ssl->buffers.certExts[0], &extSz[0], From 7251018468603c98e3f348f2aed30c354faef663 Mon Sep 17 00:00:00 2001 From: Kareem Date: Tue, 7 Apr 2026 10:26:17 -0700 Subject: [PATCH 037/167] Fix incorrect logging function name. --- src/tls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tls.c b/src/tls.c index 0aab3463cf..71f4a107c5 100644 --- a/src/tls.c +++ b/src/tls.c @@ -3615,7 +3615,7 @@ int ProcessChainOCSPRequest(WOLFSSL* ssl) if (chain && chain->buffer) { while (ret == 0 && pos + OPAQUE24_LEN < chain->length) { if (i >= MAX_CERT_EXTENSIONS) { - WOLFSSL_ERROR_MSG_EX( + WOLFSSL_MSG_EX( "OCSP request cert chain exceeds maximum length: " "i=%d, MAX_CERT_EXTENSIONS=%d", i, MAX_CERT_EXTENSIONS); ret = MAX_CERT_EXTENSIONS_ERR; From eb8ed9ed35562c437be36a99c68406a05905ab0b Mon Sep 17 00:00:00 2001 From: Kareem Date: Wed, 15 Apr 2026 17:38:41 -0700 Subject: [PATCH 038/167] Check i against the correct variable. MAX_CERT_EXTENSIONS doesn't always equal 1 + MAX_CHAIN_DEPTH, and the latter is the length of the array. --- src/internal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/internal.c b/src/internal.c index 4bbb22ceba..39b0c12fc1 100644 --- a/src/internal.c +++ b/src/internal.c @@ -25925,7 +25925,7 @@ int SendCertificateStatus(WOLFSSL* ssl) if (idx > chain->length) break; - if ((i + 1) >= MAX_CERT_EXTENSIONS) { + if ((i + 1) >= (1 + MAX_CHAIN_DEPTH)) { ret = MAX_CERT_EXTENSIONS_ERR; break; } From 9365248d6d39ad95d599c2b63b9b3d549dfa86bb Mon Sep 17 00:00:00 2001 From: Roy Carter Date: Thu, 16 Apr 2026 12:58:08 +0300 Subject: [PATCH 039/167] Refactor - allow configurating more than 99 , since large platforms which use high scale of operations require more than 99 index options back from SSL_get_ex_new_index --- configure.ac | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index e782ced3e9..5041767496 100644 --- a/configure.ac +++ b/configure.ac @@ -10376,9 +10376,10 @@ case "$ENABLED_EX_DATA" in no) ;; yes) AM_CFLAGS="$AM_CFLAGS -DHAVE_EX_DATA" ;; -[[1-9]]|[[1-9]][[0-9]]) AM_CFLAGS="$AM_CFLAGS -DHAVE_EX_DATA -DMAX_EX_DATA=$ENABLED_EX_DATA" +[[1-9]]|[[1-9]][[0-9]]|[[1-9]][[0-9]][[0-9]]|[[1-9]][[0-9]][[0-9]][[0-9]]) + AM_CFLAGS="$AM_CFLAGS -DHAVE_EX_DATA -DMAX_EX_DATA=$ENABLED_EX_DATA" ;; -*) AC_MSG_ERROR([Invalid argument to --enable-context-extra-user-data -- must be yes, no, or a number from 1 to 99]) +*) AC_MSG_ERROR([Invalid argument to --enable-context-extra-user-data -- must be yes, no, or a number from 1 to 9999]) ;; esac From e64305f9ffb1552783ef342dfabb049fa4bb154b Mon Sep 17 00:00:00 2001 From: Roy Carter Date: Thu, 16 Apr 2026 13:03:08 +0300 Subject: [PATCH 040/167] Refactor - when crafting a DTLS packet max external cookie length (for hijacking) can be more than 32 in size based on RFC6347 --- wolfssl/internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 576492d05d..86fb9ab80c 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1569,7 +1569,7 @@ enum Misc { SEED_LEN = RAN_LEN * 2, /* tls prf seed length */ ID_LEN = 32, /* session id length */ COOKIE_SECRET_SZ = 14, /* dtls cookie secret size */ - MAX_COOKIE_LEN = 32, /* max dtls cookie size */ + MAX_COOKIE_LEN = 255, /* max dtls cookie size per RFC 6347 (opaque<0..2^8-1>) */ COOKIE_SZ = 20, /* use a 20 byte cookie */ SUITE_LEN = 2, /* cipher suite sz length */ ENUM_LEN = 1, /* always a byte */ From 564248891e7addfca7484168380b97168b046d0d Mon Sep 17 00:00:00 2001 From: Roy Carter Date: Thu, 16 Apr 2026 13:24:11 +0300 Subject: [PATCH 041/167] Refactor - Change note to support maximum of 255 (based on RFC) for that we define maximum copy of <=254 to avoid buffer overflow attempts upon exactly 255.. --- wolfssl/internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 86fb9ab80c..620fb5cea2 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1569,7 +1569,7 @@ enum Misc { SEED_LEN = RAN_LEN * 2, /* tls prf seed length */ ID_LEN = 32, /* session id length */ COOKIE_SECRET_SZ = 14, /* dtls cookie secret size */ - MAX_COOKIE_LEN = 255, /* max dtls cookie size per RFC 6347 (opaque<0..2^8-1>) */ + MAX_COOKIE_LEN = 254, /* max dtls cookie size per RFC 6347 (opaque<0..2^8-1>) more than 254 */ COOKIE_SZ = 20, /* use a 20 byte cookie */ SUITE_LEN = 2, /* cipher suite sz length */ ENUM_LEN = 1, /* always a byte */ From ca018078f821108f27a70bf4605c702e960e003d Mon Sep 17 00:00:00 2001 From: Roy Carter Date: Thu, 16 Apr 2026 14:20:37 +0300 Subject: [PATCH 042/167] Cosmetic - fix documentation --- wolfssl/internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 620fb5cea2..d7ac7211e6 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1569,7 +1569,7 @@ enum Misc { SEED_LEN = RAN_LEN * 2, /* tls prf seed length */ ID_LEN = 32, /* session id length */ COOKIE_SECRET_SZ = 14, /* dtls cookie secret size */ - MAX_COOKIE_LEN = 254, /* max dtls cookie size per RFC 6347 (opaque<0..2^8-1>) more than 254 */ + MAX_COOKIE_LEN = 254, /* max dtls cookie size per RFC 6347 (opaque<0..2^8-1>) more than 254 can be malfored / malicious */ COOKIE_SZ = 20, /* use a 20 byte cookie */ SUITE_LEN = 2, /* cipher suite sz length */ ENUM_LEN = 1, /* always a byte */ From 31111287d4057b39bfd9dc9c6d3b0031aecdd1f5 Mon Sep 17 00:00:00 2001 From: Roy Carter Date: Thu, 16 Apr 2026 15:04:34 +0300 Subject: [PATCH 043/167] Cosmetic - fixed mispell --- wolfssl/internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wolfssl/internal.h b/wolfssl/internal.h index d7ac7211e6..74514a67eb 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1569,7 +1569,7 @@ enum Misc { SEED_LEN = RAN_LEN * 2, /* tls prf seed length */ ID_LEN = 32, /* session id length */ COOKIE_SECRET_SZ = 14, /* dtls cookie secret size */ - MAX_COOKIE_LEN = 254, /* max dtls cookie size per RFC 6347 (opaque<0..2^8-1>) more than 254 can be malfored / malicious */ + MAX_COOKIE_LEN = 254, /* max dtls cookie size per RFC 6347 (opaque<0..2^8-1>) more than 254 can be malformed / malicious */ COOKIE_SZ = 20, /* use a 20 byte cookie */ SUITE_LEN = 2, /* cipher suite sz length */ ENUM_LEN = 1, /* always a byte */ From f11d115ea8388f272a1accd8c4035c0a2559c2ff Mon Sep 17 00:00:00 2001 From: Anthony Hu Date: Thu, 16 Apr 2026 15:57:06 -0400 Subject: [PATCH 044/167] Prevent duplicate pragma defines in clang --- wolfssl/wolfcrypt/types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wolfssl/wolfcrypt/types.h b/wolfssl/wolfcrypt/types.h index ec1e87a00b..01de039f20 100644 --- a/wolfssl/wolfcrypt/types.h +++ b/wolfssl/wolfcrypt/types.h @@ -2082,7 +2082,7 @@ WOLFSSL_API word32 CheckRunTimeSettings(void); #define WC_MP_TO_RADIX #endif -#if defined(__GNUC__) && __GNUC__ > 5 +#if defined(__GNUC__) && (__GNUC__ > 5) && !defined(__clang__) #define PRAGMA_GCC_DIAG_PUSH _Pragma("GCC diagnostic push") #define PRAGMA_GCC(str) _Pragma(str) #define PRAGMA_GCC_DIAG_POP _Pragma("GCC diagnostic pop") From e0be9777f6bcba61786d4fff807177a88d3ce308 Mon Sep 17 00:00:00 2001 From: Lealem Amedie Date: Thu, 16 Apr 2026 18:39:32 -0600 Subject: [PATCH 045/167] Leverage wc constructors for ED* --- src/pk.c | 34 ++++++++++++++++++++++++++++------ wolfcrypt/src/ed448.c | 35 +++++++++++++++++++++++++++++++++++ wolfssl/wolfcrypt/ed448.h | 6 ++++++ 3 files changed, 69 insertions(+), 6 deletions(-) diff --git a/src/pk.c b/src/pk.c index 292c3a2d81..ec80cb6958 100644 --- a/src/pk.c +++ b/src/pk.c @@ -5516,6 +5516,9 @@ ed25519_key* wolfSSL_ED25519_new(void* heap, int devId) WOLFSSL_ENTER("wolfSSL_ED25519_new"); +#ifndef WC_NO_CONSTRUCTORS + key = wc_ed25519_new(heap, devId, NULL); +#else key = (ed25519_key*)XMALLOC(sizeof(ed25519_key), heap, DYNAMIC_TYPE_ED25519); if (key == NULL) { @@ -5526,6 +5529,7 @@ ed25519_key* wolfSSL_ED25519_new(void* heap, int devId) XFREE(key, heap, DYNAMIC_TYPE_ED25519); key = NULL; } +#endif return key; } @@ -5537,10 +5541,16 @@ ed25519_key* wolfSSL_ED25519_new(void* heap, int devId) void wolfSSL_ED25519_free(ed25519_key* key) { if (key != NULL) { - void* heap = key->heap; WOLFSSL_ENTER("wolfSSL_ED25519_free"); - wc_ed25519_free(key); - XFREE(key, heap, DYNAMIC_TYPE_ED25519); + #ifndef WC_NO_CONSTRUCTORS + wc_ed25519_delete(key, NULL); + #else + { + void* heap = key->heap; + wc_ed25519_free(key); + XFREE(key, heap, DYNAMIC_TYPE_ED25519); + } + #endif } } #endif /* (OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL) && HAVE_ED25519 */ @@ -6013,6 +6023,10 @@ ed448_key* wolfSSL_ED448_new(void* heap, int devId) WOLFSSL_ENTER("wolfSSL_ED448_new"); +#if !defined(WC_NO_CONSTRUCTORS) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION_GE(7, 0)) + key = wc_ed448_new(heap, devId, NULL); +#else key = (ed448_key*)XMALLOC(sizeof(ed448_key), heap, DYNAMIC_TYPE_ED448); if (key == NULL) { WOLFSSL_ERROR_MSG("wolfSSL_ED448_new malloc failure"); @@ -6022,6 +6036,7 @@ ed448_key* wolfSSL_ED448_new(void* heap, int devId) XFREE(key, heap, DYNAMIC_TYPE_ED448); key = NULL; } +#endif return key; } @@ -6033,10 +6048,17 @@ ed448_key* wolfSSL_ED448_new(void* heap, int devId) void wolfSSL_ED448_free(ed448_key* key) { if (key != NULL) { - void* heap = key->heap; WOLFSSL_ENTER("wolfSSL_ED448_free"); - wc_ed448_free(key); - XFREE(key, heap, DYNAMIC_TYPE_ED448); + #if !defined(WC_NO_CONSTRUCTORS) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION_GE(7, 0)) + wc_ed448_delete(key, NULL); + #else + { + void* heap = key->heap; + wc_ed448_free(key); + XFREE(key, heap, DYNAMIC_TYPE_ED448); + } + #endif } } #endif /* (OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL) && HAVE_ED448 */ diff --git a/wolfcrypt/src/ed448.c b/wolfcrypt/src/ed448.c index 37674cad51..c371eb7df6 100644 --- a/wolfcrypt/src/ed448.c +++ b/wolfcrypt/src/ed448.c @@ -959,6 +959,41 @@ void wc_ed448_free(ed448_key* key) } } +#ifndef WC_NO_CONSTRUCTORS +ed448_key* wc_ed448_new(void* heap, int devId, int *result_code) +{ + int ret; + ed448_key* key = (ed448_key*)XMALLOC(sizeof(ed448_key), heap, + DYNAMIC_TYPE_ED448); + if (key == NULL) { + ret = MEMORY_E; + } + else { + ret = wc_ed448_init_ex(key, heap, devId); + if (ret != 0) { + XFREE(key, heap, DYNAMIC_TYPE_ED448); + key = NULL; + } + } + + if (result_code != NULL) + *result_code = ret; + + return key; +} + +int wc_ed448_delete(ed448_key* key, ed448_key** key_p) { + void* heap; + if (key == NULL) + return BAD_FUNC_ARG; + heap = key->heap; + wc_ed448_free(key); + XFREE(key, heap, DYNAMIC_TYPE_ED448); + if (key_p != NULL) + *key_p = NULL; + return 0; +} +#endif /* !WC_NO_CONSTRUCTORS */ #ifdef HAVE_ED448_KEY_EXPORT diff --git a/wolfssl/wolfcrypt/ed448.h b/wolfssl/wolfcrypt/ed448.h index a72d8c0daf..44397b70e3 100644 --- a/wolfssl/wolfcrypt/ed448.h +++ b/wolfssl/wolfcrypt/ed448.h @@ -163,6 +163,12 @@ WOLFSSL_API int wc_ed448_init(ed448_key* key); WOLFSSL_API void wc_ed448_free(ed448_key* key); +#ifndef WC_NO_CONSTRUCTORS +WOLFSSL_API +ed448_key* wc_ed448_new(void* heap, int devId, int *result_code); +WOLFSSL_API +int wc_ed448_delete(ed448_key* key, ed448_key** key_p); +#endif #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) WOLFSSL_API From 56b2017405ed67e9f59e3927708a1f6799697b8f Mon Sep 17 00:00:00 2001 From: Lealem Amedie Date: Thu, 16 Apr 2026 18:42:19 -0600 Subject: [PATCH 046/167] Save heap before *_free in *_delete to avoid XFREE with zeroed memory after ForceZero --- wolfcrypt/src/aes.c | 4 +++- wolfcrypt/src/curve25519.c | 4 +++- wolfcrypt/src/dilithium.c | 4 +++- wolfcrypt/src/ed25519.c | 4 +++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/wolfcrypt/src/aes.c b/wolfcrypt/src/aes.c index cb4258e634..67887bba10 100644 --- a/wolfcrypt/src/aes.c +++ b/wolfcrypt/src/aes.c @@ -13581,10 +13581,12 @@ Aes* wc_AesNew(void* heap, int devId, int *result_code) int wc_AesDelete(Aes *aes, Aes** aes_p) { + void* heap; if (aes == NULL) return BAD_FUNC_ARG; + heap = aes->heap; wc_AesFree(aes); - XFREE(aes, aes->heap, DYNAMIC_TYPE_AES); + XFREE(aes, heap, DYNAMIC_TYPE_AES); if (aes_p != NULL) *aes_p = NULL; return 0; diff --git a/wolfcrypt/src/curve25519.c b/wolfcrypt/src/curve25519.c index bc2961aca4..f8ca74255c 100644 --- a/wolfcrypt/src/curve25519.c +++ b/wolfcrypt/src/curve25519.c @@ -1113,10 +1113,12 @@ curve25519_key* wc_curve25519_new(void* heap, int devId, int *result_code) } int wc_curve25519_delete(curve25519_key* key, curve25519_key** key_p) { + void* heap; if (key == NULL) return BAD_FUNC_ARG; + heap = key->heap; wc_curve25519_free(key); - XFREE(key, key->heap, DYNAMIC_TYPE_CURVE25519); + XFREE(key, heap, DYNAMIC_TYPE_CURVE25519); if (key_p != NULL) *key_p = NULL; return 0; diff --git a/wolfcrypt/src/dilithium.c b/wolfcrypt/src/dilithium.c index fc66b43065..e94460e01d 100644 --- a/wolfcrypt/src/dilithium.c +++ b/wolfcrypt/src/dilithium.c @@ -10730,10 +10730,12 @@ dilithium_key* wc_dilithium_new(void* heap, int devId) int wc_dilithium_delete(dilithium_key* key, dilithium_key** key_p) { + void* heap; if (key == NULL) return BAD_FUNC_ARG; + heap = key->heap; wc_dilithium_free(key); - XFREE(key, key->heap, DYNAMIC_TYPE_DILITHIUM); + XFREE(key, heap, DYNAMIC_TYPE_DILITHIUM); if (key_p != NULL) *key_p = NULL; diff --git a/wolfcrypt/src/ed25519.c b/wolfcrypt/src/ed25519.c index 425531575b..bf64f45909 100644 --- a/wolfcrypt/src/ed25519.c +++ b/wolfcrypt/src/ed25519.c @@ -1035,10 +1035,12 @@ ed25519_key* wc_ed25519_new(void* heap, int devId, int *result_code) } int wc_ed25519_delete(ed25519_key* key, ed25519_key** key_p) { + void* heap; if (key == NULL) return BAD_FUNC_ARG; + heap = key->heap; wc_ed25519_free(key); - XFREE(key, key->heap, DYNAMIC_TYPE_ED25519); + XFREE(key, heap, DYNAMIC_TYPE_ED25519); if (key_p != NULL) *key_p = NULL; return 0; From a8ca71be95befdaff95b971300fc94c08d4cc490 Mon Sep 17 00:00:00 2001 From: roy Date: Fri, 17 Apr 2026 15:14:26 +0300 Subject: [PATCH 047/167] Fix: Julek PR notes --- wolfssl/internal.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 74514a67eb..382b8c0487 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1446,6 +1446,11 @@ enum { #define TLS13_TICKET_NONCE_MAX_SZ 255 +#ifndef WOLFSSL_COOKIE_LEN +/* Maximum size for a DTLS cookie */ +#define WOLFSSL_COOKIE_LEN 32 +#endif + #if (defined(HAVE_FIPS) && \ !(defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) && \ defined(TLS13_TICKET_NONCE_STATIC_SZ) @@ -1569,7 +1574,7 @@ enum Misc { SEED_LEN = RAN_LEN * 2, /* tls prf seed length */ ID_LEN = 32, /* session id length */ COOKIE_SECRET_SZ = 14, /* dtls cookie secret size */ - MAX_COOKIE_LEN = 254, /* max dtls cookie size per RFC 6347 (opaque<0..2^8-1>) more than 254 can be malformed / malicious */ + MAX_COOKIE_LEN = WOLFSSL_COOKIE_LEN, /* max dtls cookie size */ COOKIE_SZ = 20, /* use a 20 byte cookie */ SUITE_LEN = 2, /* cipher suite sz length */ ENUM_LEN = 1, /* always a byte */ From cb495320fe6f41e4af7e58c787f7ccc9d2ec1249 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Fri, 17 Apr 2026 16:44:45 +0200 Subject: [PATCH 048/167] Zeroize DER buffer in der_to_enc_pem_alloc before free F-2139 Previously the plaintext private key DER buffer was freed via XFREE without a preceding ForceZero when no password encryption was requested. Track the actual allocation size and zeroize the buffer before release. --- src/pk.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/pk.c b/src/pk.c index 1aaf40d065..9370754c8e 100644 --- a/src/pk.c +++ b/src/pk.c @@ -480,6 +480,7 @@ static int der_to_enc_pem_alloc(unsigned char* der, int derSz, byte* tmp = NULL; byte* cipherInfo = NULL; int pemSz = 0; + int derAllocSz = derSz; int hashType = WC_HASH_TYPE_NONE; #if !defined(NO_MD5) hashType = WC_MD5; @@ -515,6 +516,7 @@ static int der_to_enc_pem_alloc(unsigned char* der, int derSz, } else { der = tmpBuf; + derAllocSz = derSz + blockSz; /* Encrypt DER inline. */ ret = EncryptDerKey(der, &derSz, cipher, passwd, passwdSz, @@ -562,7 +564,10 @@ static int der_to_enc_pem_alloc(unsigned char* der, int derSz, XFREE(tmp, NULL, DYNAMIC_TYPE_KEY); XFREE(cipherInfo, NULL, DYNAMIC_TYPE_STRING); - XFREE(der, heap, DYNAMIC_TYPE_TMP_BUFFER); + if (der != NULL) { + ForceZero(der, (word32)derAllocSz); + XFREE(der, heap, DYNAMIC_TYPE_TMP_BUFFER); + } return ret; } From a05dd200a9bba03dac8e52ae0312a46200ba29cc Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Fri, 17 Apr 2026 16:45:14 +0200 Subject: [PATCH 049/167] Zeroize DSA DER buffer in PEM write before free F-2140 wolfSSL_PEM_write_mem_DSAPrivateKey serializes the DSA private key to a heap DER buffer and freed it on five paths without ForceZero. Zeroize the buffer before each XFREE. --- src/pk.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/pk.c b/src/pk.c index 9370754c8e..be03bc3f97 100644 --- a/src/pk.c +++ b/src/pk.c @@ -2109,6 +2109,7 @@ int wolfSSL_PEM_write_mem_DSAPrivateKey(WOLFSSL_DSA* dsa, derSz = wc_DsaKeyToDer((DsaKey*)dsa->internal, derBuf, (word32)der_max_len); if (derSz < 0) { WOLFSSL_MSG("wc_DsaKeyToDer failed"); + ForceZero(derBuf, (word32)der_max_len); XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); return 0; } @@ -2121,6 +2122,7 @@ int wolfSSL_PEM_write_mem_DSAPrivateKey(WOLFSSL_DSA* dsa, &cipherInfo, der_max_len, WC_MD5); if (ret != 1) { WOLFSSL_MSG("EncryptDerKey failed"); + ForceZero(derBuf, (word32)der_max_len); XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); return ret; } @@ -2136,6 +2138,7 @@ int wolfSSL_PEM_write_mem_DSAPrivateKey(WOLFSSL_DSA* dsa, tmp = (byte*)XMALLOC((size_t)*pLen, NULL, DYNAMIC_TYPE_PEM); if (tmp == NULL) { WOLFSSL_MSG("malloc failed"); + ForceZero(derBuf, (word32)der_max_len); XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); XFREE(cipherInfo, NULL, DYNAMIC_TYPE_STRING); return 0; @@ -2146,11 +2149,13 @@ int wolfSSL_PEM_write_mem_DSAPrivateKey(WOLFSSL_DSA* dsa, type); if (*pLen <= 0) { WOLFSSL_MSG("wc_DerToPemEx failed"); + ForceZero(derBuf, (word32)der_max_len); XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); XFREE(tmp, NULL, DYNAMIC_TYPE_PEM); XFREE(cipherInfo, NULL, DYNAMIC_TYPE_STRING); return 0; } + ForceZero(derBuf, (word32)der_max_len); XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); XFREE(cipherInfo, NULL, DYNAMIC_TYPE_STRING); From dfd37f42993bb845b6ee52ed80dfcfd54c1af077 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Fri, 17 Apr 2026 16:45:29 +0200 Subject: [PATCH 050/167] Zeroize EC DER buffer in PEM write error path F-2141 The error path in wolfSSL_PEM_write_mem_ECPrivateKey freed the EC private key DER staging buffer without ForceZero. Zeroize before free. --- src/pk_ec.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pk_ec.c b/src/pk_ec.c index 66647c9eb7..f7ec038d69 100644 --- a/src/pk_ec.c +++ b/src/pk_ec.c @@ -4095,6 +4095,7 @@ int wolfSSL_PEM_write_mem_ECPrivateKey(WOLFSSL_EC_KEY* ec, derSz = wc_EccKeyToDer((ecc_key*)ec->internal, derBuf, der_max_len); if (derSz < 0) { WOLFSSL_MSG("wc_EccKeyToDer failed"); + ForceZero(derBuf, der_max_len); XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); ret = 0; } From 4c8adc50462222100130f6a44075a01cc9c96c54 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Fri, 17 Apr 2026 16:46:24 +0200 Subject: [PATCH 051/167] Zeroize RSA DER buffer in To_Der error path F-2142 wolfSSL_RSA_To_Der could free a buffer holding RSA private key material when the DER encoding step failed. Record the allocation size and ForceZero the buffer before XFREE on the private key path. --- src/pk_rsa.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/pk_rsa.c b/src/pk_rsa.c index c102f4ec21..aafe2bc839 100644 --- a/src/pk_rsa.c +++ b/src/pk_rsa.c @@ -779,6 +779,7 @@ static int wolfSSL_RSA_To_Der_ex(WOLFSSL_RSA* rsa, byte** outBuf, int publicKey, { int ret = 1; int derSz = 0; + int derAllocSz = 0; byte* derBuf = NULL; WOLFSSL_ENTER("wolfSSL_RSA_To_Der"); @@ -820,6 +821,7 @@ static int wolfSSL_RSA_To_Der_ex(WOLFSSL_RSA* rsa, byte** outBuf, int publicKey, } } + derAllocSz = derSz; if ((ret == 1) && (outBuf != NULL)) { derBuf = *outBuf; if (derBuf == NULL) { @@ -863,6 +865,9 @@ static int wolfSSL_RSA_To_Der_ex(WOLFSSL_RSA* rsa, byte** outBuf, int publicKey, if ((outBuf != NULL) && (*outBuf != derBuf)) { /* Not returning buffer, needs to be disposed of. */ + if ((derBuf != NULL) && (publicKey == 0)) { + ForceZero(derBuf, (word32)derAllocSz); + } XFREE(derBuf, heap, DYNAMIC_TYPE_TMP_BUFFER); } WOLFSSL_LEAVE("wolfSSL_RSA_To_Der", ret); From 9790719955f666ef3febf57454f5a27238ba949d Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Fri, 17 Apr 2026 16:46:43 +0200 Subject: [PATCH 052/167] Zeroize sniffer watch key buffer before free F-2143 ssl_SetWatchKey_file loaded a private key file into a heap buffer and freed it without ForceZero on both error and success paths. Zeroize before XFREE. --- src/sniffer.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sniffer.c b/src/sniffer.c index e8664721b1..6c5eba0b14 100644 --- a/src/sniffer.c +++ b/src/sniffer.c @@ -7242,12 +7242,16 @@ int ssl_SetWatchKey_file(void* vSniffer, const char* keyFile, int keyType, ret = LoadKeyFile(&keyBuf, &keyBufSz, keyFile, 0, keyType, password); if (ret < 0) { SetError(KEY_FILE_STR, error, NULL, 0); + if (keyBuf != NULL) { + ForceZero(keyBuf, keyBufSz); + } XFREE(keyBuf, NULL, DYNAMIC_TYPE_X509); return WOLFSSL_FATAL_ERROR; } ret = ssl_SetWatchKey_buffer(vSniffer, keyBuf, keyBufSz, FILETYPE_DER, error); + ForceZero(keyBuf, keyBufSz); XFREE(keyBuf, NULL, DYNAMIC_TYPE_X509); return ret; From fa3feb744227b227d2fc1ce3cf27c119502a2c05 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Fri, 17 Apr 2026 16:46:57 +0200 Subject: [PATCH 053/167] Zeroize static ephemeral key buffer before free F-2144 SetStaticEphemeralKey loaded a private key file into keyBuf and freed it without ForceZero. Static ephemeral keys are long-lived, so zeroize the buffer before XFREE. --- src/ssl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ssl.c b/src/ssl.c index 0d722f4ae0..05e7a79df3 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -18645,6 +18645,7 @@ static int SetStaticEphemeralKey(WOLFSSL_CTX* ctx, #ifndef NO_FILESYSTEM /* done with keyFile buffer */ if (keyFile && keyBuf) { + ForceZero(keyBuf, keySz); XFREE(keyBuf, heap, DYNAMIC_TYPE_TMP_BUFFER); } #endif From a82828b3ac519777c98406d9332c45089ef2e0bc Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Fri, 17 Apr 2026 16:47:19 +0200 Subject: [PATCH 054/167] Zeroize RSA DER buffer in CTX_use_RSAPrivateKey before free F-2145 wolfSSL_CTX_use_RSAPrivateKey staged the RSA private key DER (PKCS#1: n, e, d, p, q, dP, dQ, qInv) in a heap buffer and freed it without ForceZero. Zeroize before XFREE. --- src/ssl_load.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ssl_load.c b/src/ssl_load.c index 5c83e88c5a..04fecf2181 100644 --- a/src/ssl_load.c +++ b/src/ssl_load.c @@ -5365,6 +5365,9 @@ int wolfSSL_CTX_use_RSAPrivateKey(WOLFSSL_CTX* ctx, WOLFSSL_RSA* rsa) } /* Dispos of dynamically allocated data. */ + if (der != NULL) { + ForceZero(der, (word32)derSize); + } XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER); return ret; } From 9925f90720c58e571330c7df68ea1e47c62009dd Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Fri, 17 Apr 2026 16:47:33 +0200 Subject: [PATCH 055/167] Zeroize RSA DER buffer in d2i_RSAPrivateKey_bio before free F-2146 wolfSSL_d2i_RSAPrivateKey_bio read PKCS#1-encoded RSA private key DER from a BIO into a heap buffer and freed it without ForceZero. Zeroize before XFREE on both success and error paths. --- src/pk_rsa.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/pk_rsa.c b/src/pk_rsa.c index aafe2bc839..9f5ba4488b 100644 --- a/src/pk_rsa.c +++ b/src/pk_rsa.c @@ -719,6 +719,9 @@ WOLFSSL_RSA* wolfSSL_d2i_RSAPrivateKey_bio(WOLFSSL_BIO *bio, WOLFSSL_RSA **out) key = NULL; } /* Dispose of allocated data. */ + if (der != NULL) { + ForceZero(der, (word32)derLen); + } XFREE(der, bio ? bio->heap : NULL, DYNAMIC_TYPE_TMP_BUFFER); return key; } From 87e5c62111d37d6e3f3624178b65c5633c66cd53 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Fri, 17 Apr 2026 16:47:47 +0200 Subject: [PATCH 056/167] Zeroize EC DER buffer in i2d_ECPrivateKey error path F-2147 The error path in wolfSSL_i2d_ECPrivateKey could free an EC private key DER staging buffer that may contain a partial private scalar. Zeroize before XFREE. --- src/pk_ec.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/pk_ec.c b/src/pk_ec.c index f7ec038d69..faed7f20a6 100644 --- a/src/pk_ec.c +++ b/src/pk_ec.c @@ -3524,6 +3524,9 @@ int wolfSSL_i2d_ECPrivateKey(const WOLFSSL_EC_KEY *key, unsigned char **out) /* Dispose of any allocated buffer on error. */ if (err && (*out == buf)) { + if (buf != NULL) { + ForceZero(buf, len); + } XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); *out = NULL; } From 00fff0f3fc82d383560712be2d8c7c011b2af081 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Fri, 17 Apr 2026 16:48:06 +0200 Subject: [PATCH 057/167] Zeroize PKCS#8 DER staging area in PEM write helper F-2148 pem_write_mem_pkcs8privatekey stages the PKCS#8 DER encoded private key at the tail of the PEM buffer, then writes the shorter PEM output at the head of the same buffer. The DER tail is not overwritten, leaking the plaintext private key to heap memory after the callers free. Zero the DER staging area before returning. --- src/pk.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/pk.c b/src/pk.c index be03bc3f97..4fe12629f4 100644 --- a/src/pk.c +++ b/src/pk.c @@ -7208,6 +7208,12 @@ static int pem_write_mem_pkcs8privatekey(byte** pem, int* pemSz, } } + /* Zero the DER staging area at the tail of the buffer so the plaintext + * private key material is not left in freed heap memory. */ + if (key != NULL && keySz > 0) { + ForceZero(key, keySz); + } + /* Return appropriate return code. */ return (res == 0) ? 0 : ret; From 1e040923c6b7b6d798b6fb587c24f2480672937f Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Fri, 17 Apr 2026 17:02:58 +0200 Subject: [PATCH 058/167] Only zero unused tail of PKCS#8 PEM buffer F-2148 The prior fix zeroed the computed DER staging area, but PEM output from wc_DerToPemEx fills most of the buffer and overlaps that region, corrupting the valid PEM. Preserve the allocation size and zero only the bytes beyond the actual PEM length, or the whole buffer on failure. --- src/pk.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/pk.c b/src/pk.c index 4fe12629f4..f9cc7345ad 100644 --- a/src/pk.c +++ b/src/pk.c @@ -7117,6 +7117,7 @@ static int pem_write_mem_pkcs8privatekey(byte** pem, int* pemSz, char password[NAME_SZ]; byte* key = NULL; word32 keySz = 0; + word32 allocSz = 0; int type = PKCS8_PRIVATEKEY_TYPE; /* Validate parameters. */ @@ -7155,6 +7156,10 @@ static int pem_write_mem_pkcs8privatekey(byte** pem, int* pemSz, res = 0; } else { + /* Remember the allocation size before *pemSz is updated to the + * actual PEM output length, so we can zero any unused tail that + * held the DER staging area. */ + allocSz = (word32)*pemSz; /* Use end of PEM buffer for key data. */ key = *pem + *pemSz - keySz; } @@ -7208,10 +7213,18 @@ static int pem_write_mem_pkcs8privatekey(byte** pem, int* pemSz, } } - /* Zero the DER staging area at the tail of the buffer so the plaintext - * private key material is not left in freed heap memory. */ - if (key != NULL && keySz > 0) { - ForceZero(key, keySz); + /* Zero any remnants of the DER staging area that persist after PEM + * conversion so plaintext private key material is not left in freed heap + * memory. On success, only the bytes past the actual PEM output need + * clearing; on failure, the whole buffer is zeroed since its state is + * indeterminate. */ + if (*pem != NULL) { + if (res == 1 && (word32)*pemSz < allocSz) { + ForceZero(*pem + *pemSz, allocSz - (word32)*pemSz); + } + else if (res != 1) { + ForceZero(*pem, allocSz); + } } /* Return appropriate return code. */ From 46de2b3cfd489596a0aaffe1417b7d4b5f8bbb43 Mon Sep 17 00:00:00 2001 From: Roy Carter Date: Fri, 17 Apr 2026 18:40:33 +0300 Subject: [PATCH 059/167] Fix: move define to be before the define check for TLS & PSK --- wolfssl/internal.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 382b8c0487..82fb3a8a56 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1442,15 +1442,15 @@ enum { */ #define AEAD_SM4_CCM_LIMIT w64From32(0, (1 << 10) - 1) -#if defined(WOLFSSL_TLS13) || !defined(NO_PSK) - -#define TLS13_TICKET_NONCE_MAX_SZ 255 - #ifndef WOLFSSL_COOKIE_LEN /* Maximum size for a DTLS cookie */ #define WOLFSSL_COOKIE_LEN 32 #endif +#if defined(WOLFSSL_TLS13) || !defined(NO_PSK) + +#define TLS13_TICKET_NONCE_MAX_SZ 255 + #if (defined(HAVE_FIPS) && \ !(defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) && \ defined(TLS13_TICKET_NONCE_STATIC_SZ) From e26ab427a54d2b5bbb1c24d24ad20ec0381f2d9b Mon Sep 17 00:00:00 2001 From: Eric Blankenhorn Date: Tue, 7 Apr 2026 17:07:14 -0500 Subject: [PATCH 060/167] Use O_CLOEXEC to avoid race conditions --- .wolfssl_known_macro_extras | 7 ++ src/crl.c | 31 ++++++++- src/ssl.c | 2 +- src/wolfio.c | 9 +-- wolfcrypt/benchmark/benchmark.c | 16 ++++- wolfcrypt/src/port/af_alg/afalg_hash.c | 10 ++- wolfcrypt/src/port/af_alg/wc_afalg.c | 13 +++- wolfcrypt/src/port/caam/wolfcaam_qnx.c | 3 +- wolfcrypt/src/port/devcrypto/wc_devcrypto.c | 4 +- wolfcrypt/src/port/intel/quickassist_mem.c | 4 +- wolfcrypt/src/random.c | 12 ++-- wolfcrypt/src/wc_port.c | 76 +++++++++++++++++++++ wolfssl/wolfcrypt/wc_port.h | 18 +++++ 13 files changed, 182 insertions(+), 23 deletions(-) diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 0e58d4f11b..9f52a4cb5a 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -219,6 +219,7 @@ DTLS_RECEIVEFROM_NO_TIMEOUT_ON_INVALID_PEER ECCSI_ORDER_MORE_BITS_THAN_PRIME ECC_DUMP_OID ECDHE_SIZE +EFD_CLOEXEC ENABLED_BSDKM_REGISTER ENABLE_SECURE_SOCKETS_LOGS ESP32 @@ -234,6 +235,7 @@ ETHERNET_AVAILABLE ETHERNET_H EV_TRIGGER EXTERNAL_LOADER_APP +FD_CLOEXEC FIPS_OPTEST_FULL_RUN_AT_MODULE_INIT FORCE_FAILURE_GETRANDOM FP_ECC_CONTROL @@ -317,6 +319,7 @@ IGNORE_NETSCAPE_CERT_TYPE INCLUDE_uxTaskGetStackHighWaterMark INTEGRITY INTIMEVER +IN_CLOEXEC IOTSAFE_NO_GETDATA IOTSAFE_SIG_8BIT_LENGTH KCAPI_USE_XMALLOC @@ -476,7 +479,9 @@ OPENSSL_NO_PK OS_WINDOWS OTHERBOARD OTHER_BOARD +O_CLOEXEC PEER_INFO +PERF_FLAG_FD_CLOEXEC PKA_ECC_SCALAR_MUL_IN_B_COEFF PLATFORMIO PLUTON_CRYPTO_ECC @@ -519,6 +524,7 @@ SL_SE_KEY_TYPE_ECC_X25519 SL_SE_KEY_TYPE_ECC_X448 SL_SE_PRF_HMAC_SHA1 SNIFFER_SINGLE_SESSION_CACHE +SOCK_CLOEXEC SOFTDEVICE_PRESENT SO_NOSIGPIPE SO_REUSEPORT @@ -1116,6 +1122,7 @@ __sun __svr4__ __thumb__ __ti__ +__unix__ __x86_64__ __xtensa__ byte diff --git a/src/crl.c b/src/crl.c index 62c207de52..540a6d23ac 100644 --- a/src/crl.c +++ b/src/crl.c @@ -1659,6 +1659,7 @@ static int SwapLists(WOLFSSL_CRL* crl) #include #include #include +#include #ifdef __MACH__ #define XEVENT_MODE O_EVTONLY @@ -1667,6 +1668,7 @@ static int SwapLists(WOLFSSL_CRL* crl) #endif + /* we need a unique kqueue user filter fd for crl in case user is doing custom * events too */ #ifndef CRL_CUSTOM_FD @@ -1710,6 +1712,7 @@ static THREAD_RETURN WOLFSSL_THREAD DoMonitor(void* arg) SignalSetup(crl, MONITOR_SETUP_E); return NULL; } + wc_set_cloexec(crl->mfd); /* listen for custom shutdown event */ EV_SET(&change, CRL_CUSTOM_FD, EVFILT_USER, EV_ADD, 0, 0, NULL); @@ -1724,7 +1727,7 @@ static THREAD_RETURN WOLFSSL_THREAD DoMonitor(void* arg) fDER = -1; if (crl->monitors[0].path) { - fPEM = open(crl->monitors[0].path, XEVENT_MODE); + fPEM = wc_open_cloexec(crl->monitors[0].path, XEVENT_MODE); if (fPEM == -1) { WOLFSSL_MSG("PEM event dir open failed"); SignalSetup(crl, MONITOR_SETUP_E); @@ -1734,7 +1737,7 @@ static THREAD_RETURN WOLFSSL_THREAD DoMonitor(void* arg) } if (crl->monitors[1].path) { - fDER = open(crl->monitors[1].path, XEVENT_MODE); + fDER = wc_open_cloexec(crl->monitors[1].path, XEVENT_MODE); if (fDER == -1) { WOLFSSL_MSG("DER event dir open failed"); if (fPEM != -1) @@ -1801,6 +1804,13 @@ static THREAD_RETURN WOLFSSL_THREAD DoMonitor(void* arg) #include #include #include +#include +#include + +/* Fall back to no-op if EFD_CLOEXEC is unavailable. */ +#ifndef EFD_CLOEXEC + #define EFD_CLOEXEC 0 +#endif #ifndef max @@ -1836,14 +1846,29 @@ static THREAD_RETURN WOLFSSL_THREAD DoMonitor(void* arg) WOLFSSL_ENTER("DoMonitor"); - crl->mfd = eventfd(0, 0); /* our custom shutdown event */ + crl->mfd = eventfd(0, EFD_CLOEXEC); /* our custom shutdown event */ +#ifdef FD_CLOEXEC + if (crl->mfd < 0 && errno == EINVAL) { + crl->mfd = eventfd(0, 0); + wc_set_cloexec(crl->mfd); + } +#endif if (crl->mfd < 0) { WOLFSSL_MSG("eventfd failed"); SignalSetup(crl, MONITOR_SETUP_E); return NULL; } +#ifdef IN_CLOEXEC + notifyFd = inotify_init1(IN_CLOEXEC); + if (notifyFd < 0 && (errno == ENOSYS || errno == EINVAL)) { + notifyFd = inotify_init(); + wc_set_cloexec(notifyFd); + } +#else notifyFd = inotify_init(); + wc_set_cloexec(notifyFd); +#endif if (notifyFd < 0) { WOLFSSL_MSG("inotify failed"); (void)close(crl->mfd); diff --git a/src/ssl.c b/src/ssl.c index 58cd6701c0..c36671b51d 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -19601,7 +19601,7 @@ int wolfSSL_RAND_egd(const char* nm) return WOLFSSL_FATAL_ERROR; } - fd = socket(AF_UNIX, SOCK_STREAM, 0); + fd = wc_socket_cloexec(AF_UNIX, SOCK_STREAM, 0); if (fd < 0) { WOLFSSL_MSG("Error creating socket"); WC_FREE_VAR_EX(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); diff --git a/src/wolfio.c b/src/wolfio.c index c6ffe7da11..fe891da234 100644 --- a/src/wolfio.c +++ b/src/wolfio.c @@ -42,6 +42,7 @@ #include #include + #ifdef NUCLEUS_PLUS_2_3 /* Holds last Nucleus networking error number */ int Nucleus_Net_Errno; @@ -1494,7 +1495,7 @@ int wolfIO_TcpConnect(SOCKET_T* sockfd, const char* ip, word16 port, int to_sec) } #endif - *sockfd = (SOCKET_T)socket(addr.ss_family, SOCK_STREAM, 0); + *sockfd = (SOCKET_T)wc_socket_cloexec(addr.ss_family, SOCK_STREAM, 0); #ifdef USE_WINDOWS_API if (*sockfd == SOCKET_INVALID) #else @@ -1572,12 +1573,12 @@ int wolfIO_TcpBind(SOCKET_T* sockfd, word16 port) sin->sin6_family = AF_INET6; sin->sin6_addr = in6addr_any; sin->sin6_port = XHTONS(port); - *sockfd = (SOCKET_T)socket(AF_INET6, SOCK_STREAM, 0); + *sockfd = (SOCKET_T)wc_socket_cloexec(AF_INET6, SOCK_STREAM, 0); #else sin->sin_family = AF_INET; sin->sin_addr.s_addr = INADDR_ANY; sin->sin_port = XHTONS(port); - *sockfd = (SOCKET_T)socket(AF_INET, SOCK_STREAM, 0); + *sockfd = (SOCKET_T)wc_socket_cloexec(AF_INET, SOCK_STREAM, 0); #endif #ifdef USE_WINDOWS_API @@ -1623,7 +1624,7 @@ int wolfIO_TcpBind(SOCKET_T* sockfd, word16 port) #ifdef HAVE_SOCKADDR int wolfIO_TcpAccept(SOCKET_T sockfd, SOCKADDR* peer_addr, XSOCKLENT* peer_len) { - return (int)accept(sockfd, peer_addr, peer_len); + return wc_accept_cloexec((int)sockfd, peer_addr, peer_len); } #endif /* HAVE_SOCKADDR */ diff --git a/wolfcrypt/benchmark/benchmark.c b/wolfcrypt/benchmark/benchmark.c index 5d8e8efb89..18cedaeace 100644 --- a/wolfcrypt/benchmark/benchmark.c +++ b/wolfcrypt/benchmark/benchmark.c @@ -1574,16 +1574,30 @@ static const char* bench_result_words3[][5] = { #include #include #include + #include + #include + + #ifndef PERF_FLAG_FD_CLOEXEC + #define PERF_FLAG_FD_CLOEXEC (1UL << 3) + #endif static THREAD_LS_T word64 begin_cycles; static THREAD_LS_T word64 total_cycles; static THREAD_LS_T int cycles = -1; static THREAD_LS_T struct perf_event_attr atr; + /* Try with PERF_FLAG_FD_CLOEXEC first; on older kernels (< 3.14) this + * fails with EINVAL, so fall back to flags=0 and set FD_CLOEXEC via + * fcntl() as a best-effort. */ #define INIT_CYCLE_COUNTER do { \ atr.type = PERF_TYPE_HARDWARE; \ atr.config = PERF_COUNT_HW_CPU_CYCLES; \ - cycles = (int)syscall(__NR_perf_event_open, &atr, 0, -1, -1, 0); \ + cycles = (int)syscall(__NR_perf_event_open, &atr, 0, -1, -1, \ + PERF_FLAG_FD_CLOEXEC); \ + if (cycles < 0 && errno == EINVAL) { \ + cycles = (int)syscall(__NR_perf_event_open, &atr, 0, -1, -1, 0); \ + wc_set_cloexec(cycles); \ + } \ } while (0); #define BEGIN_CYCLES read(cycles, &begin_cycles, sizeof(begin_cycles)); diff --git a/wolfcrypt/src/port/af_alg/afalg_hash.c b/wolfcrypt/src/port/af_alg/afalg_hash.c index 429bb7d04b..c0e945b5d2 100644 --- a/wolfcrypt/src/port/af_alg/afalg_hash.c +++ b/wolfcrypt/src/port/af_alg/afalg_hash.c @@ -19,6 +19,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ +#if defined(__linux__) && !defined(_GNU_SOURCE) + #define _GNU_SOURCE 1 +#endif + #include #if defined(WOLFSSL_AFALG_HASH) || (defined(WOLFSSL_AFALG_XILINX_SHA3) \ @@ -26,6 +30,8 @@ #include #include +#include +#include static const char WC_TYPE_HASH[] = "hash"; @@ -223,8 +229,8 @@ static int AfalgHashCopy(wolfssl_AFALG_Hash* src, wolfssl_AFALG_Hash* dst) } #endif - dst->rdFd = accept(src->rdFd, NULL, 0); - dst->alFd = accept(src->alFd, NULL, 0); + dst->rdFd = wc_accept_cloexec(src->rdFd, NULL, NULL); + dst->alFd = wc_accept_cloexec(src->alFd, NULL, NULL); if (dst->rdFd == WC_SOCK_NOTSET || dst->alFd == WC_SOCK_NOTSET) { AfalgHashFree(dst); diff --git a/wolfcrypt/src/port/af_alg/wc_afalg.c b/wolfcrypt/src/port/af_alg/wc_afalg.c index b5a1f878ad..cda5e043db 100644 --- a/wolfcrypt/src/port/af_alg/wc_afalg.c +++ b/wolfcrypt/src/port/af_alg/wc_afalg.c @@ -19,12 +19,20 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ +#if defined(__linux__) && !defined(_GNU_SOURCE) + #define _GNU_SOURCE 1 +#endif + #include #if defined(WOLFSSL_AFALG) || defined(WOLFSSL_AFALG_XILINX) #include #include +#include +#include +#include + /* Sets the type of socket address to use */ @@ -56,7 +64,7 @@ int wc_Afalg_Accept(struct sockaddr_alg* in, int inSz, int sock) return WC_AFALG_SOCK_E; } - return accept(sock, NULL, 0); + return wc_accept_cloexec(sock, NULL, NULL); } @@ -66,7 +74,8 @@ int wc_Afalg_Socket(void) { int sock; - if ((sock = socket(AF_ALG, SOCK_SEQPACKET, 0)) < 0) { + sock = wc_socket_cloexec(AF_ALG, SOCK_SEQPACKET, 0); + if (sock < 0) { WOLFSSL_MSG("Failed to get AF_ALG socket"); return WC_AFALG_SOCK_E; } diff --git a/wolfcrypt/src/port/caam/wolfcaam_qnx.c b/wolfcrypt/src/port/caam/wolfcaam_qnx.c index 71d5cbfb61..eab9cdd572 100644 --- a/wolfcrypt/src/port/caam/wolfcaam_qnx.c +++ b/wolfcrypt/src/port/caam/wolfcaam_qnx.c @@ -34,7 +34,6 @@ #include #include -#include /* for devctl use */ int caamFd = -1; @@ -48,7 +47,7 @@ int wc_CAAMInitInterface() return -1; } - caamFd = open("/dev/wolfCrypt", O_RDWR); + caamFd = wc_open_cloexec("/dev/wolfCrypt", O_RDWR); if (caamFd < 0) { WOLFSSL_MSG("Could not open /dev/wolfCrypt"); return -1; diff --git a/wolfcrypt/src/port/devcrypto/wc_devcrypto.c b/wolfcrypt/src/port/devcrypto/wc_devcrypto.c index 21fb980800..9a939157b4 100644 --- a/wolfcrypt/src/port/devcrypto/wc_devcrypto.c +++ b/wolfcrypt/src/port/devcrypto/wc_devcrypto.c @@ -26,11 +26,13 @@ static volatile int fd; #include +#include int wc_DevCryptoInit(void) { /* create descriptor */ - if ((fd = open("/dev/crypto", O_RDWR, 0)) < 0) { + fd = wc_open_cloexec("/dev/crypto", O_RDWR); + if (fd < 0) { WOLFSSL_MSG("Error opening /dev/crypto is cryptodev module loaded?"); return WC_DEVCRYPTO_E; } diff --git a/wolfcrypt/src/port/intel/quickassist_mem.c b/wolfcrypt/src/port/intel/quickassist_mem.c index 63d01d9f32..7d44572a93 100644 --- a/wolfcrypt/src/port/intel/quickassist_mem.c +++ b/wolfcrypt/src/port/intel/quickassist_mem.c @@ -57,6 +57,8 @@ #include #include #include +#include + #ifdef SAL_IOMMU_CODE #include @@ -714,7 +716,7 @@ CpaStatus qaeMemInit(void) { if (g_qaeMemFd < 0) { #ifndef QAT_V2 - g_qaeMemFd = open(QAE_MEM, O_RDWR); + g_qaeMemFd = wc_open_cloexec(QAE_MEM, O_RDWR); if (g_qaeMemFd < 0) { printf("unable to open %s %d\n", QAE_MEM, g_qaeMemFd); return CPA_STATUS_FAIL; diff --git a/wolfcrypt/src/random.c b/wolfcrypt/src/random.c index 9fa318c760..430edda1d9 100644 --- a/wolfcrypt/src/random.c +++ b/wolfcrypt/src/random.c @@ -204,8 +204,8 @@ This library contains implementation for the random number generator. #elif defined(WOLFSSL_MAX3266X) || defined(WOLFSSL_MAX3266X_OLD) #include "wolfssl/wolfcrypt/port/maxim/max3266x.h" #else + #include #if defined(WOLFSSL_GETRANDOM) || defined(HAVE_GETRANDOM) - #include #include #endif /* include headers that may be needed to get good seed */ @@ -3829,7 +3829,7 @@ int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz) if (!os->seedFdOpen) { #ifndef NO_DEV_URANDOM /* way to disable use of /dev/urandom */ - os->fd = open("/dev/urandom", O_RDONLY); + os->fd = wc_open_cloexec("/dev/urandom", O_RDONLY); #if defined(DEBUG_WOLFSSL) WOLFSSL_MSG("opened /dev/urandom."); #endif /* DEBUG_WOLFSSL */ @@ -3837,7 +3837,7 @@ int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz) #endif /* NO_DEV_URANDOM */ { /* may still have /dev/random */ - os->fd = open("/dev/random", O_RDONLY); + os->fd = wc_open_cloexec("/dev/random", O_RDONLY); #if defined(DEBUG_WOLFSSL) WOLFSSL_MSG("opened /dev/random."); #endif /* DEBUG_WOLFSSL */ @@ -3855,7 +3855,7 @@ int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz) } #else /* WOLFSSL_KEEP_RNG_SEED_FD_OPEN */ #ifndef NO_DEV_URANDOM /* way to disable use of /dev/urandom */ - os->fd = open("/dev/urandom", O_RDONLY); + os->fd = wc_open_cloexec("/dev/urandom", O_RDONLY); #if defined(DEBUG_WOLFSSL) WOLFSSL_MSG("opened /dev/urandom."); #endif /* DEBUG_WOLFSSL */ @@ -3863,7 +3863,7 @@ int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz) #endif /* !NO_DEV_URANDOM */ { /* may still have /dev/random */ - os->fd = open("/dev/random", O_RDONLY); + os->fd = wc_open_cloexec("/dev/random", O_RDONLY); #if defined(DEBUG_WOLFSSL) WOLFSSL_MSG("opened /dev/random."); #endif /* DEBUG_WOLFSSL */ @@ -3944,7 +3944,7 @@ int wc_hwrng_generate_block(byte *output, word32 sz) { int fd; int ret = 0; - fd = open("/dev/hwrng", O_RDONLY); + fd = wc_open_cloexec("/dev/hwrng", O_RDONLY); if (fd == -1) return OPEN_RAN_E; while(sz) diff --git a/wolfcrypt/src/wc_port.c b/wolfcrypt/src/wc_port.c index 92283abdfe..4d80ef8a07 100644 --- a/wolfcrypt/src/wc_port.c +++ b/wolfcrypt/src/wc_port.c @@ -19,6 +19,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ +#if (defined(__linux__) || defined(__ANDROID__)) && \ + !defined(WOLFSSL_LINUXKM) && !defined(WOLFSSL_ZEPHYR) && \ + !defined(_GNU_SOURCE) + #define _GNU_SOURCE 1 +#endif + /* wolfCrypt Porting Build Options: @@ -5130,6 +5136,76 @@ char* wolfSSL_strnstr(const char* s1, const char* s2, unsigned int n) #endif /* not SINGLE_THREADED */ +#if (defined(__unix__) || defined(__APPLE__)) && \ + !defined(WOLFSSL_LINUXKM) && !defined(WOLFSSL_ZEPHYR) + +#include +#include +#include + +#ifndef O_CLOEXEC + #define O_CLOEXEC 0 +#endif +#ifndef SOCK_CLOEXEC + #define SOCK_CLOEXEC 0 +#endif + +void wc_set_cloexec(int fd) +{ +#ifdef FD_CLOEXEC + int fdFlags; + if (fd < 0) + return; + fdFlags = fcntl(fd, F_GETFD); + if (fdFlags >= 0) + (void)fcntl(fd, F_SETFD, fdFlags | FD_CLOEXEC); +#else + (void)fd; +#endif +} + +int wc_open_cloexec(const char* path, int flags) +{ + int fd = open(path, flags | O_CLOEXEC); +#ifdef FD_CLOEXEC + if (fd < 0 && errno == EINVAL) { + fd = open(path, flags); + wc_set_cloexec(fd); + } +#endif + return fd; +} + +int wc_socket_cloexec(int domain, int type, int protocol) +{ + int fd = socket(domain, type | SOCK_CLOEXEC, protocol); +#ifdef FD_CLOEXEC + if (fd < 0 && errno == EINVAL) { + fd = socket(domain, type, protocol); + wc_set_cloexec(fd); + } +#endif + return fd; +} + +int wc_accept_cloexec(int sockfd, void* addr, void* addrlen) +{ + int fd; +#if defined(__linux__) || defined(__ANDROID__) + fd = accept4(sockfd, (struct sockaddr*)addr, (socklen_t*)addrlen, + SOCK_CLOEXEC); + if (fd >= 0) + return fd; + if (errno != ENOSYS && errno != EINVAL) + return fd; +#endif + fd = accept(sockfd, (struct sockaddr*)addr, (socklen_t*)addrlen); + wc_set_cloexec(fd); + return fd; +} + +#endif /* (__unix__ || __APPLE__) && !WOLFSSL_LINUXKM && !WOLFSSL_ZEPHYR */ + #if defined(WOLFSSL_LINUXKM) && defined(CONFIG_ARM64) && \ defined(WC_SYM_RELOC_TABLES) #ifndef CONFIG_ARCH_TEGRA diff --git a/wolfssl/wolfcrypt/wc_port.h b/wolfssl/wolfcrypt/wc_port.h index ade6b6c1da..799066884a 100644 --- a/wolfssl/wolfcrypt/wc_port.h +++ b/wolfssl/wolfcrypt/wc_port.h @@ -1860,6 +1860,24 @@ WOLFSSL_ABI WOLFSSL_API int wolfCrypt_Cleanup(void); #define WC_GENERATE_SEED_DEFAULT wc_GenerateSeed #endif +#if (defined(__unix__) || defined(__APPLE__)) && \ + !defined(WOLFSSL_LINUXKM) && !defined(WOLFSSL_ZEPHYR) + WOLFSSL_LOCAL void wc_set_cloexec(int fd); + WOLFSSL_LOCAL int wc_open_cloexec(const char* path, int flags); + WOLFSSL_LOCAL int wc_socket_cloexec(int domain, int type, int protocol); + WOLFSSL_LOCAL int wc_accept_cloexec(int sockfd, void* addr, void* addrlen); +#else + /* Platforms without POSIX close-on-exec semantics (Windows, OS/2 OW, + * Linux kernel module, Zephyr, etc.): pass through to plain syscalls + * where the underlying headers are available in the caller. */ + #define wc_set_cloexec(fd) ((void)(fd)) + #define wc_open_cloexec(path, flags) open((path), (flags)) + #define wc_socket_cloexec(domain, type, protocol) \ + socket((domain), (type), (protocol)) + #define wc_accept_cloexec(sockfd, addr, addrlen) \ + accept((sockfd), (addr), (addrlen)) +#endif + #ifdef __cplusplus } /* extern "C" */ #endif From 6f893313771650adcbd90cd5715a2f7d4784ec98 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Fri, 17 Apr 2026 09:52:00 -0700 Subject: [PATCH 061/167] Tasking Warning Tasking compiler does not support #warning and needs the #pragma message case where available. This will fix the wolfSSH QNX nightly from failing. --- wolfssl/wolfcrypt/settings.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 9686337a22..f6991a1150 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -349,7 +349,11 @@ ((defined(BUILDING_WOLFSSL) && defined(WOLFSSL_USE_OPTIONS_H)) || \ (defined(BUILDING_WOLFSSL) && defined(WOLFSSL_OPTIONS_H) && \ !defined(EXTERNAL_OPTS_OPENVPN))) - #warning wolfssl/options.h included in compiled wolfssl library object. + #if !defined(_MSC_VER) && !defined(__TASKING__) + #warning wolfssl/options.h included in compiled wolfssl library object. + #else + #pragma message("Warning: wolfssl/options.h included in compiled wolfssl library object.") + #endif #endif #ifdef WOLFSSL_USER_SETTINGS @@ -369,7 +373,11 @@ * an application build -- then your application can avoid this warning by * defining WOLFSSL_NO_OPTIONS_H or WOLFSSL_CUSTOM_CONFIG as appropriate. */ - #warning "No configuration for wolfSSL detected, check header order" + #if !defined(_MSC_VER) && !defined(__TASKING__) + #warning "No configuration for wolfSSL detected, check header order" + #else + #pragma message("Warning: No configuration for wolfSSL detected, check header order") + #endif #endif /* Ensure WOLFSSL_DEBUG_CERTS is set when DEBUG_WOLFSSL is enabled, unless From 7718510a29399000d6af575b59f2a2b045e4b201 Mon Sep 17 00:00:00 2001 From: Anthony Hu Date: Fri, 17 Apr 2026 15:10:56 -0400 Subject: [PATCH 062/167] Add a debug message. --- src/ssl_api_cert.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ssl_api_cert.c b/src/ssl_api_cert.c index 73e598c75a..ed471be105 100644 --- a/src/ssl_api_cert.c +++ b/src/ssl_api_cert.c @@ -1542,7 +1542,10 @@ void wolfSSL_CTX_set_cert_store(WOLFSSL_CTX* ctx, WOLFSSL_X509_STORE* str) * X509_STORE_add_cert only go into store->certs, not the * CertManager. Push them into the CM now so that all * verification paths can find them. */ - X509StorePushCertsToCM(str); + if (X509StorePushCertsToCM(str) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("wolfSSL_CTX_set_cert_store: failed to push some " + "certs to CertManager"); + } #endif } } From 8342738f022cb0cb1cc1f4f6830955aef556f209 Mon Sep 17 00:00:00 2001 From: Roy Carter Date: Fri, 17 Apr 2026 22:24:48 +0300 Subject: [PATCH 063/167] Fix: PR notes fixes --- configure.ac | 2 +- wolfssl/internal.h | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 5041767496..5a2c80e53e 100644 --- a/configure.ac +++ b/configure.ac @@ -10379,7 +10379,7 @@ yes) AM_CFLAGS="$AM_CFLAGS -DHAVE_EX_DATA" [[1-9]]|[[1-9]][[0-9]]|[[1-9]][[0-9]][[0-9]]|[[1-9]][[0-9]][[0-9]][[0-9]]) AM_CFLAGS="$AM_CFLAGS -DHAVE_EX_DATA -DMAX_EX_DATA=$ENABLED_EX_DATA" ;; -*) AC_MSG_ERROR([Invalid argument to --enable-context-extra-user-data -- must be yes, no, or a number from 1 to 9999]) +*) AC_MSG_ERROR([Invalid argument to --enable-context-extra-user-data -- must be yes, no, or a number from 1 to 9999 (note: each index reserves one pointer per object, so large values increase memory use)]) ;; esac diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 82fb3a8a56..6bb51f117c 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1444,9 +1444,13 @@ enum { #ifndef WOLFSSL_COOKIE_LEN /* Maximum size for a DTLS cookie */ -#define WOLFSSL_COOKIE_LEN 32 +#define WOLFSSL_COOKIE_LEN 32 #endif +#if WOLFSSL_COOKIE_LEN > 255 +#error "WOLFSSL_COOKIE_LEN must be <= 255 per RFC 6347 (opaque<0..2^8-1>)" +#endif + #if defined(WOLFSSL_TLS13) || !defined(NO_PSK) #define TLS13_TICKET_NONCE_MAX_SZ 255 From 7f33de088244b2498f1aefc00835ff6e8a4f6c5f Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Tue, 14 Apr 2026 20:49:55 -0400 Subject: [PATCH 064/167] Rust wrapper: add digest implementations --- wrapper/rust/wolfssl-wolfcrypt/Cargo.lock | 29 +++- wrapper/rust/wolfssl-wolfcrypt/Cargo.toml | 3 + wrapper/rust/wolfssl-wolfcrypt/Makefile | 2 +- wrapper/rust/wolfssl-wolfcrypt/src/lib.rs | 2 + .../rust/wolfssl-wolfcrypt/src/sha_digest.rs | 142 +++++++++++++++++ .../tests/test_sha_digest.rs | 150 ++++++++++++++++++ 6 files changed, 326 insertions(+), 2 deletions(-) create mode 100644 wrapper/rust/wolfssl-wolfcrypt/src/sha_digest.rs create mode 100644 wrapper/rust/wolfssl-wolfcrypt/tests/test_sha_digest.rs diff --git a/wrapper/rust/wolfssl-wolfcrypt/Cargo.lock b/wrapper/rust/wolfssl-wolfcrypt/Cargo.lock index 9fe8a69681..098b575c0a 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/Cargo.lock +++ b/wrapper/rust/wolfssl-wolfcrypt/Cargo.lock @@ -8,7 +8,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ - "blobby", + "blobby 0.3.1", "crypto-common 0.1.7", "generic-array", ] @@ -54,6 +54,21 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "847495c209977a90e8aad588b959d0ca9f5dc228096d29a6bd3defd53f35eaec" +[[package]] +name = "blobby" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89af0b093cc13baa4e51e64e65ec2422f7e73aea0e612e5ad3872986671622f1" + +[[package]] +name = "block-buffer" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" +dependencies = [ + "hybrid-array", +] + [[package]] name = "cexpr" version = "0.6.0" @@ -110,6 +125,17 @@ dependencies = [ "hybrid-array", ] +[[package]] +name = "digest" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4850db49bf08e663084f7fb5c87d202ef91a3907271aff24a94eb97ff039153c" +dependencies = [ + "blobby 0.4.0", + "block-buffer", + "crypto-common 0.2.1", +] + [[package]] name = "either" version = "1.15.0" @@ -391,6 +417,7 @@ dependencies = [ "aead", "bindgen", "cipher", + "digest", "rand_core 0.10.0", "regex", "zeroize", diff --git a/wrapper/rust/wolfssl-wolfcrypt/Cargo.toml b/wrapper/rust/wolfssl-wolfcrypt/Cargo.toml index 08ee5ac62b..484a35f7c3 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/Cargo.toml +++ b/wrapper/rust/wolfssl-wolfcrypt/Cargo.toml @@ -15,16 +15,19 @@ std = [] rand_core = ["dep:rand_core"] aead = ["dep:aead"] cipher = ["dep:cipher"] +digest = ["dep:digest"] [dependencies] rand_core = { version = "0.10", optional = true, default-features = false } aead = { version = "0.5", optional = true, default-features = false } cipher = { version = "0.5", optional = true, default-features = false } +digest = { version = "0.11", optional = true, default-features = false, features = ["block-api"] } zeroize = { version = "1.3", default-features = false, features = ["derive"] } [dev-dependencies] aead = { version = "0.5", features = ["alloc", "dev"] } cipher = "0.5" +digest = { version = "0.11", features = ["dev"] } [build-dependencies] bindgen = "0.72.1" diff --git a/wrapper/rust/wolfssl-wolfcrypt/Makefile b/wrapper/rust/wolfssl-wolfcrypt/Makefile index 37dc9a8579..7a733f6481 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/Makefile +++ b/wrapper/rust/wolfssl-wolfcrypt/Makefile @@ -1,4 +1,4 @@ -FEATURES := rand_core,aead,cipher +FEATURES := rand_core,aead,cipher,digest CARGO_FEATURE_FLAGS := --features $(FEATURES) .PHONY: all diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/lib.rs b/wrapper/rust/wolfssl-wolfcrypt/src/lib.rs index 729c7cff96..f36bfdafe3 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/lib.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/lib.rs @@ -60,6 +60,8 @@ pub mod prf; pub mod random; pub mod rsa; pub mod sha; +#[cfg(feature = "digest")] +mod sha_digest; /// Convert a buffer length to `u32`, returning `BUFFER_E` if it overflows. pub(crate) fn buffer_len_to_u32(len: usize) -> Result { diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/sha_digest.rs b/wrapper/rust/wolfssl-wolfcrypt/src/sha_digest.rs new file mode 100644 index 0000000000..7a62666215 --- /dev/null +++ b/wrapper/rust/wolfssl-wolfcrypt/src/sha_digest.rs @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/*! +RustCrypto `digest` trait implementations for the wolfCrypt SHA-family hash +types. + +This module provides implementations of the traits from the `digest` crate +(`HashMarker`, `OutputSizeUser`, `BlockSizeUser`, `Update`, `Reset`, +`FixedOutput`, and `FixedOutputReset`) for the fixed-output hash types +defined in [`crate::sha`]. With these implementations the `digest::Digest` +trait becomes available via its blanket implementation, allowing these +hashers to be used anywhere a RustCrypto `Digest` is accepted. + +Any failure returned by the underlying wolfCrypt call in a trait method will +result in a panic, matching the infallible signatures required by the +RustCrypto traits. +*/ + +use digest::consts::{ + U20, U28, U32, U48, U64, U72, U104, U128, U136, U144, +}; + +macro_rules! impl_digest_traits { + ( + $(#[$attr:meta])* + $ty:path, out = $output:ty, block = $block:ty + ) => { + $(#[$attr])* + impl Default for $ty { + fn default() -> Self { + <$ty>::new().expect("wolfCrypt hash init failed") + } + } + + $(#[$attr])* + impl digest::HashMarker for $ty {} + + $(#[$attr])* + impl digest::OutputSizeUser for $ty { + type OutputSize = $output; + } + + $(#[$attr])* + impl digest::block_api::BlockSizeUser for $ty { + type BlockSize = $block; + } + + $(#[$attr])* + impl digest::Update for $ty { + fn update(&mut self, data: &[u8]) { + <$ty>::update(self, data).expect("wolfCrypt hash update failed"); + } + } + + $(#[$attr])* + impl digest::Reset for $ty { + fn reset(&mut self) { + <$ty>::init(self).expect("wolfCrypt hash init failed"); + } + } + + $(#[$attr])* + impl digest::FixedOutput for $ty { + fn finalize_into(mut self, out: &mut digest::Output) { + <$ty>::finalize(&mut self, out.as_mut_slice()) + .expect("wolfCrypt hash finalize failed"); + } + } + + $(#[$attr])* + impl digest::FixedOutputReset for $ty { + fn finalize_into_reset(&mut self, out: &mut digest::Output) { + <$ty>::finalize(self, out.as_mut_slice()) + .expect("wolfCrypt hash finalize failed"); + <$ty>::init(self).expect("wolfCrypt hash init failed"); + } + } + }; +} + +impl_digest_traits! { + #[cfg(sha)] + crate::sha::SHA, out = U20, block = U64 +} + +impl_digest_traits! { + #[cfg(sha224)] + crate::sha::SHA224, out = U28, block = U64 +} + +impl_digest_traits! { + #[cfg(sha256)] + crate::sha::SHA256, out = U32, block = U64 +} + +impl_digest_traits! { + #[cfg(sha384)] + crate::sha::SHA384, out = U48, block = U128 +} + +impl_digest_traits! { + #[cfg(sha512)] + crate::sha::SHA512, out = U64, block = U128 +} + +impl_digest_traits! { + #[cfg(sha3)] + crate::sha::SHA3_224, out = U28, block = U144 +} + +impl_digest_traits! { + #[cfg(sha3)] + crate::sha::SHA3_256, out = U32, block = U136 +} + +impl_digest_traits! { + #[cfg(sha3)] + crate::sha::SHA3_384, out = U48, block = U104 +} + +impl_digest_traits! { + #[cfg(sha3)] + crate::sha::SHA3_512, out = U64, block = U72 +} diff --git a/wrapper/rust/wolfssl-wolfcrypt/tests/test_sha_digest.rs b/wrapper/rust/wolfssl-wolfcrypt/tests/test_sha_digest.rs new file mode 100644 index 0000000000..090cf1ac3d --- /dev/null +++ b/wrapper/rust/wolfssl-wolfcrypt/tests/test_sha_digest.rs @@ -0,0 +1,150 @@ +#![cfg(feature = "digest")] + +use digest::{Digest, FixedOutputReset}; +use digest::block_api::BlockSizeUser; + +mod common; + +fn check_digest( + input: &[u8], + expected: &[u8], + expected_block_size: usize, +) { + assert_eq!(::output_size(), expected.len()); + assert_eq!(::block_size(), expected_block_size); + + /* One-shot digest via associated function. */ + let out = D::digest(input); + assert_eq!(out.as_slice(), expected); + + /* Streaming via Digest::update and finalize. */ + let mut hasher = D::new(); + Digest::update(&mut hasher, input); + let out = hasher.finalize(); + assert_eq!(out.as_slice(), expected); + + /* Split update, via Default + Update + FixedOutputReset::finalize_reset. */ + let mut hasher = D::default(); + if input.len() >= 2 { + let mid = input.len() / 2; + Digest::update(&mut hasher, &input[..mid]); + Digest::update(&mut hasher, &input[mid..]); + } else { + Digest::update(&mut hasher, input); + } + let out = hasher.finalize_reset(); + assert_eq!(out.as_slice(), expected); + + /* After reset, the same hasher should produce the same result. */ + Digest::update(&mut hasher, input); + let out = hasher.finalize(); + assert_eq!(out.as_slice(), expected); +} + +#[test] +#[cfg(sha)] +fn test_digest_sha() { + use wolfssl_wolfcrypt::sha::SHA; + common::setup(); + check_digest::( + b"abc", + b"\xA9\x99\x3E\x36\x47\x06\x81\x6A\xBA\x3E\x25\x71\x78\x50\xC2\x6C\x9C\xD0\xD8\x9D", + 64, + ); +} + +#[test] +#[cfg(sha224)] +fn test_digest_sha224() { + use wolfssl_wolfcrypt::sha::SHA224; + common::setup(); + check_digest::( + b"abc", + b"\x23\x09\x7d\x22\x34\x05\xd8\x22\x86\x42\xa4\x77\xbd\xa2\x55\xb3\x2a\xad\xbc\xe4\xbd\xa0\xb3\xf7\xe3\x6c\x9d\xa7", + 64, + ); +} + +#[test] +#[cfg(sha256)] +fn test_digest_sha256() { + use wolfssl_wolfcrypt::sha::SHA256; + common::setup(); + check_digest::( + b"abc", + b"\xBA\x78\x16\xBF\x8F\x01\xCF\xEA\x41\x41\x40\xDE\x5D\xAE\x22\x23\xB0\x03\x61\xA3\x96\x17\x7A\x9C\xB4\x10\xFF\x61\xF2\x00\x15\xAD", + 64, + ); +} + +#[test] +#[cfg(sha384)] +fn test_digest_sha384() { + use wolfssl_wolfcrypt::sha::SHA384; + common::setup(); + check_digest::( + b"abc", + b"\xcb\x00\x75\x3f\x45\xa3\x5e\x8b\xb5\xa0\x3d\x69\x9a\xc6\x50\x07\x27\x2c\x32\xab\x0e\xde\xd1\x63\x1a\x8b\x60\x5a\x43\xff\x5b\xed\x80\x86\x07\x2b\xa1\xe7\xcc\x23\x58\xba\xec\xa1\x34\xc8\x25\xa7", + 128, + ); +} + +#[test] +#[cfg(sha512)] +fn test_digest_sha512() { + use wolfssl_wolfcrypt::sha::SHA512; + common::setup(); + check_digest::( + b"abc", + b"\xdd\xaf\x35\xa1\x93\x61\x7a\xba\xcc\x41\x73\x49\xae\x20\x41\x31\x12\xe6\xfa\x4e\x89\xa9\x7e\xa2\x0a\x9e\xee\xe6\x4b\x55\xd3\x9a\x21\x92\x99\x2a\x27\x4f\xc1\xa8\x36\xba\x3c\x23\xa3\xfe\xeb\xbd\x45\x4d\x44\x23\x64\x3c\xe8\x0e\x2a\x9a\xc9\x4f\xa5\x4c\xa4\x9f", + 128, + ); +} + +#[test] +#[cfg(sha3)] +fn test_digest_sha3_224() { + use wolfssl_wolfcrypt::sha::SHA3_224; + common::setup(); + check_digest::( + b"abc", + b"\xe6\x42\x82\x4c\x3f\x8c\xf2\x4a\xd0\x92\x34\xee\x7d\x3c\x76\x6f\xc9\xa3\xa5\x16\x8d\x0c\x94\xad\x73\xb4\x6f\xdf", + 144, + ); +} + +#[test] +#[cfg(sha3)] +fn test_digest_sha3_256() { + use wolfssl_wolfcrypt::sha::SHA3_256; + common::setup(); + check_digest::( + b"abc", + b"\x3a\x98\x5d\xa7\x4f\xe2\x25\xb2\x04\x5c\x17\x2d\x6b\xd3\x90\xbd\x85\x5f\x08\x6e\x3e\x9d\x52\x5b\x46\xbf\xe2\x45\x11\x43\x15\x32", + 136, + ); +} + +#[test] +#[cfg(sha3)] +fn test_digest_sha3_384() { + use wolfssl_wolfcrypt::sha::SHA3_384; + common::setup(); + check_digest::( + b"abc", + b"\xec\x01\x49\x82\x88\x51\x6f\xc9\x26\x45\x9f\x58\xe2\xc6\xad\x8d\xf9\xb4\x73\xcb\x0f\xc0\x8c\x25\x96\xda\x7c\xf0\xe4\x9b\xe4\xb2\x98\xd8\x8c\xea\x92\x7a\xc7\xf5\x39\xf1\xed\xf2\x28\x37\x6d\x25", + 104, + ); +} + +#[test] +#[cfg(sha3)] +fn test_digest_sha3_512() { + use wolfssl_wolfcrypt::sha::SHA3_512; + common::setup(); + check_digest::( + b"abc", + b"\xb7\x51\x85\x0b\x1a\x57\x16\x8a\x56\x93\xcd\x92\x4b\x6b\x09\x6e\x08\xf6\x21\x82\x74\x44\xf7\x0d\x88\x4f\x5d\x02\x40\xd2\x71\x2e\x10\xe1\x16\xe9\x19\x2a\xf3\xc9\x1a\x7e\xc5\x76\x47\xe3\x93\x40\x57\x34\x0b\x4c\xf4\x08\xd5\xa5\x65\x92\xf8\x27\x4e\xec\x53\xf0", + 72, + ); +} From 3ca90b19049536372c2ae83b2d5beb460b8c3c2b Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Fri, 17 Apr 2026 15:51:39 -0400 Subject: [PATCH 065/167] Rust wrapper: add signature implementations --- wrapper/rust/wolfssl-wolfcrypt/Cargo.lock | 7 + wrapper/rust/wolfssl-wolfcrypt/Cargo.toml | 3 + wrapper/rust/wolfssl-wolfcrypt/Makefile | 2 +- wrapper/rust/wolfssl-wolfcrypt/build.rs | 16 + wrapper/rust/wolfssl-wolfcrypt/src/ecc.rs | 2 +- wrapper/rust/wolfssl-wolfcrypt/src/ecdsa.rs | 372 ++++++++++++++++++ wrapper/rust/wolfssl-wolfcrypt/src/ed25519.rs | 120 ++++++ wrapper/rust/wolfssl-wolfcrypt/src/ed448.rs | 124 ++++++ wrapper/rust/wolfssl-wolfcrypt/src/lib.rs | 4 + wrapper/rust/wolfssl-wolfcrypt/src/rsa.rs | 54 ++- .../wolfssl-wolfcrypt/src/rsa_pkcs1v15.rs | 346 ++++++++++++++++ .../wolfssl-wolfcrypt/tests/test_ecdsa.rs | 142 +++++++ .../wolfssl-wolfcrypt/tests/test_ed25519.rs | 37 ++ .../wolfssl-wolfcrypt/tests/test_ed448.rs | 37 ++ .../tests/test_rsa_pkcs1v15.rs | 81 ++++ 15 files changed, 1344 insertions(+), 3 deletions(-) create mode 100644 wrapper/rust/wolfssl-wolfcrypt/src/ecdsa.rs create mode 100644 wrapper/rust/wolfssl-wolfcrypt/src/rsa_pkcs1v15.rs create mode 100644 wrapper/rust/wolfssl-wolfcrypt/tests/test_ecdsa.rs create mode 100644 wrapper/rust/wolfssl-wolfcrypt/tests/test_rsa_pkcs1v15.rs diff --git a/wrapper/rust/wolfssl-wolfcrypt/Cargo.lock b/wrapper/rust/wolfssl-wolfcrypt/Cargo.lock index 098b575c0a..ea88736bdf 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/Cargo.lock +++ b/wrapper/rust/wolfssl-wolfcrypt/Cargo.lock @@ -310,6 +310,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" + [[package]] name = "syn" version = "2.0.106" @@ -420,6 +426,7 @@ dependencies = [ "digest", "rand_core 0.10.0", "regex", + "signature", "zeroize", ] diff --git a/wrapper/rust/wolfssl-wolfcrypt/Cargo.toml b/wrapper/rust/wolfssl-wolfcrypt/Cargo.toml index 484a35f7c3..9defa79fee 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/Cargo.toml +++ b/wrapper/rust/wolfssl-wolfcrypt/Cargo.toml @@ -16,18 +16,21 @@ rand_core = ["dep:rand_core"] aead = ["dep:aead"] cipher = ["dep:cipher"] digest = ["dep:digest"] +signature = ["dep:signature"] [dependencies] rand_core = { version = "0.10", optional = true, default-features = false } aead = { version = "0.5", optional = true, default-features = false } cipher = { version = "0.5", optional = true, default-features = false } digest = { version = "0.11", optional = true, default-features = false, features = ["block-api"] } +signature = { version = "2.2", optional = true, default-features = false } zeroize = { version = "1.3", default-features = false, features = ["derive"] } [dev-dependencies] aead = { version = "0.5", features = ["alloc", "dev"] } cipher = "0.5" digest = { version = "0.11", features = ["dev"] } +signature = "2.2" [build-dependencies] bindgen = "0.72.1" diff --git a/wrapper/rust/wolfssl-wolfcrypt/Makefile b/wrapper/rust/wolfssl-wolfcrypt/Makefile index 7a733f6481..51dc4c801e 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/Makefile +++ b/wrapper/rust/wolfssl-wolfcrypt/Makefile @@ -1,4 +1,4 @@ -FEATURES := rand_core,aead,cipher,digest +FEATURES := rand_core,aead,cipher,digest,signature CARGO_FEATURE_FLAGS := --features $(FEATURES) .PHONY: all diff --git a/wrapper/rust/wolfssl-wolfcrypt/build.rs b/wrapper/rust/wolfssl-wolfcrypt/build.rs index 6f275d3a3b..6495d6bdb8 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/build.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/build.rs @@ -433,6 +433,22 @@ fn scan_cfg() -> Result<()> { check_cfg(&binding, "wc_RNG_DRBG_Reseed", "random_hashdrbg"); check_cfg(&binding, "wc_InitRng", "random"); + // When WOLFSSL_NO_MALLOC is set without WOLFSSL_STATIC_MEMORY, the + // WC_RNG struct contains an inline `drbg_data` field and wolfCrypt sets + // `rng->drbg = &rng->drbg_data` — a self-referential pointer. Rust + // moves values by memcpy, which would silently invalidate that pointer. + // Detect this configuration and refuse to build. + if binding.contains("drbg_data") { + eprintln!( + "error: wolfSSL appears to be built with WOLFSSL_NO_MALLOC \ + (without WOLFSSL_STATIC_MEMORY). This embeds a self-referential \ + pointer inside WC_RNG (drbg -> drbg_data) that is incompatible \ + with Rust move semantics. Please rebuild wolfSSL without \ + WOLFSSL_NO_MALLOC, or enable WOLFSSL_STATIC_MEMORY." + ); + std::process::exit(1); + } + /* rsa */ check_cfg(&binding, "wc_InitRsaKey", "rsa"); check_cfg(&binding, "wc_RsaDirect", "rsa_direct"); diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/ecc.rs b/wrapper/rust/wolfssl-wolfcrypt/src/ecc.rs index e8a2e3700b..4fc2cd8921 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/ecc.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/ecc.rs @@ -296,7 +296,7 @@ impl Drop for ECCPoint { /// `import_x963_ex()`, `import_private_key()`, `import_private_key_ex()`, /// `import_raw()`, or `import_raw_ex()`. pub struct ECC { - wc_ecc_key: sys::ecc_key, + pub(crate) wc_ecc_key: sys::ecc_key, } #[cfg(ecc_curve_ids)] diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/ecdsa.rs b/wrapper/rust/wolfssl-wolfcrypt/src/ecdsa.rs new file mode 100644 index 0000000000..b771694b05 --- /dev/null +++ b/wrapper/rust/wolfssl-wolfcrypt/src/ecdsa.rs @@ -0,0 +1,372 @@ +/* + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/*! +ECDSA trait impls for the RustCrypto `signature` crate. + +Provides per-curve wrapper types (`P256SigningKey`, `P256VerifyingKey`, +`P256Signature`, etc.) over the inherent [`crate::ecc::ECC`] wrapper. Each +curve pairs with its canonical hash algorithm (P-256 with SHA-256, P-384 with +SHA-384, P-521 with SHA-512) and produces fixed-size `r‖s` signatures +matching the conventions used by the RustCrypto `ecdsa` crate. + +Signing and verifying use the high-level `wc_SignatureGenerate` / +`wc_SignatureVerify` wolfCrypt entry points, which hash the raw message +internally and emit/consume DER-encoded ECDSA signatures; the wrapper +converts between DER and fixed `r‖s` via `wc_ecc_sig_to_rs` and +`wc_ecc_rs_raw_to_sig`. +*/ + +#![cfg(all(feature = "signature", ecc, ecc_sign, ecc_verify, ecc_import, ecc_export, ecc_curve_ids, random))] + +use core::ffi::c_void; +use core::mem::size_of; + +use signature::{Error, Keypair, SignatureEncoding, SignerMut, Verifier}; + +use crate::ecc::ECC; +use crate::random::RNG; +use crate::sys; + +/// Build a fixed `r‖s` signature buffer from DER bytes produced by wolfCrypt. +fn der_to_rs( + der: &[u8], +) -> Result<[u8; SIG_SIZE], Error> { + debug_assert_eq!(SIG_SIZE, 2 * FIELD_SIZE); + let mut r_buf = [0u8; FIELD_SIZE]; + let mut s_buf = [0u8; FIELD_SIZE]; + let mut r_len = FIELD_SIZE as u32; + let mut s_len = FIELD_SIZE as u32; + let rc = unsafe { + sys::wc_ecc_sig_to_rs( + der.as_ptr(), der.len() as u32, + r_buf.as_mut_ptr(), &mut r_len, + s_buf.as_mut_ptr(), &mut s_len, + ) + }; + if rc != 0 { + return Err(Error::new()); + } + let r_len = r_len as usize; + let s_len = s_len as usize; + if r_len > FIELD_SIZE || s_len > FIELD_SIZE { + return Err(Error::new()); + } + let mut out = [0u8; SIG_SIZE]; + out[FIELD_SIZE - r_len..FIELD_SIZE].copy_from_slice(&r_buf[..r_len]); + out[SIG_SIZE - s_len..SIG_SIZE].copy_from_slice(&s_buf[..s_len]); + Ok(out) +} + +/// Build a DER signature from fixed `r‖s` bytes. +fn rs_to_der( + rs: &[u8], + der_out: &mut [u8], +) -> Result { + if rs.len() != 2 * FIELD_SIZE { + return Err(Error::new()); + } + let (r, s) = rs.split_at(FIELD_SIZE); + let mut der_len = der_out.len() as u32; + let rc = unsafe { + sys::wc_ecc_rs_raw_to_sig( + r.as_ptr(), FIELD_SIZE as u32, + s.as_ptr(), FIELD_SIZE as u32, + der_out.as_mut_ptr(), &mut der_len, + ) + }; + if rc != 0 { + return Err(Error::new()); + } + Ok(der_len as usize) +} + +macro_rules! define_ecdsa_curve { + ( + $(#[$meta:meta])* + ($signing_key:ident, $verifying_key:ident, $signature:ident), + field_size = $field_size:literal, + sig_size = $sig_size:literal, + x963_size = $x963_size:literal, + der_max = $der_max:literal, + curve_id = $curve_id:expr, + hash_type = $hash_type:expr, + hash_cfg = $hash_cfg:meta $(,)? + ) => { + /// Fixed-size ECDSA signature in `r‖s` form. + $(#[$meta])* + #[cfg($hash_cfg)] + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct $signature([u8; $sig_size]); + + #[cfg($hash_cfg)] + impl $signature { + /// Size in bytes of the fixed `r‖s` encoding. + pub const BYTE_SIZE: usize = $sig_size; + + /// Construct a signature from raw `r‖s` bytes. + pub const fn from_bytes(bytes: [u8; $sig_size]) -> Self { + Self(bytes) + } + + /// Return the raw `r‖s` bytes. + pub const fn to_bytes(&self) -> [u8; $sig_size] { + self.0 + } + } + + #[cfg($hash_cfg)] + impl AsRef<[u8]> for $signature { + fn as_ref(&self) -> &[u8] { &self.0 } + } + + #[cfg($hash_cfg)] + impl TryFrom<&[u8]> for $signature { + type Error = Error; + fn try_from(bytes: &[u8]) -> Result { + let arr: [u8; $sig_size] = bytes.try_into().map_err(|_| Error::new())?; + Ok(Self(arr)) + } + } + + #[cfg($hash_cfg)] + impl From<$signature> for [u8; $sig_size] { + fn from(sig: $signature) -> Self { sig.0 } + } + + #[cfg($hash_cfg)] + impl SignatureEncoding for $signature { + type Repr = [u8; $sig_size]; + } + + /// ECDSA signing key (private key + owned RNG + cached public key). + $(#[$meta])* + #[cfg($hash_cfg)] + pub struct $signing_key { + inner: ECC, + rng: RNG, + pub_bytes: [u8; $x963_size], + } + + #[cfg($hash_cfg)] + impl $signing_key { + /// Byte length of the uncompressed X9.63 public key encoding. + pub const PUB_KEY_SIZE: usize = $x963_size; + + /// Private-scalar byte length (`d`, curve field size). + pub const SCALAR_SIZE: usize = $field_size; + + /// Generate a fresh signing key using the provided RNG. + pub fn generate(mut rng: RNG) -> Result { + let ecc = ECC::generate_ex( + $field_size as i32, + &mut rng, + $curve_id, + None, None, + )?; + Self::from_ecc(ecc, rng) + } + + /// Import a signing key from unsigned big-endian public + /// coordinates `qx`, `qy` and private scalar `d`, each of exactly + /// the curve's field size in bytes. + pub fn import_unsigned( + qx: &[u8; $field_size], + qy: &[u8; $field_size], + d: &[u8; $field_size], + rng: RNG, + ) -> Result { + let ecc = ECC::import_unsigned(qx, qy, d, $curve_id, None, None)?; + Self::from_ecc(ecc, rng) + } + + /// Import a signing key from an uncompressed X9.63 public key + /// (leading `0x04` byte + `x‖y`) and a matching unsigned + /// big-endian private scalar `d`. + pub fn import_x963( + public_x963: &[u8; $x963_size], + d: &[u8; $field_size], + rng: RNG, + ) -> Result { + let ecc = ECC::import_private_key_ex( + d, public_x963, $curve_id, None, None, + )?; + Self::from_ecc(ecc, rng) + } + + /// Borrow the inner [`ECC`] key for operations not covered by the + /// signature traits. + pub fn as_ecc(&self) -> &ECC { &self.inner } + + /// Consume the signing key and return its `ECC` and `RNG` parts. + pub fn into_parts(self) -> (ECC, RNG) { + (self.inner, self.rng) + } + + /// Helper that caches the X9.63 public key bytes from an already + /// populated [`ECC`] and pairs it with the given `rng`. + fn from_ecc(mut ecc: ECC, rng: RNG) -> Result { + let mut pub_bytes = [0u8; $x963_size]; + let written = ecc.export_x963(&mut pub_bytes)?; + if written != $x963_size { + return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); + } + Ok(Self { inner: ecc, rng, pub_bytes }) + } + } + + #[cfg($hash_cfg)] + impl Keypair for $signing_key { + type VerifyingKey = $verifying_key; + fn verifying_key(&self) -> $verifying_key { + $verifying_key { pub_bytes: self.pub_bytes } + } + } + + #[cfg($hash_cfg)] + impl SignerMut<$signature> for $signing_key { + fn try_sign(&mut self, msg: &[u8]) -> Result<$signature, Error> { + let mut der = [0u8; $der_max]; + let mut der_len: u32 = der.len() as u32; + let msg_len: u32 = msg.len().try_into().map_err(|_| Error::new())?; + let rc = unsafe { + sys::wc_SignatureGenerate( + $hash_type, + sys::wc_SignatureType_WC_SIGNATURE_TYPE_ECC, + msg.as_ptr(), msg_len, + der.as_mut_ptr(), &mut der_len, + &mut self.inner.wc_ecc_key as *mut _ as *mut c_void, + size_of::() as u32, + &mut self.rng.wc_rng, + ) + }; + if rc != 0 { + return Err(Error::new()); + } + let rs = der_to_rs::<$sig_size, $field_size>(&der[..der_len as usize])?; + Ok($signature(rs)) + } + } + + /// ECDSA verifying key. Owns the uncompressed X9.63 public key bytes + /// and instantiates a short-lived [`ECC`] on each verification. + $(#[$meta])* + #[cfg($hash_cfg)] + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct $verifying_key { + pub_bytes: [u8; $x963_size], + } + + #[cfg($hash_cfg)] + impl $verifying_key { + /// Byte length of the uncompressed X9.63 public key encoding. + pub const BYTE_SIZE: usize = $x963_size; + + /// Construct a verifying key from its uncompressed X9.63 bytes. + /// + /// The buffer must start with `0x04` followed by `x‖y` (each + /// `FIELD_SIZE` bytes). + pub const fn from_bytes(bytes: [u8; $x963_size]) -> Self { + Self { pub_bytes: bytes } + } + + /// Return the uncompressed X9.63 public key bytes. + pub const fn to_bytes(&self) -> [u8; $x963_size] { + self.pub_bytes + } + } + + #[cfg($hash_cfg)] + impl AsRef<[u8]> for $verifying_key { + fn as_ref(&self) -> &[u8] { &self.pub_bytes } + } + + #[cfg($hash_cfg)] + impl TryFrom<&[u8]> for $verifying_key { + type Error = Error; + fn try_from(bytes: &[u8]) -> Result { + let arr: [u8; $x963_size] = + bytes.try_into().map_err(|_| Error::new())?; + Ok(Self { pub_bytes: arr }) + } + } + + #[cfg($hash_cfg)] + impl Verifier<$signature> for $verifying_key { + fn verify(&self, msg: &[u8], sig: &$signature) -> Result<(), Error> { + let mut der = [0u8; $der_max]; + let der_len = rs_to_der::<$field_size>(&sig.0, &mut der)?; + let mut key = ECC::import_x963_ex(&self.pub_bytes, $curve_id, None, None) + .map_err(|_| Error::new())?; + let msg_len: u32 = msg.len().try_into().map_err(|_| Error::new())?; + let rc = unsafe { + sys::wc_SignatureVerify( + $hash_type, + sys::wc_SignatureType_WC_SIGNATURE_TYPE_ECC, + msg.as_ptr(), msg_len, + der.as_ptr(), der_len as u32, + &mut key.wc_ecc_key as *mut _ as *mut c_void, + size_of::() as u32, + ) + }; + if rc != 0 { + return Err(Error::new()); + } + Ok(()) + } + } + }; +} + +define_ecdsa_curve! { + /// NIST P-256 (secp256r1) paired with SHA-256. + (P256SigningKey, P256VerifyingKey, P256Signature), + field_size = 32, + sig_size = 64, + x963_size = 65, + der_max = 72, + curve_id = sys::ecc_curve_ids_ECC_SECP256R1, + hash_type = sys::wc_HashType_WC_HASH_TYPE_SHA256, + hash_cfg = sha256, +} + +define_ecdsa_curve! { + /// NIST P-384 (secp384r1) paired with SHA-384. + (P384SigningKey, P384VerifyingKey, P384Signature), + field_size = 48, + sig_size = 96, + x963_size = 97, + der_max = 104, + curve_id = sys::ecc_curve_ids_ECC_SECP384R1, + hash_type = sys::wc_HashType_WC_HASH_TYPE_SHA384, + hash_cfg = sha384, +} + +define_ecdsa_curve! { + /// NIST P-521 (secp521r1) paired with SHA-512. + (P521SigningKey, P521VerifyingKey, P521Signature), + field_size = 66, + sig_size = 132, + x963_size = 133, + der_max = 141, + curve_id = sys::ecc_curve_ids_ECC_SECP521R1, + hash_type = sys::wc_HashType_WC_HASH_TYPE_SHA512, + hash_cfg = sha512, +} diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/ed25519.rs b/wrapper/rust/wolfssl-wolfcrypt/src/ed25519.rs index d0e7e4f1df..a0b91f1e27 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/ed25519.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/ed25519.rs @@ -1443,3 +1443,123 @@ impl Drop for Ed25519 { self.zeroize(); } } + +/// RustCrypto `signature` crate trait implementations. +/// +/// Provides a fixed-size [`Signature`] and a [`VerifyingKey`] type so that +/// [`Ed25519`] can be used wherever the `signature` crate's +/// [`signature::SignerMut`], [`signature::Keypair`], and +/// [`signature::Verifier`] traits are accepted. +#[cfg(feature = "signature")] +mod signature_impl { + use super::Ed25519; + use signature::Error; + + /// Ed25519 signature in its standard 64-byte encoded form. + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct Signature([u8; Ed25519::SIG_SIZE]); + + impl Signature { + /// Construct a signature from its raw bytes. + pub const fn from_bytes(bytes: [u8; Ed25519::SIG_SIZE]) -> Self { + Self(bytes) + } + + /// Return the raw signature bytes. + pub const fn to_bytes(&self) -> [u8; Ed25519::SIG_SIZE] { + self.0 + } + } + + impl AsRef<[u8]> for Signature { + fn as_ref(&self) -> &[u8] { + &self.0 + } + } + + impl TryFrom<&[u8]> for Signature { + type Error = Error; + fn try_from(bytes: &[u8]) -> Result { + let arr: [u8; Ed25519::SIG_SIZE] = bytes.try_into().map_err(|_| Error::new())?; + Ok(Self(arr)) + } + } + + impl From for [u8; Ed25519::SIG_SIZE] { + fn from(sig: Signature) -> Self { + sig.0 + } + } + + impl signature::SignatureEncoding for Signature { + type Repr = [u8; Ed25519::SIG_SIZE]; + } + + /// Ed25519 verifying (public) key. + /// + /// Owns a copy of the 32-byte compressed public key and instantiates a + /// short-lived wolfCrypt `ed25519_key` on each verification. + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct VerifyingKey([u8; Ed25519::PUB_KEY_SIZE]); + + impl VerifyingKey { + /// Construct a verifying key from its raw public key bytes. + pub const fn from_bytes(bytes: [u8; Ed25519::PUB_KEY_SIZE]) -> Self { + Self(bytes) + } + + /// Return the raw public key bytes. + pub const fn to_bytes(&self) -> [u8; Ed25519::PUB_KEY_SIZE] { + self.0 + } + } + + impl AsRef<[u8]> for VerifyingKey { + fn as_ref(&self) -> &[u8] { + &self.0 + } + } + + impl TryFrom<&[u8]> for VerifyingKey { + type Error = Error; + fn try_from(bytes: &[u8]) -> Result { + let arr: [u8; Ed25519::PUB_KEY_SIZE] = + bytes.try_into().map_err(|_| Error::new())?; + Ok(Self(arr)) + } + } + + #[cfg(all(ed25519_sign, ed25519_export))] + impl signature::Keypair for Ed25519 { + type VerifyingKey = VerifyingKey; + fn verifying_key(&self) -> Self::VerifyingKey { + let mut pub_key = [0u8; Ed25519::PUB_KEY_SIZE]; + self.export_public(&mut pub_key).expect("ed25519 export_public failed"); + VerifyingKey(pub_key) + } + } + + #[cfg(ed25519_sign)] + impl signature::SignerMut for Ed25519 { + fn try_sign(&mut self, msg: &[u8]) -> Result { + let mut sig = [0u8; Ed25519::SIG_SIZE]; + self.sign_msg(msg, &mut sig).map_err(|_| Error::new())?; + Ok(Signature(sig)) + } + } + + #[cfg(all(ed25519_import, ed25519_verify))] + impl signature::Verifier for VerifyingKey { + fn verify(&self, msg: &[u8], signature: &Signature) -> Result<(), Error> { + let mut key = Ed25519::new().map_err(|_| Error::new())?; + key.import_public(&self.0).map_err(|_| Error::new())?; + let valid = key + .verify_msg(&signature.0, msg) + .map_err(|_| Error::new())?; + if valid { Ok(()) } else { Err(Error::new()) } + } + } +} + +#[cfg(feature = "signature")] +pub use signature_impl::{Signature, VerifyingKey}; diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/ed448.rs b/wrapper/rust/wolfssl-wolfcrypt/src/ed448.rs index 9191bed688..0a77aa071e 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/ed448.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/ed448.rs @@ -1368,3 +1368,127 @@ impl Drop for Ed448 { self.zeroize(); } } + +/// RustCrypto `signature` crate trait implementations. +/// +/// Provides a fixed-size [`Signature`] and a [`VerifyingKey`] type so that +/// [`Ed448`] can be used wherever the `signature` crate's +/// [`signature::SignerMut`], [`signature::Keypair`], and +/// [`signature::Verifier`] traits are accepted. +/// +/// These impls use the plain Ed448 (pure) signature variant with no context; +/// the context-, hashed-, and streaming-signature variants remain accessible +/// via the inherent methods on [`Ed448`]. +#[cfg(feature = "signature")] +mod signature_impl { + use super::Ed448; + use signature::Error; + + /// Ed448 signature in its standard 114-byte encoded form. + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct Signature([u8; Ed448::SIG_SIZE]); + + impl Signature { + /// Construct a signature from its raw bytes. + pub const fn from_bytes(bytes: [u8; Ed448::SIG_SIZE]) -> Self { + Self(bytes) + } + + /// Return the raw signature bytes. + pub const fn to_bytes(&self) -> [u8; Ed448::SIG_SIZE] { + self.0 + } + } + + impl AsRef<[u8]> for Signature { + fn as_ref(&self) -> &[u8] { + &self.0 + } + } + + impl TryFrom<&[u8]> for Signature { + type Error = Error; + fn try_from(bytes: &[u8]) -> Result { + let arr: [u8; Ed448::SIG_SIZE] = bytes.try_into().map_err(|_| Error::new())?; + Ok(Self(arr)) + } + } + + impl From for [u8; Ed448::SIG_SIZE] { + fn from(sig: Signature) -> Self { + sig.0 + } + } + + impl signature::SignatureEncoding for Signature { + type Repr = [u8; Ed448::SIG_SIZE]; + } + + /// Ed448 verifying (public) key. + /// + /// Owns a copy of the 57-byte compressed public key and instantiates a + /// short-lived wolfCrypt `ed448_key` on each verification. + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct VerifyingKey([u8; Ed448::PUB_KEY_SIZE]); + + impl VerifyingKey { + /// Construct a verifying key from its raw public key bytes. + pub const fn from_bytes(bytes: [u8; Ed448::PUB_KEY_SIZE]) -> Self { + Self(bytes) + } + + /// Return the raw public key bytes. + pub const fn to_bytes(&self) -> [u8; Ed448::PUB_KEY_SIZE] { + self.0 + } + } + + impl AsRef<[u8]> for VerifyingKey { + fn as_ref(&self) -> &[u8] { + &self.0 + } + } + + impl TryFrom<&[u8]> for VerifyingKey { + type Error = Error; + fn try_from(bytes: &[u8]) -> Result { + let arr: [u8; Ed448::PUB_KEY_SIZE] = + bytes.try_into().map_err(|_| Error::new())?; + Ok(Self(arr)) + } + } + + #[cfg(all(ed448_sign, ed448_export))] + impl signature::Keypair for Ed448 { + type VerifyingKey = VerifyingKey; + fn verifying_key(&self) -> Self::VerifyingKey { + let mut pub_key = [0u8; Ed448::PUB_KEY_SIZE]; + self.export_public(&mut pub_key).expect("ed448 export_public failed"); + VerifyingKey(pub_key) + } + } + + #[cfg(ed448_sign)] + impl signature::SignerMut for Ed448 { + fn try_sign(&mut self, msg: &[u8]) -> Result { + let mut sig = [0u8; Ed448::SIG_SIZE]; + self.sign_msg(msg, None, &mut sig).map_err(|_| Error::new())?; + Ok(Signature(sig)) + } + } + + #[cfg(all(ed448_import, ed448_verify))] + impl signature::Verifier for VerifyingKey { + fn verify(&self, msg: &[u8], signature: &Signature) -> Result<(), Error> { + let mut key = Ed448::new().map_err(|_| Error::new())?; + key.import_public(&self.0).map_err(|_| Error::new())?; + let valid = key + .verify_msg(&signature.0, msg, None) + .map_err(|_| Error::new())?; + if valid { Ok(()) } else { Err(Error::new()) } + } + } +} + +#[cfg(feature = "signature")] +pub use signature_impl::{Signature, VerifyingKey}; diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/lib.rs b/wrapper/rust/wolfssl-wolfcrypt/src/lib.rs index f36bfdafe3..0c954abce9 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/lib.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/lib.rs @@ -48,6 +48,8 @@ pub mod curve25519; pub mod dh; pub mod dilithium; pub mod ecc; +#[cfg(feature = "signature")] +pub mod ecdsa; pub mod ed25519; pub mod ed448; pub mod fips; @@ -59,6 +61,8 @@ pub mod mlkem; pub mod prf; pub mod random; pub mod rsa; +#[cfg(feature = "signature")] +pub mod rsa_pkcs1v15; pub mod sha; #[cfg(feature = "digest")] mod sha_digest; diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/rsa.rs b/wrapper/rust/wolfssl-wolfcrypt/src/rsa.rs index 56526f34ab..3e89b79142 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/rsa.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/rsa.rs @@ -71,7 +71,7 @@ use core::mem::{MaybeUninit}; /// An instance can be created with `new_from_der()`, `new_public_from_der()`, /// or `generate()`. pub struct RSA { - wc_rsakey: sys::RsaKey, + pub(crate) wc_rsakey: sys::RsaKey, } impl RSA { @@ -362,6 +362,58 @@ impl RSA { Ok(rsa) } + /// Create a new RSA public key from raw modulus (`n`) and public + /// exponent (`e`) bytes in big-endian form. + /// + /// # Parameters + /// + /// * `n`: Big-endian modulus bytes. + /// * `e`: Big-endian public exponent bytes. + /// + /// # Returns + /// + /// Returns either Ok(RSA) containing the RSA struct instance or Err(e) + /// containing the wolfSSL library error code value. + pub fn new_public_from_raw(n: &[u8], e: &[u8]) -> Result { + Self::new_public_from_raw_ex(n, e, None, None) + } + + /// Create a new RSA public key from raw modulus (`n`) and public + /// exponent (`e`) bytes with optional heap and device ID. + pub fn new_public_from_raw_ex( + n: &[u8], e: &[u8], + heap: Option<*mut core::ffi::c_void>, dev_id: Option, + ) -> Result { + let n_size = crate::buffer_len_to_u32(n.len())?; + let e_size = crate::buffer_len_to_u32(e.len())?; + let mut wc_rsakey: MaybeUninit = MaybeUninit::uninit(); + let heap = match heap { + Some(heap) => heap, + None => core::ptr::null_mut(), + }; + let dev_id = match dev_id { + Some(dev_id) => dev_id, + None => sys::INVALID_DEVID, + }; + let rc = unsafe { sys::wc_InitRsaKey_ex(wc_rsakey.as_mut_ptr(), heap, dev_id) }; + if rc != 0 { + return Err(rc); + } + let mut wc_rsakey = unsafe { wc_rsakey.assume_init() }; + let rc = unsafe { + sys::wc_RsaPublicKeyDecodeRaw( + n.as_ptr(), n_size, + e.as_ptr(), e_size, + &mut wc_rsakey, + ) + }; + if rc != 0 { + unsafe { sys::wc_FreeRsaKey(&mut wc_rsakey); } + return Err(rc); + } + Ok(RSA { wc_rsakey }) + } + /// Generate a new RSA key using the given size and exponent. /// /// This function generates an RSA private key of length size (in bits) and diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/rsa_pkcs1v15.rs b/wrapper/rust/wolfssl-wolfcrypt/src/rsa_pkcs1v15.rs new file mode 100644 index 0000000000..1effa323c9 --- /dev/null +++ b/wrapper/rust/wolfssl-wolfcrypt/src/rsa_pkcs1v15.rs @@ -0,0 +1,346 @@ +/* + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/*! +RSA PKCS#1 v1.5 trait impls for the RustCrypto `signature` crate. + +Provides fixed-size const-generic wrapper types over [`crate::rsa::RSA`] so +RSA PKCS#1 v1.5 signing/verifying fits cleanly into `no_std` without `alloc`: + +- [`SigningKey`] / [`VerifyingKey`] — `H` is a [`Hash`] marker + selecting the digest algorithm, `N` is the modulus size in bytes (e.g. + `256` for RSA-2048). +- [`Signature`] — fixed-size `[u8; N]` wrapper implementing + [`signature::SignatureEncoding`]. + +Signing and verifying delegate to `wc_SignatureGenerate` and +`wc_SignatureVerify` with `WC_SIGNATURE_TYPE_RSA_W_ENC`, which hash the raw +message and apply the PKCS#1 v1.5 DigestInfo encoding internally. +*/ + +#![cfg(all(feature = "signature", rsa, random))] + +use core::ffi::c_void; +use core::marker::PhantomData; +use core::mem::size_of; + +use signature::{Error, Keypair, SignatureEncoding, SignerMut, Verifier}; + +use crate::random::RNG; +use crate::rsa::RSA; +use crate::sys; + +mod private { + pub trait Sealed {} +} + +/// Marker trait selecting the digest algorithm used by PKCS#1 v1.5 DigestInfo +/// encoding. +pub trait Hash: private::Sealed { + /// wolfCrypt hash algorithm identifier. + const HASH_TYPE: u32; +} + +/// SHA-256 digest selection for PKCS#1 v1.5. +#[cfg(sha256)] +pub enum Sha256 {} +#[cfg(sha256)] +impl private::Sealed for Sha256 {} +#[cfg(sha256)] +impl Hash for Sha256 { + const HASH_TYPE: u32 = sys::wc_HashType_WC_HASH_TYPE_SHA256; +} + +/// SHA-384 digest selection for PKCS#1 v1.5. +#[cfg(sha384)] +pub enum Sha384 {} +#[cfg(sha384)] +impl private::Sealed for Sha384 {} +#[cfg(sha384)] +impl Hash for Sha384 { + const HASH_TYPE: u32 = sys::wc_HashType_WC_HASH_TYPE_SHA384; +} + +/// SHA-512 digest selection for PKCS#1 v1.5. +#[cfg(sha512)] +pub enum Sha512 {} +#[cfg(sha512)] +impl private::Sealed for Sha512 {} +#[cfg(sha512)] +impl Hash for Sha512 { + const HASH_TYPE: u32 = sys::wc_HashType_WC_HASH_TYPE_SHA512; +} + +/// Fixed-size RSA PKCS#1 v1.5 signature. `N` is the modulus size in bytes. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct Signature([u8; N]); + +impl Signature { + /// Construct a signature from its raw bytes. + pub const fn from_bytes(bytes: [u8; N]) -> Self { + Self(bytes) + } + + /// Return the raw signature bytes. + pub const fn to_bytes(&self) -> [u8; N] { + self.0 + } +} + +impl AsRef<[u8]> for Signature { + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + +impl TryFrom<&[u8]> for Signature { + type Error = Error; + fn try_from(bytes: &[u8]) -> Result { + let arr: [u8; N] = bytes.try_into().map_err(|_| Error::new())?; + Ok(Self(arr)) + } +} + +impl From> for [u8; N] { + fn from(sig: Signature) -> Self { + sig.0 + } +} + +impl SignatureEncoding for Signature { + type Repr = [u8; N]; +} + +fn check_modulus_size(rsa: &RSA, expected: usize) -> Result<(), i32> { + let actual = rsa.get_encrypt_size()?; + if actual != expected { + return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); + } + Ok(()) +} + +/// RSA PKCS#1 v1.5 signing key. +/// +/// `H` selects the hash used in DigestInfo encoding; `N` is the expected +/// modulus size in bytes (e.g. `256` for RSA-2048, `384` for RSA-3072). +pub struct SigningKey { + inner: RSA, + rng: RNG, + _hash: PhantomData, +} + +impl SigningKey { + /// Generate a fresh `N * 8`-bit RSA key with public exponent 65537. + #[cfg(rsa_keygen)] + pub fn generate(mut rng: RNG) -> Result { + let bits: i32 = (N * 8).try_into().map_err(|_| sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG)?; + let rsa = RSA::generate(bits, 65537, &mut rng)?; + Ok(Self { inner: rsa, rng, _hash: PhantomData }) + } + + /// Adopt an existing [`RSA`] key, verifying that its modulus size in + /// bytes matches `N`. + pub fn from_rsa(rsa: RSA, rng: RNG) -> Result { + check_modulus_size(&rsa, N)?; + Ok(Self { inner: rsa, rng, _hash: PhantomData }) + } + + /// Borrow the inner [`RSA`] key. + pub fn as_rsa(&self) -> &RSA { + &self.inner + } + + /// Consume the signing key and return its `RSA` and `RNG` parts. + pub fn into_parts(self) -> (RSA, RNG) { + (self.inner, self.rng) + } +} + +impl SignerMut> for SigningKey { + fn try_sign(&mut self, msg: &[u8]) -> Result, Error> { + let mut sig = [0u8; N]; + let mut sig_len: u32 = N as u32; + let msg_len: u32 = msg.len().try_into().map_err(|_| Error::new())?; + let rc = unsafe { + sys::wc_SignatureGenerate( + H::HASH_TYPE, + sys::wc_SignatureType_WC_SIGNATURE_TYPE_RSA_W_ENC, + msg.as_ptr(), msg_len, + sig.as_mut_ptr(), &mut sig_len, + &mut self.inner.wc_rsakey as *mut _ as *mut c_void, + size_of::() as u32, + &mut self.rng.wc_rng, + ) + }; + if rc != 0 || sig_len as usize != N { + return Err(Error::new()); + } + Ok(Signature(sig)) + } +} + +const MAX_E_LEN: usize = 8; + +/// RSA PKCS#1 v1.5 verifying key. +/// +/// Owns a copy of the public key as raw `(n, e)` bytes and instantiates a +/// short-lived [`RSA`] on each verification. `H` selects the hash algorithm +/// used in DigestInfo encoding; `N` is the modulus size in bytes. +pub struct VerifyingKey { + n: [u8; N], + e: [u8; MAX_E_LEN], + e_len: u8, + _hash: PhantomData, +} + +// Manual impls avoid requiring `H: Clone`/`Copy`/etc. — `H` is a marker +// (uninhabited enum) that only appears inside `PhantomData`. +impl Clone for VerifyingKey { + fn clone(&self) -> Self { *self } +} +impl Copy for VerifyingKey {} +impl core::fmt::Debug for VerifyingKey { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("VerifyingKey") + .field("n", &&self.n[..]) + .field("e", &self.exponent()) + .finish() + } +} +impl PartialEq for VerifyingKey { + fn eq(&self, other: &Self) -> bool { + self.n == other.n && self.exponent() == other.exponent() + } +} +impl Eq for VerifyingKey {} + +impl VerifyingKey { + /// Construct a verifying key from raw big-endian modulus (`n`) and + /// public exponent (`e`) bytes. + pub fn from_components(n: &[u8], e: &[u8]) -> Result { + if n.len() != N || e.is_empty() || e.len() > MAX_E_LEN { + return Err(Error::new()); + } + let mut n_arr = [0u8; N]; + n_arr.copy_from_slice(n); + let mut e_arr = [0u8; MAX_E_LEN]; + e_arr[..e.len()].copy_from_slice(e); + Ok(Self { + n: n_arr, + e: e_arr, + e_len: e.len() as u8, + _hash: PhantomData, + }) + } + + /// Adopt an existing [`RSA`] public key, verifying its modulus size in + /// bytes matches `N`. + pub fn from_rsa(rsa: RSA) -> Result { + check_modulus_size(&rsa, N)?; + let mut n = [0u8; N]; + let mut e = [0u8; MAX_E_LEN]; + let mut n_len: u32 = n.len() as u32; + let mut e_len: u32 = e.len() as u32; + let rc = unsafe { + sys::wc_RsaFlattenPublicKey( + &rsa.wc_rsakey, + e.as_mut_ptr(), &mut e_len, + n.as_mut_ptr(), &mut n_len, + ) + }; + if rc != 0 { + return Err(rc); + } + if (n_len as usize) != N || e_len == 0 || (e_len as usize) > MAX_E_LEN { + return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); + } + Ok(Self { + n, + e, + e_len: e_len as u8, + _hash: PhantomData, + }) + } + + /// Construct a verifying key from a DER-encoded `SubjectPublicKeyInfo` + /// / PKCS#1 public key. + pub fn from_public_der(der: &[u8]) -> Result { + let rsa = RSA::new_public_from_der(der)?; + Self::from_rsa(rsa) + } + + /// Return the raw modulus bytes. + pub const fn modulus(&self) -> &[u8; N] { + &self.n + } + + /// Return the raw public exponent bytes. + pub fn exponent(&self) -> &[u8] { + &self.e[..self.e_len as usize] + } +} + +impl Verifier> for VerifyingKey { + fn verify(&self, msg: &[u8], signature: &Signature) -> Result<(), Error> { + let msg_len: u32 = msg.len().try_into().map_err(|_| Error::new())?; + let mut rsa = RSA::new_public_from_raw(&self.n, self.exponent()) + .map_err(|_| Error::new())?; + let rc = unsafe { + sys::wc_SignatureVerify( + H::HASH_TYPE, + sys::wc_SignatureType_WC_SIGNATURE_TYPE_RSA_W_ENC, + msg.as_ptr(), msg_len, + signature.0.as_ptr(), N as u32, + &mut rsa.wc_rsakey as *mut _ as *mut c_void, + size_of::() as u32, + ) + }; + if rc != 0 { + return Err(Error::new()); + } + Ok(()) + } +} + +impl Keypair for SigningKey { + type VerifyingKey = VerifyingKey; + fn verifying_key(&self) -> VerifyingKey { + let mut n = [0u8; N]; + let mut e = [0u8; MAX_E_LEN]; + let mut n_len: u32 = n.len() as u32; + let mut e_len: u32 = e.len() as u32; + let rc = unsafe { + sys::wc_RsaFlattenPublicKey( + &self.inner.wc_rsakey, + e.as_mut_ptr(), &mut e_len, + n.as_mut_ptr(), &mut n_len, + ) + }; + if rc != 0 { + panic!("wc_RsaFlattenPublicKey failed: {rc}"); + } + VerifyingKey { + n, + e, + e_len: e_len as u8, + _hash: PhantomData, + } + } +} diff --git a/wrapper/rust/wolfssl-wolfcrypt/tests/test_ecdsa.rs b/wrapper/rust/wolfssl-wolfcrypt/tests/test_ecdsa.rs new file mode 100644 index 0000000000..344a9d01e2 --- /dev/null +++ b/wrapper/rust/wolfssl-wolfcrypt/tests/test_ecdsa.rs @@ -0,0 +1,142 @@ +#![cfg(all(feature = "signature", ecc, ecc_sign, ecc_verify, ecc_curve_ids, random))] + +mod common; + +use signature::{Keypair, SignerMut, Verifier}; +use wolfssl_wolfcrypt::random::RNG; + +#[test] +#[cfg(sha256)] +fn test_p256_sign_verify() { + use wolfssl_wolfcrypt::ecdsa::{P256Signature, P256SigningKey, P256VerifyingKey}; + + common::setup(); + + let rng = RNG::new().expect("RNG"); + let mut sk = P256SigningKey::generate(rng).expect("generate P256"); + + let msg = b"ecdsa p256 signature trait test"; + let sig: P256Signature = sk.sign(msg); + + // Encoding round-trip. + let bytes = sig.to_bytes(); + assert_eq!(bytes.len(), 64); + let sig2 = P256Signature::try_from(bytes.as_ref()).expect("parse sig"); + assert_eq!(sig, sig2); + + // Wrong length must fail. + assert!(P256Signature::try_from(&bytes[..63]).is_err()); + + // Keypair provides a matching verifying key. + let vk: P256VerifyingKey = sk.verifying_key(); + vk.verify(msg, &sig).expect("verify"); + + // Tampered message fails. + let mut tampered = *msg; + tampered[0] ^= 0x01; + assert!(vk.verify(&tampered, &sig).is_err()); + + // VerifyingKey bytes round-trip. + let vk_bytes = vk.to_bytes(); + assert_eq!(vk_bytes.len(), 65); + assert_eq!(vk_bytes[0], 0x04); // uncompressed X9.63 tag + let vk2 = P256VerifyingKey::try_from(vk_bytes.as_ref()).expect("parse vk"); + assert_eq!(vk, vk2); + vk2.verify(msg, &sig).expect("verify via rebuilt vk"); +} + +#[test] +#[cfg(sha256)] +fn test_p256_import_unsigned_and_x963() { + use wolfssl_wolfcrypt::ecc::ECC; + use wolfssl_wolfcrypt::ecdsa::{P256SigningKey, P256VerifyingKey}; + + common::setup(); + + // Start from a freshly generated key so we have known-good (qx, qy, d). + let mut rng = RNG::new().expect("RNG"); + let mut src = ECC::generate_ex(32, &mut rng, ECC::SECP256R1, None, None) + .expect("generate ECC"); + let mut qx = [0u8; 32]; + let mut qy = [0u8; 32]; + let mut d_buf = [0u8; 32]; + let mut qx_len = 0u32; + let mut qy_len = 0u32; + let mut d_len = 0u32; + src.export_ex(&mut qx, &mut qx_len, &mut qy, &mut qy_len, &mut d_buf, &mut d_len, false) + .expect("export_ex"); + assert_eq!(qx_len as usize, 32); + assert_eq!(qy_len as usize, 32); + assert_eq!(d_len as usize, 32); + let mut x963 = [0u8; 65]; + let x963_written = src.export_x963(&mut x963).expect("export_x963"); + assert_eq!(x963_written, 65); + + let msg = b"ecdsa p256 import path"; + + // Path 1: raw unsigned components. + let rng = RNG::new().expect("RNG"); + let mut sk_a = P256SigningKey::import_unsigned(&qx, &qy, &d_buf, rng) + .expect("import_unsigned"); + let sig_a = sk_a.sign(msg); + sk_a.verifying_key().verify(msg, &sig_a).expect("verify a"); + + // Path 2: X9.63 public + private scalar. + let rng = RNG::new().expect("RNG"); + let mut sk_b = P256SigningKey::import_x963(&x963, &d_buf, rng) + .expect("import_x963"); + let sig_b = sk_b.sign(msg); + sk_b.verifying_key().verify(msg, &sig_b).expect("verify b"); + + // Both imported keys produce the same public key bytes. + let vk_a: P256VerifyingKey = sk_a.verifying_key(); + let vk_b: P256VerifyingKey = sk_b.verifying_key(); + assert_eq!(vk_a, vk_b); + + // Cross-verify: vk_a verifies a signature produced by sk_b. + vk_a.verify(msg, &sig_b).expect("cross-verify a/b"); +} + +#[test] +#[cfg(sha384)] +fn test_p384_sign_verify() { + use wolfssl_wolfcrypt::ecdsa::{P384Signature, P384SigningKey, P384VerifyingKey}; + + common::setup(); + + let rng = RNG::new().expect("RNG"); + let mut sk = P384SigningKey::generate(rng).expect("generate P384"); + + let msg = b"ecdsa p384 signature trait test"; + let sig: P384Signature = sk.sign(msg); + assert_eq!(sig.to_bytes().len(), 96); + + let vk: P384VerifyingKey = sk.verifying_key(); + vk.verify(msg, &sig).expect("verify p384"); + + let mut tampered = *msg; + tampered[5] ^= 0x80; + assert!(vk.verify(&tampered, &sig).is_err()); +} + +#[test] +#[cfg(sha512)] +fn test_p521_sign_verify() { + use wolfssl_wolfcrypt::ecdsa::{P521Signature, P521SigningKey, P521VerifyingKey}; + + common::setup(); + + let rng = RNG::new().expect("RNG"); + let mut sk = P521SigningKey::generate(rng).expect("generate P521"); + + let msg = b"ecdsa p521 signature trait test"; + let sig: P521Signature = sk.sign(msg); + assert_eq!(sig.to_bytes().len(), 132); + + let vk: P521VerifyingKey = sk.verifying_key(); + vk.verify(msg, &sig).expect("verify p521"); + + let mut tampered = *msg; + tampered[10] ^= 0x55; + assert!(vk.verify(&tampered, &sig).is_err()); +} diff --git a/wrapper/rust/wolfssl-wolfcrypt/tests/test_ed25519.rs b/wrapper/rust/wolfssl-wolfcrypt/tests/test_ed25519.rs index 8c7e225c28..2426281285 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/tests/test_ed25519.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/tests/test_ed25519.rs @@ -243,6 +243,43 @@ fn test_import_export() { ed.import_public_ex(&public, false).expect("Error with import_public_ex()"); } +#[test] +#[cfg(all(feature = "signature", ed25519_import, ed25519_export, ed25519_sign, ed25519_verify))] +fn test_signature_traits() { + use signature::{Keypair, SignerMut, Verifier}; + + common::setup(); + + let mut rng = RNG::new().expect("Error creating RNG"); + let mut ed = Ed25519::generate(&mut rng).expect("Error with generate()"); + + let message = b"message to sign via RustCrypto signature trait"; + let sig: Signature = ed.sign(message); + + // Round-trip the signature bytes through the SignatureEncoding machinery. + let bytes = sig.to_bytes(); + assert_eq!(bytes.len(), Ed25519::SIG_SIZE); + let sig_round_trip = Signature::try_from(bytes.as_ref()).expect("Signature::try_from bytes"); + assert_eq!(sig, sig_round_trip); + + // Reject signatures of the wrong length. + assert!(Signature::try_from(&bytes[..bytes.len() - 1]).is_err()); + + // VerifyingKey obtained via the Keypair trait verifies this signature. + let vk: VerifyingKey = ed.verifying_key(); + vk.verify(message, &sig).expect("Verifier::verify failed"); + + // A tampered message must fail verification. + let mut tampered = *message; + tampered[0] ^= 0x01; + assert!(vk.verify(&tampered, &sig).is_err()); + + // VerifyingKey bytes round-trip. + let vk_bytes = vk.to_bytes(); + let vk2 = VerifyingKey::try_from(vk_bytes.as_ref()).expect("VerifyingKey::try_from bytes"); + assert_eq!(vk, vk2); +} + #[test] fn test_sizes() { let mut rng = RNG::new().expect("Error creating RNG"); diff --git a/wrapper/rust/wolfssl-wolfcrypt/tests/test_ed448.rs b/wrapper/rust/wolfssl-wolfcrypt/tests/test_ed448.rs index d0f7186f12..858f041a34 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/tests/test_ed448.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/tests/test_ed448.rs @@ -247,6 +247,43 @@ fn test_import_export() { ed.import_public_ex(&public, false).expect("Error with import_public_ex()"); } +#[test] +#[cfg(all(feature = "signature", ed448_import, ed448_export, ed448_sign, ed448_verify))] +fn test_signature_traits() { + use signature::{Keypair, SignerMut, Verifier}; + + common::setup(); + + let mut rng = RNG::new().expect("Error creating RNG"); + let mut ed = Ed448::generate(&mut rng).expect("Error with generate()"); + + let message = b"message to sign via RustCrypto signature trait"; + let sig: Signature = ed.sign(message); + + // Round-trip the signature bytes through the SignatureEncoding machinery. + let bytes = sig.to_bytes(); + assert_eq!(bytes.len(), Ed448::SIG_SIZE); + let sig_round_trip = Signature::try_from(bytes.as_ref()).expect("Signature::try_from bytes"); + assert_eq!(sig, sig_round_trip); + + // Reject signatures of the wrong length. + assert!(Signature::try_from(&bytes[..bytes.len() - 1]).is_err()); + + // VerifyingKey obtained via the Keypair trait verifies this signature. + let vk: VerifyingKey = ed.verifying_key(); + vk.verify(message, &sig).expect("Verifier::verify failed"); + + // A tampered message must fail verification. + let mut tampered = *message; + tampered[0] ^= 0x01; + assert!(vk.verify(&tampered, &sig).is_err()); + + // VerifyingKey bytes round-trip. + let vk_bytes = vk.to_bytes(); + let vk2 = VerifyingKey::try_from(vk_bytes.as_ref()).expect("VerifyingKey::try_from bytes"); + assert_eq!(vk, vk2); +} + #[test] fn test_sizes() { let mut rng = RNG::new().expect("Error creating RNG"); diff --git a/wrapper/rust/wolfssl-wolfcrypt/tests/test_rsa_pkcs1v15.rs b/wrapper/rust/wolfssl-wolfcrypt/tests/test_rsa_pkcs1v15.rs new file mode 100644 index 0000000000..09f14ed016 --- /dev/null +++ b/wrapper/rust/wolfssl-wolfcrypt/tests/test_rsa_pkcs1v15.rs @@ -0,0 +1,81 @@ +#![cfg(all(feature = "signature", rsa, random))] + +mod common; + +use signature::{Keypair, SignerMut, Verifier}; +use wolfssl_wolfcrypt::random::RNG; + +#[test] +#[cfg(all(sha256, rsa_keygen))] +fn test_rsa2048_sha256_sign_verify() { + use wolfssl_wolfcrypt::rsa_pkcs1v15::{Sha256, Signature, SigningKey, VerifyingKey}; + + common::setup(); + + let rng = RNG::new().expect("RNG"); + let mut sk: SigningKey = SigningKey::generate(rng).expect("generate 2048"); + + let msg = b"rsa pkcs1v15 sha256 signature trait test"; + let sig: Signature<256> = sk.sign(msg); + + // Encoding round-trip. + let bytes = sig.to_bytes(); + assert_eq!(bytes.len(), 256); + let sig2 = Signature::<256>::try_from(bytes.as_ref()).expect("parse sig"); + assert_eq!(sig, sig2); + + // Wrong length must fail. + assert!(Signature::<256>::try_from(&bytes[..255]).is_err()); + + // Keypair gives a matching verifying key. + let vk: VerifyingKey = sk.verifying_key(); + vk.verify(msg, &sig).expect("verify"); + + // Tampered message fails. + let mut tampered = *msg; + tampered[0] ^= 0x01; + assert!(vk.verify(&tampered, &sig).is_err()); + + // VerifyingKey rebuilt from raw components still verifies. + let vk_copy = VerifyingKey::::from_components(vk.modulus(), vk.exponent()) + .expect("from_components"); + assert_eq!(vk, vk_copy); + vk_copy.verify(msg, &sig).expect("verify via rebuilt vk"); +} + +#[test] +#[cfg(all(sha384, rsa_keygen))] +fn test_rsa3072_sha384_sign_verify() { + use wolfssl_wolfcrypt::rsa_pkcs1v15::{Sha384, Signature, SigningKey, VerifyingKey}; + + common::setup(); + + let rng = RNG::new().expect("RNG"); + let mut sk: SigningKey = SigningKey::generate(rng).expect("generate 3072"); + + let msg = b"rsa pkcs1v15 sha384 signature trait test"; + let sig: Signature<384> = sk.sign(msg); + assert_eq!(sig.to_bytes().len(), 384); + + let vk: VerifyingKey = sk.verifying_key(); + vk.verify(msg, &sig).expect("verify"); + + let mut tampered = *msg; + tampered[2] ^= 0x10; + assert!(vk.verify(&tampered, &sig).is_err()); +} + +#[test] +#[cfg(all(sha256, rsa_keygen))] +fn test_modulus_size_mismatch_rejected() { + use wolfssl_wolfcrypt::rsa::RSA; + use wolfssl_wolfcrypt::rsa_pkcs1v15::{Sha256, SigningKey}; + + common::setup(); + + let mut rng = RNG::new().expect("RNG"); + let rsa2048 = RSA::generate(2048, 65537, &mut rng).expect("generate"); + // Attempt to adopt a 2048-bit key as if it were 3072. + let result: Result, _> = SigningKey::from_rsa(rsa2048, rng); + assert!(result.is_err(), "modulus size mismatch must be rejected"); +} From 16fd8d4910fbdea27bbd494c12ea3333e8031cb3 Mon Sep 17 00:00:00 2001 From: Roy Carter Date: Sat, 18 Apr 2026 11:15:05 +0300 Subject: [PATCH 066/167] FIx: trailing white spaces fails the job --- configure.ac | 2 +- wolfssl/internal.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 5a2c80e53e..040a77b992 100644 --- a/configure.ac +++ b/configure.ac @@ -10379,7 +10379,7 @@ yes) AM_CFLAGS="$AM_CFLAGS -DHAVE_EX_DATA" [[1-9]]|[[1-9]][[0-9]]|[[1-9]][[0-9]][[0-9]]|[[1-9]][[0-9]][[0-9]][[0-9]]) AM_CFLAGS="$AM_CFLAGS -DHAVE_EX_DATA -DMAX_EX_DATA=$ENABLED_EX_DATA" ;; -*) AC_MSG_ERROR([Invalid argument to --enable-context-extra-user-data -- must be yes, no, or a number from 1 to 9999 (note: each index reserves one pointer per object, so large values increase memory use)]) +*) AC_MSG_ERROR([Invalid argument to --enable-context-extra-user-data -- must be yes, no, or a number from 1 to 9999 (note: each index reserves one pointer per object, so large values increase memory use)]) ;; esac diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 6bb51f117c..1f99957d25 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1445,7 +1445,7 @@ enum { #ifndef WOLFSSL_COOKIE_LEN /* Maximum size for a DTLS cookie */ #define WOLFSSL_COOKIE_LEN 32 -#endif +#endif #if WOLFSSL_COOKIE_LEN > 255 #error "WOLFSSL_COOKIE_LEN must be <= 255 per RFC 6347 (opaque<0..2^8-1>)" From ba51fbd30b81444b29a4202d2640cd023bf25f6a Mon Sep 17 00:00:00 2001 From: Sameeh Jubran Date: Fri, 17 Apr 2026 16:31:25 +0300 Subject: [PATCH 067/167] Zero TLS 1.3 traffic keys after AES SE offload When WOLF_CRYPTO_CB_AES_SETKEY is enabled and a CryptoCB callback imports the AES key into a Secure Element (aes->devCtx != NULL), the TLS-layer copy in keys->{client,server}_write_key has no further consumer: the software key schedule is not populated on offload. ForceZero it in SetKeysSide() per provisioned side. The static IVs (keys->{client,server}_write_IV and keys->aead_{enc,dec}_imp_IV) are left intact because BuildTls13Nonce() reads aead_{enc,dec}_imp_IV on every record (RFC 8446 Section 5.3). Scope: TLS 1.3, non-DTLS, non-QUIC. DTLS 1.3 needs the write keys in Dtls13EpochCopyKeys; TLS 1.2 needs them for rehandshake; QUIC is untouched pending audit. Add two memio tests (test_wc_CryptoCb_Tls13_Key_{Zero_After_Offload, No_Zero_Without_Offload}) that pin AES-GCM and check key / IV state after the handshake and a KeyUpdate round. Signed-off-by: Sameeh Jubran --- ChangeLog.md | 14 ++ src/keys.c | 69 ++++++ tests/api/test_aes.c | 515 ++++++++++++++++++++++++++++++++++++++----- tests/api/test_aes.h | 21 +- 4 files changed, 560 insertions(+), 59 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index d027365474..6e09b1e892 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,3 +1,17 @@ +# wolfSSL Release (unreleased) + +## Enhancements + +* TLS 1.3: zero traffic key staging buffers in `SetKeysSide()` once a + CryptoCB callback has imported the AES key into a Secure Element + (`aes->devCtx != NULL`). Clears `keys->{client,server}_write_key` + on the provisioned side(s) after cipher init succeeds. The static + IV buffers (`keys->{client,server}_write_IV`, + `keys->aead_{enc,dec}_imp_IV`) are intentionally left intact because + `BuildTls13Nonce()` reads them on every AEAD record to construct the + per-record nonce. Scoped to TLS 1.3, non-DTLS, non-QUIC; requires + `WOLF_CRYPTO_CB` and `WOLF_CRYPTO_CB_AES_SETKEY`. + # wolfSSL Release 5.9.1 (Apr. 8, 2026) Release 5.9.1 has been developed according to wolfSSL's development and QA diff --git a/src/keys.c b/src/keys.c index 190a5d4dd3..c21b58c7f3 100644 --- a/src/keys.c +++ b/src/keys.c @@ -3591,6 +3591,75 @@ int SetKeysSide(WOLFSSL* ssl, enum encrypt_side side) ssl->heap, ssl->devId, ssl->rng, ssl->options.tls1_3); } + /* Zero the TLS-layer staging key buffers once the CryptoCB callback + * has imported the key into a Secure Element. + * + * Convention: after a successful wc_AesSetKey / wc_AesGcmSetKey where + * the CryptoCB handled the key import, the callback leaves + * aes->devCtx != NULL and the software key schedule (aes->key, + * aes->devKey, aes->gcm.H / aes->gcm.M0) is NOT populated. The TLS + * layer may therefore destroy its staging copy of the traffic key. + * + * Only the key buffers (client_write_key / server_write_key) are + * zeroed. The static IVs (client_write_IV / server_write_IV) and + * the AEAD implicit-IV copies (aead_{enc,dec}_imp_IV) are NOT + * zeroed: BuildTls13Nonce() in tls13.c reads keys->aead_*_imp_IV on + * every AEAD record to construct the per-record nonce + * (nonce = static_iv XOR seq_num, RFC 8446 Section 5.3). Zeroing + * them would break the record path or, if applied symmetrically on + * both peers, silently degenerate the nonce to the bare sequence + * number and break interop with any unpatched peer. The static_iv + * is not a confidentiality-critical secret in the same sense as + * the traffic key; losing it does not compromise plaintext. + * + * Scope: + * - TLS 1.3 only. TLS 1.2 additionally reads + * keys->{client,server}_write_key for rehandshake/secure + * renegotiation flows. + * - Non-DTLS. Dtls13EpochCopyKeys (called from Dtls13NewEpoch) + * references keys->*_write_key for epoch switching; DTLS 1.3 + * needs separate analysis. + * - Non-QUIC. QUIC traffic secrets live outside these buffers + * but the interaction with stack-installed QUIC handlers has + * not been audited; exclude until it is. + * + * When called with ENCRYPT_SIDE_ONLY or DECRYPT_SIDE_ONLY, only the + * buffer consumed by this call is zeroed; the complementary buffer + * is written in a later SetKeysSide() from its own DeriveTls13Keys() + * and StoreKeys() pair (StoreKeys gates on PROVISION_CLIENT / + * PROVISION_SERVER so only the provisioned side is written). + * + * Ordering: this block must run AFTER SetKeys() (so offload has + * happened) and BEFORE Dtls13SetRecordNumberKeys() / + * wolfSSL_quic_keys_active() below, in case a future refactor in + * either starts reading keys->*_write_key. The DTLS and QUIC gates + * in this block mean neither currently executes on the same ssl, + * but keep the order explicit. */ +#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_AES_SETKEY) + if (ret == 0 && ssl->options.tls1_3 && !ssl->options.dtls + && !WOLFSSL_IS_QUIC(ssl)) { + int encOffloaded = (wc_encrypt != NULL && wc_encrypt->aes != NULL && + wc_encrypt->aes->devCtx != NULL); + int decOffloaded = (wc_decrypt != NULL && wc_decrypt->aes != NULL && + wc_decrypt->aes->devCtx != NULL); + + if (encOffloaded || decOffloaded) { + if (ssl->options.side == WOLFSSL_CLIENT_END) { + if (encOffloaded) + ForceZero(keys->client_write_key, ssl->specs.key_size); + if (decOffloaded) + ForceZero(keys->server_write_key, ssl->specs.key_size); + } + else { + if (encOffloaded) + ForceZero(keys->server_write_key, ssl->specs.key_size); + if (decOffloaded) + ForceZero(keys->client_write_key, ssl->specs.key_size); + } + } + } +#endif /* WOLF_CRYPTO_CB && WOLF_CRYPTO_CB_AES_SETKEY */ + #ifdef WOLFSSL_DTLS13 if (ret == 0 && ssl->options.dtls && IsAtLeastTLSv1_3(ssl->version)) ret = Dtls13SetRecordNumberKeys(ssl, side); diff --git a/tests/api/test_aes.c b/tests/api/test_aes.c index 3d4eda1eec..2eb35190be 100644 --- a/tests/api/test_aes.c +++ b/tests/api/test_aes.c @@ -31,8 +31,16 @@ #include #include #include +/* is required because the CryptoCB TLS 1.3 key-zeroing + * tests below inspect session state (ssl->keys.*_write_key, + * ssl->encrypt.aes->devCtx) to verify that the TLS-layer staging buffers are + * zeroed after a CryptoCB-driven AES-GCM key offload. The tests live here + * rather than in test_tls13.c because they exercise a CryptoCB-AES + * interaction and share the existing AES test harness. */ +#include #include #include +#include #if defined(HAVE_SELFTEST) || (defined(HAVE_FIPS_VERSION) && \ (HAVE_FIPS_VERSION <= 2)) @@ -5447,7 +5455,7 @@ int test_wc_AesXtsStream(void) }; const word32 tweakLen = (word32)sizeof(tweak); XtsAes aes; - XtsAesStreamData stream; + XtsAesStreamData xtsStream; byte plain3[WC_AES_BLOCK_SIZE * 3]; /* block-aligned plaintext */ byte expEnc[sizeof(vector)]; /* expected ciphertext (non-aligned) */ byte expEnc3[WC_AES_BLOCK_SIZE * 3]; /* expected ciphertext (3 blocks) */ @@ -5473,90 +5481,90 @@ int test_wc_AesXtsStream(void) /* --- Stream encrypt: Init + Final(non-aligned, 24 bytes) --- */ XMEMSET(enc, 0, sizeof(enc)); - XMEMSET(&stream, 0, sizeof(stream)); + XMEMSET(&xtsStream, 0, sizeof(xtsStream)); ExpectIntEQ(wc_AesXtsSetKey(&aes, key32, sizeof(key32), AES_ENCRYPTION, NULL, INVALID_DEVID), 0); - ExpectIntEQ(wc_AesXtsEncryptInit(&aes, tweak, tweakLen, &stream), 0); + ExpectIntEQ(wc_AesXtsEncryptInit(&aes, tweak, tweakLen, &xtsStream), 0); ExpectIntEQ(wc_AesXtsEncryptFinal(&aes, enc, vector, sizeof(vector), - &stream), 0); + &xtsStream), 0); ExpectBufEQ(enc, expEnc, sizeof(expEnc)); wc_AesXtsFree(&aes); /* --- Stream encrypt: Init + Update(2 blocks) + Final(1 block) --- */ XMEMSET(enc, 0, sizeof(enc)); - XMEMSET(&stream, 0, sizeof(stream)); + XMEMSET(&xtsStream, 0, sizeof(xtsStream)); ExpectIntEQ(wc_AesXtsSetKey(&aes, key32, sizeof(key32), AES_ENCRYPTION, NULL, INVALID_DEVID), 0); - ExpectIntEQ(wc_AesXtsEncryptInit(&aes, tweak, tweakLen, &stream), 0); + ExpectIntEQ(wc_AesXtsEncryptInit(&aes, tweak, tweakLen, &xtsStream), 0); ExpectIntEQ(wc_AesXtsEncryptUpdate(&aes, enc, plain3, - WC_AES_BLOCK_SIZE * 2, &stream), 0); + WC_AES_BLOCK_SIZE * 2, &xtsStream), 0); ExpectIntEQ(wc_AesXtsEncryptFinal(&aes, enc + WC_AES_BLOCK_SIZE * 2, plain3 + WC_AES_BLOCK_SIZE * 2, - WC_AES_BLOCK_SIZE, &stream), 0); + WC_AES_BLOCK_SIZE, &xtsStream), 0); ExpectBufEQ(enc, expEnc3, sizeof(expEnc3)); wc_AesXtsFree(&aes); /* --- Stream encrypt: Init + Update(1 block) x3 via individual calls + * Final(0 bytes) --- */ XMEMSET(enc, 0, sizeof(enc)); - XMEMSET(&stream, 0, sizeof(stream)); + XMEMSET(&xtsStream, 0, sizeof(xtsStream)); ExpectIntEQ(wc_AesXtsSetKey(&aes, key32, sizeof(key32), AES_ENCRYPTION, NULL, INVALID_DEVID), 0); - ExpectIntEQ(wc_AesXtsEncryptInit(&aes, tweak, tweakLen, &stream), 0); + ExpectIntEQ(wc_AesXtsEncryptInit(&aes, tweak, tweakLen, &xtsStream), 0); ExpectIntEQ(wc_AesXtsEncryptUpdate(&aes, enc, - plain3, WC_AES_BLOCK_SIZE, &stream), 0); + plain3, WC_AES_BLOCK_SIZE, &xtsStream), 0); ExpectIntEQ(wc_AesXtsEncryptUpdate(&aes, enc + WC_AES_BLOCK_SIZE, - plain3 + WC_AES_BLOCK_SIZE, WC_AES_BLOCK_SIZE, &stream), 0); + plain3 + WC_AES_BLOCK_SIZE, WC_AES_BLOCK_SIZE, &xtsStream), 0); ExpectIntEQ(wc_AesXtsEncryptUpdate(&aes, enc + WC_AES_BLOCK_SIZE * 2, - plain3 + WC_AES_BLOCK_SIZE * 2, WC_AES_BLOCK_SIZE, &stream), 0); - ExpectIntEQ(wc_AesXtsEncryptFinal(&aes, NULL, NULL, 0, &stream), 0); + plain3 + WC_AES_BLOCK_SIZE * 2, WC_AES_BLOCK_SIZE, &xtsStream), 0); + ExpectIntEQ(wc_AesXtsEncryptFinal(&aes, NULL, NULL, 0, &xtsStream), 0); ExpectBufEQ(enc, expEnc3, sizeof(expEnc3)); wc_AesXtsFree(&aes); #ifdef HAVE_AES_DECRYPT /* --- Stream decrypt: Init + Final(non-aligned, 24 bytes) --- */ XMEMSET(dec, 0, sizeof(dec)); - XMEMSET(&stream, 0, sizeof(stream)); + XMEMSET(&xtsStream, 0, sizeof(xtsStream)); ExpectIntEQ(wc_AesXtsSetKey(&aes, key32, sizeof(key32), AES_DECRYPTION, NULL, INVALID_DEVID), 0); - ExpectIntEQ(wc_AesXtsDecryptInit(&aes, tweak, tweakLen, &stream), 0); + ExpectIntEQ(wc_AesXtsDecryptInit(&aes, tweak, tweakLen, &xtsStream), 0); ExpectIntEQ(wc_AesXtsDecryptFinal(&aes, dec, expEnc, sizeof(expEnc), - &stream), 0); + &xtsStream), 0); ExpectBufEQ(dec, vector, sizeof(vector)); wc_AesXtsFree(&aes); /* --- Stream decrypt: Init + Update(2 blocks) + Final(1 block) --- */ XMEMSET(dec, 0, sizeof(dec)); - XMEMSET(&stream, 0, sizeof(stream)); + XMEMSET(&xtsStream, 0, sizeof(xtsStream)); ExpectIntEQ(wc_AesXtsSetKey(&aes, key32, sizeof(key32), AES_DECRYPTION, NULL, INVALID_DEVID), 0); - ExpectIntEQ(wc_AesXtsDecryptInit(&aes, tweak, tweakLen, &stream), 0); + ExpectIntEQ(wc_AesXtsDecryptInit(&aes, tweak, tweakLen, &xtsStream), 0); ExpectIntEQ(wc_AesXtsDecryptUpdate(&aes, dec, expEnc3, - WC_AES_BLOCK_SIZE * 2, &stream), 0); + WC_AES_BLOCK_SIZE * 2, &xtsStream), 0); ExpectIntEQ(wc_AesXtsDecryptFinal(&aes, dec + WC_AES_BLOCK_SIZE * 2, expEnc3 + WC_AES_BLOCK_SIZE * 2, - WC_AES_BLOCK_SIZE, &stream), 0); + WC_AES_BLOCK_SIZE, &xtsStream), 0); ExpectBufEQ(dec, plain3, sizeof(plain3)); wc_AesXtsFree(&aes); #endif /* HAVE_AES_DECRYPT */ /* --- Bad args --- */ - XMEMSET(&stream, 0, sizeof(stream)); + XMEMSET(&xtsStream, 0, sizeof(xtsStream)); /* NULL aes */ - ExpectIntEQ(wc_AesXtsEncryptInit(NULL, tweak, tweakLen, &stream), + ExpectIntEQ(wc_AesXtsEncryptInit(NULL, tweak, tweakLen, &xtsStream), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); /* NULL tweak */ - ExpectIntEQ(wc_AesXtsEncryptInit(&aes, NULL, tweakLen, &stream), + ExpectIntEQ(wc_AesXtsEncryptInit(&aes, NULL, tweakLen, &xtsStream), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); /* NULL stream */ ExpectIntEQ(wc_AesXtsEncryptInit(&aes, tweak, tweakLen, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); /* sz not a multiple of block size */ - ExpectIntEQ(wc_AesXtsEncryptUpdate(&aes, enc, plain3, 1, &stream), + ExpectIntEQ(wc_AesXtsEncryptUpdate(&aes, enc, plain3, 1, &xtsStream), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); /* NULL stream to Update */ ExpectIntEQ(wc_AesXtsEncryptUpdate(&aes, enc, plain3, @@ -5566,9 +5574,9 @@ int test_wc_AesXtsStream(void) ExpectIntEQ(wc_AesXtsEncryptFinal(&aes, enc, vector, sizeof(vector), NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); #ifdef HAVE_AES_DECRYPT - ExpectIntEQ(wc_AesXtsDecryptInit(NULL, tweak, tweakLen, &stream), + ExpectIntEQ(wc_AesXtsDecryptInit(NULL, tweak, tweakLen, &xtsStream), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - ExpectIntEQ(wc_AesXtsDecryptInit(&aes, NULL, tweakLen, &stream), + ExpectIntEQ(wc_AesXtsDecryptInit(&aes, NULL, tweakLen, &xtsStream), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_AesXtsDecryptInit(&aes, tweak, tweakLen, NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); @@ -5625,9 +5633,9 @@ int test_wc_AesXtsStream_MidStreamState(void) 0x66,0x6f,0x72,0x20, 0x61,0x6c,0x6c,0x20 }; /* One full block for the subsequent (illegal) Update call. */ - static const byte block[WC_AES_BLOCK_SIZE] = { 0 }; + static const byte oneBlock[WC_AES_BLOCK_SIZE] = { 0 }; XtsAes aes; - XtsAesStreamData stream; + XtsAesStreamData xtsStream; byte enc[24]; byte dummy[WC_AES_BLOCK_SIZE]; @@ -5638,14 +5646,14 @@ int test_wc_AesXtsStream_MidStreamState(void) * ------------------------------------------------------------------ */ ExpectIntEQ(wc_AesXtsSetKey(&aes, key64, sizeof(key64), AES_ENCRYPTION, NULL, INVALID_DEVID), 0); - ExpectIntEQ(wc_AesXtsEncryptInit(&aes, tweak, sizeof(tweak), &stream), 0); + ExpectIntEQ(wc_AesXtsEncryptInit(&aes, tweak, sizeof(tweak), &xtsStream), 0); /* Final processes all 24 bytes; bytes_crypted_with_this_tweak becomes 24 * (not a multiple of WC_AES_BLOCK_SIZE=16). */ ExpectIntEQ(wc_AesXtsEncryptFinal(&aes, enc, plain24, sizeof(plain24), - &stream), 0); + &xtsStream), 0); /* The subsequent Update must be rejected because the stream is "done". */ - ExpectIntEQ(wc_AesXtsEncryptUpdate(&aes, dummy, block, sizeof(block), - &stream), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_AesXtsEncryptUpdate(&aes, dummy, oneBlock, sizeof(oneBlock), + &xtsStream), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); wc_AesXtsFree(&aes); #ifdef HAVE_AES_DECRYPT @@ -5655,11 +5663,11 @@ int test_wc_AesXtsStream_MidStreamState(void) XMEMSET(&aes, 0, sizeof(aes)); ExpectIntEQ(wc_AesXtsSetKey(&aes, key64, sizeof(key64), AES_DECRYPTION, NULL, INVALID_DEVID), 0); - ExpectIntEQ(wc_AesXtsDecryptInit(&aes, tweak, sizeof(tweak), &stream), 0); + ExpectIntEQ(wc_AesXtsDecryptInit(&aes, tweak, sizeof(tweak), &xtsStream), 0); ExpectIntEQ(wc_AesXtsDecryptFinal(&aes, enc, enc, sizeof(enc), - &stream), 0); - ExpectIntEQ(wc_AesXtsDecryptUpdate(&aes, dummy, block, sizeof(block), - &stream), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + &xtsStream), 0); + ExpectIntEQ(wc_AesXtsDecryptUpdate(&aes, dummy, oneBlock, sizeof(oneBlock), + &xtsStream), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); wc_AesXtsFree(&aes); #endif #endif @@ -5716,7 +5724,7 @@ int test_wc_AesXtsStream_ReinitAfterFinal(void) 0x20,0x74,0x6f,0x20, 0x63,0x6f,0x6d,0x65 }; XtsAes aes; - XtsAesStreamData stream; + XtsAesStreamData xtsStream; byte ct1[sizeof(plain)], ct2[sizeof(plain)], ct3[sizeof(plain)]; #ifdef HAVE_AES_DECRYPT byte pt[sizeof(plain)]; @@ -5730,42 +5738,42 @@ int test_wc_AesXtsStream_ReinitAfterFinal(void) * One full block via Update, the remaining 24 bytes via Final. * Note: AesXtsEncryptFinal forwards to the Update path, so the Final * size must be >= WC_AES_BLOCK_SIZE when sz > 0. */ - ExpectIntEQ(wc_AesXtsEncryptInit(&aes, tweak1, sizeof(tweak1), &stream), 0); + ExpectIntEQ(wc_AesXtsEncryptInit(&aes, tweak1, sizeof(tweak1), &xtsStream), 0); ExpectIntEQ(wc_AesXtsEncryptUpdate(&aes, ct1, plain, - WC_AES_BLOCK_SIZE, &stream), 0); + WC_AES_BLOCK_SIZE, &xtsStream), 0); ExpectIntEQ(wc_AesXtsEncryptFinal(&aes, ct1 + WC_AES_BLOCK_SIZE, plain + WC_AES_BLOCK_SIZE, - sizeof(plain) - WC_AES_BLOCK_SIZE, &stream), 0); + sizeof(plain) - WC_AES_BLOCK_SIZE, &xtsStream), 0); /* ---- Session 2: re-init with same tweak -> must match ---- */ - ExpectIntEQ(wc_AesXtsEncryptInit(&aes, tweak1, sizeof(tweak1), &stream), 0); + ExpectIntEQ(wc_AesXtsEncryptInit(&aes, tweak1, sizeof(tweak1), &xtsStream), 0); ExpectIntEQ(wc_AesXtsEncryptUpdate(&aes, ct2, plain, - WC_AES_BLOCK_SIZE, &stream), 0); + WC_AES_BLOCK_SIZE, &xtsStream), 0); ExpectIntEQ(wc_AesXtsEncryptFinal(&aes, ct2 + WC_AES_BLOCK_SIZE, plain + WC_AES_BLOCK_SIZE, - sizeof(plain) - WC_AES_BLOCK_SIZE, &stream), 0); + sizeof(plain) - WC_AES_BLOCK_SIZE, &xtsStream), 0); ExpectBufEQ(ct2, ct1, sizeof(ct1)); /* ---- Session 3: re-init with different tweak -> must differ ---- */ - ExpectIntEQ(wc_AesXtsEncryptInit(&aes, tweak2, sizeof(tweak2), &stream), 0); + ExpectIntEQ(wc_AesXtsEncryptInit(&aes, tweak2, sizeof(tweak2), &xtsStream), 0); ExpectIntEQ(wc_AesXtsEncryptUpdate(&aes, ct3, plain, - WC_AES_BLOCK_SIZE, &stream), 0); + WC_AES_BLOCK_SIZE, &xtsStream), 0); ExpectIntEQ(wc_AesXtsEncryptFinal(&aes, ct3 + WC_AES_BLOCK_SIZE, plain + WC_AES_BLOCK_SIZE, - sizeof(plain) - WC_AES_BLOCK_SIZE, &stream), 0); + sizeof(plain) - WC_AES_BLOCK_SIZE, &xtsStream), 0); ExpectIntNE(XMEMCMP(ct3, ct1, sizeof(ct1)), 0); /* ---- Session 4: re-init after abandoned (no Final) session ---- */ - ExpectIntEQ(wc_AesXtsEncryptInit(&aes, tweak2, sizeof(tweak2), &stream), 0); + ExpectIntEQ(wc_AesXtsEncryptInit(&aes, tweak2, sizeof(tweak2), &xtsStream), 0); ExpectIntEQ(wc_AesXtsEncryptUpdate(&aes, ct3, plain, - WC_AES_BLOCK_SIZE, &stream), 0); + WC_AES_BLOCK_SIZE, &xtsStream), 0); /* Abandon - re-init with tweak1, must give session-1 output. */ - ExpectIntEQ(wc_AesXtsEncryptInit(&aes, tweak1, sizeof(tweak1), &stream), 0); + ExpectIntEQ(wc_AesXtsEncryptInit(&aes, tweak1, sizeof(tweak1), &xtsStream), 0); ExpectIntEQ(wc_AesXtsEncryptUpdate(&aes, ct2, plain, - WC_AES_BLOCK_SIZE, &stream), 0); + WC_AES_BLOCK_SIZE, &xtsStream), 0); ExpectIntEQ(wc_AesXtsEncryptFinal(&aes, ct2 + WC_AES_BLOCK_SIZE, plain + WC_AES_BLOCK_SIZE, - sizeof(plain) - WC_AES_BLOCK_SIZE, &stream), 0); + sizeof(plain) - WC_AES_BLOCK_SIZE, &xtsStream), 0); ExpectBufEQ(ct2, ct1, sizeof(ct1)); wc_AesXtsFree(&aes); @@ -5777,21 +5785,21 @@ int test_wc_AesXtsStream_ReinitAfterFinal(void) AES_DECRYPTION, NULL, INVALID_DEVID), 0); /* Session A: decrypt ct1 with tweak1 -> plaintext. */ - ExpectIntEQ(wc_AesXtsDecryptInit(&aes, tweak1, sizeof(tweak1), &stream), 0); + ExpectIntEQ(wc_AesXtsDecryptInit(&aes, tweak1, sizeof(tweak1), &xtsStream), 0); ExpectIntEQ(wc_AesXtsDecryptUpdate(&aes, pt, ct1, - WC_AES_BLOCK_SIZE, &stream), 0); + WC_AES_BLOCK_SIZE, &xtsStream), 0); ExpectIntEQ(wc_AesXtsDecryptFinal(&aes, pt + WC_AES_BLOCK_SIZE, ct1 + WC_AES_BLOCK_SIZE, - sizeof(ct1) - WC_AES_BLOCK_SIZE, &stream), 0); + sizeof(ct1) - WC_AES_BLOCK_SIZE, &xtsStream), 0); ExpectBufEQ(pt, plain, sizeof(plain)); /* Session B: re-init and decrypt again -> same plaintext. */ - ExpectIntEQ(wc_AesXtsDecryptInit(&aes, tweak1, sizeof(tweak1), &stream), 0); + ExpectIntEQ(wc_AesXtsDecryptInit(&aes, tweak1, sizeof(tweak1), &xtsStream), 0); ExpectIntEQ(wc_AesXtsDecryptUpdate(&aes, pt, ct1, - WC_AES_BLOCK_SIZE, &stream), 0); + WC_AES_BLOCK_SIZE, &xtsStream), 0); ExpectIntEQ(wc_AesXtsDecryptFinal(&aes, pt + WC_AES_BLOCK_SIZE, ct1 + WC_AES_BLOCK_SIZE, - sizeof(ct1) - WC_AES_BLOCK_SIZE, &stream), 0); + sizeof(ct1) - WC_AES_BLOCK_SIZE, &xtsStream), 0); ExpectBufEQ(pt, plain, sizeof(plain)); wc_AesXtsFree(&aes); @@ -7867,6 +7875,9 @@ int test_wc_AesSivEncryptDecrypt(void) #include +/* Test CryptoCB device IDs (must be unique across test_aes.c): + * 7 = AES setkey + AES-GCM offload (see TEST_CRYPTOCB_AES_DEVID) + * 9 = TLS 1.3 key-zeroing offload (see TEST_TLS13_ZERO_DEVID) */ #define TEST_CRYPTOCB_AES_DEVID 7 /* Test state tracking */ @@ -8598,6 +8609,394 @@ out: #endif /* WOLF_CRYPTO_CB && WOLF_CRYPTO_CB_AES_SETKEY && !NO_AES && HAVE_AESGCM */ +/*----------------------------------------------------------------------------* + | CryptoCB AES-GCM TLS 1.3 Key Zeroing Tests + *----------------------------------------------------------------------------*/ + +#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_AES_SETKEY) && \ + !defined(NO_AES) && defined(HAVE_AESGCM) && \ + defined(WOLFSSL_TLS13) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \ + !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) + +#define TEST_TLS13_ZERO_DEVID 9 +#define TEST_TLS13_ZERO_MAX_SLOTS 16 + +typedef struct { + byte key[AES_256_KEY_SIZE]; + word32 keySz; + int valid; +} Tls13ZeroKeySlot; + +static Tls13ZeroKeySlot tls13ZeroSlots[TEST_TLS13_ZERO_MAX_SLOTS]; +static word32 tls13ZeroSlotCount = 0; + +/* Try to reclaim a slot previously invalidated by the FREE path + * (valid == 0) before expanding the pool. Without this, a long-running + * handshake + multiple KeyUpdate cycles can exhaust TEST_TLS13_ZERO_MAX_SLOTS + * even though most slots have been freed. */ +static Tls13ZeroKeySlot* tls13Zero_AllocSlot(void) +{ + word32 i; + for (i = 0; i < tls13ZeroSlotCount; i++) { + if (!tls13ZeroSlots[i].valid) + return &tls13ZeroSlots[i]; + } + if (tls13ZeroSlotCount >= (word32)TEST_TLS13_ZERO_MAX_SLOTS) + return NULL; + return &tls13ZeroSlots[tls13ZeroSlotCount++]; +} + +static int test_Tls13Zero_CryptoCb(int devId, wc_CryptoInfo* info, void* ctx) +{ + (void)ctx; + + if (devId != TEST_TLS13_ZERO_DEVID) + return CRYPTOCB_UNAVAILABLE; + + if (info->algo_type == WC_ALGO_TYPE_CIPHER && + info->cipher.type == WC_CIPHER_AES && + info->cipher.aessetkey.aes != NULL) { + + Aes* aes = info->cipher.aessetkey.aes; + const byte* key = info->cipher.aessetkey.key; + word32 keySz = info->cipher.aessetkey.keySz; + Tls13ZeroKeySlot* slot; + + if (key == NULL || keySz == 0 || keySz > AES_256_KEY_SIZE) + return BAD_FUNC_ARG; + + slot = tls13Zero_AllocSlot(); + if (slot == NULL) + return MEMORY_E; + + XMEMCPY(slot->key, key, keySz); + slot->keySz = keySz; + slot->valid = 1; + aes->devCtx = slot; + return 0; + } + + if (info->algo_type == WC_ALGO_TYPE_CIPHER && + info->cipher.type == WC_CIPHER_AES_GCM && + info->cipher.enc) { + + Aes* aes = info->cipher.aesgcm_enc.aes; + Tls13ZeroKeySlot* slot; + Aes tempAes; + int ret; + + if (aes == NULL || aes->devCtx == NULL) + return BAD_FUNC_ARG; + + slot = (Tls13ZeroKeySlot*)aes->devCtx; + if (!slot->valid) + return BAD_STATE_E; + + ret = wc_AesInit(&tempAes, NULL, INVALID_DEVID); + if (ret != 0) return ret; + ret = wc_AesGcmSetKey(&tempAes, slot->key, slot->keySz); + if (ret != 0) { wc_AesFree(&tempAes); return ret; } + ret = wc_AesGcmEncrypt(&tempAes, + info->cipher.aesgcm_enc.out, + info->cipher.aesgcm_enc.in, + info->cipher.aesgcm_enc.sz, + info->cipher.aesgcm_enc.iv, + info->cipher.aesgcm_enc.ivSz, + info->cipher.aesgcm_enc.authTag, + info->cipher.aesgcm_enc.authTagSz, + info->cipher.aesgcm_enc.authIn, + info->cipher.aesgcm_enc.authInSz); + wc_AesFree(&tempAes); + return ret; + } + + if (info->algo_type == WC_ALGO_TYPE_CIPHER && + info->cipher.type == WC_CIPHER_AES_GCM && + !info->cipher.enc) { + + Aes* aes = info->cipher.aesgcm_dec.aes; + Tls13ZeroKeySlot* slot; + Aes tempAes; + int ret; + + if (aes == NULL || aes->devCtx == NULL) + return BAD_FUNC_ARG; + + slot = (Tls13ZeroKeySlot*)aes->devCtx; + if (!slot->valid) + return BAD_STATE_E; + + ret = wc_AesInit(&tempAes, NULL, INVALID_DEVID); + if (ret != 0) return ret; + ret = wc_AesGcmSetKey(&tempAes, slot->key, slot->keySz); + if (ret != 0) { wc_AesFree(&tempAes); return ret; } + ret = wc_AesGcmDecrypt(&tempAes, + info->cipher.aesgcm_dec.out, + info->cipher.aesgcm_dec.in, + info->cipher.aesgcm_dec.sz, + info->cipher.aesgcm_dec.iv, + info->cipher.aesgcm_dec.ivSz, + info->cipher.aesgcm_dec.authTag, + info->cipher.aesgcm_dec.authTagSz, + info->cipher.aesgcm_dec.authIn, + info->cipher.aesgcm_dec.authInSz); + wc_AesFree(&tempAes); + return ret; + } + +#ifdef WOLF_CRYPTO_CB_FREE + if (info->algo_type == WC_ALGO_TYPE_FREE && + info->free.algo == WC_ALGO_TYPE_CIPHER && + info->free.type == WC_CIPHER_AES) { + + Aes* aes = (Aes*)info->free.obj; + if (aes != NULL && aes->devCtx != NULL) { + Tls13ZeroKeySlot* slot = (Tls13ZeroKeySlot*)aes->devCtx; + ForceZero(slot, sizeof(*slot)); + aes->devCtx = NULL; + } + return 0; + } +#endif + + return CRYPTOCB_UNAVAILABLE; +} + +/* Test helper; not constant-time. Fine for zero-fill assertions in unit + * tests, NOT for comparing secrets. */ +static int isBufferAllZero(const byte* buf, word32 sz) +{ + word32 i; + for (i = 0; i < sz; i++) { + if (buf[i] != 0) + return 0; + } + return 1; +} + +#endif /* WOLF_CRYPTO_CB && WOLF_CRYPTO_CB_AES_SETKEY && !NO_AES && HAVE_AESGCM + * && WOLFSSL_TLS13 && HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES + * && !NO_WOLFSSL_CLIENT && !NO_WOLFSSL_SERVER */ + +int test_wc_CryptoCb_Tls13_Key_Zero_After_Offload(void) +{ + EXPECT_DECLS; +#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_AES_SETKEY) && \ + !defined(NO_AES) && defined(HAVE_AESGCM) && \ + defined(WOLFSSL_TLS13) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \ + !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) + WOLFSSL_CTX* ctx_c = NULL; + WOLFSSL_CTX* ctx_s = NULL; + WOLFSSL* ssl_c = NULL; + WOLFSSL* ssl_s = NULL; + struct test_memio_ctx test_ctx; + byte msg[] = "hello"; + byte reply[sizeof(msg)]; + word32 keySz; + word32 ivSz; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + XMEMSET(tls13ZeroSlots, 0, sizeof(tls13ZeroSlots)); + tls13ZeroSlotCount = 0; + + ExpectIntEQ(wc_CryptoCb_RegisterDevice(TEST_TLS13_ZERO_DEVID, + test_Tls13Zero_CryptoCb, NULL), 0); + + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0); + + ExpectIntEQ(wolfSSL_CTX_SetDevId(ctx_c, TEST_TLS13_ZERO_DEVID), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_SetDevId(ctx_s, TEST_TLS13_ZERO_DEVID), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_SetDevId(ssl_c, TEST_TLS13_ZERO_DEVID), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_SetDevId(ssl_s, TEST_TLS13_ZERO_DEVID), + WOLFSSL_SUCCESS); + + /* Pin the ciphersuite to AES-GCM. The zeroing under test is gated on + * AES offload (devCtx set by our CryptoCB); negotiating ChaCha20 or + * any non-AES suite leaves encrypt.aes / decrypt.aes unset and turns + * the test into either a no-op (offload never runs) or a crash when + * we later dereference ssl_c->encrypt.aes. Offer both AES-GCM sizes + * so the pin succeeds regardless of WOLFSSL_AES_128 / WOLFSSL_AES_256 + * build configuration. */ + ExpectIntEQ(wolfSSL_set_cipher_list(ssl_c, + "TLS13-AES128-GCM-SHA256:TLS13-AES256-GCM-SHA384"), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_cipher_list(ssl_s, + "TLS13-AES128-GCM-SHA256:TLS13-AES256-GCM-SHA384"), WOLFSSL_SUCCESS); + + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + if (ssl_c != NULL && ssl_s != NULL) { + keySz = ssl_c->specs.key_size; + ivSz = ssl_c->specs.iv_size; + ExpectTrue(keySz > 0); + ExpectTrue(ivSz > 0); + + ExpectTrue(isBufferAllZero(ssl_c->keys.client_write_key, keySz)); + ExpectTrue(isBufferAllZero(ssl_c->keys.server_write_key, keySz)); + ExpectTrue(isBufferAllZero(ssl_s->keys.client_write_key, keySz)); + ExpectTrue(isBufferAllZero(ssl_s->keys.server_write_key, keySz)); + + /* The static IVs must be preserved: BuildTls13Nonce() reads + * keys->aead_{enc,dec}_imp_IV on every AEAD record to build the + * per-record nonce (RFC 8446 Section 5.3). If a future change + * starts zeroing these, both peers in this memio test would + * silently agree on a degenerate all-zero IV and the handshake + * would still pass, but the resulting wire format is + * non-interoperable with any unpatched TLS 1.3 peer. Assert + * both the source buffers (client/server_write_IV) and the + * AEAD copies BuildTls13Nonce() actually reads stay populated, + * so a regression that zeroes either one is caught here. */ + ExpectTrue(!isBufferAllZero(ssl_c->keys.client_write_IV, ivSz)); + ExpectTrue(!isBufferAllZero(ssl_c->keys.server_write_IV, ivSz)); + ExpectTrue(!isBufferAllZero(ssl_s->keys.client_write_IV, ivSz)); + ExpectTrue(!isBufferAllZero(ssl_s->keys.server_write_IV, ivSz)); + + ExpectTrue(!isBufferAllZero(ssl_c->keys.aead_enc_imp_IV, ivSz)); + ExpectTrue(!isBufferAllZero(ssl_c->keys.aead_dec_imp_IV, ivSz)); + ExpectTrue(!isBufferAllZero(ssl_s->keys.aead_enc_imp_IV, ivSz)); + ExpectTrue(!isBufferAllZero(ssl_s->keys.aead_dec_imp_IV, ivSz)); + + /* Guard the Aes pointer dereferences: even though the Expect* + * macros short-circuit after a prior failure via EXPECT_SUCCESS(), + * a handshake that succeeded but negotiated a non-AES suite + * would leave these NULL while _ret is still TEST_SUCCESS. */ + ExpectNotNull(ssl_c->encrypt.aes); + ExpectNotNull(ssl_c->decrypt.aes); + ExpectNotNull(ssl_s->encrypt.aes); + ExpectNotNull(ssl_s->decrypt.aes); + if (ssl_c->encrypt.aes && ssl_c->decrypt.aes && + ssl_s->encrypt.aes && ssl_s->decrypt.aes) { + ExpectPtrNE(ssl_c->encrypt.aes->devCtx, NULL); + ExpectPtrNE(ssl_c->decrypt.aes->devCtx, NULL); + ExpectPtrNE(ssl_s->encrypt.aes->devCtx, NULL); + ExpectPtrNE(ssl_s->decrypt.aes->devCtx, NULL); + } + + ExpectIntEQ(wolfSSL_write(ssl_c, msg, sizeof(msg)), + (int)sizeof(msg)); + ExpectIntEQ(wolfSSL_read(ssl_s, reply, sizeof(reply)), + (int)sizeof(msg)); + ExpectIntEQ(XMEMCMP(msg, reply, sizeof(msg)), 0); + + ExpectIntEQ(wolfSSL_write(ssl_s, msg, sizeof(msg)), + (int)sizeof(msg)); + ExpectIntEQ(wolfSSL_read(ssl_c, reply, sizeof(reply)), + (int)sizeof(msg)); + ExpectIntEQ(XMEMCMP(msg, reply, sizeof(msg)), 0); + + /* Force a KeyUpdate so SetKeysSide runs again with a fresh + * offload and we can re-check that the staging buffers remain + * zeroed. wolfSSL_update_keys is always available when + * WOLFSSL_TLS13 is defined, which is part of the test gate. */ + ExpectIntEQ(wolfSSL_update_keys(ssl_c), WOLFSSL_SUCCESS); + + ExpectIntEQ(wolfSSL_write(ssl_c, msg, sizeof(msg)), + (int)sizeof(msg)); + ExpectIntEQ(wolfSSL_read(ssl_s, reply, sizeof(reply)), + (int)sizeof(msg)); + ExpectIntEQ(XMEMCMP(msg, reply, sizeof(msg)), 0); + + ExpectIntEQ(wolfSSL_write(ssl_s, msg, sizeof(msg)), + (int)sizeof(msg)); + ExpectIntEQ(wolfSSL_read(ssl_c, reply, sizeof(reply)), + (int)sizeof(msg)); + ExpectIntEQ(XMEMCMP(msg, reply, sizeof(msg)), 0); + + keySz = ssl_c->specs.key_size; + ivSz = ssl_c->specs.iv_size; + ExpectTrue(isBufferAllZero(ssl_c->keys.client_write_key, keySz)); + ExpectTrue(isBufferAllZero(ssl_c->keys.server_write_key, keySz)); + ExpectTrue(isBufferAllZero(ssl_s->keys.client_write_key, keySz)); + ExpectTrue(isBufferAllZero(ssl_s->keys.server_write_key, keySz)); + + /* Same invariant as the post-handshake block above: the static + * IVs (both the source *_write_IV buffers and the AEAD copies + * BuildTls13Nonce() actually reads) are required on every + * record and must survive SetKeysSide after KeyUpdate. */ + ExpectTrue(!isBufferAllZero(ssl_c->keys.client_write_IV, ivSz)); + ExpectTrue(!isBufferAllZero(ssl_c->keys.server_write_IV, ivSz)); + ExpectTrue(!isBufferAllZero(ssl_s->keys.client_write_IV, ivSz)); + ExpectTrue(!isBufferAllZero(ssl_s->keys.server_write_IV, ivSz)); + + ExpectTrue(!isBufferAllZero(ssl_c->keys.aead_enc_imp_IV, ivSz)); + ExpectTrue(!isBufferAllZero(ssl_c->keys.aead_dec_imp_IV, ivSz)); + ExpectTrue(!isBufferAllZero(ssl_s->keys.aead_enc_imp_IV, ivSz)); + ExpectTrue(!isBufferAllZero(ssl_s->keys.aead_dec_imp_IV, ivSz)); + } + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + wc_CryptoCb_UnRegisterDevice(TEST_TLS13_ZERO_DEVID); +#endif + return EXPECT_RESULT(); +} + +int test_wc_CryptoCb_Tls13_Key_No_Zero_Without_Offload(void) +{ + EXPECT_DECLS; +#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_AES_SETKEY) && \ + !defined(NO_AES) && defined(HAVE_AESGCM) && \ + defined(WOLFSSL_TLS13) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \ + !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) + WOLFSSL_CTX* ctx_c = NULL; + WOLFSSL_CTX* ctx_s = NULL; + WOLFSSL* ssl_c = NULL; + WOLFSSL* ssl_s = NULL; + struct test_memio_ctx test_ctx; + word32 keySz; + word32 ivSz; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0); + + /* Pin the ciphersuite for the same reason as the offload test: so the + * regression assertions below reference the same buffers the offload + * test expects to see zeroed (or not zeroed, here). See the companion + * comment in test_wc_CryptoCb_Tls13_Key_Zero_After_Offload. */ + ExpectIntEQ(wolfSSL_set_cipher_list(ssl_c, + "TLS13-AES128-GCM-SHA256:TLS13-AES256-GCM-SHA384"), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_cipher_list(ssl_s, + "TLS13-AES128-GCM-SHA256:TLS13-AES256-GCM-SHA384"), WOLFSSL_SUCCESS); + + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + if (ssl_c != NULL && ssl_s != NULL) { + keySz = ssl_c->specs.key_size; + ivSz = ssl_c->specs.iv_size; + ExpectTrue(keySz > 0); + ExpectTrue(ivSz > 0); + + /* Check each buffer independently. AND-combining these would + * mask the case where one buffer was never populated, which + * would produce a confusing "regression, keys were zeroed" + * failure when the real issue is upstream. */ + ExpectTrue(!isBufferAllZero(ssl_c->keys.client_write_key, keySz)); + ExpectTrue(!isBufferAllZero(ssl_c->keys.server_write_key, keySz)); + ExpectTrue(!isBufferAllZero(ssl_s->keys.client_write_key, keySz)); + ExpectTrue(!isBufferAllZero(ssl_s->keys.server_write_key, keySz)); + + ExpectTrue(!isBufferAllZero(ssl_c->keys.client_write_IV, ivSz)); + ExpectTrue(!isBufferAllZero(ssl_c->keys.server_write_IV, ivSz)); + ExpectTrue(!isBufferAllZero(ssl_s->keys.client_write_IV, ivSz)); + ExpectTrue(!isBufferAllZero(ssl_s->keys.server_write_IV, ivSz)); + } + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + + /******************************************************************************* * Monte Carlo tests for AES modes ******************************************************************************/ diff --git a/tests/api/test_aes.h b/tests/api/test_aes.h index 51f0ba3efc..133170ff17 100644 --- a/tests/api/test_aes.h +++ b/tests/api/test_aes.h @@ -94,6 +94,24 @@ int test_wc_CryptoCb_AesSetKey(void); int test_wc_CryptoCb_AesGcm_EncryptDecrypt(void); #endif +/* These test functions always have a (possibly empty) definition in + * test_aes.c so that callers can reference them unconditionally. Declare + * the prototypes unconditionally to satisfy -Wmissing-prototypes. The + * TEST_CRYPTOCB_TLS13_KEY_ZERO_DECL macro below, however, only registers + * them with the test harness when the real bodies are compiled in. */ +int test_wc_CryptoCb_Tls13_Key_Zero_After_Offload(void); +int test_wc_CryptoCb_Tls13_Key_No_Zero_Without_Offload(void); +#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_AES_SETKEY) && \ + !defined(NO_AES) && defined(HAVE_AESGCM) && \ + defined(WOLFSSL_TLS13) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \ + !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) +#define TEST_CRYPTOCB_TLS13_KEY_ZERO_DECL \ + , TEST_DECL_GROUP("aes", test_wc_CryptoCb_Tls13_Key_Zero_After_Offload) \ + , TEST_DECL_GROUP("aes", test_wc_CryptoCb_Tls13_Key_No_Zero_Without_Offload) +#else +#define TEST_CRYPTOCB_TLS13_KEY_ZERO_DECL +#endif + #if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_AES_SETKEY) && \ !defined(NO_AES) && defined(HAVE_AESGCM) #define TEST_CRYPTOCB_AES_SETKEY_DECL , TEST_DECL_GROUP("aes", test_wc_CryptoCb_AesSetKey), \ @@ -153,7 +171,8 @@ int test_wc_CryptoCb_AesGcm_EncryptDecrypt(void); TEST_DECL_GROUP("aes", test_wc_AesCcm_MonteCarlo), \ TEST_DECL_GROUP("aes", test_wc_AesCfb_MonteCarlo), \ TEST_DECL_GROUP("aes", test_wc_AesOfb_MonteCarlo) \ - TEST_CRYPTOCB_AES_SETKEY_DECL + TEST_CRYPTOCB_AES_SETKEY_DECL \ + TEST_CRYPTOCB_TLS13_KEY_ZERO_DECL #if defined(WOLFSSL_AES_EAX) && defined(WOLFSSL_AES_256) && \ (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5, 3)) && !defined(HAVE_SELFTEST) From fccced4935de0c7022032fb5660e39db7f0531a0 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Mon, 20 Apr 2026 08:57:41 -0400 Subject: [PATCH 068/167] Rust wrapper: verify RSA lengths in verifying_key() --- wrapper/rust/wolfssl-wolfcrypt/src/rsa_pkcs1v15.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/rsa_pkcs1v15.rs b/wrapper/rust/wolfssl-wolfcrypt/src/rsa_pkcs1v15.rs index 1effa323c9..c20d2a3e26 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/rsa_pkcs1v15.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/rsa_pkcs1v15.rs @@ -336,6 +336,9 @@ impl Keypair for SigningKey { if rc != 0 { panic!("wc_RsaFlattenPublicKey failed: {rc}"); } + if (n_len as usize) != N || e_len == 0 || (e_len as usize) > MAX_E_LEN { + panic!("wc_RsaFlattenPublicKey failed: e_len: {e_len}, n_len: {n_len}"); + } VerifyingKey { n, e, From e8ae1536af8ecc1f7879a78566e407cb6b8973be Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Mon, 20 Apr 2026 08:58:21 -0400 Subject: [PATCH 069/167] Mark sha_digest module public --- wrapper/rust/wolfssl-wolfcrypt/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/lib.rs b/wrapper/rust/wolfssl-wolfcrypt/src/lib.rs index 0c954abce9..ec817dcf4c 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/lib.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/lib.rs @@ -65,7 +65,7 @@ pub mod rsa; pub mod rsa_pkcs1v15; pub mod sha; #[cfg(feature = "digest")] -mod sha_digest; +pub mod sha_digest; /// Convert a buffer length to `u32`, returning `BUFFER_E` if it overflows. pub(crate) fn buffer_len_to_u32(len: usize) -> Result { From 1b5d77e53f822ae1d8c428c72e7b9f3b13e24ad9 Mon Sep 17 00:00:00 2001 From: Eric Blankenhorn Date: Mon, 20 Apr 2026 08:22:53 -0500 Subject: [PATCH 070/167] Fix from review --- src/crl.c | 13 +++++-------- wolfcrypt/src/port/caam/wolfcaam_qnx.c | 1 + 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/crl.c b/src/crl.c index 540a6d23ac..5247f18709 100644 --- a/src/crl.c +++ b/src/crl.c @@ -1807,12 +1807,6 @@ static THREAD_RETURN WOLFSSL_THREAD DoMonitor(void* arg) #include #include -/* Fall back to no-op if EFD_CLOEXEC is unavailable. */ -#ifndef EFD_CLOEXEC - #define EFD_CLOEXEC 0 -#endif - - #ifndef max static WC_INLINE int max(int a, int b) { @@ -1846,12 +1840,15 @@ static THREAD_RETURN WOLFSSL_THREAD DoMonitor(void* arg) WOLFSSL_ENTER("DoMonitor"); +#ifdef EFD_CLOEXEC crl->mfd = eventfd(0, EFD_CLOEXEC); /* our custom shutdown event */ -#ifdef FD_CLOEXEC - if (crl->mfd < 0 && errno == EINVAL) { + if (crl->mfd < 0 && (errno == ENOSYS || errno == EINVAL)) { crl->mfd = eventfd(0, 0); wc_set_cloexec(crl->mfd); } +#else + crl->mfd = eventfd(0, 0); /* our custom shutdown event */ + wc_set_cloexec(crl->mfd); #endif if (crl->mfd < 0) { WOLFSSL_MSG("eventfd failed"); diff --git a/wolfcrypt/src/port/caam/wolfcaam_qnx.c b/wolfcrypt/src/port/caam/wolfcaam_qnx.c index eab9cdd572..fff951b56d 100644 --- a/wolfcrypt/src/port/caam/wolfcaam_qnx.c +++ b/wolfcrypt/src/port/caam/wolfcaam_qnx.c @@ -33,6 +33,7 @@ #include #include #include +#include /* for devctl use */ From fb7e1aa39681e433488856fe9924b389f520e8d6 Mon Sep 17 00:00:00 2001 From: Eric Blankenhorn Date: Mon, 20 Apr 2026 10:12:40 -0500 Subject: [PATCH 071/167] Fix from review --- src/wolfio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wolfio.c b/src/wolfio.c index fe891da234..3144d4f7d1 100644 --- a/src/wolfio.c +++ b/src/wolfio.c @@ -1624,7 +1624,7 @@ int wolfIO_TcpBind(SOCKET_T* sockfd, word16 port) #ifdef HAVE_SOCKADDR int wolfIO_TcpAccept(SOCKET_T sockfd, SOCKADDR* peer_addr, XSOCKLENT* peer_len) { - return wc_accept_cloexec((int)sockfd, peer_addr, peer_len); + return (int)wc_accept_cloexec((int)sockfd, peer_addr, peer_len); } #endif /* HAVE_SOCKADDR */ From 8b762301ef22bd78bad30a9d303043d5837b3d56 Mon Sep 17 00:00:00 2001 From: Lealem Amedie Date: Mon, 20 Apr 2026 09:31:42 -0600 Subject: [PATCH 072/167] Add EVP_PKEY_new_raw_public_key and EVP_PKEY_new_raw_private_key --- src/internal.c | 27 ++++- tests/api/test_evp_pkey.c | 13 ++- wolfcrypt/src/evp_pk.c | 222 ++++++++++++++++++++++++++++++++------ wolfssl/openssl/evp.h | 6 ++ 4 files changed, 226 insertions(+), 42 deletions(-) diff --git a/src/internal.c b/src/internal.c index 067b7a6c08..8662a9bbaf 100644 --- a/src/internal.c +++ b/src/internal.c @@ -13894,9 +13894,30 @@ int CopyDecodedToX509(WOLFSSL_X509* x509, DecodedCert* dCert) } wolfSSL_EVP_PKEY_free(x509->key.pkey); - if (!(x509->key.pkey = wolfSSL_d2i_PUBKEY(NULL, - &dCert->publicKey, - dCert->pubKeySize))) { + x509->key.pkey = NULL; + + switch (dCert->keyOID) { + #ifdef HAVE_ED25519 + case ED25519k: + x509->key.pkey = wolfSSL_EVP_PKEY_new_raw_public_key( + WC_EVP_PKEY_ED25519, NULL, dCert->publicKey, + dCert->pubKeySize); + break; + #endif + #ifdef HAVE_ED448 + case ED448k: + x509->key.pkey = wolfSSL_EVP_PKEY_new_raw_public_key( + WC_EVP_PKEY_ED448, NULL, dCert->publicKey, + dCert->pubKeySize); + break; + #endif + default: + x509->key.pkey = wolfSSL_d2i_PUBKEY(NULL, + &dCert->publicKey, dCert->pubKeySize); + break; + } + + if (x509->key.pkey == NULL) { ret = PUBLIC_KEY_E; WOLFSSL_ERROR_VERBOSE(ret); } diff --git a/tests/api/test_evp_pkey.c b/tests/api/test_evp_pkey.c index eee753125e..ec46779a71 100644 --- a/tests/api/test_evp_pkey.c +++ b/tests/api/test_evp_pkey.c @@ -2400,10 +2400,9 @@ int test_wolfSSL_EVP_PKEY_ed25519(void) wolfSSL_EVP_PKEY_free(pkey); pkey = NULL; - /* Exercise d2iTryEd25519Key's raw fallback where the caller passes - * the raw bytes from the SPKI BIT STRING rather than a wrapped SPKI. */ - p = rawPub; - ExpectNotNull(pkey = wolfSSL_d2i_PUBKEY(NULL, &p, (long)sizeof(rawPub))); + /* Exercise EVP_PKEY_new_raw_public_key to parse 32 raw BIT STRING bytes */ + ExpectNotNull(pkey = wolfSSL_EVP_PKEY_new_raw_public_key( + WC_EVP_PKEY_ED25519, NULL, rawPub, sizeof(rawPub))); ExpectIntEQ(wolfSSL_EVP_PKEY_id(pkey), EVP_PKEY_ED25519); wolfSSL_EVP_PKEY_free(pkey); pkey = NULL; @@ -2490,9 +2489,9 @@ int test_wolfSSL_EVP_PKEY_ed448(void) wolfSSL_EVP_PKEY_free(pkey); pkey = NULL; - /* Raw 57-byte fallback path. */ - p = rawPub; - ExpectNotNull(pkey = wolfSSL_d2i_PUBKEY(NULL, &p, (long)sizeof(rawPub))); + /* Parse raw bytes */ + ExpectNotNull(pkey = wolfSSL_EVP_PKEY_new_raw_public_key( + WC_EVP_PKEY_ED448, NULL, rawPub, sizeof(rawPub))); ExpectIntEQ(wolfSSL_EVP_PKEY_id(pkey), EVP_PKEY_ED448); wolfSSL_EVP_PKEY_free(pkey); pkey = NULL; diff --git a/wolfcrypt/src/evp_pk.c b/wolfcrypt/src/evp_pk.c index 4a82d4931f..68fecb8fda 100644 --- a/wolfcrypt/src/evp_pk.c +++ b/wolfcrypt/src/evp_pk.c @@ -262,13 +262,8 @@ static int d2iTryEd25519Key(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, return 0; } - /* Try decoding data as an Ed25519 private/public key. Private keys must - * be PKCS#8 PrivateKeyInfo DER (matching OpenSSL d2i_PrivateKey - * semantics). Public keys may be DER-encoded SubjectPublicKeyInfo (the - * normal d2i_PUBKEY input) or raw 32-byte key material (as passed from - * CopyDecodedToX509 where dCert->publicKey is the raw bytes from the - * SPKI BIT STRING); the structured form is tried first, then the raw - * import as fallback. */ + /* Decode data as an Ed25519 key in DER form (SubjectPublicKeyInfo for + * public keys, PKCS#8 PrivateKeyInfo for private keys). */ if (priv) { isEdKey = (wc_Ed25519PrivateKeyDecode(mem, &keyIdx, edKey, (word32)memSz) == 0); @@ -276,11 +271,6 @@ static int d2iTryEd25519Key(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, else { isEdKey = (wc_Ed25519PublicKeyDecode(mem, &keyIdx, edKey, (word32)memSz) == 0); - if (!isEdKey && memSz == ED25519_PUB_KEY_SIZE) { - keyIdx = (word32)memSz; - isEdKey = (wc_ed25519_import_public(mem, (word32)memSz, edKey) - == 0); - } } if (!isEdKey) { @@ -288,10 +278,9 @@ static int d2iTryEd25519Key(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, return WOLFSSL_FATAL_ERROR; } - /* Create an EVP PKEY object holding the input bytes. These are the - * SPKI / PKCS#8 DER on the structured path, or the raw 32-byte key - * on the raw fallback path. If the caller already populated the EVP - * PKEY with the input bytes (pkey.ptr set), skip the allocate/copy. */ + /* Create an EVP PKEY object holding the input DER bytes. If the caller + * already populated the EVP PKEY with the input bytes (pkey.ptr set), + * skip the allocate/copy. */ if (*out == NULL || (*out)->pkey.ptr == NULL) { ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_ED25519); } @@ -338,13 +327,8 @@ static int d2iTryEd448Key(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, return 0; } - /* Try decoding data as an Ed448 private/public key. Private keys must - * be PKCS#8 PrivateKeyInfo DER (matching OpenSSL d2i_PrivateKey - * semantics). Public keys may be DER-encoded SubjectPublicKeyInfo (the - * normal d2i_PUBKEY input) or raw 57-byte key material (as passed from - * CopyDecodedToX509 where dCert->publicKey is the raw bytes from the - * SPKI BIT STRING); the structured form is tried first, then the raw - * import as fallback. */ + /* Decode data as an Ed448 key in DER form (SubjectPublicKeyInfo for + * public keys, PKCS#8 PrivateKeyInfo for private keys). */ if (priv) { isEdKey = (wc_Ed448PrivateKeyDecode(mem, &keyIdx, edKey, (word32)memSz) == 0); @@ -352,11 +336,6 @@ static int d2iTryEd448Key(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, else { isEdKey = (wc_Ed448PublicKeyDecode(mem, &keyIdx, edKey, (word32)memSz) == 0); - if (!isEdKey && memSz == ED448_PUB_KEY_SIZE) { - keyIdx = (word32)memSz; - isEdKey = (wc_ed448_import_public(mem, (word32)memSz, edKey) - == 0); - } } if (!isEdKey) { @@ -364,10 +343,9 @@ static int d2iTryEd448Key(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, return WOLFSSL_FATAL_ERROR; } - /* Create an EVP PKEY object holding the input bytes. These are the - * SPKI / PKCS#8 DER on the structured path, or the raw 57-byte key - * on the raw fallback path. If the caller already populated the EVP - * PKEY with the input bytes (pkey.ptr set), skip the allocate/copy. */ + /* Create an EVP PKEY object holding the input DER bytes. If the caller + * already populated the EVP PKEY with the input bytes (pkey.ptr set), + * skip the allocate/copy. */ if (*out == NULL || (*out)->pkey.ptr == NULL) { ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_ED448); } @@ -383,6 +361,186 @@ static int d2iTryEd448Key(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, } #endif /* HAVE_ED448 */ +/* Create a new EVP_PKEY from raw Ed25519 or Ed448 key material. + * + * Used for for callers who already have the raw key bytes and shouldn't need + * to rewrap them in an SPKI just to decode. + * + * @param [in] type WC_EVP_PKEY_ED25519 or WC_EVP_PKEY_ED448. + * @param [in] e Engine. Ignored; accepted for OpenSSL API parity. + * @param [in] pub Raw public key bytes. + * @param [in] len Length of pub. Must match the curve's public key size + * (ED25519_PUB_KEY_SIZE or ED448_PUB_KEY_SIZE). + * @return WOLFSSL_EVP_PKEY on success, NULL on failure. + */ +WOLFSSL_EVP_PKEY* wolfSSL_EVP_PKEY_new_raw_public_key(int type, + WOLFSSL_ENGINE* e, const unsigned char* pub, size_t len) +{ + WOLFSSL_EVP_PKEY* pkey; + int ok = 0; + + (void)e; + WOLFSSL_ENTER("wolfSSL_EVP_PKEY_new_raw_public_key"); + + if (pub == NULL || len == 0) { + return NULL; + } + + pkey = wolfSSL_EVP_PKEY_new(); + if (pkey == NULL) { + return NULL; + } + + switch (type) { + #ifdef HAVE_ED25519 + case WC_EVP_PKEY_ED25519: { + ed25519_key* edKey; + if (len != ED25519_PUB_KEY_SIZE) { + break; + } + edKey = wolfSSL_ED25519_new(pkey->heap, INVALID_DEVID); + if (edKey == NULL) { + break; + } + if (wc_ed25519_import_public(pub, (word32)len, edKey) != 0) { + wolfSSL_ED25519_free(edKey); + break; + } + pkey->type = WC_EVP_PKEY_ED25519; + pkey->ed25519 = edKey; + pkey->ownEd25519 = 1; + ok = 1; + break; + } + #endif + #ifdef HAVE_ED448 + case WC_EVP_PKEY_ED448: { + ed448_key* edKey; + if (len != ED448_PUB_KEY_SIZE) { + break; + } + edKey = wolfSSL_ED448_new(pkey->heap, INVALID_DEVID); + if (edKey == NULL) { + break; + } + if (wc_ed448_import_public(pub, (word32)len, edKey) != 0) { + wolfSSL_ED448_free(edKey); + break; + } + pkey->type = WC_EVP_PKEY_ED448; + pkey->ed448 = edKey; + pkey->ownEd448 = 1; + ok = 1; + break; + } + #endif + default: + break; + } + + if (!ok) { + wolfSSL_EVP_PKEY_free(pkey); + return NULL; + } + + /* Stash the raw bytes so callers that later serialize the EVP_PKEY see + * consistent state. */ + pkey->pkey.ptr = (char*)XMALLOC(len, pkey->heap, DYNAMIC_TYPE_PUBLIC_KEY); + if (pkey->pkey.ptr == NULL) { + wolfSSL_EVP_PKEY_free(pkey); + return NULL; + } + XMEMCPY(pkey->pkey.ptr, pub, len); + pkey->pkey_sz = (int)len; + + return pkey; +} + +/* Private-key counterpart to wolfSSL_EVP_PKEY_new_raw_public_key. The raw + * input is the 32-byte seed (Ed25519) or 57-byte seed (Ed448). + */ +WOLFSSL_EVP_PKEY* wolfSSL_EVP_PKEY_new_raw_private_key(int type, + WOLFSSL_ENGINE* e, const unsigned char* priv, size_t len) +{ + WOLFSSL_EVP_PKEY* pkey; + int ok = 0; + + (void)e; + WOLFSSL_ENTER("wolfSSL_EVP_PKEY_new_raw_private_key"); + + if (priv == NULL || len == 0) { + return NULL; + } + + pkey = wolfSSL_EVP_PKEY_new(); + if (pkey == NULL) { + return NULL; + } + + switch (type) { + #ifdef HAVE_ED25519 + case WC_EVP_PKEY_ED25519: { + ed25519_key* edKey; + if (len != ED25519_KEY_SIZE) { + break; + } + edKey = wolfSSL_ED25519_new(pkey->heap, INVALID_DEVID); + if (edKey == NULL) { + break; + } + if (wc_ed25519_import_private_only(priv, (word32)len, edKey) + != 0) { + wolfSSL_ED25519_free(edKey); + break; + } + pkey->type = WC_EVP_PKEY_ED25519; + pkey->ed25519 = edKey; + pkey->ownEd25519 = 1; + ok = 1; + break; + } + #endif + #ifdef HAVE_ED448 + case WC_EVP_PKEY_ED448: { + ed448_key* edKey; + if (len != ED448_KEY_SIZE) { + break; + } + edKey = wolfSSL_ED448_new(pkey->heap, INVALID_DEVID); + if (edKey == NULL) { + break; + } + if (wc_ed448_import_private_only(priv, (word32)len, edKey) != 0) { + wolfSSL_ED448_free(edKey); + break; + } + pkey->type = WC_EVP_PKEY_ED448; + pkey->ed448 = edKey; + pkey->ownEd448 = 1; + ok = 1; + break; + } + #endif + default: + break; + } + + if (!ok) { + wolfSSL_EVP_PKEY_free(pkey); + return NULL; + } + + pkey->pkey.ptr = (char*)XMALLOC(len, pkey->heap, DYNAMIC_TYPE_PRIVATE_KEY); + if (pkey->pkey.ptr == NULL) { + wolfSSL_EVP_PKEY_free(pkey); + return NULL; + } + XMEMCPY(pkey->pkey.ptr, priv, len); + pkey->pkey_sz = (int)len; + + return pkey; +} + #if !defined(NO_DSA) /** * Try to make a DSA EVP PKEY from data. diff --git a/wolfssl/openssl/evp.h b/wolfssl/openssl/evp.h index dc41bd11a4..05cd80f314 100644 --- a/wolfssl/openssl/evp.h +++ b/wolfssl/openssl/evp.h @@ -991,6 +991,10 @@ WOLFSSL_API int wolfSSL_EVP_PKEY_encrypt(WOLFSSL_EVP_PKEY_CTX *ctx, WOLFSSL_API int wolfSSL_EVP_PKEY_encrypt_init(WOLFSSL_EVP_PKEY_CTX *ctx); WOLFSSL_API WOLFSSL_EVP_PKEY *wolfSSL_EVP_PKEY_new(void); WOLFSSL_API WOLFSSL_EVP_PKEY* wolfSSL_EVP_PKEY_new_ex(void* heap); +WOLFSSL_API WOLFSSL_EVP_PKEY* wolfSSL_EVP_PKEY_new_raw_public_key(int type, + WOLFSSL_ENGINE* e, const unsigned char* pub, size_t len); +WOLFSSL_API WOLFSSL_EVP_PKEY* wolfSSL_EVP_PKEY_new_raw_private_key(int type, + WOLFSSL_ENGINE* e, const unsigned char* priv, size_t len); WOLFSSL_API void wolfSSL_EVP_PKEY_free(WOLFSSL_EVP_PKEY* key); WOLFSSL_API int wolfSSL_EVP_PKEY_size(WOLFSSL_EVP_PKEY *pkey); WOLFSSL_API int wolfSSL_EVP_PKEY_copy_parameters(WOLFSSL_EVP_PKEY *to, const WOLFSSL_EVP_PKEY *from); @@ -1400,6 +1404,8 @@ WOLFSSL_API int wolfSSL_EVP_SignInit_ex(WOLFSSL_EVP_MD_CTX* ctx, #define EVP_PKEY_encrypt wolfSSL_EVP_PKEY_encrypt #define EVP_PKEY_encrypt_init wolfSSL_EVP_PKEY_encrypt_init #define EVP_PKEY_new wolfSSL_EVP_PKEY_new +#define EVP_PKEY_new_raw_public_key wolfSSL_EVP_PKEY_new_raw_public_key +#define EVP_PKEY_new_raw_private_key wolfSSL_EVP_PKEY_new_raw_private_key #define EVP_PKEY_free wolfSSL_EVP_PKEY_free #define EVP_PKEY_up_ref wolfSSL_EVP_PKEY_up_ref #define EVP_PKEY_size wolfSSL_EVP_PKEY_size From fc63047411fa9cc3f24c6c5d37ec4c9c336ab57a Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Mon, 20 Apr 2026 18:11:16 +0200 Subject: [PATCH 073/167] Additional related minor fixes --- src/ssl.c | 7 +++++-- src/ssl_load.c | 8 ++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/ssl.c b/src/ssl.c index 4e44a6360b..999fb13845 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -14544,10 +14544,13 @@ void* wolfSSL_GetHKDFExtractCtx(WOLFSSL* ssl) } else if (a->type == WOLFSSL_GEN_DNS || a->type == WOLFSSL_GEN_EMAIL || a->type == WOLFSSL_GEN_URI) { - bufSz = (int)XSTRLEN((const char*)a->obj); - if (bufSz >= bufLen) { + size_t objLen = XSTRLEN((const char*)a->obj); + if (objLen >= (size_t)bufLen) { bufSz = bufLen - 1; } + else { + bufSz = (int)objLen; + } XMEMCPY(buf, a->obj, (size_t)bufSz); } else if ((bufSz = wolfssl_obj2txt_numeric(buf, bufLen, a)) > 0) { diff --git a/src/ssl_load.c b/src/ssl_load.c index 9260aa2b9a..c3b5c81dc9 100644 --- a/src/ssl_load.c +++ b/src/ssl_load.c @@ -4290,7 +4290,7 @@ int wolfSSL_CTX_use_AltPrivateKey_Id(WOLFSSL_CTX* ctx, const unsigned char* id, } } if (ret == 1) { - XMEMCPY(ctx->altPrivateKey->buffer, id, sz); + XMEMCPY(ctx->altPrivateKey->buffer, id, (word32)sz); ctx->altPrivateKeyId = 1; if (devId != INVALID_DEVID) { ctx->altPrivateKeyDevId = devId; @@ -4704,12 +4704,12 @@ int wolfSSL_use_AltPrivateKey_Id(WOLFSSL* ssl, const unsigned char* id, long sz, #endif } if (AllocDer(&ssl->buffers.altKey, (word32)sz, ALT_PRIVATEKEY_TYPE, - ssl->heap) == 0) { + ssl->heap) != 0) { ret = 0; } } if (ret == 1) { - XMEMCPY(ssl->buffers.altKey->buffer, id, sz); + XMEMCPY(ssl->buffers.altKey->buffer, id, (word32)sz); ssl->buffers.weOwnAltKey = 1; ssl->buffers.altKeyId = 1; if (devId != INVALID_DEVID) { @@ -4752,7 +4752,7 @@ int wolfSSL_use_AltPrivateKey_Label(WOLFSSL* ssl, const char* label, int devId) #endif } if (AllocDer(&ssl->buffers.altKey, (word32)sz, ALT_PRIVATEKEY_TYPE, - ssl->heap) == 0) { + ssl->heap) != 0) { ret = 0; } } From a010825bb08103be70da93b67ebab70e2de85b46 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Mon, 20 Apr 2026 12:46:58 +0000 Subject: [PATCH 074/167] Address review comments on Fenrir zeroization fixes Two follow-ups raised by Copilot review on PR #10247: src/pk_rsa.c: Make derAllocSz a word32 instead of int and only assign it after a successful XMALLOC, so the cleanup path can never call ForceZero with a wrapped-around size derived from a negative derSz. src/pk.c: Capture allocSz at the XMALLOC call site (and clear it back to 0 on allocation failure) so the relationship between the buffer allocation and the recorded size is explicit and cannot drift if the surrounding control flow changes. --- src/pk.c | 8 +++----- src/pk_rsa.c | 10 ++++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/pk.c b/src/pk.c index f9cc7345ad..a0df3af265 100644 --- a/src/pk.c +++ b/src/pk.c @@ -7150,16 +7150,14 @@ static int pem_write_mem_pkcs8privatekey(byte** pem, int* pemSz, *pemSz += 54; } + allocSz = (word32)*pemSz; /* Allocate enough memory to hold PEM encoded encrypted key. */ - *pem = (byte*)XMALLOC((size_t)*pemSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + *pem = (byte*)XMALLOC((size_t)allocSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (*pem == NULL) { + allocSz = 0; res = 0; } else { - /* Remember the allocation size before *pemSz is updated to the - * actual PEM output length, so we can zero any unused tail that - * held the DER staging area. */ - allocSz = (word32)*pemSz; /* Use end of PEM buffer for key data. */ key = *pem + *pemSz - keySz; } diff --git a/src/pk_rsa.c b/src/pk_rsa.c index 9f5ba4488b..682b1d2808 100644 --- a/src/pk_rsa.c +++ b/src/pk_rsa.c @@ -782,7 +782,7 @@ static int wolfSSL_RSA_To_Der_ex(WOLFSSL_RSA* rsa, byte** outBuf, int publicKey, { int ret = 1; int derSz = 0; - int derAllocSz = 0; + word32 derAllocSz = 0; byte* derBuf = NULL; WOLFSSL_ENTER("wolfSSL_RSA_To_Der"); @@ -824,7 +824,6 @@ static int wolfSSL_RSA_To_Der_ex(WOLFSSL_RSA* rsa, byte** outBuf, int publicKey, } } - derAllocSz = derSz; if ((ret == 1) && (outBuf != NULL)) { derBuf = *outBuf; if (derBuf == NULL) { @@ -835,6 +834,9 @@ static int wolfSSL_RSA_To_Der_ex(WOLFSSL_RSA* rsa, byte** outBuf, int publicKey, WOLFSSL_ERROR_MSG("Memory allocation failed"); ret = MEMORY_ERROR; } + else { + derAllocSz = (word32)derSz; + } } } if ((ret == 1) && (outBuf != NULL)) { @@ -868,8 +870,8 @@ static int wolfSSL_RSA_To_Der_ex(WOLFSSL_RSA* rsa, byte** outBuf, int publicKey, if ((outBuf != NULL) && (*outBuf != derBuf)) { /* Not returning buffer, needs to be disposed of. */ - if ((derBuf != NULL) && (publicKey == 0)) { - ForceZero(derBuf, (word32)derAllocSz); + if ((derBuf != NULL) && (publicKey == 0) && (derAllocSz > 0)) { + ForceZero(derBuf, derAllocSz); } XFREE(derBuf, heap, DYNAMIC_TYPE_TMP_BUFFER); } From 6596419cb0b8cde60284bcad0dff81ffea31dd6c Mon Sep 17 00:00:00 2001 From: Jeremiah Mackey Date: Mon, 20 Apr 2026 17:20:54 +0000 Subject: [PATCH 075/167] add NULL validation to wolfCrypt APIs --- wolfcrypt/src/camellia.c | 2 +- wolfcrypt/src/compress.c | 6 ++++++ wolfcrypt/src/hmac.c | 2 +- wolfcrypt/src/wc_lms.c | 3 ++- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/wolfcrypt/src/camellia.c b/wolfcrypt/src/camellia.c index facc436265..abf4a3f220 100644 --- a/wolfcrypt/src/camellia.c +++ b/wolfcrypt/src/camellia.c @@ -1521,7 +1521,7 @@ int wc_CamelliaSetKey(wc_Camellia* cam, const byte* key, word32 len, const byte* { int ret = 0; - if (cam == NULL) return BAD_FUNC_ARG; + if (cam == NULL || key == NULL) return BAD_FUNC_ARG; XMEMSET(cam->key, 0, WC_CAMELLIA_TABLE_BYTE_LEN); diff --git a/wolfcrypt/src/compress.c b/wolfcrypt/src/compress.c index 71dd619f7a..17bfe07010 100644 --- a/wolfcrypt/src/compress.c +++ b/wolfcrypt/src/compress.c @@ -81,6 +81,9 @@ int wc_Compress_ex(byte* out, word32 outSz, const byte* in, word32 inSz, z_stream stream; int result = 0; + if (out == NULL || in == NULL) + return BAD_FUNC_ARG; + stream.next_in = (Bytef*)in; stream.avail_in = (uInt)inSz; #ifdef MAXSEG_64K @@ -149,6 +152,9 @@ int wc_DeCompress_ex(byte* out, word32 outSz, const byte* in, word32 inSz, z_stream stream; int result = 0; + if (out == NULL || in == NULL) + return BAD_FUNC_ARG; + stream.next_in = (Bytef*)in; stream.avail_in = (uInt)inSz; /* Check for source > 64K on 16-bit machine: */ diff --git a/wolfcrypt/src/hmac.c b/wolfcrypt/src/hmac.c index 8e8ad3ff3e..cd59087bdc 100644 --- a/wolfcrypt/src/hmac.c +++ b/wolfcrypt/src/hmac.c @@ -1395,7 +1395,7 @@ int wc_HmacInit_Id(Hmac* hmac, unsigned char* id, int len, void* heap, if (ret == 0) ret = wc_HmacInit(hmac, heap, devId); - if (ret == 0) { + if (ret == 0 && id != NULL && len != 0) { XMEMCPY(hmac->id, id, (size_t)len); hmac->idLen = len; } diff --git a/wolfcrypt/src/wc_lms.c b/wolfcrypt/src/wc_lms.c index 402b2f3c5a..2a3c1edc46 100644 --- a/wolfcrypt/src/wc_lms.c +++ b/wolfcrypt/src/wc_lms.c @@ -1159,7 +1159,8 @@ int wc_LmsKey_ExportPubRaw(const LmsKey* key, byte* out, word32* outLen) int ret = 0; /* Validate parameters. */ - if ((key == NULL) || (out == NULL) || (outLen == NULL)) { + if ((key == NULL) || (out == NULL) || (outLen == NULL) || + (key->params == NULL)) { ret = BAD_FUNC_ARG; } /* Check size of out is sufficient. */ From 4a103a1b4efcba496221fc21ea987f9852d4203d Mon Sep 17 00:00:00 2001 From: Jeremiah Mackey Date: Mon, 20 Apr 2026 17:20:54 +0000 Subject: [PATCH 076/167] AES: tighten AEAD input validation --- wolfcrypt/src/aes.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/wolfcrypt/src/aes.c b/wolfcrypt/src/aes.c index 02a6e1d424..72c1df4946 100644 --- a/wolfcrypt/src/aes.c +++ b/wolfcrypt/src/aes.c @@ -10062,8 +10062,11 @@ int wc_AesGcmEncrypt(Aes* aes, byte* out, const byte* in, word32 sz, int ret; /* argument checks */ - if (aes == NULL || authTagSz > WC_AES_BLOCK_SIZE || ivSz == 0 || - ((authTagSz > 0) && (authTag == NULL)) || + /* If sz is non-zero, both in and out must be set; if sz is 0, in and + * out are don't cares (GMAC case), matching wc_AesGcmDecrypt. */ + if (aes == NULL || iv == NULL || ivSz == 0 || + (sz != 0 && (in == NULL || out == NULL)) || + authTag == NULL || authTagSz > WC_AES_BLOCK_SIZE || ((authInSz > 0) && (authIn == NULL))) { return BAD_FUNC_ARG; @@ -17140,7 +17143,8 @@ int wc_AesEaxEncryptFinal(AesEax* eax, byte* authTag, word32 authTagSz) int ret; word32 i; - if (eax == NULL || authTag == NULL || authTagSz > WC_AES_BLOCK_SIZE) { + if (eax == NULL || authTag == NULL || authTagSz == 0 || + authTagSz > WC_AES_BLOCK_SIZE) { return BAD_FUNC_ARG; } @@ -17197,7 +17201,8 @@ int wc_AesEaxDecryptFinal(AesEax* eax, byte authTag[WC_AES_BLOCK_SIZE]; #endif - if (eax == NULL || authIn == NULL || authInSz > WC_AES_BLOCK_SIZE) { + if (eax == NULL || authIn == NULL || authInSz == 0 || + authInSz > WC_AES_BLOCK_SIZE) { return BAD_FUNC_ARG; } From c417a1ce1ebf28e19390a131299129f0853a3945 Mon Sep 17 00:00:00 2001 From: Jeremiah Mackey Date: Mon, 20 Apr 2026 17:20:54 +0000 Subject: [PATCH 077/167] zero sensitive state before free --- wolfcrypt/src/arc4.c | 11 +++++++++++ wolfcrypt/src/des3.c | 1 + wolfcrypt/src/wc_lms_impl.c | 1 + 3 files changed, 13 insertions(+) diff --git a/wolfcrypt/src/arc4.c b/wolfcrypt/src/arc4.c index a2f951fb52..6d83ed2569 100644 --- a/wolfcrypt/src/arc4.c +++ b/wolfcrypt/src/arc4.c @@ -25,6 +25,13 @@ #include +#ifdef NO_INLINE + #include +#else + #define WOLFSSL_MISC_INCLUDED + #include +#endif + int wc_Arc4SetKey(Arc4* arc4, const byte* key, word32 length) { @@ -137,6 +144,10 @@ void wc_Arc4Free(Arc4* arc4) #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ARC4) wolfAsync_DevCtxFree(&arc4->asyncDev, WOLFSSL_ASYNC_MARKER_ARC4); #endif /* WOLFSSL_ASYNC_CRYPT */ + + ForceZero(arc4->state, sizeof(arc4->state)); + arc4->x = 0; + arc4->y = 0; } #endif /* NO_RC4 */ diff --git a/wolfcrypt/src/des3.c b/wolfcrypt/src/des3.c index 45fa1771f5..12f884e0a5 100644 --- a/wolfcrypt/src/des3.c +++ b/wolfcrypt/src/des3.c @@ -2002,6 +2002,7 @@ void wc_Des3Free(Des3* des3) (defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_3DES)) ForceZero(des3->devKey, sizeof(des3->devKey)); #endif + ForceZero(des3, sizeof(Des3)); #ifdef WOLFSSL_CHECK_MEM_ZERO wc_MemZero_Check(des3, sizeof(Des3)); #endif diff --git a/wolfcrypt/src/wc_lms_impl.c b/wolfcrypt/src/wc_lms_impl.c index 44191dbb33..d0baf82183 100644 --- a/wolfcrypt/src/wc_lms_impl.c +++ b/wolfcrypt/src/wc_lms_impl.c @@ -2855,6 +2855,7 @@ static int wc_hss_next_subtree_inc(LmsState* state, HssPrivKey* priv_key, q64_hi = cq64_hi; } + ForceZero(tmp_priv, sizeof(tmp_priv)); return ret; } From 9c1b8cf4f145efe4c8ba1617e0e0314bdf048fe4 Mon Sep 17 00:00:00 2001 From: Jeremiah Mackey Date: Mon, 20 Apr 2026 17:20:54 +0000 Subject: [PATCH 078/167] wc_rng_bank_init: fall through on size error --- wolfcrypt/src/rng_bank.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wolfcrypt/src/rng_bank.c b/wolfcrypt/src/rng_bank.c index 3cea1c7520..61a0ce479b 100644 --- a/wolfcrypt/src/rng_bank.c +++ b/wolfcrypt/src/rng_bank.c @@ -52,7 +52,7 @@ WOLFSSL_API int wc_rng_bank_init( #ifdef WC_RNG_BANK_STATIC if (n_rngs > WC_RNG_BANK_STATIC_SIZE) - return BAD_LENGTH_E; + ret = BAD_LENGTH_E; #else ctx->rngs = (struct wc_rng_bank_inst *) XMALLOC(sizeof(*ctx->rngs) * (size_t)n_rngs, From d5312ba35030abc4309edfa4550d84c4c9723960 Mon Sep 17 00:00:00 2001 From: Jeremiah Mackey Date: Mon, 20 Apr 2026 17:20:54 +0000 Subject: [PATCH 079/167] wc_MakeDsaKey: match tmpQ alloc and free --- wolfcrypt/src/dsa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wolfcrypt/src/dsa.c b/wolfcrypt/src/dsa.c index 14a9aca106..e881f8470a 100644 --- a/wolfcrypt/src/dsa.c +++ b/wolfcrypt/src/dsa.c @@ -174,8 +174,8 @@ int wc_MakeDsaKey(WC_RNG *rng, DsaKey *dsa) SAVE_VECTOR_REGISTERS(;); #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) - if ((tmpQ = (mp_int *)XMALLOC(sizeof(*tmpQ), NULL, - DYNAMIC_TYPE_WOLF_BIGINT)) == NULL) + if ((tmpQ = (mp_int *)XMALLOC(sizeof(*tmpQ), dsa->heap, + DYNAMIC_TYPE_TMP_BUFFER)) == NULL) err = MEMORY_E; else err = MP_OKAY; From a2b1f580c60468f1aeed028eda849faf0e62f876 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Mon, 20 Apr 2026 13:58:36 -0400 Subject: [PATCH 080/167] Rust wrapper: add buffer size checks in Rust wrapper for ChaCha20_Poly1305 one-shot encrypt/decrypt wrappers --- .../src/chacha20_poly1305.rs | 6 ++++ .../tests/test_chacha20_poly1305.rs | 29 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/chacha20_poly1305.rs b/wrapper/rust/wolfssl-wolfcrypt/src/chacha20_poly1305.rs index ae4e69b833..f053b8c565 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/chacha20_poly1305.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/chacha20_poly1305.rs @@ -74,6 +74,9 @@ impl ChaCha20Poly1305 { if auth_tag.len() != Self::AUTH_TAG_SIZE { return Err(sys::wolfCrypt_ErrorCodes_BUFFER_E); } + if plaintext.len() < ciphertext.len() { + return Err(sys::wolfCrypt_ErrorCodes_BUFFER_E); + } let aad_size = crate::buffer_len_to_u32(aad.len())?; let ciphertext_size = crate::buffer_len_to_u32(ciphertext.len())?; let rc = unsafe { @@ -116,6 +119,9 @@ impl ChaCha20Poly1305 { if auth_tag.len() != Self::AUTH_TAG_SIZE { return Err(sys::wolfCrypt_ErrorCodes_BUFFER_E); } + if ciphertext.len() < plaintext.len() { + return Err(sys::wolfCrypt_ErrorCodes_BUFFER_E); + } let aad_size = crate::buffer_len_to_u32(aad.len())?; let plaintext_size = crate::buffer_len_to_u32(plaintext.len())?; let rc = unsafe { diff --git a/wrapper/rust/wolfssl-wolfcrypt/tests/test_chacha20_poly1305.rs b/wrapper/rust/wolfssl-wolfcrypt/tests/test_chacha20_poly1305.rs index ac18fd21b0..71ae101fab 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/tests/test_chacha20_poly1305.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/tests/test_chacha20_poly1305.rs @@ -1,6 +1,7 @@ #![cfg(chacha20_poly1305)] use wolfssl_wolfcrypt::chacha20_poly1305::*; +use wolfssl_wolfcrypt::sys; #[test] fn test_chacha20_poly1305_1() { @@ -274,6 +275,34 @@ fn test_xchacha20_poly1305() { assert_eq!(plaintext_buffer, PLAINTEXT); } +#[test] +fn test_chacha20_poly1305_encrypt_short_ciphertext_buffer() { + let key = [0x55u8; ChaCha20Poly1305::KEYSIZE]; + let iv = [0x66u8; ChaCha20Poly1305::IV_SIZE]; + let aad = []; + let plaintext = [0u8; 32]; + let mut ciphertext = [0u8; 16]; /* shorter than plaintext */ + let mut auth_tag = [0u8; ChaCha20Poly1305::AUTH_TAG_SIZE]; + let rc = ChaCha20Poly1305::encrypt(&key, &iv, &aad, &plaintext, + &mut ciphertext, &mut auth_tag) + .expect_err("encrypt() should fail with short ciphertext buffer"); + assert_eq!(rc, sys::wolfCrypt_ErrorCodes_BUFFER_E); +} + +#[test] +fn test_chacha20_poly1305_decrypt_short_plaintext_buffer() { + let key = [0x55u8; ChaCha20Poly1305::KEYSIZE]; + let iv = [0x66u8; ChaCha20Poly1305::IV_SIZE]; + let aad = []; + let ciphertext = [0u8; 32]; + let mut plaintext = [0u8; 16]; /* shorter than ciphertext */ + let auth_tag = [0u8; ChaCha20Poly1305::AUTH_TAG_SIZE]; + let rc = ChaCha20Poly1305::decrypt(&key, &iv, &aad, &ciphertext, + &auth_tag, &mut plaintext) + .expect_err("decrypt() should fail with short plaintext buffer"); + assert_eq!(rc, sys::wolfCrypt_ErrorCodes_BUFFER_E); +} + // --------------------------------------------------------------------------- // ChaCha20-Poly1305 aead trait implementations // --------------------------------------------------------------------------- From c950a6aa462631dca1f30fcd512947df2dce7f60 Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Mon, 20 Apr 2026 12:29:26 -0700 Subject: [PATCH 081/167] zephyr: changes needed for Zephyr 4.3 default TLS support Follow-up to #7731 ("Changes needed for default TLS support in zephyr kernel"). Zephyr 4.3's TLS socket integration uses three additional wolfSSL features that were not needed by the 3.7 integration, plus an extension to the native_sim time-source gates introduced in #7731. native_sim timer gates (src/internal.c, wolfcrypt/src/wc_port.c): Extend the !CONFIG_BOARD_NATIVE_POSIX gate in LowResTimer() and the CONFIG_BOARD_NATIVE_POSIX RTC path in z_time() to also cover CONFIG_BOARD_NATIVE_SIM. Zephyr 4.3 renamed the simulator board from native_posix to native_sim; without this, k_cpu_idle() on native_sim advances simulated time during DTLS retransmit loops and the RTC path falls through to uptime-since-boot. Behavior on native_posix is unchanged. New Kconfig options (zephyr/Kconfig, zephyr/user_settings.h): CONFIG_WOLFSSL_SESSION_EXPORT -> HAVE_EXT_CACHE Required by consumers that serialize TLS session state across connections via wolfSSL_i2d_SSL_SESSION / wolfSSL_d2i_SSL_SESSION. CONFIG_WOLFSSL_KEEP_PEER_CERT -> KEEP_PEER_CERT Retain the peer certificate after handshake so the application layer can inspect it via wolfSSL_get_peer_certificate. CONFIG_WOLFSSL_ALWAYS_VERIFY_CB -> WOLFSSL_ALWAYS_VERIFY_CB Invoke an application-set verify callback on successful chain validation in addition to validation failures. All three are default-off; customers opt in the same way they do for the existing CONFIG_WOLFSSL_DTLS / ALPN / PSK feature options. .wolfssl_known_macro_extras: register HAVE_EXT_CACHE. --- .wolfssl_known_macro_extras | 1 + src/internal.c | 3 ++- wolfcrypt/src/wc_port.c | 6 +++--- zephyr/Kconfig | 15 +++++++++++++++ zephyr/user_settings.h | 15 +++++++++++++++ 5 files changed, 36 insertions(+), 4 deletions(-) diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 3943d47739..9dfce8514c 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -279,6 +279,7 @@ HAVE_ECC512 HAVE_ECC_CDH_CAST HAVE_ECC_SM2 HAVE_ESP_CLK +HAVE_EXT_CACHE HAVE_FIPS_VERSION_PORT HAVE_FUZZER HAVE_INTEL_MULX diff --git a/src/internal.c b/src/internal.c index 2ba6cabc15..9280884e51 100644 --- a/src/internal.c +++ b/src/internal.c @@ -10602,7 +10602,8 @@ ProtocolVersion MakeDTLSv1_3(void) word32 LowResTimer(void) { int64_t t; - #if defined(CONFIG_ARCH_POSIX) && !defined(CONFIG_BOARD_NATIVE_POSIX) + #if defined(CONFIG_ARCH_POSIX) && !defined(CONFIG_BOARD_NATIVE_POSIX) \ + && !defined(CONFIG_BOARD_NATIVE_SIM) k_cpu_idle(); #endif t = k_uptime_get(); /* returns current uptime in milliseconds */ diff --git a/wolfcrypt/src/wc_port.c b/wolfcrypt/src/wc_port.c index ba740423ea..c34bb4c18a 100644 --- a/wolfcrypt/src/wc_port.c +++ b/wolfcrypt/src/wc_port.c @@ -215,7 +215,7 @@ Threading/Mutex options: #endif #if defined(WOLFSSL_ZEPHYR) -#if defined(CONFIG_BOARD_NATIVE_POSIX) +#if defined(CONFIG_BOARD_NATIVE_POSIX) || defined(CONFIG_BOARD_NATIVE_SIM) #include "native_rtc.h" #define CONFIG_RTC #endif @@ -4088,7 +4088,7 @@ time_t z_time(time_t * timer) #if defined(CONFIG_RTC) && \ (defined(CONFIG_PICOLIBC) || defined(CONFIG_NEWLIB_LIBC)) - #if defined(CONFIG_BOARD_NATIVE_POSIX) + #if defined(CONFIG_BOARD_NATIVE_POSIX) || defined(CONFIG_BOARD_NATIVE_SIM) /* When using native sim, get time from simulator rtc */ uint32_t nsec = 0; @@ -4120,7 +4120,7 @@ time_t z_time(time_t * timer) return epochTime; } } - #endif /* defined(CONFIG_BOARD_NATIVE_POSIX) */ + #endif /* CONFIG_BOARD_NATIVE_POSIX || CONFIG_BOARD_NATIVE_SIM */ #endif /* Fallback to uptime since boot. This works for relative times, but diff --git a/zephyr/Kconfig b/zephyr/Kconfig index ff05e74d23..fb6084893a 100644 --- a/zephyr/Kconfig +++ b/zephyr/Kconfig @@ -98,6 +98,21 @@ config WOLFSSL_MAX_FRAGMENT_LEN Sets the maximum fragment length wolfSSL will use, values 1-6 correspond to enum values WOLFSSL_MFL_* in ssl.h +config WOLFSSL_SESSION_EXPORT + bool "wolfSSL session export support" + help + Enable external session cache (HAVE_EXT_CACHE) + +config WOLFSSL_KEEP_PEER_CERT + bool "wolfSSL keep peer certificate support" + help + Retain peer certificate after handshake (KEEP_PEER_CERT) + +config WOLFSSL_ALWAYS_VERIFY_CB + bool "wolfSSL always invoke verify callback" + help + Invoke verify callback on success as well as failure (WOLFSSL_ALWAYS_VERIFY_CB) + config WOLFCRYPT_ARMASM bool "wolfCrypt ARM Assembly support" depends on WOLFSSL_BUILTIN diff --git a/zephyr/user_settings.h b/zephyr/user_settings.h index cc333bdaaa..29aea487c8 100644 --- a/zephyr/user_settings.h +++ b/zephyr/user_settings.h @@ -133,6 +133,21 @@ extern "C" { #define NO_SESSION_CACHE /* disable session resumption */ #endif +/* Session export (external session cache) */ +#if defined(CONFIG_WOLFSSL_SESSION_EXPORT) + #define HAVE_EXT_CACHE +#endif + +/* Keep peer certificate after handshake */ +#if defined(CONFIG_WOLFSSL_KEEP_PEER_CERT) + #define KEEP_PEER_CERT +#endif + +/* Always invoke verify callback (on success as well as failure) */ +#if defined(CONFIG_WOLFSSL_ALWAYS_VERIFY_CB) + #define WOLFSSL_ALWAYS_VERIFY_CB +#endif + /* DTLS */ #if defined(CONFIG_WOLFSSL_DTLS) #define WOLFSSL_DTLS From 2dc007678ddfad5a393d89ec6123723088c74608 Mon Sep 17 00:00:00 2001 From: Eric Blankenhorn Date: Mon, 20 Apr 2026 19:06:40 -0500 Subject: [PATCH 082/167] Fix latent test issue found with the PR --- wolfssl/test.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/wolfssl/test.h b/wolfssl/test.h index b03c81d69a..7f64b76cde 100644 --- a/wolfssl/test.h +++ b/wolfssl/test.h @@ -1669,6 +1669,12 @@ static WC_INLINE void tcp_listen(SOCKET_T* sockfd, word16* port, int useAnyAddr, if (res < 0) err_sys_with_errno("setsockopt SO_REUSEADDR failed\n"); } +/* glibc hides SO_REUSEPORT under strict C99 feature-test visibility + * (no _DEFAULT_SOURCE/__USE_MISC). Fall back to the Linux numeric value + * so concurrent binds on the same port remain supported. */ +#if defined(__linux__) && !defined(SO_REUSEPORT) + #define SO_REUSEPORT 15 +#endif #ifdef SO_REUSEPORT { int res, on = 1; From c3e5f196436a3c6d2b64b846d1fbffc8a574f0e4 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Tue, 21 Apr 2026 02:35:57 +0200 Subject: [PATCH 083/167] Address Copilot suggestions --- tests/api/test_ossl_x509_ext.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/api/test_ossl_x509_ext.c b/tests/api/test_ossl_x509_ext.c index 653c0d7e1f..dfc2451529 100644 --- a/tests/api/test_ossl_x509_ext.c +++ b/tests/api/test_ossl_x509_ext.c @@ -1020,6 +1020,7 @@ int test_wolfSSL_X509V3_EXT_nconf(void) ExpectNull(X509V3_EXT_nconf(NULL, NULL, ext_names[0], NULL)); ExpectNull(X509V3_EXT_nconf_nid(NULL, NULL, ext_nids[0], NULL)); ExpectNull(X509V3_EXT_nconf(NULL, NULL, "", ext_values[0])); + ExpectNull(X509V3_EXT_nconf(NULL, NULL, NULL, ext_values[0])); ExpectNull(X509V3_EXT_nconf_nid(NULL, NULL, 0, ext_values[0])); /* conf and ctx ignored. */ From 6f37b1775760b2a9f8172d34395d28fc2f7e1b8b Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Tue, 21 Apr 2026 02:56:36 +0200 Subject: [PATCH 084/167] Address Copilot suggestions --- src/internal.c | 12 ++++++------ tests/api.c | 5 +++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/internal.c b/src/internal.c index 25acacf882..b950af6198 100644 --- a/src/internal.c +++ b/src/internal.c @@ -8953,10 +8953,10 @@ void wolfSSL_ResourceFree(WOLFSSL* ssl) #if !defined(NO_TLS) TLSX_FreeAll(ssl->extensions, ssl->heap); ssl->extensions = NULL; - #if defined(HAVE_SECURE_RENEGOTIATION) \ - || defined(HAVE_SERVER_RENEGOTIATION_INFO) +#if defined(HAVE_SECURE_RENEGOTIATION) \ + || defined(HAVE_SERVER_RENEGOTIATION_INFO) ssl->secure_renegotiation = NULL; - #endif +#endif #endif /* !NO_TLS */ #ifdef HAVE_ALPN if (ssl->alpn_peer_requested != NULL) { @@ -9320,10 +9320,10 @@ void FreeHandshakeResources(WOLFSSL* ssl) /* Some extensions need to be kept for post-handshake querying. */ TLSX_FreeAll(ssl->extensions, ssl->heap); ssl->extensions = NULL; - #if defined(HAVE_SECURE_RENEGOTIATION) \ - || defined(HAVE_SERVER_RENEGOTIATION_INFO) +#if defined(HAVE_SECURE_RENEGOTIATION) \ + || defined(HAVE_SERVER_RENEGOTIATION_INFO) ssl->secure_renegotiation = NULL; - #endif +#endif #else #if !defined(NO_CERTS) && !defined(WOLFSSL_NO_SIGALG) TLSX_Remove(&ssl->extensions, TLSX_SIGNATURE_ALGORITHMS, ssl->heap); diff --git a/tests/api.c b/tests/api.c index e53ec70385..5618982669 100644 --- a/tests/api.c +++ b/tests/api.c @@ -10215,6 +10215,7 @@ static int test_wolfSSL_clear_secure_renegotiation(void) !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS) WOLFSSL_CTX *ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()); WOLFSSL *ssl = wolfSSL_new(ctx); + int support; ExpectNotNull(ctx); ExpectNotNull(ssl); @@ -10225,9 +10226,9 @@ static int test_wolfSSL_clear_secure_renegotiation(void) ssl->secure_renegotiation->enabled = 1; ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_clear(ssl)); + support = wolfSSL_SSL_get_secure_renegotiation_support(ssl); ExpectNull(ssl->secure_renegotiation); - ExpectIntEQ(WOLFSSL_FAILURE, - wolfSSL_SSL_get_secure_renegotiation_support(ssl)); + ExpectIntEQ(WOLFSSL_FAILURE, support); wolfSSL_free(ssl); wolfSSL_CTX_free(ctx); From 389d15fa459b805d5181baecbec7832665b6cece Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Tue, 21 Apr 2026 03:30:39 +0200 Subject: [PATCH 085/167] Fix compile error --- tests/api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/api.c b/tests/api.c index 5618982669..35ddd98371 100644 --- a/tests/api.c +++ b/tests/api.c @@ -10215,7 +10215,7 @@ static int test_wolfSSL_clear_secure_renegotiation(void) !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS) WOLFSSL_CTX *ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()); WOLFSSL *ssl = wolfSSL_new(ctx); - int support; + long support; ExpectNotNull(ctx); ExpectNotNull(ssl); From ddacd6b8226b3fe054587a15e3ba94ba4c2d1c1b Mon Sep 17 00:00:00 2001 From: Andrew Hutchings Date: Tue, 21 Apr 2026 06:31:42 +0100 Subject: [PATCH 086/167] Move SE050 simulator under wolfSSL The simulator is now in the simulators repo instead of LinuxJedi's private repo. --- .github/workflows/se050-sim.yml | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/.github/workflows/se050-sim.yml b/.github/workflows/se050-sim.yml index 08f94b93d9..9ce5a8c892 100644 --- a/.github/workflows/se050-sim.yml +++ b/.github/workflows/se050-sim.yml @@ -12,15 +12,16 @@ concurrency: cancel-in-progress: true # END OF COMMON SECTION -# Build the SE050 software simulator (https://github.com/LinuxJedi/SE050Sim), -# build wolfSSL against its NXP Plug&Trust SDK + simulator bridge, and run the -# wolfCrypt SE050 test binary against the simulator TCP server. +# Build the SE050 software simulator (https://github.com/wolfSSL/simulators, +# SE050Sim/ subdirectory), build wolfSSL against its NXP Plug&Trust SDK + +# simulator bridge, and run the wolfCrypt SE050 test binary against the +# simulator TCP server. # # The simulator's own Dockerfile (Dockerfile.wolfcrypt) clones wolfSSL master. # We patch it to COPY the PR checkout instead so CI reflects the PR's source. env: - SE050SIM_REF: 8fda9212c306fbee0dcd66f2dd52b13f65f13e00 + SIMULATORS_REF: 745893640e21a15b7df8c70567c522953aba2f2c jobs: se050_sim: @@ -36,14 +37,14 @@ jobs: - name: Clone SE050 simulator run: | - git clone https://github.com/LinuxJedi/SE050Sim se050sim - cd se050sim && git checkout "$SE050SIM_REF" + git clone https://github.com/wolfSSL/simulators simulators + cd simulators && git checkout "$SIMULATORS_REF" - name: Stage PR wolfSSL into simulator build context - run: mv wolfssl-src se050sim/wolfssl + run: mv wolfssl-src simulators/SE050Sim/wolfssl - name: Patch Dockerfile to use PR wolfSSL instead of upstream master - working-directory: se050sim + working-directory: simulators/SE050Sim run: | sed -i 's|^RUN git clone --depth 1 https://github.com/wolfSSL/wolfssl.git /app/wolfssl$|COPY wolfssl /app/wolfssl|' Dockerfile.wolfcrypt # Fail fast if the pattern drifted upstream -- better a clear error @@ -56,8 +57,8 @@ jobs: - name: Build wolfCrypt-SE050 test image uses: docker/build-push-action@v5 with: - context: se050sim - file: se050sim/Dockerfile.wolfcrypt + context: simulators/SE050Sim + file: simulators/SE050Sim/Dockerfile.wolfcrypt push: false load: true tags: wolfssl-se050-sim:ci From 0dbb6d28efc9db10670170ad5f75fa4fdb925ed0 Mon Sep 17 00:00:00 2001 From: S-P Chan Date: Tue, 21 Apr 2026 13:30:57 +0800 Subject: [PATCH 087/167] Update RPM spec for changes in examples and cmake - copy wolfssl/options to -devel package --- rpm/spec.in | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/rpm/spec.in b/rpm/spec.in index f45998e1fd..8f2b872135 100644 --- a/rpm/spec.in +++ b/rpm/spec.in @@ -51,6 +51,7 @@ fi %{__make} install DESTDIR="%{buildroot}" AM_INSTALL_PROGRAM_FLAGS="" %{__rm} -f %{buildroot}/%{_libdir}/libwolfssl@LIBSUFFIX@.la %{__rm} -f %{buildroot}/%{_libdir}/libwolfssl.a +%{__cp} wolfssl/options.h %{buildroot}/%{_includedir}/%{name}/ %check @@ -66,8 +67,6 @@ fi %defattr(-,root,root,-) %doc AUTHORS ChangeLog.md COPYING README README.md %{_docdir}/wolfssl/taoCert.txt -%{_docdir}/wolfssl/example/async_client.c -%{_docdir}/wolfssl/example/async_server.c %{_docdir}/wolfssl/example/client.c %{_docdir}/wolfssl/example/server.c %{_docdir}/wolfssl/example/echoclient.c @@ -77,6 +76,7 @@ fi %{_docdir}/wolfssl/example/sctp-client-dtls.c %{_docdir}/wolfssl/example/sctp-server-dtls.c %{_docdir}/wolfssl/example/tls_bench.c +%{_docdir}/wolfssl/example/ocsp_responder.c %{_docdir}/wolfssl/README.txt %{_docdir}/wolfssl/QUIC.md %{_libdir}/libwolfssl@LIBSUFFIX@.so.* @@ -90,6 +90,7 @@ fi %{_includedir}/wolfssl/openssl/*.h %{_libdir}/pkgconfig/wolfssl.pc %{_libdir}/libwolfssl@LIBSUFFIX@.so +%{_libdir}/cmake/wolfssl %changelog * Mon Oct 17 2022 Juliusz Sosinowicz From 6353ad36834047cd1982a44b5751f9d53b4b12e0 Mon Sep 17 00:00:00 2001 From: Roy Carter Date: Tue, 7 Apr 2026 17:35:19 +0300 Subject: [PATCH 088/167] Feat: support openssl compatibility layer functionality for libevent integration Cosmetic: remove empty whitespace --- doc/dox_comments/header_files/ssl.h | 47 +++++++++++++++++++++++++++++ src/bio.c | 6 ++++ tests/api/test_ossl_bio.c | 36 ++++++++++++++++++++++ tests/api/test_ossl_bio.h | 4 ++- wolfssl/openssl/bio.h | 1 + wolfssl/ssl.h | 1 + 6 files changed, 94 insertions(+), 1 deletion(-) diff --git a/doc/dox_comments/header_files/ssl.h b/doc/dox_comments/header_files/ssl.h index e33ef60f79..b92cfbeb8a 100644 --- a/doc/dox_comments/header_files/ssl.h +++ b/doc/dox_comments/header_files/ssl.h @@ -4496,6 +4496,53 @@ WOLFSSL_METHOD* wolfSSLv23_client_method(void); */ int wolfSSL_BIO_get_mem_data(WOLFSSL_BIO* bio,void* p); +/*! + \ingroup IO + + \brief This is used to set the init flag of a BIO, indicating whether + the BIO has been initialised and is ready for use. Typically called + from a custom BIO create callback. + + \param bio WOLFSSL_BIO structure to set the init flag on. + \param init value to set (0 = not initialised, 1 = initialised). + + _Example_ + \code + WOLFSSL_BIO* bio; + // inside a custom BIO create callback + wolfSSL_BIO_set_init(bio, 1); + \endcode + + \sa wolfSSL_BIO_get_init + \sa wolfSSL_BIO_new +*/ +void wolfSSL_BIO_set_init(WOLFSSL_BIO* bio, int init); + +/*! + \ingroup IO + + \brief This is used to retrieve the init flag of a BIO, indicating + whether the BIO has been initialised and is ready for use. + + \return 1 if the BIO has been initialised. + \return 0 if the BIO has not been initialised or bio is NULL. + + \param bio WOLFSSL_BIO structure to query. + + _Example_ + \code + WOLFSSL_BIO* bio; + // create bio with custom method + if (wolfSSL_BIO_get_init(bio)) { + // bio is ready + } + \endcode + + \sa wolfSSL_BIO_set_init + \sa wolfSSL_BIO_new +*/ +int wolfSSL_BIO_get_init(WOLFSSL_BIO* bio); + /*! \ingroup IO diff --git a/src/bio.c b/src/bio.c index 978b1b6247..85cb1ea8ed 100644 --- a/src/bio.c +++ b/src/bio.c @@ -2032,6 +2032,12 @@ void wolfSSL_BIO_set_init(WOLFSSL_BIO* bio, int init) bio->init = (byte)(init != 0); } +int wolfSSL_BIO_get_init(WOLFSSL_BIO* bio) +{ + WOLFSSL_ENTER("wolfSSL_BIO_get_init"); + return bio != NULL && bio->init; +} + /* If flag is 0 then blocking is set, if 1 then non blocking. * Always returns WOLFSSL_SUCCESS. */ diff --git a/tests/api/test_ossl_bio.c b/tests/api/test_ossl_bio.c index 732005b25c..c5612ff542 100644 --- a/tests/api/test_ossl_bio.c +++ b/tests/api/test_ossl_bio.c @@ -1803,5 +1803,41 @@ int test_wolfSSL_BIO_meth_type_large(void) return EXPECT_RESULT(); } +int test_wolfSSL_BIO_get_init(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) + BIO_METHOD* method = NULL; + BIO* bio = NULL; + + /* BIO_new with a custom method that calls BIO_set_init(bio, 1) */ + ExpectNotNull(method = BIO_meth_new(WOLFSSL_BIO_UNDEF, "get_init_test")); + ExpectIntEQ(BIO_meth_set_create(method, custom_bio_createCb), + WOLFSSL_SUCCESS); + ExpectIntEQ(BIO_meth_set_destroy(method, custom_bio_destroyCb), + WOLFSSL_SUCCESS); + + ExpectNotNull(bio = BIO_new(method)); + + /* createCb calls BIO_set_init(bio, 1), so get_init should return 1 */ + ExpectIntEQ(BIO_get_init(bio), 1); + + /* Clear init and verify it returns 0 */ + BIO_set_init(bio, 0); + ExpectIntEQ(BIO_get_init(bio), 0); + + /* Set init back and verify */ + BIO_set_init(bio, 1); + ExpectIntEQ(BIO_get_init(bio), 1); + + /* NULL should return 0 */ + ExpectIntEQ(BIO_get_init(NULL), 0); + + BIO_free(bio); + BIO_meth_free(method); +#endif + return EXPECT_RESULT(); +} + #endif /* !NO_BIO */ diff --git a/tests/api/test_ossl_bio.h b/tests/api/test_ossl_bio.h index 010c8bee63..d401193b14 100644 --- a/tests/api/test_ossl_bio.h +++ b/tests/api/test_ossl_bio.h @@ -46,6 +46,7 @@ int test_wolfSSL_BIO_custom_method(void); int test_wolfSSL_BIO_set_conn_hostname(void); int test_wolfSSL_BIO_ctrl_pending_chain(void); int test_wolfSSL_BIO_meth_type_large(void); +int test_wolfSSL_BIO_get_init(void); #define TEST_OSSL_BIO_DECLS \ TEST_DECL_GROUP("ossl_bio", test_wolfSSL_BIO_gets), \ @@ -64,7 +65,8 @@ int test_wolfSSL_BIO_meth_type_large(void); TEST_DECL_GROUP("ossl_bio", test_wolfSSL_BIO_custom_method), \ TEST_DECL_GROUP("ossl_bio", test_wolfSSL_BIO_set_conn_hostname), \ TEST_DECL_GROUP("ossl_bio", test_wolfSSL_BIO_ctrl_pending_chain), \ - TEST_DECL_GROUP("ossl_bio", test_wolfSSL_BIO_meth_type_large) + TEST_DECL_GROUP("ossl_bio", test_wolfSSL_BIO_meth_type_large), \ + TEST_DECL_GROUP("ossl_bio", test_wolfSSL_BIO_get_init) #define TEST_OSSL_BIO_TLS_DECLS \ TEST_DECL_GROUP("ossl_bio_tls", test_wolfSSL_BIO_connect), \ diff --git a/wolfssl/openssl/bio.h b/wolfssl/openssl/bio.h index 1d84c96a5b..f797d94ab5 100644 --- a/wolfssl/openssl/bio.h +++ b/wolfssl/openssl/bio.h @@ -159,6 +159,7 @@ /* BIO for 1.1.0 or later */ #define BIO_set_init wolfSSL_BIO_set_init +#define BIO_get_init wolfSSL_BIO_get_init #define BIO_get_data wolfSSL_BIO_get_data #define BIO_set_data wolfSSL_BIO_set_data #define BIO_get_shutdown wolfSSL_BIO_get_shutdown diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 236515157b..4755cbfb87 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -2120,6 +2120,7 @@ WOLFSSL_API long wolfSSL_BIO_set_nbio(WOLFSSL_BIO* bio, long on); WOLFSSL_API int wolfSSL_BIO_get_mem_data(WOLFSSL_BIO* bio,void* p); WOLFSSL_API void wolfSSL_BIO_set_init(WOLFSSL_BIO* bio, int init); +WOLFSSL_API int wolfSSL_BIO_get_init(WOLFSSL_BIO* bio); WOLFSSL_API void wolfSSL_BIO_set_data(WOLFSSL_BIO* bio, void* ptr); WOLFSSL_API void* wolfSSL_BIO_get_data(WOLFSSL_BIO* bio); WOLFSSL_API void wolfSSL_BIO_set_shutdown(WOLFSSL_BIO* bio, int shut); From d5957e6247e65d16baca0f02182f8e64f1e944b7 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Wed, 22 Apr 2026 00:19:59 -0400 Subject: [PATCH 089/167] Rust wrapper: tweak wc_RsaFlattenPublicKey error message in RSA SigningKey::verifying_key() --- wrapper/rust/wolfssl-wolfcrypt/src/rsa_pkcs1v15.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/rsa_pkcs1v15.rs b/wrapper/rust/wolfssl-wolfcrypt/src/rsa_pkcs1v15.rs index c20d2a3e26..cd0079beda 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/rsa_pkcs1v15.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/rsa_pkcs1v15.rs @@ -337,7 +337,7 @@ impl Keypair for SigningKey { panic!("wc_RsaFlattenPublicKey failed: {rc}"); } if (n_len as usize) != N || e_len == 0 || (e_len as usize) > MAX_E_LEN { - panic!("wc_RsaFlattenPublicKey failed: e_len: {e_len}, n_len: {n_len}"); + panic!("wc_RsaFlattenPublicKey returned unexpected lengths: e_len: {e_len}, n_len: {n_len}"); } VerifyingKey { n, From 9c506896c67f68fa8a30bb7e55a2a2c0f467ba5e Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Wed, 22 Apr 2026 00:23:02 -0400 Subject: [PATCH 090/167] Rust wrapper: add doc comment for MAX_E_LEN --- wrapper/rust/wolfssl-wolfcrypt/src/rsa_pkcs1v15.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/rsa_pkcs1v15.rs b/wrapper/rust/wolfssl-wolfcrypt/src/rsa_pkcs1v15.rs index cd0079beda..40314f9548 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/rsa_pkcs1v15.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/rsa_pkcs1v15.rs @@ -196,6 +196,8 @@ impl SignerMut> for SigningKey { } } +/// Maximum number of bytes that the E exponent can use. An error is returned +/// if longer exponent byte arrays are provided. const MAX_E_LEN: usize = 8; /// RSA PKCS#1 v1.5 verifying key. From e05ce26fc990bfe43c603b44011d12be8176912d Mon Sep 17 00:00:00 2001 From: David Garske Date: Tue, 24 Mar 2026 13:47:26 -0700 Subject: [PATCH 091/167] wolfCrypt SRAM PUF Support Add SRAM PUF (Physically Unclonable Function) support to wolfCrypt. Derives device-unique cryptographic keys from the power-on state of SRAM memory using a BCH(127,64,t=10) fuzzy extractor with HKDF key derivation. - **wolfCrypt PUF API** (`wolfcrypt/src/puf.c`, `wolfssl/wolfcrypt/puf.h`) - `wc_PufInit`, `wc_PufReadSram`, `wc_PufEnroll`, `wc_PufReconstruct` - `wc_PufDeriveKey` (HKDF-SHA256), `wc_PufGetIdentity` (SHA-256 device fingerprint) - `wc_PufZeroize` (secure context cleanup) - `wc_PufSetTestData` (synthetic SRAM for testing without hardware) - **BCH(127,64,t=10) error-correcting codec** - corrects up to 10 bit flips per 127-bit codeword across 16 codewords - **`WC_PUF_SHA3` build option** - select SHA3-256 instead of SHA-256 for identity hash and HKDF (default: SHA-256) - **Precomputed GF(2^7) tables** - `const` arrays in `.rodata` (no runtime init, thread-safe, flash-resident on embedded) - `./configure --enable-puf` (auto-enables HKDF dependency) - CMake: `WOLFSSL_PUF=yes` - `WOLFSSL_USER_SETTINGS`: define `WOLFSSL_PUF` and `WOLFSSL_PUF_SRAM` - See wolfssl-examples/puf for example implementation on STM32 NUCLEO-H563ZI (Cortex-M33, STM32H563ZI) - Supports test mode (synthetic SRAM) - Builds to ~13KB `.elf` - Tested on NUCLEO-H563ZI: enrollment, noisy reconstruction, key derivation all pass - `.github/workflows/puf.yml`: host build + test workflow for PUF feature - Doxygen API docs for all 8 public functions - PUF group added to `doxygen_groups.h` --- .github/workflows/puf.yml | 37 + .wolfssl_known_macro_extras | 1 + CMakeLists.txt | 22 + README.md | 4 + cmake/functions.cmake | 7 + configure.ac | 28 + .../header_files/doxygen_groups.h | 1 + doc/dox_comments/header_files/puf.h | 212 ++++++ src/include.am | 4 + wolfcrypt/src/error.c | 18 + wolfcrypt/src/puf.c | 698 ++++++++++++++++++ wolfcrypt/test/test.c | 235 ++++++ wolfssl/wolfcrypt/error-crypt.h | 12 +- wolfssl/wolfcrypt/include.am | 1 + wolfssl/wolfcrypt/puf.h | 116 +++ 15 files changed, 1394 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/puf.yml create mode 100644 doc/dox_comments/header_files/puf.h create mode 100644 wolfcrypt/src/puf.c create mode 100644 wolfssl/wolfcrypt/puf.h diff --git a/.github/workflows/puf.yml b/.github/workflows/puf.yml new file mode 100644 index 0000000000..8ad4827a1d --- /dev/null +++ b/.github/workflows/puf.yml @@ -0,0 +1,37 @@ +name: PUF Tests + +# START OF COMMON SECTION +on: + push: + branches: [ 'master', 'main', 'release/**' ] + pull_request: + branches: [ '*' ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +# END OF COMMON SECTION + +jobs: + puf_host_test: + name: PUF host test + if: github.repository_owner == 'wolfssl' + runs-on: ubuntu-24.04 + timeout-minutes: 6 + steps: + - uses: actions/checkout@v4 + name: Checkout wolfSSL + + - name: Build and test PUF + run: | + ./autogen.sh + ./configure --enable-puf --enable-puf-test + make + ./wolfcrypt/test/testwolfcrypt + + - name: Print errors + if: ${{ failure() }} + run: | + if [ -f test-suite.log ] ; then + cat test-suite.log + fi diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 3943d47739..657ba1ab5e 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -652,6 +652,7 @@ WC_NO_VERBOSE_RNG WC_PKCS11_FIND_WITH_ID_ONLY WC_PKCS12_PBKDF_USING_MP_API WC_PROTECT_ENCRYPTED_MEM +WC_PUF_SHA3 WC_RNG_BANK_NO_DEFAULT_SUPPORT WC_RNG_BLOCKING WC_RSA_NONBLOCK diff --git a/CMakeLists.txt b/CMakeLists.txt index 663c3cf2cc..317aa9c8e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1772,6 +1772,28 @@ endif() # TODO: - XCHACHA +# SRAM PUF +add_option("WOLFSSL_PUF" + "Enable SRAM PUF support (default: disabled)" + "no" "yes;no") + +if(WOLFSSL_PUF) + list(APPEND WOLFSSL_DEFINITIONS + "-DWOLFSSL_PUF" + "-DWOLFSSL_PUF_SRAM" + "-DHAVE_HKDF") + override_cache(WOLFSSL_HKDF "yes") +endif() + +# PUF test mode (synthetic SRAM data injection) +add_option("WOLFSSL_PUF_TEST" + "Enable PUF test mode with synthetic data (default: disabled)" + "no" "yes;no") + +if(WOLFSSL_PUF_TEST) + list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_PUF_TEST") +endif() + # Hash DRBG add_option("WOLFSSL_HASH_DRBG" "Enable Hash DRBG support (default: enabled)" diff --git a/README.md b/README.md index 4c800d85a4..ae1f22a08c 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,10 @@ certificate #3389). FIPS 140-3 validated (Certificate #4718). For additional information, visit the [wolfCrypt FIPS FAQ](https://www.wolfssl.com/license/fips/) or contact fips@wolfssl.com. +wolfCrypt also includes support for deriving device-unique keys from hardware entropy +(`--enable-puf`). An example exists at +[SRAM PUF](https://github.com/wolfSSL/wolfssl-examples/tree/master/puf). + ## Why Choose wolfSSL? There are many reasons to choose wolfSSL as your embedded, desktop, mobile, or diff --git a/cmake/functions.cmake b/cmake/functions.cmake index 1a5442ddfd..84e2d1039b 100644 --- a/cmake/functions.cmake +++ b/cmake/functions.cmake @@ -348,6 +348,9 @@ function(generate_build_flags) if(WOLFSSL_SHE AND NOT WOLFSSL_SHE STREQUAL "no") set(BUILD_SHE "yes" PARENT_SCOPE) endif() + if(WOLFSSL_PUF OR WOLFSSL_USER_SETTINGS) + set(BUILD_PUF "yes" PARENT_SCOPE) + endif() set(BUILD_FLAGS_GENERATED "yes" PARENT_SCOPE) endfunction() @@ -1209,6 +1212,10 @@ function(generate_lib_src_list LIB_SOURCES) list(APPEND LIB_SOURCES wolfcrypt/src/hpke.c) endif() + if(BUILD_PUF) + list(APPEND LIB_SOURCES wolfcrypt/src/puf.c) + endif() + set(LIB_SOURCES ${LIB_SOURCES} PARENT_SCOPE) endfunction() diff --git a/configure.ac b/configure.ac index 69f8501f04..09a763d542 100644 --- a/configure.ac +++ b/configure.ac @@ -7222,6 +7222,32 @@ then AM_CFLAGS="$AM_CFLAGS -DHAVE_ASCON" fi +# PUF +AC_ARG_ENABLE([puf], + [AS_HELP_STRING([--enable-puf],[Enable SRAM PUF support (default: disabled)])], + [ ENABLED_PUF=$enableval ], + [ ENABLED_PUF=no ] + ) + +if test "$ENABLED_PUF" = "yes" +then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_PUF -DWOLFSSL_PUF_SRAM" + AS_IF([test "$ENABLED_HKDF" != "yes"], + [ENABLED_HKDF="yes"; AM_CFLAGS="$AM_CFLAGS -DHAVE_HKDF"]) +fi + +# PUF test mode +AC_ARG_ENABLE([puf-test], + [AS_HELP_STRING([--enable-puf-test],[Enable PUF test mode with synthetic data (default: disabled)])], + [ ENABLED_PUF_TEST=$enableval ], + [ ENABLED_PUF_TEST=no ] + ) + +if test "$ENABLED_PUF_TEST" = "yes" +then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_PUF_TEST" +fi + # Hash DRBG AC_ARG_ENABLE([hashdrbg], [AS_HELP_STRING([--enable-hashdrbg],[Enable Hash DRBG support (default: enabled)])], @@ -11610,6 +11636,7 @@ AM_CONDITIONAL([BUILD_CHACHA],[test "x$ENABLED_CHACHA" = "xyes" || test "x$ENABL AM_CONDITIONAL([BUILD_CHACHA_NOASM],[test "$ENABLED_CHACHA" = "noasm"]) AM_CONDITIONAL([BUILD_XCHACHA],[test "x$ENABLED_XCHACHA" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_ASCON],[test "x$ENABLED_ASCON" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) +AM_CONDITIONAL([BUILD_PUF],[test "x$ENABLED_PUF" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_SM2],[test "x$ENABLED_SM2" != "xno" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_SM3],[test "x$ENABLED_SM3" != "xno" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_SM4],[test "x$ENABLED_SM4" != "xno" || test "x$ENABLED_USERSETTINGS" = "xyes"]) @@ -12276,6 +12303,7 @@ echo " * AutoSAR : $ENABLED_AUTOSAR" echo " * ML-KEM standalone: $ENABLED_MLKEM_STANDALONE" echo " * PQ/T hybrids: $ENABLED_PQC_HYBRIDS" echo " * Extra PQ/T hybrids: $ENABLED_EXTRA_PQC_HYBRIDS" +echo " * PUF: $ENABLED_PUF" echo "" echo "---" diff --git a/doc/dox_comments/header_files/doxygen_groups.h b/doc/dox_comments/header_files/doxygen_groups.h index 5cda0f2229..c9469fe186 100644 --- a/doc/dox_comments/header_files/doxygen_groups.h +++ b/doc/dox_comments/header_files/doxygen_groups.h @@ -202,6 +202,7 @@ \defgroup PKCS11 Algorithms - PKCS11 \defgroup Password Algorithms - Password Based \defgroup Poly1305 Algorithms - Poly1305 + \defgroup PUF Algorithms - PUF \defgroup RIPEMD Algorithms - RIPEMD \defgroup RSA Algorithms - RSA \defgroup SHA Algorithms - SHA 128/224/256/384/512 diff --git a/doc/dox_comments/header_files/puf.h b/doc/dox_comments/header_files/puf.h new file mode 100644 index 0000000000..73e5a2340b --- /dev/null +++ b/doc/dox_comments/header_files/puf.h @@ -0,0 +1,212 @@ +/*! + \ingroup PUF + + For a complete bare-metal example (tested on NUCLEO-H563ZI), see + https://github.com/wolfSSL/wolfssl-examples/tree/master/puf +*/ + +/*! + \ingroup PUF + + \brief Initialize a wc_PufCtx structure, zeroing all fields. + Must be called before any other PUF operations. + + \return 0 on success + \return BAD_FUNC_ARG if ctx is NULL + + \param ctx pointer to wc_PufCtx structure to initialize + + _Example_ + \code + wc_PufCtx ctx; + ret = wc_PufInit(&ctx); + \endcode + + \sa wc_PufReadSram + \sa wc_PufEnroll + \sa wc_PufZeroize +*/ +int wc_PufInit(wc_PufCtx* ctx); + +/*! + \ingroup PUF + + \brief Read raw SRAM data into the PUF context. The sramAddr should + point to a NOLOAD linker section to preserve the power-on state. + + \return 0 on success + \return BAD_FUNC_ARG if ctx or sramAddr is NULL + \return PUF_READ_E if sramSz < WC_PUF_RAW_BYTES + + \param ctx pointer to wc_PufCtx structure + \param sramAddr pointer to raw SRAM memory region + \param sramSz size of SRAM buffer (must be >= WC_PUF_RAW_BYTES) + + _Example_ + \code + __attribute__((section(".puf_sram"))) + static volatile uint8_t puf_sram[256]; + wc_PufReadSram(&ctx, (const byte*)puf_sram, sizeof(puf_sram)); + \endcode + + \sa wc_PufInit + \sa wc_PufEnroll + \sa wc_PufReconstruct +*/ +int wc_PufReadSram(wc_PufCtx* ctx, const byte* sramAddr, word32 sramSz); + +/*! + \ingroup PUF + + \brief Perform PUF enrollment. Encodes raw SRAM using BCH(127,64,t=10) + and generates public helper data. After enrollment the context is ready + for key derivation and identity retrieval. + + \return 0 on success + \return BAD_FUNC_ARG if ctx is NULL + \return PUF_ENROLL_E if enrollment fails + + \param ctx pointer to wc_PufCtx (must have SRAM data loaded) + + _Example_ + \code + wc_PufEnroll(&ctx); + XMEMCPY(helperData, ctx.helperData, WC_PUF_HELPER_BYTES); + \endcode + + \sa wc_PufReadSram + \sa wc_PufReconstruct + \sa wc_PufDeriveKey +*/ +int wc_PufEnroll(wc_PufCtx* ctx); + +/*! + \ingroup PUF + + \brief Reconstruct stable PUF bits from noisy SRAM using stored helper + data. BCH error correction (t=10) corrects up to 10 bit flips per + 127-bit codeword. + + \return 0 on success + \return BAD_FUNC_ARG if ctx or helperData is NULL + \return PUF_RECONSTRUCT_E on failure (too many bit errors or helperSz + too small) + + \param ctx pointer to wc_PufCtx (must have SRAM data loaded) + \param helperData pointer to helper data from previous enrollment + \param helperSz size of helper data (>= WC_PUF_HELPER_BYTES) + + _Example_ + \code + wc_PufReconstruct(&ctx, helperData, sizeof(helperData)); + \endcode + + \sa wc_PufEnroll + \sa wc_PufDeriveKey + \sa wc_PufGetIdentity +*/ +int wc_PufReconstruct(wc_PufCtx* ctx, const byte* helperData, word32 helperSz); + +/*! + \ingroup PUF + + \brief Derive a cryptographic key from PUF stable bits using HKDF. + Uses SHA-256 by default, or SHA3-256 when WC_PUF_SHA3 is defined. + The info parameter provides domain separation for multiple keys. + Requires HAVE_HKDF. + + \return 0 on success + \return BAD_FUNC_ARG if ctx or key is NULL, or keySz is 0 + \return PUF_DERIVE_KEY_E if PUF not ready or HKDF fails + + \param ctx pointer to wc_PufCtx (must be enrolled or reconstructed) + \param info optional context info for domain separation (may be NULL; + when NULL, infoSz is treated as 0) + \param infoSz size of info in bytes + \param key output buffer for derived key + \param keySz desired key size in bytes + + _Example_ + \code + byte key[32]; + const byte info[] = "my-app-key"; + wc_PufDeriveKey(&ctx, info, sizeof(info), key, sizeof(key)); + \endcode + + \sa wc_PufEnroll + \sa wc_PufReconstruct + \sa wc_PufGetIdentity +*/ +int wc_PufDeriveKey(wc_PufCtx* ctx, const byte* info, word32 infoSz, + byte* key, word32 keySz); + +/*! + \ingroup PUF + + \brief Retrieve the device identity hash (SHA-256 or SHA3-256 of stable + bits). Deterministic for a given device. + + \return 0 on success + \return BAD_FUNC_ARG if ctx or id is NULL + \return PUF_IDENTITY_E if PUF not ready or idSz < WC_PUF_ID_SZ + + \param ctx pointer to wc_PufCtx (must be enrolled or reconstructed) + \param id output buffer for identity hash + \param idSz size of id buffer (>= WC_PUF_ID_SZ, 32 bytes) + + _Example_ + \code + byte identity[WC_PUF_ID_SZ]; + wc_PufGetIdentity(&ctx, identity, sizeof(identity)); + \endcode + + \sa wc_PufEnroll + \sa wc_PufReconstruct + \sa wc_PufDeriveKey +*/ +int wc_PufGetIdentity(wc_PufCtx* ctx, byte* id, word32 idSz); + +/*! + \ingroup PUF + + \brief Securely zeroize all sensitive data in the PUF context using + ForceZero. Call when PUF is no longer needed. + + \return 0 on success + \return BAD_FUNC_ARG if ctx is NULL + + \param ctx pointer to wc_PufCtx to zeroize + + _Example_ + \code + wc_PufZeroize(&ctx); + \endcode + + \sa wc_PufInit +*/ +int wc_PufZeroize(wc_PufCtx* ctx); + +/*! + \ingroup PUF + + \brief Inject synthetic SRAM test data for testing without hardware. + Only available when WOLFSSL_PUF_TEST is defined. + + \return 0 on success + \return BAD_FUNC_ARG if ctx or data is NULL + \return PUF_READ_E if sz < WC_PUF_RAW_BYTES + + \param ctx pointer to wc_PufCtx + \param data pointer to synthetic SRAM data + \param sz size of data (>= WC_PUF_RAW_BYTES, 256 bytes) + + _Example_ + \code + byte testSram[WC_PUF_RAW_BYTES]; + wc_PufSetTestData(&ctx, testSram, sizeof(testSram)); + \endcode + + \sa wc_PufInit + \sa wc_PufReadSram +*/ +int wc_PufSetTestData(wc_PufCtx* ctx, const byte* data, word32 sz); diff --git a/src/include.am b/src/include.am index c4f6b8a673..09610bcfdf 100644 --- a/src/include.am +++ b/src/include.am @@ -1372,6 +1372,10 @@ if BUILD_ASCON src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/ascon.c endif +if BUILD_PUF +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/puf.c +endif + if !BUILD_INLINE src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/misc.c endif diff --git a/wolfcrypt/src/error.c b/wolfcrypt/src/error.c index 4e02795e89..f676c23bad 100644 --- a/wolfcrypt/src/error.c +++ b/wolfcrypt/src/error.c @@ -671,6 +671,24 @@ const char* wc_GetErrorString(int error) case SEQ_OVERFLOW_E: return "Sequence counter would overflow"; + case PUF_INIT_E: + return "PUF initialization failed"; + + case PUF_READ_E: + return "PUF SRAM read failed"; + + case PUF_ENROLL_E: + return "PUF enrollment failed"; + + case PUF_RECONSTRUCT_E: + return "PUF reconstruction failed"; + + case PUF_DERIVE_KEY_E: + return "PUF key derivation failed"; + + case PUF_IDENTITY_E: + return "PUF identity retrieval failed"; + case MAX_CODE_E: case WC_SPAN1_MIN_CODE_E: case MIN_CODE_E: diff --git a/wolfcrypt/src/puf.c b/wolfcrypt/src/puf.c new file mode 100644 index 0000000000..74c5992548 --- /dev/null +++ b/wolfcrypt/src/puf.c @@ -0,0 +1,698 @@ +/* puf.c + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + + +#include + +#ifdef WOLFSSL_PUF + +/* Currently only SRAM PUF is implemented. Other PUF types (ring-oscillator, + * arbiter) may be added in the future with their own guard macros. */ +#if !defined(WOLFSSL_PUF_SRAM) + #define WOLFSSL_PUF_SRAM +#endif + +/* PUF is not a FIPS-validated algorithm. The combination WOLFSSL_PUF + + * HAVE_FIPS is rejected at compile time by puf.h, so no per-translation-unit + * gate is needed here. */ + +#include +#include +#include + +#ifdef HAVE_HKDF + #include +#endif + +/* Hash algorithm selection: SHA3-256 or SHA-256 (default) */ +#ifdef WC_PUF_SHA3 + #if !defined(WOLFSSL_SHA3) + #error "WC_PUF_SHA3 requires WOLFSSL_SHA3 to be enabled" + #endif + #include + #define WC_PUF_HASH_TYPE WC_SHA3_256 + #define wc_PufHashDirect wc_Sha3_256Hash +#else + #ifdef NO_SHA256 + #error "WOLFSSL_PUF requires SHA-256 or WC_PUF_SHA3" + #endif + #define WC_PUF_HASH_TYPE WC_SHA256 + #define wc_PufHashDirect wc_Sha256Hash +#endif + +#ifdef NO_INLINE + #include +#else + #define WOLFSSL_MISC_INCLUDED + #include +#endif + +/* ========================================================================== */ +/* BCH(127,64,t=10) codec over GF(2^7) */ +/* ========================================================================== */ + +/* GF(2^7) arithmetic with primitive polynomial p(x) = x^7 + x^3 + 1 (0x89) */ +#define GF_M 7 +#define GF_SIZE (1 << GF_M) /* 128 */ +#define GF_MASK (GF_SIZE - 1) /* 127 */ + +/* Precomputed GF(2^7) exp table: gf_exp[i] = alpha^i for i=0..127 + * Generated with primitive polynomial 0x89 (x^7 + x^3 + 1). + * gf_exp[127] wraps to gf_exp[0] = 1. */ +static const byte gf_exp[GF_SIZE] = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x09, + 0x12, 0x24, 0x48, 0x19, 0x32, 0x64, 0x41, 0x0B, + 0x16, 0x2C, 0x58, 0x39, 0x72, 0x6D, 0x53, 0x2F, + 0x5E, 0x35, 0x6A, 0x5D, 0x33, 0x66, 0x45, 0x03, + 0x06, 0x0C, 0x18, 0x30, 0x60, 0x49, 0x1B, 0x36, + 0x6C, 0x51, 0x2B, 0x56, 0x25, 0x4A, 0x1D, 0x3A, + 0x74, 0x61, 0x4B, 0x1F, 0x3E, 0x7C, 0x71, 0x6B, + 0x5F, 0x37, 0x6E, 0x55, 0x23, 0x46, 0x05, 0x0A, + 0x14, 0x28, 0x50, 0x29, 0x52, 0x2D, 0x5A, 0x3D, + 0x7A, 0x7D, 0x73, 0x6F, 0x57, 0x27, 0x4E, 0x15, + 0x2A, 0x54, 0x21, 0x42, 0x0D, 0x1A, 0x34, 0x68, + 0x59, 0x3B, 0x76, 0x65, 0x43, 0x0F, 0x1E, 0x3C, + 0x78, 0x79, 0x7B, 0x7F, 0x77, 0x67, 0x47, 0x07, + 0x0E, 0x1C, 0x38, 0x70, 0x69, 0x5B, 0x3F, 0x7E, + 0x75, 0x63, 0x4F, 0x17, 0x2E, 0x5C, 0x31, 0x62, + 0x4D, 0x13, 0x26, 0x4C, 0x11, 0x22, 0x44, 0x01 +}; + +/* Precomputed GF(2^7) log table: gf_log[x] = log_alpha(x) for x=0..127 + * gf_log[0] is undefined (set to 0 for safety). */ +static const byte gf_log[GF_SIZE] = { + 0x00, 0x00, 0x01, 0x1F, 0x02, 0x3E, 0x20, 0x67, + 0x03, 0x07, 0x3F, 0x0F, 0x21, 0x54, 0x68, 0x5D, + 0x04, 0x7C, 0x08, 0x79, 0x40, 0x4F, 0x10, 0x73, + 0x22, 0x0B, 0x55, 0x26, 0x69, 0x2E, 0x5E, 0x33, + 0x05, 0x52, 0x7D, 0x3C, 0x09, 0x2C, 0x7A, 0x4D, + 0x41, 0x43, 0x50, 0x2A, 0x11, 0x45, 0x74, 0x17, + 0x23, 0x76, 0x0C, 0x1C, 0x56, 0x19, 0x27, 0x39, + 0x6A, 0x13, 0x2F, 0x59, 0x5F, 0x47, 0x34, 0x6E, + 0x06, 0x0E, 0x53, 0x5C, 0x7E, 0x1E, 0x3D, 0x66, + 0x0A, 0x25, 0x2D, 0x32, 0x7B, 0x78, 0x4E, 0x72, + 0x42, 0x29, 0x44, 0x16, 0x51, 0x3B, 0x2B, 0x4C, + 0x12, 0x58, 0x46, 0x6D, 0x75, 0x1B, 0x18, 0x38, + 0x24, 0x31, 0x77, 0x71, 0x0D, 0x5B, 0x1D, 0x65, + 0x57, 0x6C, 0x1A, 0x37, 0x28, 0x15, 0x3A, 0x4B, + 0x6B, 0x36, 0x14, 0x4A, 0x30, 0x70, 0x5A, 0x64, + 0x60, 0x61, 0x48, 0x62, 0x35, 0x49, 0x6F, 0x63 +}; + +/* GF multiplication */ +static WC_INLINE byte gf_mul(byte a, byte b) +{ + if (a == 0 || b == 0) + return 0; + return gf_exp[(gf_log[a] + gf_log[b]) % GF_MASK]; +} + +/* GF inverse */ +static WC_INLINE byte gf_inv(byte a) +{ + if (a == 0) + return 0; + return gf_exp[GF_MASK - gf_log[a]]; +} + +/* ---- BCH syndrome computation ---- */ + +/* Evaluate syndrome: S_root = c(alpha^root) where codeword bits are packed + * MSB-first. Bit at position j in the byte array corresponds to the + * coefficient of x^(N-1-j) in the codeword polynomial, so we evaluate + * using alpha^(root*(N-1-j)) to correctly compute c(alpha^root). */ +static byte bch_syndrome_eval(const byte* codeword, int root) +{ + byte s = 0; + int j; + + for (j = 0; j < WC_PUF_BCH_N; j++) { + int byteIdx = j / 8; + int bitIdx = 7 - (j % 8); + + if (codeword[byteIdx] & (1 << bitIdx)) { + /* coefficient of x^(N-1-j), evaluated at alpha^root */ + s ^= gf_exp[(root * (WC_PUF_BCH_N - 1 - j)) % GF_MASK]; + } + } + return s; +} + +/* Compute 2t syndromes S[1..2t] */ +static void bch_syndromes(const byte* codeword, byte* syndromes) +{ + int i; + for (i = 1; i <= 2 * WC_PUF_BCH_T; i++) { + syndromes[i] = bch_syndrome_eval(codeword, i); + } +} + +/* ---- Berlekamp-Massey algorithm ---- */ + +/* Find error locator polynomial sigma(x) from syndromes. + * sigma[] has degree <= t, coefficients in GF(2^7). + * Returns degree of sigma, or -1 on failure. */ +static int bch_berlekamp_massey(const byte* syndromes, byte* sigma) +{ + byte C[WC_PUF_BCH_T + 1]; /* current polynomial */ + byte B[WC_PUF_BCH_T + 1]; /* previous polynomial */ + byte T[WC_PUF_BCH_T + 1]; /* temp */ + int L = 0; /* current length */ + int m = 1; /* shift counter */ + byte b = 1; /* previous discrepancy */ + int n, i, degC; + + XMEMSET(C, 0, sizeof(C)); + XMEMSET(B, 0, sizeof(B)); + C[0] = 1; + B[0] = 1; + + for (n = 0; n < 2 * WC_PUF_BCH_T; n++) { + /* compute discrepancy d */ + byte d = syndromes[n + 1]; + for (i = 1; i <= L; i++) { + d ^= gf_mul(C[i], syndromes[n + 1 - i]); + } + + if (d == 0) { + m++; + } + else if (2 * L <= n) { + /* update: T(x) = C(x), C(x) -= (d/b)*x^m * B(x), B=T, L=n+1-L */ + byte coeff = gf_mul(d, gf_inv(b)); + XMEMCPY(T, C, sizeof(T)); + for (i = m; i <= WC_PUF_BCH_T; i++) { + C[i] ^= gf_mul(coeff, B[i - m]); + } + XMEMCPY(B, T, sizeof(B)); + L = n + 1 - L; + b = d; + m = 1; + } + else { + /* C(x) -= (d/b)*x^m * B(x) */ + byte coeff = gf_mul(d, gf_inv(b)); + for (i = m; i <= WC_PUF_BCH_T; i++) { + C[i] ^= gf_mul(coeff, B[i - m]); + } + m++; + } + } + + XMEMCPY(sigma, C, (WC_PUF_BCH_T + 1)); + + /* find degree */ + degC = 0; + for (i = WC_PUF_BCH_T; i >= 0; i--) { + if (sigma[i] != 0) { + degC = i; + break; + } + } + + if (degC > WC_PUF_BCH_T) + return -1; + + return degC; +} + +/* ---- Chien search: find error locations ---- */ + +/* Evaluate sigma at alpha^(-j) for j=0..126. Returns number of roots found. + * Error positions stored in errPos[] as byte-scan positions (MSB-first). + * Chien search root j maps to bit position (N-1-j) to match the MSB-first + * codeword layout used by the syndrome computation. */ +static int bch_chien_search(const byte* sigma, int deg, int* errPos) +{ + int count = 0; + int j; + + for (j = 0; j < WC_PUF_BCH_N; j++) { + byte val = 0; + int i; + for (i = 0; i <= deg; i++) { + if (sigma[i] != 0) { + /* sigma[i] * alpha^(-i*j) */ + int exp_val = (GF_MASK - ((i * j) % GF_MASK)) % GF_MASK; + val ^= gf_mul(sigma[i], gf_exp[exp_val]); + } + } + if (val == 0) { + if (count >= WC_PUF_BCH_T) + return -1; /* too many roots, protect errPos[] bounds */ + errPos[count] = WC_PUF_BCH_N - 1 - j; + count++; + } + } + + return count; +} + +/* ---- BCH encode: compute parity for 64-bit message ---- */ + +/* Generator polynomial for BCH(127,64,t=10) over GF(2). + * This is the product of minimal polynomials of alpha^1..alpha^(2t). + * Degree = n - k = 63. Stored as 64-bit value (coefficients mod 2). + * g(x) = GCD of min polys of consecutive roots. Precomputed. */ + +/* We store g(x) as 8 bytes, MSB first, degree-63 coefficient in bit 63. + * The leading coefficient (x^63) is implicit. */ +static const byte bch_genpoly[8] = { + 0x21, 0xAB, 0x81, 0x5B, 0xC7, 0xEC, 0x80, 0x25 +}; + +/* Encode 64-bit message into 127-bit codeword. + * msg: 8 bytes (64 bits), output: 16 bytes (127 bits, MSB aligned). + * Systematic encoding: codeword = [msg(64) | parity(63)]. */ +static void bch_encode(const byte* msg, byte* codeword) +{ + byte shift_reg[8]; /* 63-bit shift register for parity */ + int i, j; + + XMEMSET(shift_reg, 0, sizeof(shift_reg)); + + /* Process each of the 64 message bits */ + for (i = 0; i < WC_PUF_BCH_K; i++) { + int byteIdx = i / 8; + int bitIdx = 7 - (i % 8); + byte msgBit = (msg[byteIdx] >> bitIdx) & 1; + + /* feedback = msgBit XOR MSB of shift register */ + byte fb = msgBit ^ ((shift_reg[0] >> 6) & 1); + + /* shift register left by 1 */ + for (j = 0; j < 7; j++) { + shift_reg[j] = (byte)((shift_reg[j] << 1) | + (shift_reg[j + 1] >> 7)); + } + shift_reg[7] = (byte)(shift_reg[7] << 1); + /* keep the register at exactly 63 bits - bit 7 of byte 0 is unused */ + shift_reg[0] &= 0x7F; + + /* XOR with generator if feedback is 1 */ + if (fb) { + for (j = 0; j < 8; j++) { + shift_reg[j] ^= bch_genpoly[j]; + } + /* generator polynomial bit 7 is 0; mask defensively in case it + * ever changes so the unused slot can never affect parity */ + shift_reg[0] &= 0x7F; + } + } + + /* Build codeword: [msg(64 bits) | parity(63 bits)] = 127 bits */ + XMEMSET(codeword, 0, 16); + XMEMCPY(codeword, msg, 8); /* message in first 64 bits */ + + /* parity: bits 64..126 from shift_reg bits 0..62 */ + /* shift_reg holds 63 bits in bits [6..0] of byte 0, then bytes 1..7 */ + /* We need to place these starting at bit position 64 in codeword */ + for (i = 0; i < 63; i++) { + int srcByte; + int srcBit; + + /* shift_reg MSB is bit 6 of byte 0 */ + if (i < 7) { + srcByte = 0; + srcBit = 6 - i; + } + else { + srcByte = (i - 7) / 8 + 1; + srcBit = 7 - ((i - 7) % 8); + } + + if (shift_reg[srcByte] & (1 << srcBit)) { + int dstPos = 64 + i; + int dstByte = dstPos / 8; + int dstBit = 7 - (dstPos % 8); + codeword[dstByte] |= (byte)(1 << dstBit); + } + } +} + +/* ---- BCH decode ---- */ + +/* Decode 127-bit codeword, correct up to t=10 errors. + * Extracts 64-bit message into msg (8 bytes). + * Returns 0 on success, negative on uncorrectable error. */ +static int bch_decode(byte* codeword, byte* msg) +{ + byte syndr[2 * WC_PUF_BCH_T + 1]; + byte sigma[WC_PUF_BCH_T + 1]; + int errPos[WC_PUF_BCH_T]; + int deg, numErr; + int i; + int allZero = 1; + + bch_syndromes(codeword, syndr); + + /* check if all syndromes are zero (no errors) */ + for (i = 1; i <= 2 * WC_PUF_BCH_T; i++) { + if (syndr[i] != 0) { + allZero = 0; + break; + } + } + + if (allZero) { + /* no errors, extract message directly */ + XMEMCPY(msg, codeword, 8); + return 0; + } + + deg = bch_berlekamp_massey(syndr, sigma); + if (deg < 0) + return PUF_RECONSTRUCT_E; + + numErr = bch_chien_search(sigma, deg, errPos); + if (numErr != deg) + return PUF_RECONSTRUCT_E; /* number of roots must match degree */ + + /* correct errors by flipping bits */ + for (i = 0; i < numErr; i++) { + int pos = errPos[i]; + if (pos < WC_PUF_BCH_N) { + int byteIdx = pos / 8; + int bitIdx = 7 - (pos % 8); + codeword[byteIdx] ^= (byte)(1 << bitIdx); + } + } + + /* verify the correction actually fixed the codeword by recomputing + * syndromes - guards against silent miscorrection when the input has + * more than t errors and the decoder is led to a different valid + * codeword (which would otherwise produce a wrong key/identity) */ + bch_syndromes(codeword, syndr); + for (i = 1; i <= 2 * WC_PUF_BCH_T; i++) { + if (syndr[i] != 0) + return PUF_RECONSTRUCT_E; + } + + /* extract message (first 64 bits) */ + XMEMCPY(msg, codeword, 8); + return 0; +} + +/* ========================================================================== */ +/* PUF API */ +/* ========================================================================== */ + +/* Get a single bit from byte array (MSB-first bit ordering) */ +static WC_INLINE byte getBit(const byte* data, int bitPos) +{ + return (data[bitPos / 8] >> (7 - (bitPos % 8))) & 1; +} + +/* Set a single bit in byte array (MSB-first bit ordering) */ +static WC_INLINE void setBit(byte* data, int bitPos, byte val) +{ + int byteIdx = bitPos / 8; + int bitIdx = 7 - (bitPos % 8); + if (val) + data[byteIdx] |= (byte)(1 << bitIdx); + else + data[byteIdx] &= (byte)~(1 << bitIdx); +} + +/* Extract 127 bits from raw SRAM starting at given bit offset */ +static void extractCodeword(const byte* sram, int bitOffset, byte* cw) +{ + int i; + XMEMSET(cw, 0, 16); + for (i = 0; i < WC_PUF_BCH_N; i++) { + setBit(cw, i, getBit(sram, bitOffset + i)); + } +} + +/* Store 127 bits into helper data at given bit offset */ +static void storeCodeword(byte* helper, int bitOffset, const byte* cw) +{ + int i; + for (i = 0; i < WC_PUF_BCH_N; i++) { + setBit(helper, bitOffset + i, getBit(cw, i)); + } +} + + +int wc_PufInit(wc_PufCtx* ctx) +{ + WOLFSSL_ENTER("wc_PufInit"); + + if (ctx == NULL) + return BAD_FUNC_ARG; + + XMEMSET(ctx, 0, sizeof(wc_PufCtx)); + + return 0; +} + +int wc_PufReadSram(wc_PufCtx* ctx, const byte* sramAddr, word32 sramSz) +{ + WOLFSSL_ENTER("wc_PufReadSram"); + + if (ctx == NULL || sramAddr == NULL) + return BAD_FUNC_ARG; + if (sramSz < WC_PUF_RAW_BYTES) + return PUF_READ_E; + +#ifdef WOLFSSL_PUF_TEST + if (ctx->testDataSet) { + /* rawSram already populated by wc_PufSetTestData */ + ctx->flags |= WC_PUF_FLAG_SRAM_SET; + return 0; + } +#endif + + XMEMCPY(ctx->rawSram, sramAddr, WC_PUF_RAW_BYTES); + ctx->flags |= WC_PUF_FLAG_SRAM_SET; + return 0; +} + +int wc_PufEnroll(wc_PufCtx* ctx) +{ + int i, ret; + byte msg[8]; /* 64-bit message */ + byte cw[16]; /* 127-bit codeword */ + byte rawCw[16]; + byte helperCw[16]; + + WOLFSSL_ENTER("wc_PufEnroll"); + + if (ctx == NULL) + return BAD_FUNC_ARG; + if (!(ctx->flags & WC_PUF_FLAG_SRAM_SET)) + return PUF_ENROLL_E; + + XMEMSET(ctx->helperData, 0, WC_PUF_HELPER_BYTES); + XMEMSET(ctx->stableBits, 0, WC_PUF_STABLE_BYTES); + + for (i = 0; i < WC_PUF_NUM_CODEWORDS; i++) { + /* extract 64 message bits from raw SRAM */ + int bitOff = i * 128; /* 128-bit stride for alignment */ + int j; + XMEMSET(msg, 0, sizeof(msg)); + for (j = 0; j < WC_PUF_BCH_K; j++) { + setBit(msg, j, getBit(ctx->rawSram, bitOff + j)); + } + + /* save stable bits */ + XMEMCPY(ctx->stableBits + i * 8, msg, 8); + + /* encode message into BCH codeword */ + bch_encode(msg, cw); + + /* helper = raw XOR codeword (mask) */ + extractCodeword(ctx->rawSram, bitOff, rawCw); + XMEMSET(helperCw, 0, 16); + for (j = 0; j < 16; j++) { + helperCw[j] = rawCw[j] ^ cw[j]; + } + storeCodeword(ctx->helperData, i * WC_PUF_BCH_N, helperCw); + } + + /* compute identity = SHA-256(stableBits) */ + ret = wc_PufHashDirect(ctx->stableBits, WC_PUF_STABLE_BYTES, ctx->identity); + + /* zeroize sensitive stack buffers */ + ForceZero(msg, sizeof(msg)); + ForceZero(cw, sizeof(cw)); + ForceZero(rawCw, sizeof(rawCw)); + ForceZero(helperCw, sizeof(helperCw)); + + if (ret != 0) + return PUF_ENROLL_E; + + ctx->flags |= WC_PUF_FLAG_ENROLLED | WC_PUF_FLAG_READY; + return 0; +} + +int wc_PufReconstruct(wc_PufCtx* ctx, const byte* helperData, word32 helperSz) +{ + int i, ret; + byte rawCw[16]; + byte helperCw[16]; + byte noisyCw[16]; + byte msg[8]; + + WOLFSSL_ENTER("wc_PufReconstruct"); + + if (ctx == NULL || helperData == NULL) + return BAD_FUNC_ARG; + if (helperSz < WC_PUF_HELPER_BYTES) + return PUF_RECONSTRUCT_E; + if (!(ctx->flags & WC_PUF_FLAG_SRAM_SET)) + return PUF_RECONSTRUCT_E; + + XMEMSET(ctx->stableBits, 0, WC_PUF_STABLE_BYTES); + + for (i = 0; i < WC_PUF_NUM_CODEWORDS; i++) { + int bitOff = i * 128; + int j; + + /* get raw SRAM bits for this codeword */ + extractCodeword(ctx->rawSram, bitOff, rawCw); + + /* get helper data for this codeword */ + XMEMSET(helperCw, 0, 16); + for (j = 0; j < WC_PUF_BCH_N; j++) { + setBit(helperCw, j, getBit(helperData, i * WC_PUF_BCH_N + j)); + } + + /* noisy codeword = raw XOR helper */ + for (j = 0; j < 16; j++) { + noisyCw[j] = rawCw[j] ^ helperCw[j]; + } + + /* BCH decode to recover original message */ + ret = bch_decode(noisyCw, msg); + if (ret != 0) { + ForceZero(rawCw, sizeof(rawCw)); + ForceZero(helperCw, sizeof(helperCw)); + ForceZero(noisyCw, sizeof(noisyCw)); + ForceZero(msg, sizeof(msg)); + ForceZero(ctx->stableBits, WC_PUF_STABLE_BYTES); + ctx->flags &= (word32)~WC_PUF_FLAG_READY; + return PUF_RECONSTRUCT_E; + } + + XMEMCPY(ctx->stableBits + i * 8, msg, 8); + } + + /* compute identity */ + ret = wc_PufHashDirect(ctx->stableBits, WC_PUF_STABLE_BYTES, ctx->identity); + + /* zeroize sensitive stack buffers */ + ForceZero(rawCw, sizeof(rawCw)); + ForceZero(helperCw, sizeof(helperCw)); + ForceZero(noisyCw, sizeof(noisyCw)); + ForceZero(msg, sizeof(msg)); + + if (ret != 0) + return PUF_RECONSTRUCT_E; + + ctx->flags |= WC_PUF_FLAG_READY; + return 0; +} + +int wc_PufDeriveKey(wc_PufCtx* ctx, const byte* info, word32 infoSz, + byte* key, word32 keySz) +{ + WOLFSSL_ENTER("wc_PufDeriveKey"); + + if (ctx == NULL || key == NULL) + return BAD_FUNC_ARG; + if (!(ctx->flags & WC_PUF_FLAG_READY)) + return PUF_DERIVE_KEY_E; + if (keySz == 0) + return BAD_FUNC_ARG; + + /* Documented contract: info may be NULL. Normalize so callers can pass + * (NULL, anything) without forwarding an invalid pointer/length pair to + * HKDF. */ + if (info == NULL) + infoSz = 0; + +#ifdef HAVE_HKDF + { + /* HKDF with stable bits as IKM, identity as salt */ + int ret; + ret = wc_HKDF(WC_PUF_HASH_TYPE, + ctx->stableBits, WC_PUF_STABLE_BYTES, + ctx->identity, WC_PUF_ID_SZ, + info, infoSz, + key, keySz); + if (ret != 0) + return PUF_DERIVE_KEY_E; + + return 0; + } +#else + (void)info; + (void)infoSz; + return PUF_DERIVE_KEY_E; +#endif +} + +int wc_PufGetIdentity(wc_PufCtx* ctx, byte* id, word32 idSz) +{ + WOLFSSL_ENTER("wc_PufGetIdentity"); + + if (ctx == NULL || id == NULL) + return BAD_FUNC_ARG; + if (!(ctx->flags & WC_PUF_FLAG_READY)) + return PUF_IDENTITY_E; + if (idSz < WC_PUF_ID_SZ) + return PUF_IDENTITY_E; + + XMEMCPY(id, ctx->identity, WC_PUF_ID_SZ); + return 0; +} + +int wc_PufZeroize(wc_PufCtx* ctx) +{ + WOLFSSL_ENTER("wc_PufZeroize"); + + if (ctx == NULL) + return BAD_FUNC_ARG; + + ForceZero(ctx, sizeof(wc_PufCtx)); + return 0; +} + +#ifdef WOLFSSL_PUF_TEST +int wc_PufSetTestData(wc_PufCtx* ctx, const byte* data, word32 sz) +{ + WOLFSSL_ENTER("wc_PufSetTestData"); + + if (ctx == NULL || data == NULL) + return BAD_FUNC_ARG; + if (sz < WC_PUF_RAW_BYTES) + return PUF_READ_E; + + /* Copy test data directly into rawSram and set flag */ + XMEMCPY(ctx->rawSram, data, WC_PUF_RAW_BYTES); + ctx->testDataSet = 1; + ctx->flags |= WC_PUF_FLAG_SRAM_SET; + return 0; +} +#endif /* WOLFSSL_PUF_TEST */ + +#endif /* WOLFSSL_PUF */ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index befb652b01..373898ff82 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -437,6 +437,9 @@ static const byte const_byte_array[] = "A+Gd\0\0\0"; #ifdef WOLFSSL_SM4 #include #endif +#ifdef WOLFSSL_PUF + #include +#endif #ifdef HAVE_LIBZ #include #endif @@ -889,6 +892,9 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t camellia_test(void); #ifdef WOLFSSL_SM4 WOLFSSL_TEST_SUBROUTINE wc_test_ret_t sm4_test(void); #endif +#ifdef WOLFSSL_PUF +WOLFSSL_TEST_SUBROUTINE wc_test_ret_t puf_test(void); +#endif #ifdef WC_RSA_NO_PADDING WOLFSSL_TEST_SUBROUTINE wc_test_ret_t rsa_no_pad_test(void); #endif @@ -2940,6 +2946,13 @@ options: [-s max_relative_stack_bytes] [-m max_relative_heap_memory_bytes]\n\ TEST_PASS("SM-4 test passed!\n"); #endif +#ifdef WOLFSSL_PUF + if ( (ret = puf_test()) != 0) + return err_sys("PUF test failed!\n", ret); + else + TEST_PASS("PUF test passed!\n"); +#endif + #if !defined(NO_RSA) && !defined(HAVE_RENESAS_SYNC) #ifdef WC_RSA_NO_PADDING if ( (ret = rsa_no_pad_test()) != 0) @@ -20537,6 +20550,228 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t sm4_test(void) } #endif +#ifdef WOLFSSL_PUF +WOLFSSL_TEST_SUBROUTINE wc_test_ret_t puf_test(void) +{ +#if defined(WOLFSSL_PUF_TEST) && defined(HAVE_HKDF) && \ + (!defined(NO_SHA256) || defined(WOLFSSL_SHA3)) + wc_test_ret_t ret = 0; + wc_PufCtx ctx; + byte key1[WC_PUF_KEY_SZ]; + byte key2[WC_PUF_KEY_SZ]; + byte id1[WC_PUF_ID_SZ]; + byte id2[WC_PUF_ID_SZ]; + + /* deterministic test SRAM pattern: 256 bytes */ + WOLFSSL_SMALL_STACK_STATIC const byte testSram[WC_PUF_RAW_BYTES] = { + 0xA5, 0x3C, 0x7E, 0x19, 0xF0, 0x82, 0x4D, 0xBB, + 0x6A, 0xC1, 0x55, 0x93, 0xE7, 0x2F, 0xD8, 0x04, + 0x91, 0x68, 0xAE, 0x3B, 0xFC, 0xD7, 0x42, 0x0E, + 0x85, 0x5A, 0xC9, 0x76, 0x1D, 0xB3, 0xEF, 0x60, + 0x4C, 0x87, 0xDA, 0x25, 0xF1, 0x6E, 0x09, 0xB2, + 0x73, 0xAC, 0x58, 0xE4, 0x3F, 0x96, 0xCB, 0x17, + 0x8D, 0x62, 0xA0, 0x4E, 0xFB, 0xD5, 0x31, 0x79, + 0xC6, 0x14, 0xBE, 0x8A, 0x47, 0xF3, 0x2D, 0x98, + 0x5B, 0xE6, 0x0C, 0xA7, 0x64, 0xDF, 0x39, 0x80, + 0xB5, 0x52, 0xCD, 0x18, 0x7B, 0xE1, 0x46, 0x9F, + 0x23, 0xAA, 0x6D, 0xD0, 0x84, 0xF7, 0x3E, 0xB9, + 0x51, 0xC2, 0x0F, 0x75, 0xEC, 0x48, 0x97, 0x2A, + 0xDE, 0x63, 0xBC, 0x10, 0x86, 0xF9, 0x43, 0xAD, + 0x5E, 0xC8, 0x27, 0x94, 0x6B, 0xD1, 0x3A, 0xB0, + 0x7C, 0xE5, 0x08, 0xA1, 0x56, 0xCF, 0x4A, 0x8E, + 0x35, 0xFD, 0x61, 0xB7, 0x22, 0x99, 0xD4, 0x1C, + 0x70, 0xEE, 0x4B, 0x83, 0x2E, 0xA6, 0x5D, 0xF4, + 0x36, 0xBD, 0x69, 0xC0, 0x15, 0x9B, 0xE8, 0x41, + 0x8C, 0x53, 0xAB, 0x07, 0x74, 0xDC, 0x28, 0x95, + 0x6F, 0xD3, 0x3D, 0xBA, 0x50, 0xC4, 0x1E, 0x89, + 0xF6, 0x44, 0xAE, 0x5F, 0xC7, 0x12, 0x9A, 0xE3, + 0x37, 0xB1, 0x66, 0xDB, 0x29, 0x8B, 0x54, 0xA2, + 0x0D, 0x78, 0xED, 0x40, 0x93, 0x2C, 0xBF, 0x67, + 0xD6, 0x3C, 0xA9, 0x57, 0xCE, 0x1A, 0x81, 0xF5, + 0x49, 0x9E, 0x24, 0xB8, 0x6C, 0xD2, 0x38, 0xA4, + 0x5C, 0xE9, 0x01, 0x7A, 0xDD, 0x45, 0x90, 0x2B, + 0xBB, 0x62, 0xC3, 0x16, 0x8F, 0xF8, 0x4E, 0xA3, + 0x34, 0xB6, 0x6E, 0xD9, 0x20, 0x9C, 0x59, 0xE2, + 0x0B, 0x77, 0xEA, 0x42, 0x8D, 0x33, 0xCA, 0x5B, + 0xFE, 0x11, 0x7F, 0xA8, 0x46, 0xD4, 0x2F, 0x96, + 0x65, 0xBC, 0x03, 0x9D, 0xE0, 0x58, 0xAF, 0x71, + 0xC5, 0x1B, 0x87, 0xFA, 0x4D, 0xB4, 0x26, 0xDF + }; + + /* noisy SRAM: same as testSram but with a few flipped bits */ + byte noisySram[WC_PUF_RAW_BYTES]; + byte helperBuf[WC_PUF_HELPER_BYTES]; + const byte info[] = "puf-test-context"; + + WOLFSSL_ENTER("puf_test"); + + /* ---- Test 1: Init ---- */ + ret = wc_PufInit(&ctx); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + /* ---- Test 2: SetTestData + Enroll ---- */ + ret = wc_PufSetTestData(&ctx, testSram, sizeof(testSram)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + ret = wc_PufEnroll(&ctx); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + /* save helper data and identity */ + XMEMCPY(helperBuf, ctx.helperData, WC_PUF_HELPER_BYTES); + + ret = wc_PufGetIdentity(&ctx, id1, sizeof(id1)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + /* derive a key */ + ret = wc_PufDeriveKey(&ctx, info, sizeof(info), key1, sizeof(key1)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + /* ---- Test 3: Reconstruct with same data (no noise) ---- */ + ret = wc_PufInit(&ctx); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + ret = wc_PufSetTestData(&ctx, testSram, sizeof(testSram)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + /* need to call ReadSram to populate rawSram (test data already set) */ + ret = wc_PufReadSram(&ctx, testSram, sizeof(testSram)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + ret = wc_PufReconstruct(&ctx, helperBuf, WC_PUF_HELPER_BYTES); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + ret = wc_PufGetIdentity(&ctx, id2, sizeof(id2)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + /* identity must match */ + if (XMEMCMP(id1, id2, WC_PUF_ID_SZ) != 0) + return WC_TEST_RET_ENC_NC; + + /* derive key again - must match */ + ret = wc_PufDeriveKey(&ctx, info, sizeof(info), key2, sizeof(key2)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + if (XMEMCMP(key1, key2, WC_PUF_KEY_SZ) != 0) + return WC_TEST_RET_ENC_NC; + + /* ---- Test 4: Reconstruct with noisy data (few bit flips) ---- */ + XMEMCPY(noisySram, testSram, sizeof(testSram)); + /* flip a few bits in each 128-bit block (within BCH correction limit) */ + noisySram[0] ^= 0x01; /* block 0: 1 bit flip */ + noisySram[16] ^= 0x03; /* block 1: 2 bit flips */ + noisySram[32] ^= 0x05; /* block 2: 2 bit flips */ + noisySram[48] ^= 0x11; /* block 3: 2 bit flips */ + noisySram[64] ^= 0x80; /* block 4: 1 bit flip */ + + ret = wc_PufInit(&ctx); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + ret = wc_PufSetTestData(&ctx, noisySram, sizeof(noisySram)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + ret = wc_PufReadSram(&ctx, noisySram, sizeof(noisySram)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + ret = wc_PufReconstruct(&ctx, helperBuf, WC_PUF_HELPER_BYTES); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + /* identity should still match after error correction */ + ret = wc_PufGetIdentity(&ctx, id2, sizeof(id2)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + if (XMEMCMP(id1, id2, WC_PUF_ID_SZ) != 0) + return WC_TEST_RET_ENC_NC; + + /* derived key should still match */ + ret = wc_PufDeriveKey(&ctx, info, sizeof(info), key2, sizeof(key2)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + if (XMEMCMP(key1, key2, WC_PUF_KEY_SZ) != 0) + return WC_TEST_RET_ENC_NC; + + /* ---- Test 4b: Reconstruct with too many bit errors (should fail) ---- */ + { + byte tooNoisySram[WC_PUF_RAW_BYTES]; + XMEMCPY(tooNoisySram, testSram, sizeof(testSram)); + /* flip 12 bits in block 0 (exceeds t=10 correction limit) */ + tooNoisySram[0] ^= 0xFF; /* 8 flips */ + tooNoisySram[1] ^= 0x0F; /* 4 flips = 12 total > t=10 */ + + ret = wc_PufInit(&ctx); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + ret = wc_PufSetTestData(&ctx, tooNoisySram, sizeof(tooNoisySram)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + ret = wc_PufReadSram(&ctx, tooNoisySram, sizeof(tooNoisySram)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + if (wc_PufReconstruct(&ctx, helperBuf, WC_PUF_HELPER_BYTES) + != WC_NO_ERR_TRACE(PUF_RECONSTRUCT_E)) + return WC_TEST_RET_ENC_NC; + } + + /* ---- Test 5: Bad argument checks ---- */ + if (wc_PufInit(NULL) != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + return WC_TEST_RET_ENC_NC; + + if (wc_PufReadSram(NULL, testSram, sizeof(testSram)) + != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + return WC_TEST_RET_ENC_NC; + + if (wc_PufDeriveKey(&ctx, info, sizeof(info), NULL, 32) + != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + return WC_TEST_RET_ENC_NC; + + if (wc_PufEnroll(NULL) != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + return WC_TEST_RET_ENC_NC; + + if (wc_PufReconstruct(NULL, helperBuf, WC_PUF_HELPER_BYTES) + != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + return WC_TEST_RET_ENC_NC; + + if (wc_PufZeroize(NULL) != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + return WC_TEST_RET_ENC_NC; + + /* too-small identity buffer */ + if (wc_PufGetIdentity(&ctx, id1, WC_PUF_ID_SZ - 1) + != WC_NO_ERR_TRACE(PUF_IDENTITY_E)) + return WC_TEST_RET_ENC_NC; + + /* ---- Test 6: Zeroize ---- */ + ret = wc_PufZeroize(&ctx); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + /* after zeroize, derive should fail (not ready) */ + if (wc_PufDeriveKey(&ctx, info, sizeof(info), key1, sizeof(key1)) + != WC_NO_ERR_TRACE(PUF_DERIVE_KEY_E)) + return WC_TEST_RET_ENC_NC; + + return 0; +#else + return 0; +#endif /* WOLFSSL_PUF_TEST && HAVE_HKDF && (!NO_SHA256 || WOLFSSL_SHA3) */ +} +#endif /* WOLFSSL_PUF */ + #ifdef HAVE_XCHACHA WOLFSSL_TEST_SUBROUTINE wc_test_ret_t XChaCha_test(void) { diff --git a/wolfssl/wolfcrypt/error-crypt.h b/wolfssl/wolfcrypt/error-crypt.h index 40962ee084..d17cfafd9f 100644 --- a/wolfssl/wolfcrypt/error-crypt.h +++ b/wolfssl/wolfcrypt/error-crypt.h @@ -314,8 +314,16 @@ enum wolfCrypt_ErrorCodes { ALREADY_E = -1007, /* Operation was redundant or preempted */ SEQ_OVERFLOW_E = -1008, /* Sequence counter would overflow */ - WC_SPAN2_LAST_E = -1008, /* Update to indicate last used error code */ - WC_LAST_E = -1008, /* the last code used either here or in + + PUF_INIT_E = -1009, /* PUF initialization failed (reserved) */ + PUF_READ_E = -1010, /* PUF SRAM read failed */ + PUF_ENROLL_E = -1011, /* PUF enrollment failed */ + PUF_RECONSTRUCT_E = -1012, /* PUF reconstruction failed */ + PUF_DERIVE_KEY_E = -1013, /* PUF key derivation failed */ + PUF_IDENTITY_E = -1014, /* PUF identity retrieval failed */ + + WC_SPAN2_LAST_E = -1014, /* Update to indicate last used error code */ + WC_LAST_E = -1014, /* the last code used either here or in * error-ssl.h */ WC_SPAN2_MIN_CODE_E = -1999, /* Last usable code in span 2 */ diff --git a/wolfssl/wolfcrypt/include.am b/wolfssl/wolfcrypt/include.am index 1c23469d20..7f07389a07 100644 --- a/wolfssl/wolfcrypt/include.am +++ b/wolfssl/wolfcrypt/include.am @@ -90,6 +90,7 @@ nobase_include_HEADERS+= \ wolfssl/wolfcrypt/wc_xmss.h \ wolfssl/wolfcrypt/ext_xmss.h \ wolfssl/wolfcrypt/wc_slhdsa.h \ + wolfssl/wolfcrypt/puf.h \ wolfssl/wolfcrypt/oid_sum.h noinst_HEADERS+= \ diff --git a/wolfssl/wolfcrypt/puf.h b/wolfssl/wolfcrypt/puf.h new file mode 100644 index 0000000000..855848574f --- /dev/null +++ b/wolfssl/wolfcrypt/puf.h @@ -0,0 +1,116 @@ +/* puf.h + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/*! + \file wolfssl/wolfcrypt/puf.h + \brief SRAM PUF (Physically Unclonable Function) support for wolfCrypt. + + Derives device-unique cryptographic keys from the power-on state of SRAM + memory using a BCH(127,64,t=10) fuzzy extractor with HKDF key derivation. + + Build: ./configure --enable-puf (auto-enables HKDF) + + For a bare-metal example (tested on NUCLEO-H563ZI), see: + https://github.com/wolfSSL/wolfssl-examples/tree/master/puf +*/ + +#ifndef WOLF_CRYPT_PUF_H +#define WOLF_CRYPT_PUF_H + +#include + +#ifdef WOLFSSL_PUF + +/* PUF is not a FIPS-validated algorithm. Fail loudly at compile time rather + * than producing undefined references at link time when WOLFSSL_PUF is + * combined with HAVE_FIPS. */ +#if defined(HAVE_FIPS) + #error "WOLFSSL_PUF is not available when HAVE_FIPS is defined" +#endif + +#include + +#ifdef __cplusplus + extern "C" { +#endif + +/* BCH(127,64,t=10) parameters */ +#define WC_PUF_BCH_M 7 /* GF(2^7) */ +#define WC_PUF_BCH_N 127 /* codeword length */ +#define WC_PUF_BCH_K 64 /* message length */ +#define WC_PUF_BCH_T 10 /* error correction capability */ + +/* PUF dimensions */ +#define WC_PUF_NUM_CODEWORDS 16 /* 16 codewords */ +#define WC_PUF_RAW_BITS 2048 /* 16 x 128 bits (rounded up for storage) */ +#define WC_PUF_RAW_BYTES (WC_PUF_RAW_BITS / 8) /* 256 bytes */ +#define WC_PUF_STABLE_BITS 1024 /* 16 x 64 message bits */ +#define WC_PUF_STABLE_BYTES (WC_PUF_STABLE_BITS / 8) /* 128 bytes */ + +/* Helper data: 16 codewords x 127 bits, packed into bytes */ +#define WC_PUF_HELPER_BITS (WC_PUF_NUM_CODEWORDS * WC_PUF_BCH_N) +#define WC_PUF_HELPER_BYTES ((WC_PUF_HELPER_BITS + 7) / 8) /* 254 bytes */ + +/* Output key size */ +#define WC_PUF_KEY_SZ 32 /* 256-bit derived key */ + +/* Identity hash size (SHA-256 or SHA3-256 with WC_PUF_SHA3) */ +#define WC_PUF_ID_SZ 32 + +/* Flags for wc_PufCtx.flags */ +#define WC_PUF_FLAG_ENROLLED 0x01 +#define WC_PUF_FLAG_READY 0x02 +#define WC_PUF_FLAG_SRAM_SET 0x04 + +typedef struct wc_PufCtx { + byte rawSram[WC_PUF_RAW_BYTES]; /* raw SRAM readout */ + byte helperData[WC_PUF_HELPER_BYTES]; /* enrollment helper data */ + byte stableBits[WC_PUF_STABLE_BYTES]; /* reconstructed stable bits */ + byte identity[WC_PUF_ID_SZ]; /* device identity hash */ + word32 flags; + +#ifdef WOLFSSL_PUF_TEST + word32 testDataSet; /* flag: test data was injected */ +#endif +} wc_PufCtx; + +WOLFSSL_API int wc_PufInit(wc_PufCtx* ctx); +WOLFSSL_API int wc_PufReadSram(wc_PufCtx* ctx, const byte* sramAddr, + word32 sramSz); +WOLFSSL_API int wc_PufEnroll(wc_PufCtx* ctx); +WOLFSSL_API int wc_PufReconstruct(wc_PufCtx* ctx, const byte* helperData, + word32 helperSz); +WOLFSSL_API int wc_PufDeriveKey(wc_PufCtx* ctx, const byte* info, word32 infoSz, + byte* key, word32 keySz); +WOLFSSL_API int wc_PufGetIdentity(wc_PufCtx* ctx, byte* id, word32 idSz); +WOLFSSL_API int wc_PufZeroize(wc_PufCtx* ctx); + +#ifdef WOLFSSL_PUF_TEST +WOLFSSL_API int wc_PufSetTestData(wc_PufCtx* ctx, const byte* data, word32 sz); +#endif + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* WOLFSSL_PUF */ + +#endif /* WOLF_CRYPT_PUF_H */ From 6aa3cd653e71cc35c65cb8b81798ce1afec047f4 Mon Sep 17 00:00:00 2001 From: jordan Date: Wed, 22 Apr 2026 15:16:19 -0500 Subject: [PATCH 092/167] wc_port: guard stddef header include. --- wolfssl/wolfcrypt/settings.h | 1 + wolfssl/wolfcrypt/wc_port.h | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 5a32d53516..4496c342ab 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -3954,6 +3954,7 @@ extern void uITRON4_free(void *p) ; #undef HAVE_LIMITS_H #define NO_STRING_H #define NO_LIMITS_H + #define NO_STDDEF_H #define NO_STDLIB_H #define NO_STDINT_H #define NO_CTYPE_H diff --git a/wolfssl/wolfcrypt/wc_port.h b/wolfssl/wolfcrypt/wc_port.h index 9c595f2b0c..d815c1b3a4 100644 --- a/wolfssl/wolfcrypt/wc_port.h +++ b/wolfssl/wolfcrypt/wc_port.h @@ -1727,7 +1727,9 @@ WOLFSSL_ABI WOLFSSL_API int wolfCrypt_Cleanup(void); #if (!defined(WOLFSSL_LEANPSK) && !defined(STRING_USER)) || \ defined(USE_WOLF_STRNSTR) - #include /* for size_t */ + #ifndef NO_STDDEF_H + #include /* for size_t */ + #endif /* NO_STDDEF_H */ WOLFSSL_TEST_VIS char* wolfSSL_strnstr(const char* s1, const char* s2, size_t n); #endif From ea6af18bc1cf5fd185add1d215b42b4c4a7081ae Mon Sep 17 00:00:00 2001 From: Paul Adelsbach Date: Wed, 22 Apr 2026 13:17:28 -0700 Subject: [PATCH 093/167] Set hashType in ports --- wolfcrypt/src/port/caam/caam_sha.c | 8 +++++- wolfcrypt/src/port/cypress/psoc6_crypto.c | 15 +++++++++++ wolfcrypt/src/port/kcapi/kcapi_hash.c | 31 ++++++++++++++++++---- wolfcrypt/src/port/maxim/max3266x.c | 3 +++ wolfcrypt/src/port/riscv/riscv-64-sha512.c | 9 +++++++ wolfcrypt/src/port/silabs/silabs_hash.c | 9 ++++++- wolfcrypt/src/sha512.c | 27 +++++++++++++++++-- 7 files changed, 93 insertions(+), 9 deletions(-) diff --git a/wolfcrypt/src/port/caam/caam_sha.c b/wolfcrypt/src/port/caam/caam_sha.c index d64c6954b8..04aff85e62 100644 --- a/wolfcrypt/src/port/caam/caam_sha.c +++ b/wolfcrypt/src/port/caam/caam_sha.c @@ -376,7 +376,13 @@ int wc_Sha384Final(wc_Sha384* sha, byte* out) #ifdef WOLFSSL_SHA512 int wc_InitSha512_ex(wc_Sha512* sha, void* heap, int devId) { - return _InitSha(sha, heap, devId, SHA512_DIGEST_SIZE, CAAM_SHA512); + int ret = _InitSha(sha, heap, devId, SHA512_DIGEST_SIZE, CAAM_SHA512); +#if defined(WOLFSSL_SHA512_HASHTYPE) + if (ret == 0) { + sha->hashType = WC_HASH_TYPE_SHA512; + } +#endif + return ret; } diff --git a/wolfcrypt/src/port/cypress/psoc6_crypto.c b/wolfcrypt/src/port/cypress/psoc6_crypto.c index 4587998960..2cb0007fbb 100644 --- a/wolfcrypt/src/port/cypress/psoc6_crypto.c +++ b/wolfcrypt/src/port/cypress/psoc6_crypto.c @@ -536,6 +536,11 @@ int wc_InitSha512_ex(wc_Sha512* sha, void* heap, int devid) /* Release the lock */ wolfSSL_CryptHwMutexUnLock(); } +#if defined(WOLFSSL_SHA512_HASHTYPE) + if (ret == 0) { + sha->hashType = WC_HASH_TYPE_SHA512; + } +#endif return ret; } @@ -606,6 +611,11 @@ int wc_InitSha512_224_ex(wc_Sha512* sha, void* heap, int devid) /* Release the lock */ wolfSSL_CryptHwMutexUnLock(); } +#if defined(WOLFSSL_SHA512_HASHTYPE) + if (ret == 0) { + sha->hashType = WC_HASH_TYPE_SHA512_224; + } +#endif return ret; } @@ -658,6 +668,11 @@ int wc_InitSha512_256_ex(wc_Sha512* sha, void* heap, int devid) /* Release the lock */ wolfSSL_CryptHwMutexUnLock(); } +#if defined(WOLFSSL_SHA512_HASHTYPE) + if (ret == 0) { + sha->hashType = WC_HASH_TYPE_SHA512_256; + } +#endif return ret; } diff --git a/wolfcrypt/src/port/kcapi/kcapi_hash.c b/wolfcrypt/src/port/kcapi/kcapi_hash.c index 83dfa27d7e..cd6945b467 100644 --- a/wolfcrypt/src/port/kcapi/kcapi_hash.c +++ b/wolfcrypt/src/port/kcapi/kcapi_hash.c @@ -427,10 +427,17 @@ static const char WC_NAME_SHA512[] = "sha512"; /* create KCAPI handle for SHA512 operation */ int wc_InitSha512_ex(wc_Sha512* sha, void* heap, int devid) { + int ret; if (sha == NULL) { return BAD_FUNC_ARG; } - return KcapiHashInit(&sha->kcapi, heap, devid, WC_NAME_SHA512); + ret = KcapiHashInit(&sha->kcapi, heap, devid, WC_NAME_SHA512); +#if defined(WOLFSSL_SHA512_HASHTYPE) + if (ret == 0) { + sha->hashType = WC_HASH_TYPE_SHA512; + } +#endif + return ret; } @@ -473,13 +480,20 @@ int wc_Sha512Copy(wc_Sha512* src, wc_Sha512* dst) #if !defined(WOLFSSL_NOSHA512_224) static const char WC_NAME_SHA512_224[] = "sha512-224"; -/* create KCAPI handle for SHA512 operation */ +/* create KCAPI handle for SHA512/224 operation */ int wc_InitSha512_224_ex(wc_Sha512* sha, void* heap, int devid) { + int ret; if (sha == NULL) { return BAD_FUNC_ARG; } - return KcapiHashInit(&sha->kcapi, heap, devid, WC_NAME_SHA512_224); + ret = KcapiHashInit(&sha->kcapi, heap, devid, WC_NAME_SHA512_224); +#if defined(WOLFSSL_SHA512_HASHTYPE) + if (ret == 0) { + sha->hashType = WC_HASH_TYPE_SHA512_224; + } +#endif + return ret; } @@ -512,13 +526,20 @@ int wc_Sha512_224Copy(wc_Sha512* src, wc_Sha512* dst) #if !defined(WOLFSSL_NOSHA512_256) static const char WC_NAME_SHA512_256[] = "sha512-256"; -/* create KCAPI handle for SHA512 operation */ +/* create KCAPI handle for SHA512/256 operation */ int wc_InitSha512_256_ex(wc_Sha512* sha, void* heap, int devid) { + int ret; if (sha == NULL) { return BAD_FUNC_ARG; } - return KcapiHashInit(&sha->kcapi, heap, devid, WC_NAME_SHA512_256); + ret = KcapiHashInit(&sha->kcapi, heap, devid, WC_NAME_SHA512_256); +#if defined(WOLFSSL_SHA512_HASHTYPE) + if (ret == 0) { + sha->hashType = WC_HASH_TYPE_SHA512_256; + } +#endif + return ret; } diff --git a/wolfcrypt/src/port/maxim/max3266x.c b/wolfcrypt/src/port/maxim/max3266x.c index 4aed830c00..e326ecadbe 100644 --- a/wolfcrypt/src/port/maxim/max3266x.c +++ b/wolfcrypt/src/port/maxim/max3266x.c @@ -1136,6 +1136,9 @@ WOLFSSL_API int wc_InitSha512_ex(wc_Sha512* sha512, void* heap, int devId) (void)devId; XMEMSET(sha512, 0, sizeof(*sha512)); sha512->heap = heap; +#if defined(WOLFSSL_SHA512_HASHTYPE) + sha512->hashType = WC_HASH_TYPE_SHA512; +#endif return 0; } diff --git a/wolfcrypt/src/port/riscv/riscv-64-sha512.c b/wolfcrypt/src/port/riscv/riscv-64-sha512.c index 5c00f28d16..473b115dc0 100644 --- a/wolfcrypt/src/port/riscv/riscv-64-sha512.c +++ b/wolfcrypt/src/port/riscv/riscv-64-sha512.c @@ -999,6 +999,9 @@ int wc_InitSha512_ex(wc_Sha512* sha512, void* heap, int devId) int ret = InitSha512(sha512, heap, devId); if (ret == 0) { InitSha512_State(sha512); +#if defined(WOLFSSL_SHA512_HASHTYPE) + sha512->hashType = WC_HASH_TYPE_SHA512; +#endif } return ret; } @@ -1302,6 +1305,9 @@ int wc_InitSha512_224_ex(wc_Sha512* sha512, void* heap, int devId) int ret = InitSha512(sha512, heap, devId); if (ret == 0) { InitSha512_224_State(sha512); +#if defined(WOLFSSL_SHA512_HASHTYPE) + sha512->hashType = WC_HASH_TYPE_SHA512_224; +#endif } return ret; } @@ -1402,6 +1408,9 @@ int wc_InitSha512_256_ex(wc_Sha512* sha512, void* heap, int devId) int ret = InitSha512(sha512, heap, devId); if (ret == 0) { InitSha512_256_State(sha512); +#if defined(WOLFSSL_SHA512_HASHTYPE) + sha512->hashType = WC_HASH_TYPE_SHA512_256; +#endif } return ret; } diff --git a/wolfcrypt/src/port/silabs/silabs_hash.c b/wolfcrypt/src/port/silabs/silabs_hash.c index d6bcbf357d..1510bd2385 100644 --- a/wolfcrypt/src/port/silabs/silabs_hash.c +++ b/wolfcrypt/src/port/silabs/silabs_hash.c @@ -277,6 +277,7 @@ int wc_Sha384Final(wc_Sha384* sha, byte* hash) #ifdef WOLFSSL_SILABS_SHA512 int wc_InitSha512_ex(wc_Sha512* sha, void* heap, int devId) { + int ret; if (sha == NULL) { return BAD_FUNC_ARG; } @@ -284,7 +285,13 @@ int wc_InitSha512_ex(wc_Sha512* sha, void* heap, int devId) (void)devId; (void)heap; - return wc_silabs_se_hash_init(&sha->silabsCtx, WC_HASH_TYPE_SHA512); + ret = wc_silabs_se_hash_init(&sha->silabsCtx, WC_HASH_TYPE_SHA512); +#if defined(WOLFSSL_SHA512_HASHTYPE) + if (ret == 0) { + sha->hashType = WC_HASH_TYPE_SHA512; + } +#endif + return ret; } diff --git a/wolfcrypt/src/sha512.c b/wolfcrypt/src/sha512.c index cc219db77f..5d1d10b109 100644 --- a/wolfcrypt/src/sha512.c +++ b/wolfcrypt/src/sha512.c @@ -179,17 +179,31 @@ #elif defined(WOLFSSL_SE050) && defined(WOLFSSL_SE050_HASH) int wc_InitSha512(wc_Sha512* sha512) { + int ret; if (sha512 == NULL) return BAD_FUNC_ARG; - return se050_hash_init(&sha512->se050Ctx, NULL); + ret = se050_hash_init(&sha512->se050Ctx, NULL); +#if defined(WOLFSSL_SHA512_HASHTYPE) + if (ret == 0) { + sha512->hashType = WC_HASH_TYPE_SHA512; + } +#endif + return ret; } int wc_InitSha512_ex(wc_Sha512* sha512, void* heap, int devId) { + int ret; if (sha512 == NULL) { return BAD_FUNC_ARG; } (void)devId; - return se050_hash_init(&sha512->se050Ctx, heap); + ret = se050_hash_init(&sha512->se050Ctx, heap); +#if defined(WOLFSSL_SHA512_HASHTYPE) + if (ret == 0) { + sha512->hashType = WC_HASH_TYPE_SHA512; + } +#endif + return ret; } int wc_Sha512Update(wc_Sha512* sha512, const byte* data, word32 len) { @@ -252,6 +266,9 @@ XMEMSET(sha512, 0, sizeof(wc_Sha512)); wc_Stm32_Hash_Init(&sha512->stmCtx); +#if defined(WOLFSSL_SHA512_HASHTYPE) + sha512->hashType = WC_HASH_TYPE_SHA512; +#endif return 0; } @@ -2375,6 +2392,9 @@ int wc_InitSha512_224_ex(wc_Sha512* sha512, void* heap, int devId) XMEMSET(sha512, 0, sizeof(wc_Sha512)); wc_Stm32_Hash_Init(&sha512->stmCtx); +#if defined(WOLFSSL_SHA512_HASHTYPE) + sha512->hashType = WC_HASH_TYPE_SHA512_224; +#endif return 0; } @@ -2518,6 +2538,9 @@ int wc_Sha512_224Transform(wc_Sha512* sha, const unsigned char* data) XMEMSET(sha512, 0, sizeof(wc_Sha512)); wc_Stm32_Hash_Init(&sha512->stmCtx); +#if defined(WOLFSSL_SHA512_HASHTYPE) + sha512->hashType = WC_HASH_TYPE_SHA512_256; +#endif return 0; } From 7f218574c4d30a8aa8c520c7023c3d017fc13b86 Mon Sep 17 00:00:00 2001 From: Kareem Date: Fri, 3 Apr 2026 16:05:44 -0700 Subject: [PATCH 094/167] Ensure esd->signedAttribsCount contains the correct count in case some are skipped by using the current idx rather than the total array size. Thanks to Zou Dikai for the report. --- wolfcrypt/src/pkcs7.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index 36b817ed51..7df99f41b1 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -2253,7 +2253,7 @@ static int wc_PKCS7_BuildSignedAttributes(wc_PKCS7* pkcs7, ESD* esd, idx++; } - esd->signedAttribsCount += cannedAttribsCount; + esd->signedAttribsCount += idx; esd->signedAttribsSz += (word32)EncodeAttributes( &esd->signedAttribs[atrIdx], (int)idx, cannedAttribs, (int)cannedAttribsCount); From 1397268aa12e2cf3f80c3acfa9b6036b809c08ef Mon Sep 17 00:00:00 2001 From: Kareem Date: Fri, 3 Apr 2026 16:06:35 -0700 Subject: [PATCH 095/167] In wc_PKCS7_DecodeEnvelopedData, confirm encryptedContentTotalSz does not exceed the total message size before using it in the non-streaming case. Thanks to Zou Dikai for the report. --- wolfcrypt/src/pkcs7.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index 7df99f41b1..2ab1a2fd7a 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -13242,6 +13242,11 @@ int wc_PKCS7_DecodeEnvelopedData(wc_PKCS7* pkcs7, byte* in, } wc_PKCS7_DecryptContentFree(pkcs7, encOID, pkcs7->heap); } else { + if ((idx + (word32)encryptedContentTotalSz) > pkiMsgSz) { + ret = BUFFER_E; + break; + } + pkcs7->cachedEncryptedContentSz = (word32)encryptedContentTotalSz; pkcs7->totalEncryptedContentSz = From ebdcc03b718cd7175355097b1a3831a0eb4875b2 Mon Sep 17 00:00:00 2001 From: Kareem Date: Fri, 3 Apr 2026 16:56:04 -0700 Subject: [PATCH 096/167] Code review feedback --- wolfcrypt/src/pkcs7.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index 2ab1a2fd7a..3fc8a41be4 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -2256,7 +2256,7 @@ static int wc_PKCS7_BuildSignedAttributes(wc_PKCS7* pkcs7, ESD* esd, esd->signedAttribsCount += idx; esd->signedAttribsSz += (word32)EncodeAttributes( &esd->signedAttribs[atrIdx], (int)idx, cannedAttribs, - (int)cannedAttribsCount); + (int)idx); atrIdx += idx; } else { esd->signedAttribsCount = 0; @@ -13242,7 +13242,9 @@ int wc_PKCS7_DecodeEnvelopedData(wc_PKCS7* pkcs7, byte* in, } wc_PKCS7_DecryptContentFree(pkcs7, encOID, pkcs7->heap); } else { - if ((idx + (word32)encryptedContentTotalSz) > pkiMsgSz) { + word32 tmpSum; + if (!WC_SAFE_SUM_WORD32(idx, (word32)encryptedContentTotalSz, tmpSum) || + tmpSum > pkiMsgSz) { ret = BUFFER_E; break; } From 3e04475875a4942652fdf6794a01fdfd65801fdc Mon Sep 17 00:00:00 2001 From: Kareem Date: Mon, 6 Apr 2026 11:58:12 -0700 Subject: [PATCH 097/167] Fix unused variable error --- wolfcrypt/src/pkcs7.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index 3fc8a41be4..7889ce4a00 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -2197,7 +2197,6 @@ static int wc_PKCS7_BuildSignedAttributes(wc_PKCS7* pkcs7, ESD* esd, #endif word32 idx = 0; word32 atrIdx = 0; - word32 cannedAttribsCount; if (pkcs7 == NULL || esd == NULL || contentType == NULL || contentTypeOid == NULL || messageDigestOid == NULL || @@ -2220,8 +2219,6 @@ static int wc_PKCS7_BuildSignedAttributes(wc_PKCS7* pkcs7, ESD* esd, return timeSz; #endif - cannedAttribsCount = sizeof(cannedAttribs)/sizeof(PKCS7Attrib); - XMEMSET(&cannedAttribs[idx], 0, sizeof(cannedAttribs[idx])); if ((pkcs7->defaultSignedAttribs & WOLFSSL_CONTENT_TYPE_ATTRIBUTE) || From b3c2877a146e0c75715368ca5dfe2387bfc2cadf Mon Sep 17 00:00:00 2001 From: Kareem Date: Mon, 6 Apr 2026 16:41:32 -0700 Subject: [PATCH 098/167] Add additional checks for encryptedContentSz exceeding pkiMsgSz. --- wolfcrypt/src/pkcs7.c | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index 7889ce4a00..bc7bd25fd7 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -14391,9 +14391,17 @@ int wc_PKCS7_DecodeAuthEnvelopedData(wc_PKCS7* pkcs7, byte* in, } if (ret == 0) { - XMEMCPY(encryptedContent, &pkiMsg[idx], + word32 tmpSum; + if (!WC_SAFE_SUM_WORD32(idx, (word32)encryptedContentSz, + tmpSum) || + tmpSum > pkiMsgSz) { + ret = BUFFER_E; + break; + } else { + XMEMCPY(encryptedContent, &pkiMsg[idx], (word32)encryptedContentSz); - idx += (word32)encryptedContentSz; + idx += (word32)encryptedContentSz; + } } #ifndef NO_PKCS7_STREAM pkcs7->stream->bufferPt = encryptedContent; @@ -15327,16 +15335,22 @@ int wc_PKCS7_DecodeEncryptedData(wc_PKCS7* pkcs7, byte* in, word32 inSz, } if (ret == 0) { - XMEMCPY(encryptedContent, &pkiMsg[idx], - (unsigned int)encryptedContentSz); - idx += (word32)encryptedContentSz; + word32 tmpSum; + if (!WC_SAFE_SUM_WORD32(idx, (word32)encryptedContentSz, tmpSum) || + tmpSum > pkiMsgSz) { + ret = BUFFER_E; + } else { + XMEMCPY(encryptedContent, &pkiMsg[idx], + (unsigned int)encryptedContentSz); + idx += (word32)encryptedContentSz; - /* decrypt encryptedContent */ - ret = wc_PKCS7_DecryptContent(pkcs7, encOID, - pkcs7->encryptionKey, pkcs7->encryptionKeySz, - tmpIv, expBlockSz, NULL, 0, NULL, 0, - encryptedContent, encryptedContentSz, - encryptedContent, pkcs7->devId, pkcs7->heap); + /* decrypt encryptedContent */ + ret = wc_PKCS7_DecryptContent(pkcs7, encOID, + pkcs7->encryptionKey, pkcs7->encryptionKeySz, + tmpIv, expBlockSz, NULL, 0, NULL, 0, + encryptedContent, encryptedContentSz, + encryptedContent, pkcs7->devId, pkcs7->heap); + } if (ret != 0) { XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); } From 9fef016106ea8574bf8b84b1c3383ac169ac284c Mon Sep 17 00:00:00 2001 From: Kareem Date: Wed, 22 Apr 2026 15:47:39 -0700 Subject: [PATCH 099/167] Fix W560 "possible truncation at implicit conversion to type unsigned char" warnings raised by Tasking compiler. --- src/tls13.c | 2 +- src/wolfio.c | 6 +++++- wolfcrypt/src/fe_low_mem.c | 18 +++++++++--------- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/tls13.c b/src/tls13.c index 824ad08b69..a3a6607e5b 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -8577,7 +8577,7 @@ static WC_INLINE int DecodeTls13SigAlg(byte* input, byte* hashAlgo, break; #endif case NEW_SA_MAJOR: - *hashAlgo = GetNewSAHashAlgo(input[1]); + *hashAlgo = (byte)GetNewSAHashAlgo(input[1]); /* PSS encryption: 0x080[4-6] */ if (input[1] >= RSA_PSS_RSAE_SHA256_MINOR && diff --git a/src/wolfio.c b/src/wolfio.c index c6ffe7da11..22a4e6ee6b 100644 --- a/src/wolfio.c +++ b/src/wolfio.c @@ -3286,7 +3286,11 @@ int LwIPNativeSend(WOLFSSL* ssl, char* buf, int sz, void* ctx) err_t ret; WOLFSSL_LWIP_NATIVE_STATE* nlwip = (WOLFSSL_LWIP_NATIVE_STATE*)ctx; - ret = tcp_write(nlwip->pcb, buf, sz, TCP_WRITE_FLAG_COPY); + if (sz > UINT16_MAX || sz < 0) { + return BAD_FUNC_ARG; + } + + ret = tcp_write(nlwip->pcb, buf, (u16_t)sz, TCP_WRITE_FLAG_COPY); if (ret != ERR_OK) { sz = WOLFSSL_FATAL_ERROR; } diff --git a/wolfcrypt/src/fe_low_mem.c b/wolfcrypt/src/fe_low_mem.c index f1c5eddd34..61b8876904 100644 --- a/wolfcrypt/src/fe_low_mem.c +++ b/wolfcrypt/src/fe_low_mem.c @@ -546,7 +546,7 @@ void fe_load(byte *x, word32 c) word32 i; for (i = 0; i < sizeof(c); i++) { - x[i] = c; + x[i] = (byte)c; c >>= 8; } @@ -636,7 +636,7 @@ void lm_sub(byte* r, const byte* a, const byte* b) c = 218; for (i = 0; i + 1 < F25519_SIZE; i++) { c += 65280 + ((word32)a[i]) - ((word32)b[i]); - r[i] = c; + r[i] = (byte)c; c >>= 8; } @@ -646,7 +646,7 @@ void lm_sub(byte* r, const byte* a, const byte* b) for (i = 0; i < F25519_SIZE; i++) { c += r[i]; - r[i] = c; + r[i] = (byte)c; c >>= 8; } } @@ -661,7 +661,7 @@ void lm_neg(byte* r, const byte* a) c = 218; for (i = 0; i + 1 < F25519_SIZE; i++) { c += 65280 - ((word32)a[i]); - r[i] = c; + r[i] = (byte)c; c >>= 8; } @@ -671,7 +671,7 @@ void lm_neg(byte* r, const byte* a) for (i = 0; i < F25519_SIZE; i++) { c += r[i]; - r[i] = c; + r[i] = (byte)c; c >>= 8; } } @@ -693,7 +693,7 @@ void fe_mul__distinct(byte *r, const byte *a, const byte *b) c += ((word32)a[j]) * ((word32)b[i + F25519_SIZE - j]) * 38; - r[i] = c; + r[i] = (byte)c; } r[31] &= 127; @@ -701,7 +701,7 @@ void fe_mul__distinct(byte *r, const byte *a, const byte *b) for (i = 0; i < F25519_SIZE; i++) { c += r[i]; - r[i] = c; + r[i] = (byte)c; c >>= 8; } } @@ -724,7 +724,7 @@ void fe_mul_c(byte *r, const byte *a, word32 b) for (i = 0; i < F25519_SIZE; i++) { c >>= 8; c += b * ((word32)a[i]); - r[i] = c; + r[i] = (byte)c; } r[31] &= 127; @@ -733,7 +733,7 @@ void fe_mul_c(byte *r, const byte *a, word32 b) for (i = 0; i < F25519_SIZE; i++) { c += r[i]; - r[i] = c; + r[i] = (byte)c; c >>= 8; } } From c69d9693f017e6468fb5a47ef760e1e75632752c Mon Sep 17 00:00:00 2001 From: Kareem Date: Wed, 22 Apr 2026 16:33:07 -0700 Subject: [PATCH 100/167] Fix code review feedback and test failure. --- src/tls13.c | 5 ++++- src/wolfio.c | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/tls13.c b/src/tls13.c index a3a6607e5b..8b49cc33bc 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -8577,7 +8577,10 @@ static WC_INLINE int DecodeTls13SigAlg(byte* input, byte* hashAlgo, break; #endif case NEW_SA_MAJOR: - *hashAlgo = (byte)GetNewSAHashAlgo(input[1]); + { + enum wc_MACAlgorithm mac = GetNewSAHashAlgo(input[1]); + *hashAlgo = (byte)mac; + } /* PSS encryption: 0x080[4-6] */ if (input[1] >= RSA_PSS_RSAE_SHA256_MINOR && diff --git a/src/wolfio.c b/src/wolfio.c index 22a4e6ee6b..e438e8fe7f 100644 --- a/src/wolfio.c +++ b/src/wolfio.c @@ -3286,7 +3286,7 @@ int LwIPNativeSend(WOLFSSL* ssl, char* buf, int sz, void* ctx) err_t ret; WOLFSSL_LWIP_NATIVE_STATE* nlwip = (WOLFSSL_LWIP_NATIVE_STATE*)ctx; - if (sz > UINT16_MAX || sz < 0) { + if (sz < 0 || sz > (int)WOLFSSL_MAX_16BIT) { return BAD_FUNC_ARG; } From d673b62143f615a46e827833c581c31b0a031a92 Mon Sep 17 00:00:00 2001 From: night1rider Date: Wed, 22 Apr 2026 16:48:37 -0600 Subject: [PATCH 101/167] Fix double-free of she2 in she_test --- wolfcrypt/test/test.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index f1f08eba69..48f14f41c2 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -57626,6 +57626,9 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t she_test(void) ret = wc_SHE_Init(she2, HEAP_HINT, devId); if (ret != 0) { WC_FREE_VAR(she2, HEAP_HINT); + #ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC + she2 = NULL; + #endif goto exit_SHE_Test; } @@ -57639,6 +57642,9 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t she_test(void) if (ret != 0) { wc_SHE_Free(she2); WC_FREE_VAR(she2, HEAP_HINT); + #ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC + she2 = NULL; + #endif goto exit_SHE_Test; } @@ -57652,6 +57658,9 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t she_test(void) wc_SHE_Free(she2); WC_FREE_VAR(she2, HEAP_HINT); +#ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC + she2 = NULL; +#endif if (ret != 0) { goto exit_SHE_Test; From 8810160da72801d0059964f1a10f94df838cc728 Mon Sep 17 00:00:00 2001 From: Andrew Hutchings Date: Thu, 23 Apr 2026 06:47:49 +0100 Subject: [PATCH 102/167] ci: add PR commit message sanity check workflow Adds a GitHub Actions workflow that scans every commit in a pull request and fails if any commit message carries a Co-authored-by or Signed-off-by trailer pointing at noreply@anthropic.com. --- .github/workflows/pr-commit-check.yml | 41 +++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 .github/workflows/pr-commit-check.yml diff --git a/.github/workflows/pr-commit-check.yml b/.github/workflows/pr-commit-check.yml new file mode 100644 index 0000000000..bd989b1d48 --- /dev/null +++ b/.github/workflows/pr-commit-check.yml @@ -0,0 +1,41 @@ +name: PR commit message checks + +on: + pull_request: + branches: [ '**' ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +# END OF COMMON SECTION + +jobs: + commit-messages: + if: github.repository_owner == 'wolfssl' + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Reject AI attribution trailers + env: + BASE_SHA: ${{ github.event.pull_request.base.sha }} + HEAD_SHA: ${{ github.event.pull_request.head.sha }} + run: | + set -euo pipefail + fail=0 + while IFS= read -r sha; do + [ -z "$sha" ] && continue + if git log -1 --format=%B "$sha" | git interpret-trailers --parse | \ + grep -iE '^(Co-authored-by|Signed-off-by):.*?' >/dev/null; then + echo "::error::Commit $sha contains a Co-authored-by or Signed-off-by trailer for noreply@anthropic.com" + git log -1 --format=' %h %s' "$sha" + fail=1 + fi + done < <(git rev-list "$BASE_SHA".."$HEAD_SHA") + if [ "$fail" -ne 0 ]; then + echo "One or more commits contain disallowed AI attribution trailers; please amend them out." + exit 1 + fi + echo "No disallowed AI attribution trailers found." From 84fb0f694cfaac4187c0beba4298a4a8a7995235 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Mon, 13 Apr 2026 14:30:06 +0200 Subject: [PATCH 103/167] Fix various range and size bugs in PKCS#7 code --- tests/api.c | 102 ++++++++++++++++++++++++++++++++++++++++++ wolfcrypt/src/pkcs7.c | 64 +++++++++++++++++++++++--- 2 files changed, 159 insertions(+), 7 deletions(-) diff --git a/tests/api.c b/tests/api.c index db7b595522..7e20480484 100644 --- a/tests/api.c +++ b/tests/api.c @@ -35859,6 +35859,107 @@ static int test_pkcs7_ori_oversized_oid(void) return EXPECT_RESULT(); } +/* ORI callback that flags if oriValueSz looks like an underflow (>= 0x80000000) */ +#if defined(HAVE_PKCS7) && !defined(WOLFSSL_NO_MALLOC) +static int test_ori_underflow_cb(wc_PKCS7* pkcs7, byte* oriType, + word32 oriTypeSz, byte* oriValue, + word32 oriValueSz, byte* decryptedKey, + word32* decryptedKeySz, void* ctx) +{ + int* called = (int*)ctx; + (void)pkcs7; (void)oriType; (void)oriTypeSz; + (void)oriValue; (void)decryptedKey; (void)decryptedKeySz; + if (called != NULL) + *called = (int)oriValueSz; /* record what we received */ + return -1; +} +#endif + +/* Test: PKCS#7 ORI must reject when OID consumption exceeds the [4] implicit + * SEQUENCE length (integer underflow in oriValueSz computation). + * + * With implicit tagging, [4] CONSTRUCTED replaces the SEQUENCE tag, so + * wc_PKCS7_DecryptOri reads seqSz directly from the [4] length field. + * We set [4] length = 5 while the OID inside consumes 22 bytes + * (tag + length + 20 content), triggering oriValueSz = 5 - 22 = underflow. + * + * The buffer includes a dummy EncryptedContentInfo after the RecipientInfos + * so the total message is large enough for the PKCS7 streaming code (which + * requests the full remaining message before parsing the ORI). */ +static int test_pkcs7_ori_seqsz_underflow(void) +{ + EXPECT_DECLS; +#if defined(HAVE_PKCS7) && !defined(WOLFSSL_NO_MALLOC) + wc_PKCS7* p7 = NULL; + byte out[256]; + int cbCalled = 0; + + /* + * Byte layout (all outer lengths match actual byte counts on wire): + * + * OID inside [4]: 06 14 <20 bytes> = 22 bytes + * [4] (declared len 5, actual content 22): + * a4 05 <22 bytes> = 24 bytes on wire + * SET: 31 18 <24 bytes> = 26 bytes on wire + * version: 02 01 00 = 3 bytes + * EncryptedContentInfo (filler, never parsed): + * 30 0b { 06 09 <9 bytes OID> } = 13 bytes on wire + * EnvelopedData: 30 2a <3+26+13=42 bytes> = 44 bytes on wire + * [0] EXPLICIT: a0 2c <44 bytes> = 46 bytes on wire + * OID(envelopedData): 06 09 <9 bytes> = 11 bytes on wire + * ContentInfo: 30 39 <11+46=57 bytes> = 59 bytes total + */ + static const byte poc[] = { + /* ContentInfo SEQUENCE (length 57) */ + 0x30, 0x39, + /* contentType = envelopedData 1.2.840.113549.1.7.3 */ + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x03, + /* [0] EXPLICIT (length 44) */ + 0xa0, 0x2c, + /* EnvelopedData SEQUENCE (length 42) */ + 0x30, 0x2a, + /* version = 0 */ + 0x02, 0x01, 0x00, + /* RecipientInfos SET (length 24) */ + 0x31, 0x18, + /* [4] CONSTRUCTED = ORI implicit SEQUENCE, declared len 5 */ + /* Actual OID is 22 bytes -> exceeds declared 5 */ + 0xa4, 0x05, + /* OID: tag=06, len=0x14(20), content=20 bytes = 22 total */ + 0x06, 0x14, + 0x2a, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, + 0x12, 0x13, 0x14, 0x15, + /* EncryptedContentInfo SEQUENCE (length 11) - filler so + * streaming has enough data; never actually parsed because + * DecryptOri fails before we get here */ + 0x30, 0x0b, + /* contentType = data 1.2.840.113549.1.7.1 */ + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, + 0x01 + }; + + p7 = wc_PKCS7_New(NULL, INVALID_DEVID); + ExpectNotNull(p7); + if (p7 != NULL) { + wc_PKCS7_SetOriDecryptCb(p7, test_ori_underflow_cb); + wc_PKCS7_SetOriDecryptCtx(p7, &cbCalled); + + /* Must return an error before the callback sees an underflowed size */ + ExpectIntLT(wc_PKCS7_DecodeEnvelopedData(p7, (byte*)poc, sizeof(poc), + out, sizeof(out)), 0); + + /* The callback must NOT have been invoked with a wrapped oriValueSz. + * cbCalled == 0 means the callback was never reached (ideal). + * cbCalled < 0 would indicate the underflow was passed through. */ + ExpectIntGE(cbCalled, 0); + + wc_PKCS7_Free(p7); + } +#endif + return EXPECT_RESULT(); +} + /* Dilithium verify_ctx_msg must reject absurdly large msgLen */ static int test_dilithium_hash(void) { @@ -36800,6 +36901,7 @@ TEST_CASE testCases[] = { TEST_DECL(test_ed448_rejects_identity_key), TEST_DECL(test_pkcs7_decode_encrypted_outputsz), TEST_DECL(test_pkcs7_ori_oversized_oid), + TEST_DECL(test_pkcs7_ori_seqsz_underflow), TEST_DECL(test_pkcs7_padding), #if defined(WOLFSSL_SNIFFER) && defined(WOLFSSL_SNIFFER_CHAIN_INPUT) diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index 36b817ed51..7678bed965 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -10769,15 +10769,19 @@ static int wc_PKCS7_DecryptKtri(wc_PKCS7* pkcs7, byte* in, word32 inSz, if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; - if ((word32)keyIdSize > pkiMsgSz - (*idx)) + /* Validate SKID container and keyIdSize against buffer */ + if ((word32)length > pkiMsgSz - (*idx)) return BUFFER_E; + if (length < keyIdSize) + return ASN_PARSE_E; + /* if we found correct recipient, SKID will match */ if (XMEMCMP(pkiMsg + (*idx), pkcs7->issuerSubjKeyId, (word32)keyIdSize) == 0) { *recipFound = 1; } - (*idx) += (word32)keyIdSize; + (*idx) += (word32)length; } if (GetAlgoId(pkiMsg, idx, &encOID, oidKeyType, pkiMsgSz) < 0) @@ -11054,6 +11058,14 @@ static int wc_PKCS7_KariGetOriginatorIdentifierOrKey(WC_PKCS7_KARI* kari, if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; + /* BIT STRING must have at least unused-bits byte + 1 byte of content */ + if (length < 2) + return ASN_PARSE_E; + + /* Validate BIT STRING content is within input buffer */ + if (*idx > pkiMsgSz || (word32)length > pkiMsgSz - *idx) + return ASN_PARSE_E; + if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0) return ASN_EXPECT_0_E; @@ -11533,9 +11545,22 @@ static int wc_PKCS7_DecryptOri(wc_PKCS7* pkcs7, byte* in, word32 inSz, XMEMCPY(oriOID, pkiMsg + *idx, (word32)oriOIDSz); *idx += (word32)oriOIDSz; + /* Validate OID did not consume more than the SEQUENCE declared */ + if ((*idx - tmpIdx) > (word32)seqSz) { + WOLFSSL_MSG("ORI oriType OID exceeds SEQUENCE boundary"); + return ASN_PARSE_E; + } + /* get oriValue, increment idx */ oriValue = pkiMsg + *idx; oriValueSz = (word32)seqSz - (*idx - tmpIdx); + + /* Validate oriValue region is within input buffer */ + if (*idx > pkiMsgSz || oriValueSz > pkiMsgSz - *idx) { + WOLFSSL_MSG("ORI oriValue exceeds input buffer"); + return ASN_PARSE_E; + } + *idx += oriValueSz; /* pass oriOID and oriValue to user callback, expect back @@ -11713,6 +11738,12 @@ static int wc_PKCS7_DecryptPwri(wc_PKCS7* pkcs7, byte* in, word32 inSz, return ASN_PARSE_E; } + /* Validate IV is within input buffer */ + if (*idx > pkiMsgSz || (word32)length > pkiMsgSz - *idx) { + XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + return ASN_PARSE_E; + } + XMEMCPY(tmpIv, pkiMsg + (*idx), (word32)length); *idx += (word32)length; @@ -11732,6 +11763,12 @@ static int wc_PKCS7_DecryptPwri(wc_PKCS7* pkcs7, byte* in, word32 inSz, return ASN_PARSE_E; } + /* Validate EncryptedKey is within input buffer */ + if (*idx > pkiMsgSz || (word32)length > pkiMsgSz - *idx) { + XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + return ASN_PARSE_E; + } + /* allocate temporary space for decrypted key */ cekSz = (word32)length; cek = (byte*)XMALLOC(cekSz, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); @@ -11818,7 +11855,7 @@ static int wc_PKCS7_DecryptKekri(wc_PKCS7* pkcs7, byte* in, word32 inSz, byte* keyId = NULL; const byte* datePtr = NULL; byte dateFormat, tag; - word32 keyIdSz, kekIdSz, keyWrapOID, localIdx; + word32 keyIdSz, kekIdSz, kekIdEnd, keyWrapOID, localIdx; int ret = 0; byte* pkiMsg = in; @@ -11844,6 +11881,11 @@ static int wc_PKCS7_DecryptKekri(wc_PKCS7* pkcs7, byte* in, word32 inSz, return ASN_PARSE_E; kekIdSz = (word32)length; + kekIdEnd = *idx + kekIdSz; + + /* Validate KEKIdentifier boundary is within input buffer */ + if (kekIdEnd < *idx || kekIdEnd > pkiMsgSz) + return ASN_PARSE_E; if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0) return ASN_PARSE_E; @@ -11854,6 +11896,10 @@ static int wc_PKCS7_DecryptKekri(wc_PKCS7* pkcs7, byte* in, word32 inSz, if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; + /* Validate keyIdentifier is within input buffer */ + if (*idx > pkiMsgSz || (word32)length > pkiMsgSz - *idx) + return ASN_PARSE_E; + /* save keyIdentifier and length */ keyId = pkiMsg + *idx; keyIdSz = (word32)length; @@ -11861,10 +11907,10 @@ static int wc_PKCS7_DecryptKekri(wc_PKCS7* pkcs7, byte* in, word32 inSz, /* may have OPTIONAL GeneralizedTime */ localIdx = *idx; - if ((*idx < kekIdSz) && GetASNTag(pkiMsg, &localIdx, &tag, + if ((*idx < kekIdEnd) && GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz) == 0 && tag == ASN_GENERALIZED_TIME) { - if (wc_GetDateInfo(pkiMsg + *idx, (int)pkiMsgSz, &datePtr, - &dateFormat, &dateLen) != 0) { + if (wc_GetDateInfo(pkiMsg + *idx, (int)(pkiMsgSz - *idx), + &datePtr, &dateFormat, &dateLen) != 0) { return ASN_PARSE_E; } *idx += (word32)(dateLen + 1); @@ -11876,7 +11922,7 @@ static int wc_PKCS7_DecryptKekri(wc_PKCS7* pkcs7, byte* in, word32 inSz, /* may have OPTIONAL OtherKeyAttribute */ localIdx = *idx; - if ((*idx < kekIdSz) && GetASNTag(pkiMsg, &localIdx, &tag, + if ((*idx < kekIdEnd) && GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz) == 0 && tag == (ASN_SEQUENCE | ASN_CONSTRUCTED)) { if (GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0) @@ -11905,6 +11951,10 @@ static int wc_PKCS7_DecryptKekri(wc_PKCS7* pkcs7, byte* in, word32 inSz, if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; + /* Validate EncryptedKey is within input buffer */ + if (*idx > pkiMsgSz || (word32)length > pkiMsgSz - *idx) + return ASN_PARSE_E; + #ifndef NO_AES direction = AES_DECRYPTION; #else From e2167e4bbd021eb69305315098a18e3714095882 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Mon, 13 Apr 2026 15:52:56 +0200 Subject: [PATCH 104/167] add length check in PKCS#7 --- wolfcrypt/src/pkcs7.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index 7678bed965..622f23d228 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -14455,7 +14455,16 @@ int wc_PKCS7_DecodeAuthEnvelopedData(wc_PKCS7* pkcs7, byte* in, if (GetLength_ex(pkiMsg, &idx, &length, pkiMsgSz, 0) <= 0) { ret = ASN_PARSE_E; } - #ifndef NO_PKCS7_STREAM + + #ifdef NO_PKCS7_STREAM + /* In non-streaming mode, validate authenticatedAttributes + * length is within the input buffer. The streaming path + * handles this via wc_PKCS7_AddDataToStream instead. */ + if (ret == 0 && + (idx > pkiMsgSz || (word32)length > pkiMsgSz - idx)) { + ret = ASN_PARSE_E; + } + #else pkcs7->stream->expected = (word32)length; #endif encodedAttribSz = (word32)length + (idx - encodedAttribIdx); From 5634cfd67c3b04087a3839f564fbd111f0f8121b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Mon, 13 Apr 2026 15:53:35 +0200 Subject: [PATCH 105/167] Fix PKCS#7 regression with --enable-all and NO_PKCS7_STREAM --- tests/api/test_pkcs7.c | 34 ++++++++++++++++------------------ wolfcrypt/src/pkcs7.c | 11 ++++++----- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/tests/api/test_pkcs7.c b/tests/api/test_pkcs7.c index 3c8b59fb8e..cd9f7aa575 100644 --- a/tests/api/test_pkcs7.c +++ b/tests/api/test_pkcs7.c @@ -2397,7 +2397,8 @@ static int myCEKwrapFunc(PKCS7* pkcs7, byte* cek, word32 cekSz, byte* keyId, HAVE_AES_KEYWRAP */ -#if defined(HAVE_PKCS7) && defined(ASN_BER_TO_DER) && !defined(NO_RSA) +#if defined(HAVE_PKCS7) && defined(ASN_BER_TO_DER) && !defined(NO_RSA) && \ + !defined(NO_PKCS7_STREAM) #define MAX_TEST_DECODE_SIZE 6000 static int test_wc_PKCS7_DecodeEnvelopedData_stream_decrypt_cb(wc_PKCS7* pkcs7, const byte* output, word32 outputSz, void* ctx) { @@ -2430,7 +2431,8 @@ static int test_wc_PKCS7_DecodeEnvelopedData_stream_decrypt_cb(wc_PKCS7* pkcs7, int test_wc_PKCS7_DecodeEnvelopedData_stream(void) { EXPECT_DECLS; -#if defined(HAVE_PKCS7) && defined(ASN_BER_TO_DER) && !defined(NO_RSA) +#if defined(HAVE_PKCS7) && defined(ASN_BER_TO_DER) && !defined(NO_RSA) && \ + !defined(NO_PKCS7_STREAM) PKCS7* pkcs7 = NULL; int ret = 0; XFILE f = XBADFILE; @@ -2579,7 +2581,7 @@ int test_wc_PKCS7_EncodeDecodeEnvelopedData(void) EXPECT_DECLS; #if defined(HAVE_PKCS7) PKCS7* pkcs7 = NULL; -#ifdef ASN_BER_TO_DER +#if defined(ASN_BER_TO_DER) && !defined(NO_PKCS7_STREAM) int encodedSz = 0; #endif #ifdef ECC_TIMING_RESISTANT @@ -2784,7 +2786,7 @@ int test_wc_PKCS7_EncodeDecodeEnvelopedData(void) testSz = (int)sizeof(testVectors)/(int)sizeof(pkcs7EnvelopedVector); for (i = 0; i < testSz; i++) { - #ifdef ASN_BER_TO_DER + #if defined(ASN_BER_TO_DER) && !defined(NO_PKCS7_STREAM) encodeSignedDataStream strm; /* test setting stream mode, the first one using IO callbacks */ @@ -2950,17 +2952,11 @@ int test_wc_PKCS7_EncodeDecodeEnvelopedData(void) pkcs7->singleCert = NULL; } #ifndef NO_RSA - #if defined(NO_PKCS7_STREAM) - /* when none streaming mode is used and PKCS7 is in bad state buffer error - * is returned from kari parse which gets set to bad func arg */ - ExpectIntEQ(wc_PKCS7_DecodeEnvelopedData(pkcs7, output, - (word32)sizeof(output), decoded, (word32)sizeof(decoded)), - WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - #else + /* With corrupted singleCert, decode should fail with a parse error. + * State is properly reset on error so re-decode starts from scratch. */ ExpectIntEQ(wc_PKCS7_DecodeEnvelopedData(pkcs7, output, (word32)sizeof(output), decoded, (word32)sizeof(decoded)), WC_NO_ERR_TRACE(ASN_PARSE_E)); - #endif #endif /* !NO_RSA */ if (pkcs7 != NULL) { pkcs7->singleCert = tmpBytePtr; @@ -3991,7 +3987,8 @@ int test_wc_PKCS7_Degenerate(void) } /* END test_wc_PKCS7_Degenerate() */ #if defined(HAVE_PKCS7) && !defined(NO_FILESYSTEM) && \ - defined(ASN_BER_TO_DER) && !defined(NO_DES3) && !defined(NO_SHA) + defined(ASN_BER_TO_DER) && !defined(NO_DES3) && !defined(NO_SHA) && \ + !defined(NO_PKCS7_STREAM) static byte berContent[] = { 0x30, 0x80, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x03, 0xA0, 0x80, 0x30, @@ -4182,7 +4179,7 @@ static byte berContent[] = { 0x00, 0x00, 0x00, 0x00, 0x00 }; #endif /* HAVE_PKCS7 && !NO_FILESYSTEM && ASN_BER_TO_DER && - * !NO_DES3 && !NO_SHA + * !NO_DES3 && !NO_SHA && !NO_PKCS7_STREAM */ /* @@ -4197,7 +4194,7 @@ int test_wc_PKCS7_BER(void) char fName[] = "./certs/test-ber-exp02-05-2022.p7b"; XFILE f = XBADFILE; byte der[4096]; -#ifndef NO_DES3 +#if !defined(NO_DES3) && !defined(NO_PKCS7_STREAM) byte decoded[2048]; #endif word32 derSz = 0; @@ -4242,8 +4239,9 @@ int test_wc_PKCS7_BER(void) wc_PKCS7_Free(pkcs7); pkcs7 = NULL; -#ifndef NO_DES3 - /* decode BER content */ +#if !defined(NO_DES3) && !defined(NO_PKCS7_STREAM) + /* decode BER content - requires PKCS7 streaming to handle indefinite + * length encoding in the EnvelopedData structure */ ExpectTrue((f = XFOPEN("./certs/1024/client-cert.der", "rb")) != XBADFILE); ExpectTrue((derSz = (word32)XFREAD(der, 1, sizeof(der), f)) > 0); if (f != XBADFILE) { @@ -4280,7 +4278,7 @@ int test_wc_PKCS7_BER(void) sizeof(berContent), decoded, sizeof(decoded)), WC_NO_ERR_TRACE(NOT_COMPILED_IN)); #endif wc_PKCS7_Free(pkcs7); -#endif /* !NO_DES3 */ +#endif /* !NO_DES3 && !NO_PKCS7_STREAM */ #endif return EXPECT_RESULT(); } /* END test_wc_PKCS7_BER() */ diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index 622f23d228..e5a1987c56 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -10769,15 +10769,13 @@ static int wc_PKCS7_DecryptKtri(wc_PKCS7* pkcs7, byte* in, word32 inSz, if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; - /* Validate SKID container and keyIdSize against buffer */ + /* Validate SKID container is within buffer */ if ((word32)length > pkiMsgSz - (*idx)) return BUFFER_E; - if (length < keyIdSize) - return ASN_PARSE_E; - /* if we found correct recipient, SKID will match */ - if (XMEMCMP(pkiMsg + (*idx), pkcs7->issuerSubjKeyId, + if (length == keyIdSize && + XMEMCMP(pkiMsg + (*idx), pkcs7->issuerSubjKeyId, (word32)keyIdSize) == 0) { *recipFound = 1; } @@ -13400,6 +13398,9 @@ int wc_PKCS7_DecodeEnvelopedData(wc_PKCS7* pkcs7, byte* in, } } #else + if (ret < 0) { + wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START); + } if (decryptedKey != NULL && ret < 0) { ForceZero(decryptedKey, MAX_ENCRYPTED_KEY_SZ); XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); From 16e1d33f24959f3addaf9f58df737ed6edbfc81a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Mon, 13 Apr 2026 15:58:47 +0200 Subject: [PATCH 106/167] Fix invalid preprocessor guard in PKCS7 with SHA224 Also add missing ForceZero for ECDH shared secret on the heap. --- wolfcrypt/src/pkcs7.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index e5a1987c56..dcb33c7914 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -7782,7 +7782,7 @@ static int wc_PKCS7_KariGenerateKEK(WC_PKCS7_KARI* kari, WC_RNG* rng, kdfType = WC_HASH_TYPE_SHA; break; #endif - #ifndef WOLFSSL_SHA224 + #ifdef WOLFSSL_SHA224 case dhSinglePass_stdDH_sha224kdf_scheme: kdfType = WC_HASH_TYPE_SHA224; break; @@ -7804,6 +7804,7 @@ static int wc_PKCS7_KariGenerateKEK(WC_PKCS7_KARI* kari, WC_RNG* rng, #endif default: WOLFSSL_MSG("Unsupported key agreement algorithm"); + ForceZero(secret, secretSz); XFREE(secret, kari->heap, DYNAMIC_TYPE_PKCS7); return BAD_FUNC_ARG; }; @@ -7816,6 +7817,7 @@ static int wc_PKCS7_KariGenerateKEK(WC_PKCS7_KARI* kari, WC_RNG* rng, ret = NOT_COMPILED_IN; #endif + ForceZero(secret, secretSz); XFREE(secret, kari->heap, DYNAMIC_TYPE_PKCS7); return ret; } From 46f3ebb0c6fb4188fb348e1eedae0139f7119b87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Mon, 13 Apr 2026 16:20:55 +0200 Subject: [PATCH 107/167] Add missing ForceZero calls in PKCS#7 --- wolfcrypt/src/pkcs7.c | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index dcb33c7914..c27ce5e2b1 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -211,6 +211,9 @@ static void wc_PKCS7_ResetStream(wc_PKCS7* pkcs7) XFREE(pkcs7->stream->tag, pkcs7->heap, DYNAMIC_TYPE_PKCS7); XFREE(pkcs7->stream->nonce, pkcs7->heap, DYNAMIC_TYPE_PKCS7); XFREE(pkcs7->stream->buffer, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + /* stream->key is always allocated with MAX_ENCRYPTED_KEY_SZ */ + if (pkcs7->stream->key != NULL) + ForceZero(pkcs7->stream->key, MAX_ENCRYPTED_KEY_SZ); XFREE(pkcs7->stream->key, pkcs7->heap, DYNAMIC_TYPE_PKCS7); pkcs7->stream->aad = NULL; pkcs7->stream->tag = NULL; @@ -7770,6 +7773,7 @@ static int wc_PKCS7_KariGenerateKEK(WC_PKCS7_KARI* kari, WC_RNG* rng, } if (ret != 0) { + ForceZero(secret, secretSz); XFREE(secret, kari->heap, DYNAMIC_TYPE_PKCS7); return ret; } @@ -9763,6 +9767,7 @@ int wc_PKCS7_AddRecipient_PWRI(wc_PKCS7* pkcs7, byte* passwd, word32 pLen, (word32)kekKeySz); if (ret < 0) { XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + ForceZero(kek, (word32)kekKeySz); XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7); XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return ret; @@ -9774,6 +9779,7 @@ int wc_PKCS7_AddRecipient_PWRI(wc_PKCS7* pkcs7, byte* passwd, word32 pLen, tmpIv, (word32)kekBlockSz, encryptOID); if (ret < 0) { XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + ForceZero(kek, (word32)kekKeySz); XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7); XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return ret; @@ -9798,6 +9804,7 @@ int wc_PKCS7_AddRecipient_PWRI(wc_PKCS7* pkcs7, byte* passwd, word32 pLen, ret = wc_SetContentType(PWRI_KEK_WRAP, keyEncAlgoId, sizeof(keyEncAlgoId)); if (ret <= 0) { XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + ForceZero(kek, (word32)kekKeySz); XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7); XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return ret; @@ -9829,6 +9836,7 @@ int wc_PKCS7_AddRecipient_PWRI(wc_PKCS7* pkcs7, byte* passwd, word32 pLen, ret = wc_SetContentType(kdfOID, kdfAlgoId, sizeof(kdfAlgoId)); if (ret <= 0) { XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + ForceZero(kek, (word32)kekKeySz); XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7); XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return ret; @@ -9854,6 +9862,7 @@ int wc_PKCS7_AddRecipient_PWRI(wc_PKCS7* pkcs7, byte* passwd, word32 pLen, if (totalSz > MAX_RECIP_SZ) { WOLFSSL_MSG("CMS Recipient output buffer too small"); XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + ForceZero(kek, (word32)kekKeySz); XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7); XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return BUFFER_E; @@ -9891,7 +9900,7 @@ int wc_PKCS7_AddRecipient_PWRI(wc_PKCS7* pkcs7, byte* passwd, word32 pLen, XMEMCPY(recip->recip + idx, encryptedKey, encryptedKeySz); idx += encryptedKeySz; - ForceZero(kek, (word32)kekBlockSz); + ForceZero(kek, (word32)kekKeySz); ForceZero(encryptedKey, encryptedKeySz); XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7); XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); @@ -10612,7 +10621,9 @@ static int wc_PKCS7_DecryptKtri(wc_PKCS7* pkcs7, byte* in, word32 inSz, word32 pkiMsgSz = inSz; byte tag; - +#ifndef WC_NO_RSA_OAEP + word32 outKeySz = 0; +#endif #ifndef NO_PKCS7_STREAM word32 tmpIdx = *idx; #endif @@ -10921,8 +10932,8 @@ static int wc_PKCS7_DecryptKtri(wc_PKCS7* pkcs7, byte* in, word32 inSz, #ifndef WC_NO_RSA_OAEP } else { - word32 outLen = (word32)wc_RsaEncryptSize(privKey); - outKey = (byte*)XMALLOC(outLen, pkcs7->heap, + outKeySz = (word32)wc_RsaEncryptSize(privKey); + outKey = (byte*)XMALLOC(outKeySz, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); if (!outKey) { WOLFSSL_MSG("Failed to allocate out key buffer"); @@ -10936,9 +10947,9 @@ static int wc_PKCS7_DecryptKtri(wc_PKCS7* pkcs7, byte* in, word32 inSz, } keySz = wc_RsaPrivateDecrypt_ex(encryptedKey, - (word32)encryptedKeySz, outKey, outLen, privKey, - WC_RSA_OAEP_PAD, - WC_HASH_TYPE_SHA, WC_MGF1SHA1, NULL, 0); + (word32)encryptedKeySz, outKey, outKeySz, + privKey, WC_RSA_OAEP_PAD, WC_HASH_TYPE_SHA, + WC_MGF1SHA1, NULL, 0); } #endif } @@ -10961,6 +10972,7 @@ static int wc_PKCS7_DecryptKtri(wc_PKCS7* pkcs7, byte* in, word32 inSz, #ifndef WC_NO_RSA_OAEP if (encOID == RSAESOAEPk) { if (outKey) { + ForceZero(outKey, outKeySz); XFREE(outKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); } } @@ -10977,6 +10989,7 @@ static int wc_PKCS7_DecryptKtri(wc_PKCS7* pkcs7, byte* in, word32 inSz, #ifndef WC_NO_RSA_OAEP if (encOID == RSAESOAEPk) { if (outKey) { + ForceZero(outKey, outKeySz); XFREE(outKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); } } @@ -11791,6 +11804,7 @@ static int wc_PKCS7_DecryptPwri(wc_PKCS7* pkcs7, byte* in, word32 inSz, iterations, kek, (word32)kekKeySz); if (ret < 0) { XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + ForceZero(kek, (word32)kekKeySz); XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7); XFREE(cek, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return ASN_PARSE_E; @@ -11803,7 +11817,9 @@ static int wc_PKCS7_DecryptPwri(wc_PKCS7* pkcs7, byte* in, word32 inSz, pwriEncAlgoId); if (ret < 0) { XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + ForceZero(kek, (word32)kekKeySz); XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + ForceZero(cek, cekSz); XFREE(cek, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return ret; } @@ -11812,7 +11828,9 @@ static int wc_PKCS7_DecryptPwri(wc_PKCS7* pkcs7, byte* in, word32 inSz, if (*decryptedKeySz < cekSz) { WOLFSSL_MSG("Decrypted key buffer too small for CEK"); XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + ForceZero(kek, (word32)kekKeySz); XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + ForceZero(cek, cekSz); XFREE(cek, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return BUFFER_E; } @@ -11821,7 +11839,9 @@ static int wc_PKCS7_DecryptPwri(wc_PKCS7* pkcs7, byte* in, word32 inSz, *decryptedKeySz = cekSz; XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + ForceZero(kek, (word32)kekKeySz); XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + ForceZero(cek, cekSz); XFREE(cek, pkcs7->heap, DYNAMIC_TYPE_PKCS7); /* mark recipFound, since we only support one RecipientInfo for now */ From 4e423fde170608e67db623b3d9b10f3a489e00ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Tue, 14 Apr 2026 13:51:28 +0200 Subject: [PATCH 108/167] More PKCS#7 bounds checks --- wolfcrypt/src/pkcs7.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index c27ce5e2b1..ec7fd317d2 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -7046,6 +7046,9 @@ static int PKCS7_VerifySignedData(wc_PKCS7* pkcs7, const byte* hashBuf, idx += (word32)length; } + else if (ret == 0) { + ret = ASN_PARSE_E; + } pkcs7->content = content; pkcs7->contentSz = (word32)contentSz; @@ -9626,7 +9629,7 @@ static int wc_PKCS7_PwriKek_KeyUnWrap(wc_PKCS7* pkcs7, const byte* kek, cekLen = outTmp[0]; /* verify length */ - fail |= ctMaskGT(cekLen, (int)inSz); + fail |= ctMaskGT(cekLen, (int)inSz - 4); /* verify check bytes */ fail |= ctMaskNotEq((int)(outTmp[1] ^ outTmp[4]), 0xFF); fail |= ctMaskNotEq((int)(outTmp[2] ^ outTmp[5]), 0xFF); @@ -11933,7 +11936,9 @@ static int wc_PKCS7_DecryptKekri(wc_PKCS7* pkcs7, byte* in, word32 inSz, &datePtr, &dateFormat, &dateLen) != 0) { return ASN_PARSE_E; } - *idx += (word32)(dateLen + 1); + /* datePtr points to the start of the date value + * within pkiMsg; advance past the full TLV. */ + *idx = (word32)(datePtr - pkiMsg) + (word32)dateLen; } if (*idx > pkiMsgSz) { @@ -13102,6 +13107,14 @@ int wc_PKCS7_DecodeEnvelopedData(wc_PKCS7* pkcs7, byte* in, ret = ASN_PARSE_E; } + #ifdef NO_PKCS7_STREAM + if (ret == 0 && encryptedContentTotalSz > (int)(pkiMsgSz - idx)) { + /* In non-streaming mode, ensure the content fits in the buffer. + * Streaming mode handles this via AddDataToStream. */ + ret = BUFFER_E; + } + #endif + if (ret != 0) break; @@ -15355,6 +15368,12 @@ int wc_PKCS7_DecodeEncryptedData(wc_PKCS7* pkcs7, byte* in, word32 inSz, pkiMsgSz, NO_USER_CHECK) <= 0) ret = ASN_PARSE_E; +#ifdef NO_PKCS7_STREAM + if (ret == 0 && encryptedContentSz > (int)(pkiMsgSz - idx)) { + ret = BUFFER_E; + } +#endif + if (ret < 0) break; #ifndef NO_PKCS7_STREAM @@ -15392,7 +15411,8 @@ int wc_PKCS7_DecodeEncryptedData(wc_PKCS7* pkcs7, byte* in, word32 inSz, version = (int)pkcs7->stream->vers; tmpIv = pkcs7->stream->tmpIv; #endif - if (encryptedContentSz <= 0) { + if (encryptedContentSz <= 0 || + encryptedContentSz > (int)(pkiMsgSz - idx)) { ret = BUFFER_E; break; } From 3fd4060458baf3feb558bc935d2dc248aa62675a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Tue, 14 Apr 2026 14:23:17 +0200 Subject: [PATCH 109/167] Add more PKCS#7 tests --- tests/api.c | 605 +++++++++++++++++++++++++++++++++++++++++ tests/api/test_pkcs7.c | 5 + 2 files changed, 610 insertions(+) diff --git a/tests/api.c b/tests/api.c index 7e20480484..eca1ba38f1 100644 --- a/tests/api.c +++ b/tests/api.c @@ -35960,6 +35960,605 @@ static int test_pkcs7_ori_seqsz_underflow(void) return EXPECT_RESULT(); } +/* Test: PKCS#7 ORI must reject when seqSz extends oriValue past input buffer. + * + * The first ORI bounds check (OID exceeds SEQUENCE boundary) is covered by + * test_pkcs7_ori_seqsz_underflow. This test covers the *second* check: + * oriValue region extends past the end of the input buffer. We craft a + * message where the [4] SEQUENCE length is valid relative to the OID + * (OID fits inside it), but the remaining oriValue portion extends past + * the end of the actual input buffer. + * + * To bypass GetLength's own bounds validation, we set the outer lengths + * (EnvelopedData SEQUENCE, RecipientInfos SET) to match the [4] claim, + * but truncate the actual buffer we pass to DecodeEnvelopedData. */ +static int test_pkcs7_ori_orivalue_overflow(void) +{ + EXPECT_DECLS; +#if defined(HAVE_PKCS7) && !defined(WOLFSSL_NO_MALLOC) + wc_PKCS7* p7 = NULL; + byte out[256]; + + /* EnvelopedData with [4] ORI whose seqSz (40) is valid for the OID + * (6 bytes consumed) but oriValueSz (34) extends past the truncated + * input buffer. + * + * Layout: + * ContentInfo SEQUENCE + * OID envelopedData + * [0] EXPLICIT + * EnvelopedData SEQUENCE + * version = 0 + * RecipientInfos SET + * [4] CONSTRUCTED (seqSz = 40) + * OID (tag 06, len 04, 4 content bytes = 6 total) + * oriValue should be 34 bytes but input is truncated + * EncryptedContentInfo (filler for streaming) + * + * We pass the full array to DecodeEnvelopedData, but the actual + * input ends before [4]'s declared 40 bytes are consumed. + */ + static const byte poc[] = { + /* ContentInfo SEQUENCE */ + 0x30, 0x43, + /* contentType = envelopedData 1.2.840.113549.1.7.3 */ + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x03, + /* [0] EXPLICIT */ + 0xa0, 0x36, + /* EnvelopedData SEQUENCE */ + 0x30, 0x34, + /* version = 0 */ + 0x02, 0x01, 0x00, + /* RecipientInfos SET (len = 44 covers [4] tag+len+40) */ + 0x31, 0x2c, + /* [4] CONSTRUCTED = ORI implicit SEQUENCE, seqSz = 40 */ + 0xa4, 0x28, + /* OID: tag=06, len=04, 4 content bytes = 6 total */ + 0x06, 0x04, 0x2a, 0x03, 0x04, 0x05, + /* Only 4 bytes of oriValue here, but seqSz claims 34 more */ + 0x00, 0x00, 0x00, 0x00, + /* EncryptedContentInfo SEQUENCE (filler) */ + 0x30, 0x0b, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, + 0x01 + }; + + p7 = wc_PKCS7_New(NULL, INVALID_DEVID); + ExpectNotNull(p7); + if (p7 != NULL) { + wc_PKCS7_SetOriDecryptCb(p7, test_dummy_ori_cb); + + /* Must return error - oriValue extends past input buffer */ + ExpectIntLT(wc_PKCS7_DecodeEnvelopedData(p7, (byte*)poc, sizeof(poc), + out, sizeof(out)), 0); + + wc_PKCS7_Free(p7); + } +#endif + return EXPECT_RESULT(); +} + +/* Test: PKCS#7 KTRI must not match recipient when SKID length differs + * from expected keyIdSize. + * + * The fix adds a `length == keyIdSize` check before comparing the SKID + * bytes. Without this check, XMEMCMP could compare against data beyond + * the SKID content. This test crafts a KTRI RecipientInfo where the + * [0] SubjectKeyIdentifier has length 5 instead of KEYID_SIZE (20). + * The decode must return an error (no matching recipient). */ +static int test_pkcs7_ktri_skid_length_mismatch(void) +{ + EXPECT_DECLS; +#if defined(HAVE_PKCS7) && !defined(NO_RSA) && !defined(WOLFSSL_NO_MALLOC) + wc_PKCS7* p7 = NULL; + byte out[256]; + + /* Minimal EnvelopedData with KTRI using version=2 (SKID path). + * The SKID [0] has length 5 instead of 20. + * + * ContentInfo SEQUENCE + * OID envelopedData + * [0] EXPLICIT + * EnvelopedData SEQUENCE + * version = 2 + * RecipientInfos SET + * KTRI SEQUENCE + * version = 2 + * [0] SKID (5 bytes, should be 20) + * AlgorithmIdentifier (RSA OID) + * OCTET STRING (fake encrypted key) + * EncryptedContentInfo (filler) + */ + static const byte poc[] = { + /* ContentInfo SEQUENCE */ + 0x30, 0x46, + /* contentType = envelopedData 1.2.840.113549.1.7.3 */ + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x03, + /* [0] EXPLICIT */ + 0xa0, 0x39, + /* EnvelopedData SEQUENCE */ + 0x30, 0x37, + /* version = 2 (triggers SKID-based recipient identification) */ + 0x02, 0x01, 0x02, + /* RecipientInfos SET */ + 0x31, 0x21, + /* KTRI SEQUENCE */ + 0x30, 0x1f, + /* version = 2 (SKID) */ + 0x02, 0x01, 0x02, + /* [0] IMPLICIT SubjectKeyIdentifier, length = 5 (wrong!) */ + 0x80, 0x05, 0x01, 0x02, 0x03, 0x04, 0x05, + /* AlgorithmIdentifier: RSA 1.2.840.113549.1.1.1 */ + 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x01, + 0x05, 0x00, /* NULL params */ + /* encryptedKey OCTET STRING (2 bytes fake) */ + 0x04, 0x02, 0xAA, 0xBB, + /* EncryptedContentInfo SEQUENCE (filler) */ + 0x30, 0x0b, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, + 0x01 + }; + + p7 = wc_PKCS7_New(NULL, INVALID_DEVID); + ExpectNotNull(p7); + if (p7 != NULL) { + /* Decode without a cert - SKID will never match, and the + * mismatched SKID length must not cause out-of-bounds reads */ + ExpectIntLT(wc_PKCS7_DecodeEnvelopedData(p7, (byte*)poc, sizeof(poc), + out, sizeof(out)), 0); + + wc_PKCS7_Free(p7); + } +#endif + return EXPECT_RESULT(); +} + +/* Test: PKCS#7 KARI must reject BIT STRING with length < 2 in + * OriginatorPublicKey. + * + * The fix adds `if (length < 2) return ASN_PARSE_E` after parsing + * the BIT STRING tag and length. A BIT STRING must have at least + * the unused-bits byte plus one byte of content. This test crafts + * a KARI [1] RecipientInfo where the OriginatorPublicKey's BIT STRING + * has length 1 (degenerate). The PKCS7 object is initialized with a + * real ECC cert so that KariParseRecipCert succeeds and parsing reaches + * the BIT STRING validation. */ +static int test_pkcs7_kari_degenerate_bitstring(void) +{ + EXPECT_DECLS; +#if defined(HAVE_PKCS7) && defined(HAVE_ECC) && defined(HAVE_X963_KDF) && \ + !defined(WOLFSSL_NO_MALLOC) + wc_PKCS7* p7 = NULL; + byte out[256]; + byte* eccCert = NULL; + byte* eccPrivKey = NULL; + word32 eccCertSz = 0; + word32 eccPrivKeySz = 0; +#if !defined(USE_CERT_BUFFERS_256) && !defined(NO_FILESYSTEM) + XFILE f = XBADFILE; +#endif + + /* Minimal EnvelopedData with KARI [1] containing a degenerate + * BIT STRING (length 1) in OriginatorPublicKey. + * + * ContentInfo SEQUENCE + * OID envelopedData + * [0] EXPLICIT + * EnvelopedData SEQUENCE + * version = 2 + * RecipientInfos SET + * [1] CONSTRUCTED (KARI) + * version = 3 + * [0] CONSTRUCTED (OriginatorIdentifierOrKey) + * [1] CONSTRUCTED (OriginatorPublicKey) + * AlgorithmIdentifier (ECDSAk) + * BIT STRING length=1 (degenerate!) + * EncryptedContentInfo (filler) + */ + static const byte poc[] = { + /* ContentInfo SEQUENCE */ + 0x30, 0x44, + /* contentType = envelopedData 1.2.840.113549.1.7.3 */ + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x03, + /* [0] EXPLICIT */ + 0xa0, 0x37, + /* EnvelopedData SEQUENCE */ + 0x30, 0x35, + /* version = 2 */ + 0x02, 0x01, 0x02, + /* RecipientInfos SET */ + 0x31, 0x1f, + /* [1] CONSTRUCTED (KARI implicit) */ + 0xa1, 0x1d, + /* version = 3 */ + 0x02, 0x01, 0x03, + /* [0] CONSTRUCTED (OriginatorIdentifierOrKey) */ + 0xa0, 0x18, + /* [1] CONSTRUCTED (OriginatorPublicKey) */ + 0xa1, 0x16, + /* AlgorithmIdentifier SEQUENCE */ + 0x30, 0x13, + /* OID: id-ecPublicKey 1.2.840.10045.2.1 */ + 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, + /* OID: prime256v1 1.2.840.10045.3.1.7 */ + 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, + 0x01, 0x07, + /* BIT STRING with length 1 - degenerate! */ + 0x03, 0x01, 0x00, + /* EncryptedContentInfo SEQUENCE (filler) */ + 0x30, 0x0b, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, + 0x01 + }; + + /* Load ECC cert and key so KariParseRecipCert succeeds and + * parsing reaches the BIT STRING check */ +#ifdef USE_CERT_BUFFERS_256 + eccCertSz = (word32)sizeof_cliecc_cert_der_256; + ExpectNotNull(eccCert = (byte*)XMALLOC(eccCertSz, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER)); + if (eccCert != NULL) + XMEMCPY(eccCert, cliecc_cert_der_256, eccCertSz); + eccPrivKeySz = (word32)sizeof_ecc_clikey_der_256; + ExpectNotNull(eccPrivKey = (byte*)XMALLOC(eccPrivKeySz, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER)); + if (eccPrivKey != NULL) + XMEMCPY(eccPrivKey, ecc_clikey_der_256, eccPrivKeySz); +#elif !defined(NO_FILESYSTEM) + eccCertSz = FOURK_BUF; + ExpectNotNull(eccCert = (byte*)XMALLOC(eccCertSz, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER)); + ExpectTrue((f = XFOPEN("./certs/client-ecc-cert.der", "rb")) != XBADFILE); + ExpectTrue((eccCertSz = (word32)XFREAD(eccCert, 1, eccCertSz, f)) > 0); + if (f != XBADFILE) { + XFCLOSE(f); + f = XBADFILE; + } + eccPrivKeySz = FOURK_BUF; + ExpectNotNull(eccPrivKey = (byte*)XMALLOC(eccPrivKeySz, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER)); + ExpectTrue((f = XFOPEN("./certs/ecc-client-key.der", "rb")) != XBADFILE); + ExpectTrue((eccPrivKeySz = (word32)XFREAD(eccPrivKey, 1, eccPrivKeySz, + f)) > 0); + if (f != XBADFILE) + XFCLOSE(f); +#else + eccCert = NULL; + eccCertSz = 0; + eccPrivKey = NULL; + eccPrivKeySz = 0; +#endif + + p7 = wc_PKCS7_New(HEAP_HINT, INVALID_DEVID); + ExpectNotNull(p7); + if (p7 != NULL && eccCert != NULL) { + ExpectIntEQ(wc_PKCS7_InitWithCert(p7, eccCert, eccCertSz), 0); + if (p7 != NULL) { + p7->privateKey = eccPrivKey; + p7->privateKeySz = eccPrivKeySz; + } + + /* Must return error - BIT STRING length < 2 is invalid */ + ExpectIntLT(wc_PKCS7_DecodeEnvelopedData(p7, (byte*)poc, sizeof(poc), + out, sizeof(out)), 0); + + if (p7 != NULL) { + p7->privateKey = NULL; + p7->privateKeySz = 0; + } + wc_PKCS7_Free(p7); + } + else if (p7 != NULL) { + wc_PKCS7_Free(p7); + } + + XFREE(eccCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(eccPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return EXPECT_RESULT(); +} + +/* Test: PKCS#7 EncryptedData must reject when encryptedContentSz exceeds + * the remaining input buffer. + * + * The fix adds `encryptedContentSz > (int)(pkiMsgSz - idx)` to the + * existing `encryptedContentSz <= 0` check in stage 6. This test crafts + * a minimal EncryptedData where the [0] IMPLICIT content length claims + * 0x200 (512) bytes but only 32 bytes of ciphertext are present. */ +static int test_pkcs7_encrypted_content_size_overflow(void) +{ + EXPECT_DECLS; +#if defined(HAVE_PKCS7) && !defined(NO_AES) && defined(HAVE_AES_CBC) && \ + defined(WOLFSSL_AES_256) && !defined(NO_PKCS7_ENCRYPTED_DATA) && \ + !defined(WOLFSSL_NO_MALLOC) + wc_PKCS7* p7 = NULL; + byte key[32]; + byte out[256]; + + /* EncryptedData with [0] content claiming 512 bytes but only 32 present. + * + * ContentInfo SEQUENCE + * OID encryptedData (1.2.840.113549.1.7.6) + * [0] EXPLICIT + * EncryptedData SEQUENCE + * version = 0 + * EncryptedContentInfo SEQUENCE + * OID data (1.2.840.113549.1.7.1) + * AlgorithmIdentifier + * OID AES-256-CBC (2.16.840.1.101.3.4.1.42) + * OCTET STRING IV (16 zero bytes) + * [0] IMPLICIT content (claimed len=0x200, actual=32 bytes) + */ + static const byte poc[] = { + /* ContentInfo SEQUENCE (len covers entire message) */ + 0x30, 0x50, + /* OID encryptedData 1.2.840.113549.1.7.6 */ + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x06, + /* [0] EXPLICIT */ + 0xa0, 0x43, + /* EncryptedData SEQUENCE */ + 0x30, 0x41, + /* version = 0 */ + 0x02, 0x01, 0x00, + /* EncryptedContentInfo SEQUENCE */ + 0x30, 0x3c, + /* OID data 1.2.840.113549.1.7.1 */ + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, + 0x01, + /* AlgorithmIdentifier SEQUENCE */ + 0x30, 0x1d, + /* OID AES-256-CBC 2.16.840.1.101.3.4.1.42 */ + 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, + 0x2a, + /* IV: OCTET STRING (16 zero bytes) */ + 0x04, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* [0] IMPLICIT encryptedContent - claims 512 bytes! + * Only 16 bytes of fake ciphertext follow. */ + 0x80, 0x82, 0x02, 0x00, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA + }; + + XMEMSET(key, 0, sizeof(key)); + + p7 = wc_PKCS7_New(NULL, INVALID_DEVID); + ExpectNotNull(p7); + if (p7 != NULL) { + p7->encryptionKey = key; + p7->encryptionKeySz = sizeof(key); + + /* Must return error - content extends past input buffer */ + ExpectIntLT(wc_PKCS7_DecodeEncryptedData(p7, (byte*)poc, sizeof(poc), + out, sizeof(out)), 0); + + wc_PKCS7_Free(p7); + } +#endif + return EXPECT_RESULT(); +} + +/* Test: PKCS#7 SignedData must reject when the signature field is not + * an OCTET STRING. + * + * The fix adds `else if (ret == 0) { ret = ASN_PARSE_E; }` so that + * when the tag at the signature position is not ASN_OCTET_STRING, + * parsing returns an error instead of silently continuing with no + * signature. This test encodes a valid SignedData, then corrupts + * the signature OCTET STRING tag and verifies that decode fails. */ +static int test_pkcs7_signed_bad_sig_tag(void) +{ + EXPECT_DECLS; +#if defined(HAVE_PKCS7) && !defined(NO_RSA) && !defined(NO_SHA256) && \ + !defined(WOLFSSL_NO_MALLOC) + PKCS7* pkcs7 = NULL; + WC_RNG rng; + byte encoded[FOURK_BUF]; + int encodedSz = 0; + int i; + byte* rsaCert = NULL; + byte* rsaPrivKey = NULL; + word32 rsaCertSz = 0; + word32 rsaPrivKeySz = 0; +#if !defined(USE_CERT_BUFFERS_2048) && !defined(USE_CERT_BUFFERS_1024) && \ + !defined(NO_FILESYSTEM) + XFILE f = XBADFILE; +#endif + + const byte data[] = "Test signed data"; + + XMEMSET(&rng, 0, sizeof(WC_RNG)); + + /* Load RSA cert and key */ +#if defined(USE_CERT_BUFFERS_2048) + rsaCertSz = (word32)sizeof_client_cert_der_2048; + ExpectNotNull(rsaCert = (byte*)XMALLOC(rsaCertSz, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER)); + if (rsaCert != NULL) + XMEMCPY(rsaCert, client_cert_der_2048, rsaCertSz); + rsaPrivKeySz = (word32)sizeof_client_key_der_2048; + ExpectNotNull(rsaPrivKey = (byte*)XMALLOC(rsaPrivKeySz, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER)); + if (rsaPrivKey != NULL) + XMEMCPY(rsaPrivKey, client_key_der_2048, rsaPrivKeySz); +#elif defined(USE_CERT_BUFFERS_1024) + rsaCertSz = (word32)sizeof_client_cert_der_1024; + ExpectNotNull(rsaCert = (byte*)XMALLOC(rsaCertSz, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER)); + if (rsaCert != NULL) + XMEMCPY(rsaCert, client_cert_der_1024, rsaCertSz); + rsaPrivKeySz = (word32)sizeof_client_key_der_1024; + ExpectNotNull(rsaPrivKey = (byte*)XMALLOC(rsaPrivKeySz, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER)); + if (rsaPrivKey != NULL) + XMEMCPY(rsaPrivKey, client_key_der_1024, rsaPrivKeySz); +#elif !defined(NO_FILESYSTEM) + rsaCertSz = FOURK_BUF; + ExpectNotNull(rsaCert = (byte*)XMALLOC(rsaCertSz, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER)); + ExpectTrue((f = XFOPEN("./certs/client-cert.der", "rb")) != XBADFILE); + ExpectTrue((rsaCertSz = (word32)XFREAD(rsaCert, 1, rsaCertSz, f)) > 0); + if (f != XBADFILE) { XFCLOSE(f); f = XBADFILE; } + rsaPrivKeySz = FOURK_BUF; + ExpectNotNull(rsaPrivKey = (byte*)XMALLOC(rsaPrivKeySz, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER)); + ExpectTrue((f = XFOPEN("./certs/client-key.der", "rb")) != XBADFILE); + ExpectTrue((rsaPrivKeySz = (word32)XFREAD(rsaPrivKey, 1, + rsaPrivKeySz, f)) > 0); + if (f != XBADFILE) XFCLOSE(f); +#else + rsaCert = NULL; rsaCertSz = 0; + rsaPrivKey = NULL; rsaPrivKeySz = 0; +#endif + + if (rsaCert == NULL || rsaPrivKey == NULL) { + XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + return TEST_SKIPPED; + } + + ExpectIntEQ(wc_InitRng(&rng), 0); + + /* Encode a valid SignedData */ + ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId)); + ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, rsaCert, rsaCertSz), 0); + if (pkcs7 != NULL) { + pkcs7->content = (byte*)data; + pkcs7->contentSz = (word32)sizeof(data); + pkcs7->contentOID = DATA; + pkcs7->hashOID = SHA256h; + pkcs7->encryptOID = RSAk; + pkcs7->privateKey = rsaPrivKey; + pkcs7->privateKeySz = rsaPrivKeySz; + pkcs7->rng = &rng; + } + + ExpectIntGT(encodedSz = wc_PKCS7_EncodeSignedData(pkcs7, encoded, + sizeof(encoded)), 0); + wc_PKCS7_Free(pkcs7); + pkcs7 = NULL; + + /* Find the signature OCTET STRING tag (0x04) near the end of the + * encoded message and corrupt it. The signature is the last large + * OCTET STRING in the SignerInfo. Search backwards for 0x04 followed + * by a length that looks like an RSA signature (>= 64 bytes). + * This heuristic depends on the signature being the last large + * OCTET STRING; the found==1 assertion below guards against + * silent false passes if encoding changes. */ + if (EXPECT_SUCCESS()) { + int found = 0; + for (i = encodedSz - 10; i > 10; i--) { + if (encoded[i] == 0x04) { + int len = 0, lbytes = 0; + if (encoded[i+1] < 0x80) { + len = encoded[i+1]; lbytes = 1; + } + else if (encoded[i+1] == 0x81) { + len = encoded[i+2]; lbytes = 2; + } + else if (encoded[i+1] == 0x82) { + len = (encoded[i+2] << 8) | encoded[i+3]; lbytes = 3; + } + /* RSA signature is typically >= 128 bytes */ + if (len >= 64 && i + 1 + lbytes + len <= encodedSz) { + /* Corrupt the OCTET STRING tag to INTEGER */ + encoded[i] = 0x02; /* ASN_INTEGER instead of OCTET STRING */ + found = 1; + break; + } + } + } + ExpectIntEQ(found, 1); + } + + /* Verify the corrupted SignedData - must fail */ + if (EXPECT_SUCCESS()) { + ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId)); + ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, NULL, 0), 0); + ExpectIntLT(wc_PKCS7_VerifySignedData(pkcs7, encoded, + (word32)encodedSz), 0); + wc_PKCS7_Free(pkcs7); + pkcs7 = NULL; + } + + DoExpectIntEQ(wc_FreeRng(&rng), 0); + XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return EXPECT_RESULT(); +} + +/* Test: PKCS#7 EnvelopedData must reject when encryptedContentTotalSz + * exceeds the remaining input buffer. + * + * The fix adds a bounds check under NO_PKCS7_STREAM, but the same + * crafted message should also be properly handled in streaming mode. + * This test crafts an EnvelopedData where the [0] content length + * claims 512 bytes but only minimal data follows. */ +static int test_pkcs7_enveloped_content_size_overflow(void) +{ + EXPECT_DECLS; +#if defined(HAVE_PKCS7) && !defined(WOLFSSL_NO_MALLOC) && !defined(NO_RSA) + wc_PKCS7* p7 = NULL; + byte out[256]; + + /* EnvelopedData with KTRI where the EncryptedContentInfo [0] claims + * 512 bytes but only 16 are present. + * + * The outer structure is valid enough to reach the content parsing: + * ContentInfo -> EnvelopedData -> version=0 -> + * RecipientInfos (empty SET) -> EncryptedContentInfo -> + * contentType + AlgorithmIdentifier + [0] oversized content */ + static const byte poc[] = { + /* ContentInfo SEQUENCE */ + 0x30, 0x50, + /* OID envelopedData 1.2.840.113549.1.7.3 */ + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x03, + /* [0] EXPLICIT */ + 0xa0, 0x43, + /* EnvelopedData SEQUENCE */ + 0x30, 0x41, + /* version = 0 */ + 0x02, 0x01, 0x00, + /* RecipientInfos SET (empty - no recipients) */ + 0x31, 0x00, + /* EncryptedContentInfo SEQUENCE */ + 0x30, 0x3c, + /* OID data 1.2.840.113549.1.7.1 */ + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, + 0x01, + /* AlgorithmIdentifier SEQUENCE */ + 0x30, 0x1d, + /* OID AES-256-CBC 2.16.840.1.101.3.4.1.42 */ + 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, + 0x2a, + /* IV: OCTET STRING (16 zero bytes) */ + 0x04, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* [0] IMPLICIT encryptedContent - claims 512 bytes! */ + 0x80, 0x82, 0x02, 0x00, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA + }; + + p7 = wc_PKCS7_New(NULL, INVALID_DEVID); + ExpectNotNull(p7); + if (p7 != NULL) { + /* With an empty RecipientInfos SET, the function may fail at + * the recipient matching stage before reaching the content-size + * bounds check. The ExpectIntLT assertion ensures the + * oversized content does not cause a buffer over-read. */ + ExpectIntLT(wc_PKCS7_DecodeEnvelopedData(p7, (byte*)poc, sizeof(poc), + out, sizeof(out)), 0); + + wc_PKCS7_Free(p7); + } +#endif + return EXPECT_RESULT(); +} + /* Dilithium verify_ctx_msg must reject absurdly large msgLen */ static int test_dilithium_hash(void) { @@ -36902,6 +37501,12 @@ TEST_CASE testCases[] = { TEST_DECL(test_pkcs7_decode_encrypted_outputsz), TEST_DECL(test_pkcs7_ori_oversized_oid), TEST_DECL(test_pkcs7_ori_seqsz_underflow), + TEST_DECL(test_pkcs7_ori_orivalue_overflow), + TEST_DECL(test_pkcs7_ktri_skid_length_mismatch), + TEST_DECL(test_pkcs7_kari_degenerate_bitstring), + TEST_DECL(test_pkcs7_encrypted_content_size_overflow), + TEST_DECL(test_pkcs7_signed_bad_sig_tag), + TEST_DECL(test_pkcs7_enveloped_content_size_overflow), TEST_DECL(test_pkcs7_padding), #if defined(WOLFSSL_SNIFFER) && defined(WOLFSSL_SNIFFER_CHAIN_INPUT) diff --git a/tests/api/test_pkcs7.c b/tests/api/test_pkcs7.c index cd9f7aa575..646db1bdb8 100644 --- a/tests/api/test_pkcs7.c +++ b/tests/api/test_pkcs7.c @@ -2763,6 +2763,11 @@ int test_wc_PKCS7_EncodeDecodeEnvelopedData(void) AES128CBCb, AES128_WRAP, dhSinglePass_stdDH_sha1kdf_scheme, eccCert, eccCertSz, eccPrivKey, eccPrivKeySz}, #endif + #if defined(WOLFSSL_SHA224) && defined(WOLFSSL_AES_128) + {(byte*)input, (word32)(sizeof(input)/sizeof(char)), DATA, + AES128CBCb, AES128_WRAP, dhSinglePass_stdDH_sha224kdf_scheme, + eccCert, eccCertSz, eccPrivKey, eccPrivKeySz}, + #endif #if !defined(NO_SHA256) && defined(WOLFSSL_AES_256) {(byte*)input, (word32)(sizeof(input)/sizeof(char)), DATA, AES256CBCb, AES256_WRAP, dhSinglePass_stdDH_sha256kdf_scheme, From 589feabc0cb13a1747139cb1fdef5b6d26ed4baf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Tue, 14 Apr 2026 18:04:12 +0200 Subject: [PATCH 110/167] Harden PKCS#7 EnvelopedData key unwrap --- .wolfssl_known_macro_extras | 1 + tests/api/test_pkcs7.c | 251 +++++++++++++++++++++++++++++++++++- tests/api/test_pkcs7.h | 21 +++ wolfcrypt/src/pkcs7.c | 250 ++++++++++++++++++++++++++++++++++- 4 files changed, 510 insertions(+), 13 deletions(-) diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 3943d47739..cd06d68a1f 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -829,6 +829,7 @@ WOLFSSL_NO_KCAPI_HMAC_SHA256 WOLFSSL_NO_KCAPI_HMAC_SHA384 WOLFSSL_NO_KCAPI_HMAC_SHA512 WOLFSSL_NO_KCAPI_SHA224 +WOLFSSL_NO_KTRI_ORACLE_WARNING WOLFSSL_NO_OCSP_DATE_CHECK WOLFSSL_NO_OCSP_ISSUER_CHAIN_CHECK WOLFSSL_NO_OCSP_OPTIONAL_CERTS diff --git a/tests/api/test_pkcs7.c b/tests/api/test_pkcs7.c index 646db1bdb8..a22fd9e10e 100644 --- a/tests/api/test_pkcs7.c +++ b/tests/api/test_pkcs7.c @@ -1118,6 +1118,229 @@ int test_wc_PKCS7_EnvelopedData_KTRI_RSA_PSS(void) #endif +/* + * Bleichenbacher padding-oracle regression: wc_PKCS7_DecryptKtri must not + * return a distinguishable error when RSA PKCS#1 v1.5 unwrap of the + * encrypted CEK fails vs. when it succeeds with a wrong key. The + * mitigation substitutes a deterministic pseudo-random CEK on RSA failure + * so content decryption fails indistinguishably. This test corrupts the + * encryptedKey in a valid EnvelopedData and asserts the error matches + * content corruption rather than surfacing an RSA/recipient-level code. + * Runs for AES-128 and AES-256 because the fake CEK is a fixed 32 bytes: + * AES-128 (key size 16) exercises the path where the fake size differs + * from the real CEK size. + */ +#if defined(HAVE_PKCS7) && !defined(NO_RSA) && !defined(NO_SHA256) && \ + !defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_128) && \ + defined(WOLFSSL_AES_256) && !defined(NO_HMAC) && \ + !defined(WOLFSSL_NO_MALLOC) && \ + (defined(USE_CERT_BUFFERS_2048) || defined(USE_CERT_BUFFERS_1024) || \ + !defined(NO_FILESYSTEM)) +static int pkcs7_ktri_bad_pad_case(int encryptOID, byte* rsaCert, + word32 rsaCertSz, byte* rsaPrivKey, + word32 rsaPrivKeySz, byte* encrypted, + word32 encryptedCap, byte* decoded, + word32 decodedCap) +{ + EXPECT_DECLS; + PKCS7* pkcs7 = NULL; + byte data[] = "PKCS7 KTRI bad-RSA-padding regression payload."; + int encryptedSz = 0; + int badKeyRet = 0; + int badContentRet = 0; + byte savedKeyByte = 0; + byte savedContentByte = 0; + word32 i; + word32 encryptedKeyOff = 0; + static const byte rsaEncOid[] = { + 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, + 0x01, 0x01, 0x01 + }; + + ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId)); + ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, rsaCert, rsaCertSz), 0); + if (pkcs7 != NULL) { + pkcs7->content = data; + pkcs7->contentSz = (word32)sizeof(data); + pkcs7->contentOID = DATA; + pkcs7->encryptOID = encryptOID; + } + ExpectIntGT(encryptedSz = wc_PKCS7_EncodeEnvelopedData(pkcs7, + encrypted, encryptedCap), 0); + wc_PKCS7_Free(pkcs7); + pkcs7 = NULL; + + /* Locate the KTRI encryptedKey OCTET STRING. After the rsaEncryption + * OID there are NULL algorithm parameters (05 00), then a 256-byte + * OCTET STRING (tag 04, long-form length 82 01 00 for RSA-2048). */ + for (i = 0; (int)(i + sizeof(rsaEncOid)) < encryptedSz; i++) { + if (XMEMCMP(&encrypted[i], rsaEncOid, sizeof(rsaEncOid)) == 0) { + word32 p = i + (word32)sizeof(rsaEncOid); + if (p + 2 < (word32)encryptedSz && + encrypted[p] == 0x05 && encrypted[p + 1] == 0x00) { + p += 2; + } + if (p + 4 < (word32)encryptedSz && encrypted[p] == 0x04) { + if (encrypted[p + 1] == 0x82) { + encryptedKeyOff = p + 4; + } + else if (encrypted[p + 1] == 0x81) { + encryptedKeyOff = p + 3; + } + else { + encryptedKeyOff = p + 2; + } + } + break; + } + } + ExpectIntGT(encryptedKeyOff, 0); + ExpectIntLT(encryptedKeyOff + 32, (word32)encryptedSz); + + /* Case 1: corrupt a byte inside the RSA ciphertext, decode, restore. */ + savedKeyByte = encrypted[encryptedKeyOff + 16]; + encrypted[encryptedKeyOff + 16] ^= 0xA5; + + ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId)); + ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, rsaCert, rsaCertSz), 0); + if (pkcs7 != NULL) { + pkcs7->privateKey = rsaPrivKey; + pkcs7->privateKeySz = rsaPrivKeySz; + } + badKeyRet = wc_PKCS7_DecodeEnvelopedData(pkcs7, encrypted, + (word32)encryptedSz, decoded, decodedCap); + wc_PKCS7_Free(pkcs7); + pkcs7 = NULL; + encrypted[encryptedKeyOff + 16] = savedKeyByte; + + /* Case 2: corrupt a byte in the second-to-last AES ciphertext block. + * In CBC mode this deterministically XOR-flips the corresponding byte + * in the last plaintext block, invalidating the PKCS#7 padding + * (original pad byte 0x01 becomes 0x01^0xA5 = 0xA4 > blockSz). + * Corrupting the last ciphertext block directly would randomize the + * entire last plaintext block, giving ~1/256 chance of accidentally + * valid padding and intermittent test failures. */ + savedContentByte = encrypted[encryptedSz - 17]; + encrypted[encryptedSz - 17] ^= 0xA5; + + ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId)); + ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, rsaCert, rsaCertSz), 0); + if (pkcs7 != NULL) { + pkcs7->privateKey = rsaPrivKey; + pkcs7->privateKeySz = rsaPrivKeySz; + } + badContentRet = wc_PKCS7_DecodeEnvelopedData(pkcs7, encrypted, + (word32)encryptedSz, decoded, decodedCap); + wc_PKCS7_Free(pkcs7); + pkcs7 = NULL; + encrypted[encryptedSz - 17] = savedContentByte; + + /* Case 2 must always fail: the CBC-chain corruption deterministically + * invalidates the PKCS#7 padding. */ + ExpectIntLT(badContentRet, 0); + /* Bad-key must NOT leak as an RSA- or recipient-level error. */ + ExpectIntNE(badKeyRet, WC_NO_ERR_TRACE(PKCS7_RECIP_E)); + ExpectIntNE(badKeyRet, WC_NO_ERR_TRACE(RSA_PAD_E)); + ExpectIntNE(badKeyRet, WC_NO_ERR_TRACE(RSA_BUFFER_E)); + ExpectIntNE(badKeyRet, WC_NO_ERR_TRACE(BAD_PADDING_E)); + /* Case 1 (bad RSA key) decrypts content with a random fake CEK, + * producing fully random plaintext. With ~1/256 probability the + * PKCS#7 padding accidentally looks valid, causing a positive + * garbage-length return instead of an error. This does not leak + * RSA key information, so it is acceptable. When both cases do + * fail, verify they fail at the same content-decryption layer. */ + if (badKeyRet < 0) { + ExpectIntEQ(badKeyRet, badContentRet); + } + + return EXPECT_RESULT(); +} + +int test_wc_PKCS7_EnvelopedData_KTRI_BadRsaPad(void) +{ + EXPECT_DECLS; + byte encrypted[FOURK_BUF]; + byte decoded[FOURK_BUF]; + byte* rsaCert = NULL; + byte* rsaPrivKey = NULL; + word32 rsaCertSz = 0; + word32 rsaPrivKeySz = 0; +#if !defined(USE_CERT_BUFFERS_1024) && !defined(USE_CERT_BUFFERS_2048) && \ + !defined(NO_FILESYSTEM) + XFILE f = XBADFILE; +#endif + + /* Load RSA cert and key */ +#if defined(USE_CERT_BUFFERS_1024) + rsaCertSz = (word32)sizeof_client_cert_der_1024; + ExpectNotNull(rsaCert = (byte*)XMALLOC(rsaCertSz, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER)); + if (rsaCert != NULL) + XMEMCPY(rsaCert, client_cert_der_1024, rsaCertSz); + rsaPrivKeySz = (word32)sizeof_client_key_der_1024; + ExpectNotNull(rsaPrivKey = (byte*)XMALLOC(rsaPrivKeySz, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER)); + if (rsaPrivKey != NULL) + XMEMCPY(rsaPrivKey, client_key_der_1024, rsaPrivKeySz); +#elif defined(USE_CERT_BUFFERS_2048) + rsaCertSz = (word32)sizeof_client_cert_der_2048; + ExpectNotNull(rsaCert = (byte*)XMALLOC(rsaCertSz, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER)); + if (rsaCert != NULL) + XMEMCPY(rsaCert, client_cert_der_2048, rsaCertSz); + rsaPrivKeySz = (word32)sizeof_client_key_der_2048; + ExpectNotNull(rsaPrivKey = (byte*)XMALLOC(rsaPrivKeySz, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER)); + if (rsaPrivKey != NULL) + XMEMCPY(rsaPrivKey, client_key_der_2048, rsaPrivKeySz); +#elif !defined(NO_FILESYSTEM) + rsaCertSz = FOURK_BUF; + ExpectNotNull(rsaCert = (byte*)XMALLOC(rsaCertSz, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER)); + ExpectTrue((f = XFOPEN("./certs/client-cert.der", "rb")) != XBADFILE); + ExpectTrue((rsaCertSz = (word32)XFREAD(rsaCert, 1, rsaCertSz, f)) > 0); + if (f != XBADFILE) { + XFCLOSE(f); + f = XBADFILE; + } + rsaPrivKeySz = FOURK_BUF; + ExpectNotNull(rsaPrivKey = (byte*)XMALLOC(rsaPrivKeySz, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER)); + ExpectTrue((f = XFOPEN("./certs/client-key.der", "rb")) != XBADFILE); + ExpectTrue((rsaPrivKeySz = (word32)XFREAD(rsaPrivKey, 1, + rsaPrivKeySz, f)) > 0); + if (f != XBADFILE) + XFCLOSE(f); +#endif + + if (rsaCert == NULL || rsaPrivKey == NULL) { + XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + return TEST_SKIPPED; + } + + /* AES-128: 32-byte fake CEK larger than real CEK size (16 bytes). */ + ExpectIntEQ(pkcs7_ktri_bad_pad_case(AES128CBCb, rsaCert, rsaCertSz, + rsaPrivKey, rsaPrivKeySz, encrypted, sizeof(encrypted), + decoded, sizeof(decoded)), TEST_SUCCESS); +#ifdef WOLFSSL_AES_192 + /* AES-192: fake CEK (32) vs real CEK (24) - another size mismatch. */ + ExpectIntEQ(pkcs7_ktri_bad_pad_case(AES192CBCb, rsaCert, rsaCertSz, + rsaPrivKey, rsaPrivKeySz, encrypted, sizeof(encrypted), + decoded, sizeof(decoded)), TEST_SUCCESS); +#endif + /* AES-256: fake CEK size matches real CEK size (32 bytes). */ + ExpectIntEQ(pkcs7_ktri_bad_pad_case(AES256CBCb, rsaCert, rsaCertSz, + rsaPrivKey, rsaPrivKeySz, encrypted, sizeof(encrypted), + decoded, sizeof(decoded)), TEST_SUCCESS); + + XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + return EXPECT_RESULT(); +} /* END test_wc_PKCS7_EnvelopedData_KTRI_BadRsaPad */ +#endif + + /* * Testing wc_PKCS7_EncodeSignedData_ex() and wc_PKCS7_VerifySignedData_ex() */ @@ -2503,6 +2726,8 @@ int test_wc_PKCS7_DecodeEnvelopedData_multiple_recipients(void) bytes */ size_t testDerBufferSz = 0; byte decodedData[8192]; + byte serverDecodedData[8192]; + int serverRet = 0; ExpectTrue((f = XFOPEN(testFile, "rb")) != XBADFILE); if (f != XBADFILE) { @@ -2522,12 +2747,13 @@ int test_wc_PKCS7_DecodeEnvelopedData_multiple_recipients(void) ExpectIntEQ(wc_PKCS7_SetKey(pkcs7, (byte*)server_key_der_2048, sizeof_server_key_der_2048), 0); - ret = wc_PKCS7_DecodeEnvelopedData(pkcs7, testDerBuffer, - (word32)testDerBufferSz, decodedData, sizeof(decodedData)); + serverRet = wc_PKCS7_DecodeEnvelopedData(pkcs7, testDerBuffer, + (word32)testDerBufferSz, serverDecodedData, + sizeof(serverDecodedData)); #if defined(NO_AES) || defined(NO_AES_256) - ExpectIntEQ(ret, ALGO_ID_E); + ExpectIntEQ(serverRet, ALGO_ID_E); #else - ExpectIntGT(ret, 0); + ExpectIntGT(serverRet, 0); #endif wc_PKCS7_Free(pkcs7); pkcs7 = NULL; @@ -2553,7 +2779,14 @@ int test_wc_PKCS7_DecodeEnvelopedData_multiple_recipients(void) pkcs7 = NULL; } - /* test with ca cert recipient (which should fail) */ + /* Test with ca cert recipient. The ca cert is not a listed recipient, + * so RSA unwrap fails. The Bleichenbacher mitigation substitutes a + * pseudo-random fake CEK on unwrap failure, so the call normally + * returns a negative error when content decryption rejects the + * resulting garbage padding - but around 1/256 of the time the random + * CEK yields plaintext with accidentally-valid PKCS#7 padding and the + * call returns a non-negative "decrypted" size. That case must not + * produce the real plaintext. */ ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId)); if (pkcs7) { ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, (byte*)ca_cert_der_2048, @@ -2562,9 +2795,15 @@ int test_wc_PKCS7_DecodeEnvelopedData_multiple_recipients(void) ExpectIntEQ(wc_PKCS7_SetKey(pkcs7, (byte*)ca_key_der_2048, sizeof_ca_key_der_2048), 0); + XMEMSET(decodedData, 0, sizeof(decodedData)); ret = wc_PKCS7_DecodeEnvelopedData(pkcs7, testDerBuffer, (word32)testDerBufferSz, decodedData, sizeof(decodedData)); - ExpectIntLT(ret, 0); + #if defined(NO_AES) || defined(NO_AES_256) + ExpectIntEQ(ret, ALGO_ID_E); + #else + ExpectTrue(ret < 0 || ret != serverRet || + XMEMCMP(decodedData, serverDecodedData, (size_t)ret) != 0); + #endif wc_PKCS7_Free(pkcs7); pkcs7 = NULL; } diff --git a/tests/api/test_pkcs7.h b/tests/api/test_pkcs7.h index 084744d43c..e1c71c911d 100644 --- a/tests/api/test_pkcs7.h +++ b/tests/api/test_pkcs7.h @@ -38,6 +38,14 @@ int test_wc_PKCS7_EncodeSignedData_RSA_PSS(void); !defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_256) int test_wc_PKCS7_EnvelopedData_KTRI_RSA_PSS(void); #endif +#if defined(HAVE_PKCS7) && !defined(NO_RSA) && !defined(NO_SHA256) && \ + !defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_128) && \ + defined(WOLFSSL_AES_256) && !defined(NO_HMAC) && \ + !defined(WOLFSSL_NO_MALLOC) && \ + (defined(USE_CERT_BUFFERS_2048) || defined(USE_CERT_BUFFERS_1024) || \ + !defined(NO_FILESYSTEM)) +int test_wc_PKCS7_EnvelopedData_KTRI_BadRsaPad(void); +#endif int test_wc_PKCS7_EncodeSignedData_ex(void); int test_wc_PKCS7_VerifySignedData_RSA(void); int test_wc_PKCS7_VerifySignedData_ECC(void); @@ -82,6 +90,18 @@ int test_wc_PKCS7_VerifySignedData_IndefLenOOB(void); #define TEST_PKCS7_RSA_PSS_ED_DECL #endif +#if defined(HAVE_PKCS7) && !defined(NO_RSA) && !defined(NO_SHA256) && \ + !defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_128) && \ + defined(WOLFSSL_AES_256) && !defined(NO_HMAC) && \ + !defined(WOLFSSL_NO_MALLOC) && \ + (defined(USE_CERT_BUFFERS_2048) || defined(USE_CERT_BUFFERS_1024) || \ + !defined(NO_FILESYSTEM)) +#define TEST_PKCS7_KTRI_BADRSAPAD_DECL \ + TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_EnvelopedData_KTRI_BadRsaPad), +#else +#define TEST_PKCS7_KTRI_BADRSAPAD_DECL +#endif + #define TEST_PKCS7_SIGNED_DATA_DECLS \ TEST_DECL_GROUP("pkcs7_sd", test_wc_PKCS7_InitWithCert), \ TEST_DECL_GROUP("pkcs7_sd", test_wc_PKCS7_EncodeData), \ @@ -100,6 +120,7 @@ int test_wc_PKCS7_VerifySignedData_IndefLenOOB(void); TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_DecodeEnvelopedData_stream), \ TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_EncodeDecodeEnvelopedData), \ TEST_PKCS7_RSA_PSS_ED_DECL \ + TEST_PKCS7_KTRI_BADRSAPAD_DECL \ TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_SetAESKeyWrapUnwrapCb), \ TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_GetEnvelopedDataKariRid), \ TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_EncodeEncryptedData), \ diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index ec7fd317d2..5d1a25bb31 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -44,6 +44,9 @@ #include #include +#ifndef NO_HMAC + #include +#endif #ifndef NO_RSA #include #endif @@ -207,6 +210,8 @@ static void wc_PKCS7_ResetStream(wc_PKCS7* pkcs7) #endif /* free any buffers that may be allocated */ + if (pkcs7->stream->aad != NULL && pkcs7->stream->aadSz > 0) + ForceZero(pkcs7->stream->aad, pkcs7->stream->aadSz); XFREE(pkcs7->stream->aad, pkcs7->heap, DYNAMIC_TYPE_PKCS7); XFREE(pkcs7->stream->tag, pkcs7->heap, DYNAMIC_TYPE_PKCS7); XFREE(pkcs7->stream->nonce, pkcs7->heap, DYNAMIC_TYPE_PKCS7); @@ -7741,6 +7746,9 @@ static int wc_PKCS7_KariGenerateKEK(WC_PKCS7_KARI* kari, WC_RNG* rng, secret = (byte*)XMALLOC(secretSz, kari->heap, DYNAMIC_TYPE_PKCS7); if (secret == NULL) return MEMORY_E; +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("wc_PKCS7_KariGenerateKEK secret", secret, secretSz); +#endif #if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \ (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION != 2))) && \ @@ -10608,6 +10616,81 @@ int wc_PKCS7_EncodeEnvelopedData(wc_PKCS7* pkcs7, byte* output, word32 outputSz) } #ifndef NO_RSA +#if !defined(NO_HMAC) && !defined(NO_SHA256) +/* Bleichenbacher padding-oracle mitigation for PKCS#7/CMS KTRI: produce a + * WC_SHA256_DIGEST_SIZE-byte pseudo-random CEK derived from a fresh + * random seed and the encrypted-key ciphertext. The output is random per + * call (driven by the RNG seed); deriving via HMAC of the ciphertext + * simply gives the same value within one call regardless of where it is + * referenced. Called unconditionally so the work is in the timing path + * regardless of RSA padding validity. */ +static int wc_PKCS7_KtriFakeCEK(wc_PKCS7* pkcs7, const byte* encryptedKey, + word32 encryptedKeySz, byte* out) +{ + int ret; + byte seed[WC_SHA256_DIGEST_SIZE]; + WC_RNG* rng = NULL; + int ownRng = 0; + WC_DECLARE_VAR(localRng, WC_RNG, 1, pkcs7->heap); + WC_DECLARE_VAR(hmac, Hmac, 1, pkcs7->heap); + + if (pkcs7 == NULL || encryptedKey == NULL || out == NULL) { + return BAD_FUNC_ARG; + } + + WC_ALLOC_VAR_EX(hmac, Hmac, 1, pkcs7->heap, DYNAMIC_TYPE_HMAC, + return MEMORY_E); + + /* Prefer a caller-provided RNG to avoid paying a DRBG init/reseed cost + * on every decrypt (and to keep the timing envelope flatter on FIPS / + * HW-RNG builds). Fall back to a one-shot RNG when pkcs7->rng is not + * set. */ + if (pkcs7->rng != NULL) { + rng = pkcs7->rng; + } + else { + WC_ALLOC_VAR_EX(localRng, WC_RNG, 1, pkcs7->heap, DYNAMIC_TYPE_RNG, + WC_FREE_VAR_EX(hmac, pkcs7->heap, DYNAMIC_TYPE_HMAC); + return MEMORY_E); + ret = wc_InitRng_ex(localRng, pkcs7->heap, pkcs7->devId); + if (ret != 0) { + WC_FREE_VAR_EX(localRng, pkcs7->heap, DYNAMIC_TYPE_RNG); + WC_FREE_VAR_EX(hmac, pkcs7->heap, DYNAMIC_TYPE_HMAC); + return ret; + } + rng = localRng; + ownRng = 1; + } + + ret = wc_RNG_GenerateBlock(rng, seed, (word32)sizeof(seed)); + + if (ownRng) { + wc_FreeRng(localRng); + WC_FREE_VAR_EX(localRng, pkcs7->heap, DYNAMIC_TYPE_RNG); + } + + if (ret != 0) { + WC_FREE_VAR_EX(hmac, pkcs7->heap, DYNAMIC_TYPE_HMAC); + return ret; + } + + ret = wc_HmacInit(hmac, pkcs7->heap, pkcs7->devId); + if (ret == 0) { + ret = wc_HmacSetKey(hmac, WC_SHA256, seed, (word32)sizeof(seed)); + if (ret == 0) { + ret = wc_HmacUpdate(hmac, encryptedKey, encryptedKeySz); + } + if (ret == 0) { + ret = wc_HmacFinal(hmac, out); + } + wc_HmacFree(hmac); + } + ForceZero(seed, sizeof(seed)); + WC_FREE_VAR_EX(hmac, pkcs7->heap, DYNAMIC_TYPE_HMAC); + return ret; +} +#endif /* !NO_HMAC && !NO_SHA256 */ + /* decode KeyTransRecipientInfo (ktri), return 0 on success, <0 on error */ static int wc_PKCS7_DecryptKtri(wc_PKCS7* pkcs7, byte* in, word32 inSz, word32* idx, byte* decryptedKey, @@ -10967,25 +11050,146 @@ static int wc_PKCS7_DecryptKtri(wc_PKCS7* pkcs7, byte* in, word32 inSz, } wc_FreeRsaKey(privKey); + #if !defined(NO_HMAC) && !defined(NO_SHA256) + { + /* Bleichenbacher padding-oracle mitigation: always compute + * a pseudo-random fallback CEK so timing and error + * behaviour do not depend on RSA padding validity. On + * unwrap failure we substitute the fallback and let + * content decryption fail indistinguishably from "unwrap + * succeeded but CEK is wrong". */ + byte fakeKey[WC_SHA256_DIGEST_SIZE]; + int fakeRet = wc_PKCS7_KtriFakeCEK(pkcs7, encryptedKey, + (word32)encryptedKeySz, + fakeKey); + + if (fakeRet != 0) { + /* Fallback generation failed (e.g. RNG/HMAC error). + * Return the fallback-generation status, which does + * not depend on RSA padding validity, rather than the + * RSA status which would re-open the oracle. */ + ForceZero(fakeKey, sizeof(fakeKey)); + /* In the non-OAEP path RSA is decrypted in-place via + * wc_RsaPrivateDecryptInline, so encryptedKey holds + * the (possibly valid) plaintext CEK. Zero it before + * free. */ + ForceZero(encryptedKey, (word32)encryptedKeySz); + XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT); + WC_FREE_VAR_EX(privKey, pkcs7->heap, + DYNAMIC_TYPE_TMP_BUFFER); + #ifndef WC_NO_RSA_OAEP + if (encOID == RSAESOAEPk) { + if (outKey != NULL) { + ForceZero(outKey, outKeySz); + XFREE(outKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + } + } + #endif + return fakeRet; + } + + /* Constant-time select between fake and real CEK. On RSA + * failure outKey may be NULL or keySz may be <= 0; in + * both cases the mask selects fakeKey for every byte. + * + * To avoid data-dependent branches that leak realLen, + * copy the real key into a fixed-size zero-padded buffer + * first, then select byte-by-byte in constant time. */ + { + word32 i; + byte useFake; + int realLen = keySz; + byte realPad[WC_SHA256_DIGEST_SIZE]; + + XMEMSET(realPad, 0, sizeof(realPad)); + /* Constant-time copy: avoid data-dependent branches + * that could leak whether RSA padding was valid. + * When outKey is NULL (inline RSA failure), use + * encryptedKey as a safe readable source; the mask + * will zero out all bytes anyway. Both encryptedKey + * and outKey (when non-NULL) are at least + * sizeof(realPad) bytes for any RSA key size. + * + * Use constant-time pointer selection to avoid + * branching on outKey nullity, which would leak + * whether RSA PKCS#1 v1.5 padding was valid. */ + { + byte haveSrc = ctMaskGTE(realLen, 1); + const byte* srcTbl[2]; + const byte* src; + word32 j = 0; + word32 safeJ = 0; + + /* Select source without integer pointer synthesis. + * Some safety-oriented compilers (e.g. Fil-C) treat + * int-to-pointer reconstruction as a null-object + * pointer on dereference. */ + srcTbl[0] = encryptedKey; + srcTbl[1] = outKey; + src = srcTbl[haveSrc & 1]; + + /* safeJ is clamped to max(0, realLen-1): it + * only advances while the next index would + * still be inside realLen, so src[safeJ] is + * always in bounds. Bytes at j >= realLen are + * masked to zero by inBounds anyway. */ + for (j = 0; j < (word32)sizeof(realPad); j++) { + byte inBounds = ctMaskLT((int)j, realLen); + byte advance = ctMaskLT((int)(safeJ + 1), + realLen); + realPad[j] = src[safeJ] & haveSrc & inBounds; + safeJ += (word32)(advance & 1); + } + } + useFake = ctMaskLT(realLen, 1); /* 0xFF if realLen<=0 */ + + for (i = 0; i < (word32)sizeof(fakeKey); i++) { + decryptedKey[i] = ctMaskSel(useFake, fakeKey[i], + realPad[i]); + } + /* Report the real key size on success; on RSA + * failure (realLen <= 0) report sizeof(fakeKey). + * Constant-time select avoids branching on RSA + * padding validity. */ + *decryptedKeySz = (word32)ctMaskSelInt(useFake, + (int)sizeof(fakeKey), realLen); + ForceZero(realPad, sizeof(realPad)); + } + ForceZero(fakeKey, sizeof(fakeKey)); + /* In the non-OAEP path RSA is decrypted in-place via + * wc_RsaPrivateDecryptInline, so encryptedKey holds the + * plaintext CEK after the unwrap. Zero it before free. */ + ForceZero(encryptedKey, (word32)encryptedKeySz); + } + #else /* NO_HMAC || NO_SHA256: mitigation unavailable */ + #if !defined(WOLFSSL_NO_KTRI_ORACLE_WARNING) + #warning "PKCS7 KTRI Bleichenbacher mitigation requires HMAC " \ + "and SHA256; build without them leaves the RSA unwrap " \ + "error path observable to callers. " \ + "Define WOLFSSL_NO_KTRI_ORACLE_WARNING to silence." + #endif + if (keySz <= 0 || outKey == NULL) { ForceZero(encryptedKey, (word32)encryptedKeySz); XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT); WC_FREE_VAR_EX(privKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - #ifndef WC_NO_RSA_OAEP + #ifndef WC_NO_RSA_OAEP if (encOID == RSAESOAEPk) { if (outKey) { ForceZero(outKey, outKeySz); XFREE(outKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); } } - #endif + #endif return keySz; - } else { + } + else { *decryptedKeySz = (word32)keySz; XMEMCPY(decryptedKey, outKey, (word32)keySz); ForceZero(encryptedKey, (word32)encryptedKeySz); } + #endif /* !NO_HMAC && !NO_SHA256 */ XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT); WC_FREE_VAR_EX(privKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); @@ -12888,6 +13092,11 @@ int wc_PKCS7_DecodeEnvelopedData(wc_PKCS7* pkcs7, byte* in, DYNAMIC_TYPE_PKCS7); if (decryptedKey == NULL) return MEMORY_E; + XMEMSET(decryptedKey, 0, MAX_ENCRYPTED_KEY_SZ); + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("wc_PKCS7 decryptedKey", decryptedKey, + MAX_ENCRYPTED_KEY_SZ); + #endif wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_ENV_2); tmpIdx = idx; recipientSetSz = (word32)ret; @@ -13130,10 +13339,18 @@ int wc_PKCS7_DecodeEnvelopedData(wc_PKCS7* pkcs7, byte* in, wc_PKCS7_StreamStoreVar(pkcs7, encOID, expBlockSz, explicitOctet); if (explicitOctet) { - /* initialize decryption state in preparation */ + /* initialize decryption state in preparation. Use + * contentSz (blockKeySz from the content algorithm) as + * the AES key size rather than aadSz (the unwrapped CEK + * length): the two are equal for well-formed messages, + * but using blockKeySz avoids BAD_FUNC_ARG on crafted + * messages where the CEK length does not match the + * content cipher, which would otherwise be a + * distinguishable error. */ if (pkcs7->decryptionCb == NULL) { ret = wc_PKCS7_DecryptContentInit(pkcs7, encOID, - pkcs7->stream->aad, pkcs7->stream->aadSz, + pkcs7->stream->aad, + (word32)pkcs7->stream->contentSz, pkcs7->stream->tmpIv, expBlockSz, pkcs7->devId, pkcs7->heap); if (ret != 0) @@ -13409,8 +13626,13 @@ int wc_PKCS7_DecodeEnvelopedData(wc_PKCS7* pkcs7, byte* in, ret = (int)pkcs7->totalEncryptedContentSz - padLen; #ifndef NO_PKCS7_STREAM - pkcs7->stream->aad = NULL; - pkcs7->stream->aadSz = 0; + /* decryptedKey (just freed) is the same buffer stream->aad + * aliases. Null the stream handle so ResetStream doesn't + * double-free it. */ + if (pkcs7->stream != NULL) { + pkcs7->stream->aad = NULL; + pkcs7->stream->aadSz = 0; + } wc_PKCS7_ResetStream(pkcs7); #endif wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START); @@ -13423,6 +13645,16 @@ int wc_PKCS7_DecodeEnvelopedData(wc_PKCS7* pkcs7, byte* in, #ifndef NO_PKCS7_STREAM if (ret < 0 && ret != WC_NO_ERR_TRACE(WC_PKCS7_WANT_READ_E)) { + /* stream->aad aliases the MAX_ENCRYPTED_KEY_SZ decryptedKey + * buffer in this flow. ResetStream only zeros aadSz bytes, so + * explicitly zero and release the full buffer here to satisfy + * WOLFSSL_CHECK_MEM_ZERO and avoid leaking key material. */ + if (pkcs7->stream != NULL && pkcs7->stream->aad != NULL) { + ForceZero(pkcs7->stream->aad, MAX_ENCRYPTED_KEY_SZ); + XFREE(pkcs7->stream->aad, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + pkcs7->stream->aad = NULL; + pkcs7->stream->aadSz = 0; + } wc_PKCS7_ResetStream(pkcs7); wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START); if (pkcs7->cachedEncryptedContent != NULL) { @@ -14196,6 +14428,10 @@ int wc_PKCS7_DecodeAuthEnvelopedData(wc_PKCS7* pkcs7, byte* in, } else { XMEMSET(decryptedKey, 0, MAX_ENCRYPTED_KEY_SZ); + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("wc_PKCS7 decryptedKey", decryptedKey, + MAX_ENCRYPTED_KEY_SZ); + #endif } #ifndef NO_PKCS7_STREAM pkcs7->stream->key = decryptedKey; From b7f6e77a95bfeda306b22dd34394e49c0a6c8a8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Tue, 21 Apr 2026 13:31:38 +0200 Subject: [PATCH 111/167] Reject PKCS#7 SignedData signer-identity forgery --- src/ssl_p7p12.c | 28 ++- tests/api/test_ossl_p7p12.c | 454 ++++++++++++++++++++++++++++++++++++ tests/api/test_ossl_p7p12.h | 4 + wolfcrypt/src/pkcs7.c | 159 +++++++++++++ 4 files changed, 640 insertions(+), 5 deletions(-) diff --git a/src/ssl_p7p12.c b/src/ssl_p7p12.c index ee48d700aa..a07f018b2a 100644 --- a/src/ssl_p7p12.c +++ b/src/ssl_p7p12.c @@ -269,24 +269,42 @@ WOLFSSL_STACK* wolfSSL_PKCS7_get0_signers(PKCS7* pkcs7, WOLFSSL_STACK* certs, WOLFSSL_X509* x509 = NULL; WOLFSSL_STACK* signers = NULL; WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7; + byte* signerCert; + word32 signerCertSz; if (p7 == NULL) return NULL; - /* Only PKCS#7 messages with a single cert that is the verifying certificate - * is supported. - */ if (flags & PKCS7_NOINTERN) { WOLFSSL_MSG("PKCS7_NOINTERN flag not supported"); return NULL; } + /* Prefer the certificate that actually verified the signature. Falling + * back to singleCert (cert[0]) would let an attacker that bundles a + * trusted cert ahead of their own attacker cert have the trusted cert + * reported as the signer even though it did not produce the signature. + * + * Copy the chosen pointer into a local before passing its address to + * wolfSSL_d2i_X509; d2i_X509 advances *in by the DER length, and if + * we handed it the address of the struct field directly it would + * permanently corrupt the field, producing a heap-OOB read on the + * next use (pointer advanced, singleCertSz unchanged). */ + if (p7->pkcs7.verifyCert != NULL && p7->pkcs7.verifyCertSz > 0) { + signerCert = p7->pkcs7.verifyCert; + signerCertSz = p7->pkcs7.verifyCertSz; + } + else { + signerCert = p7->pkcs7.singleCert; + signerCertSz = p7->pkcs7.singleCertSz; + } + signers = wolfSSL_sk_X509_new_null(); if (signers == NULL) return NULL; - if (wolfSSL_d2i_X509(&x509, (const byte**)&p7->pkcs7.singleCert, - p7->pkcs7.singleCertSz) == NULL) { + if (wolfSSL_d2i_X509(&x509, (const byte**)&signerCert, + signerCertSz) == NULL) { wolfSSL_sk_X509_pop_free(signers, NULL); return NULL; } diff --git a/tests/api/test_ossl_p7p12.c b/tests/api/test_ossl_p7p12.c index c92b80ee5f..03590a3ad7 100644 --- a/tests/api/test_ossl_p7p12.c +++ b/tests/api/test_ossl_p7p12.c @@ -446,6 +446,460 @@ int test_wolfSSL_PKCS7_sign(void) return EXPECT_RESULT(); } +/* Regression test for CMS SignedData signer-identity forgery. + * + * The embedded DER is a CMS SignedData message crafted so that the + * certificates SET contains two certificates: + * cert[0] = certs/ca-cert.pem (trusted wolfSSL CA; attacker does NOT hold + * its private key) + * cert[1] = a self-signed "attacker" P-256 certificate (attacker holds + * the private key) + * The signerInfo sid names the attacker certificate, and the signature + * was produced with the attacker's key over "Hello World". + * + * The bug that was present: wolfSSL_PKCS7_verify() iterated all bundled + * certificates trying each public key against the signature. When the + * attacker's key verified, it still reported cert[0] (the trusted CA cert, + * via singleCert) as the signer, and chain validation therefore succeeded + * on an unrelated trusted cert - a full signer-identity forgery. + * + * The expected, correct behavior: the CMS message is rejected because the + * signer certificate named by the sid (the attacker cert) does not chain + * to any certificate in the trust store. */ +int test_wolfSSL_PKCS7_verify_signer_forgery(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_ALL) && defined(HAVE_PKCS7) && !defined(NO_BIO) && \ + !defined(NO_FILESYSTEM) && !defined(NO_RSA) && defined(HAVE_ECC) + static const byte forgedSignedData[] = { + 0x30, 0x82, 0x07, 0x9c, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x07, 0x02, 0xa0, 0x82, 0x07, 0x8d, 0x30, 0x82, 0x07, 0x89, 0x02, + 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, + 0x65, 0x03, 0x04, 0x02, 0x01, 0x30, 0x1b, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x0e, 0x04, 0x0c, 0x48, 0x65, + 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x0a, 0xa0, 0x82, + 0x06, 0xab, 0x30, 0x82, 0x04, 0xff, 0x30, 0x82, 0x03, 0xe7, 0xa0, 0x03, + 0x02, 0x01, 0x02, 0x02, 0x14, 0x3f, 0x29, 0x11, 0x20, 0x57, 0x71, 0xe7, + 0x8e, 0xf9, 0x18, 0x0d, 0xca, 0x70, 0x4d, 0x5b, 0x15, 0x2a, 0x43, 0xd6, + 0x24, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0x94, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, 0x0e, + 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x07, 0x4d, 0x6f, 0x6e, 0x74, 0x61, + 0x6e, 0x61, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, + 0x07, 0x42, 0x6f, 0x7a, 0x65, 0x6d, 0x61, 0x6e, 0x31, 0x11, 0x30, 0x0f, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x08, 0x53, 0x61, 0x77, 0x74, 0x6f, + 0x6f, 0x74, 0x68, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0b, + 0x0c, 0x0a, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x74, 0x69, 0x6e, 0x67, + 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0f, 0x77, + 0x77, 0x77, 0x2e, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e, 0x63, + 0x6f, 0x6d, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6e, 0x66, 0x6f, 0x40, + 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x30, + 0x1e, 0x17, 0x0d, 0x32, 0x35, 0x31, 0x31, 0x31, 0x33, 0x32, 0x30, 0x34, + 0x31, 0x31, 0x31, 0x5a, 0x17, 0x0d, 0x32, 0x38, 0x30, 0x38, 0x30, 0x39, + 0x32, 0x30, 0x34, 0x31, 0x31, 0x31, 0x5a, 0x30, 0x81, 0x94, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x07, 0x4d, 0x6f, + 0x6e, 0x74, 0x61, 0x6e, 0x61, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, + 0x04, 0x07, 0x0c, 0x07, 0x42, 0x6f, 0x7a, 0x65, 0x6d, 0x61, 0x6e, 0x31, + 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x08, 0x53, 0x61, + 0x77, 0x74, 0x6f, 0x6f, 0x74, 0x68, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, + 0x55, 0x04, 0x0b, 0x0c, 0x0a, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x74, + 0x69, 0x6e, 0x67, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x0c, 0x0f, 0x77, 0x77, 0x77, 0x2e, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, + 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6e, + 0x66, 0x6f, 0x40, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e, 0x63, + 0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, + 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xbf, + 0x0c, 0xca, 0x2d, 0x14, 0xb2, 0x1e, 0x84, 0x42, 0x5b, 0xcd, 0x38, 0x1f, + 0x4a, 0xf2, 0x4d, 0x75, 0x10, 0xf1, 0xb6, 0x35, 0x9f, 0xdf, 0xca, 0x7d, + 0x03, 0x98, 0xd3, 0xac, 0xde, 0x03, 0x66, 0xee, 0x2a, 0xf1, 0xd8, 0xb0, + 0x7d, 0x6e, 0x07, 0x54, 0x0b, 0x10, 0x98, 0x21, 0x4d, 0x80, 0xcb, 0x12, + 0x20, 0xe7, 0xcc, 0x4f, 0xde, 0x45, 0x7d, 0xc9, 0x72, 0x77, 0x32, 0xea, + 0xca, 0x90, 0xbb, 0x69, 0x52, 0x10, 0x03, 0x2f, 0xa8, 0xf3, 0x95, 0xc5, + 0xf1, 0x8b, 0x62, 0x56, 0x1b, 0xef, 0x67, 0x6f, 0xa4, 0x10, 0x41, 0x95, + 0xad, 0x0a, 0x9b, 0xe3, 0xa5, 0xc0, 0xb0, 0xd2, 0x70, 0x76, 0x50, 0x30, + 0x5b, 0xa8, 0xe8, 0x08, 0x2c, 0x7c, 0xed, 0xa7, 0xa2, 0x7a, 0x8d, 0x38, + 0x29, 0x1c, 0xac, 0xc7, 0xed, 0xf2, 0x7c, 0x95, 0xb0, 0x95, 0x82, 0x7d, + 0x49, 0x5c, 0x38, 0xcd, 0x77, 0x25, 0xef, 0xbd, 0x80, 0x75, 0x53, 0x94, + 0x3c, 0x3d, 0xca, 0x63, 0x5b, 0x9f, 0x15, 0xb5, 0xd3, 0x1d, 0x13, 0x2f, + 0x19, 0xd1, 0x3c, 0xdb, 0x76, 0x3a, 0xcc, 0xb8, 0x7d, 0xc9, 0xe5, 0xc2, + 0xd7, 0xda, 0x40, 0x6f, 0xd8, 0x21, 0xdc, 0x73, 0x1b, 0x42, 0x2d, 0x53, + 0x9c, 0xfe, 0x1a, 0xfc, 0x7d, 0xab, 0x7a, 0x36, 0x3f, 0x98, 0xde, 0x84, + 0x7c, 0x05, 0x67, 0xce, 0x6a, 0x14, 0x38, 0x87, 0xa9, 0xf1, 0x8c, 0xb5, + 0x68, 0xcb, 0x68, 0x7f, 0x71, 0x20, 0x2b, 0xf5, 0xa0, 0x63, 0xf5, 0x56, + 0x2f, 0xa3, 0x26, 0xd2, 0xb7, 0x6f, 0xb1, 0x5a, 0x17, 0xd7, 0x38, 0x99, + 0x08, 0xfe, 0x93, 0x58, 0x6f, 0xfe, 0xc3, 0x13, 0x49, 0x08, 0x16, 0x0b, + 0xa7, 0x4d, 0x67, 0x00, 0x52, 0x31, 0x67, 0x23, 0x4e, 0x98, 0xed, 0x51, + 0x45, 0x1d, 0xb9, 0x04, 0xd9, 0x0b, 0xec, 0xd8, 0x28, 0xb3, 0x4b, 0xbd, + 0xed, 0x36, 0x79, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x45, + 0x30, 0x82, 0x01, 0x41, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, + 0x16, 0x04, 0x14, 0x27, 0x8e, 0x67, 0x11, 0x74, 0xc3, 0x26, 0x1d, 0x3f, + 0xed, 0x33, 0x63, 0xb3, 0xa4, 0xd8, 0x1d, 0x30, 0xe5, 0xe8, 0xd5, 0x30, + 0x81, 0xd4, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x81, 0xcc, 0x30, 0x81, + 0xc9, 0x80, 0x14, 0x27, 0x8e, 0x67, 0x11, 0x74, 0xc3, 0x26, 0x1d, 0x3f, + 0xed, 0x33, 0x63, 0xb3, 0xa4, 0xd8, 0x1d, 0x30, 0xe5, 0xe8, 0xd5, 0xa1, + 0x81, 0x9a, 0xa4, 0x81, 0x97, 0x30, 0x81, 0x94, 0x31, 0x0b, 0x30, 0x09, + 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, + 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x07, 0x4d, 0x6f, 0x6e, 0x74, + 0x61, 0x6e, 0x61, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, + 0x0c, 0x07, 0x42, 0x6f, 0x7a, 0x65, 0x6d, 0x61, 0x6e, 0x31, 0x11, 0x30, + 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x08, 0x53, 0x61, 0x77, 0x74, + 0x6f, 0x6f, 0x74, 0x68, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, + 0x0b, 0x0c, 0x0a, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x74, 0x69, 0x6e, + 0x67, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0f, + 0x77, 0x77, 0x77, 0x2e, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e, + 0x63, 0x6f, 0x6d, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6e, 0x66, 0x6f, + 0x40, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, + 0x82, 0x14, 0x3f, 0x29, 0x11, 0x20, 0x57, 0x71, 0xe7, 0x8e, 0xf9, 0x18, + 0x0d, 0xca, 0x70, 0x4d, 0x5b, 0x15, 0x2a, 0x43, 0xd6, 0x24, 0x30, 0x0c, + 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, + 0x30, 0x1c, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x15, 0x30, 0x13, 0x82, + 0x0b, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, + 0x87, 0x04, 0x7f, 0x00, 0x00, 0x01, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, + 0x25, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, + 0x02, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x0f, 0xae, 0x89, + 0xd5, 0x68, 0xe4, 0x41, 0xf8, 0x9b, 0xe0, 0xc5, 0x61, 0x06, 0x57, 0xff, + 0xa0, 0x92, 0x0f, 0xb2, 0xed, 0xd3, 0x99, 0x5b, 0x99, 0x5e, 0x32, 0x7e, + 0x97, 0xc7, 0xaf, 0x6c, 0xfe, 0x8c, 0xa6, 0xae, 0x32, 0xa1, 0x0d, 0xca, + 0xcd, 0xfc, 0x18, 0xe5, 0xd1, 0xf8, 0x20, 0x5b, 0x5a, 0x38, 0x81, 0x46, + 0x5b, 0x48, 0x87, 0xa5, 0x3f, 0x3b, 0x7b, 0xc7, 0xea, 0xf5, 0x35, 0x29, + 0x31, 0x15, 0x39, 0x38, 0x5d, 0x48, 0xe6, 0x01, 0x81, 0x5c, 0x5e, 0x7c, + 0x10, 0xf5, 0x16, 0xe3, 0x59, 0xaf, 0x44, 0xc8, 0xb5, 0x8d, 0xc1, 0x32, + 0x23, 0xb3, 0xb8, 0x12, 0x6e, 0x5c, 0x8d, 0xe6, 0xc2, 0xd2, 0x41, 0x03, + 0xeb, 0x17, 0x42, 0xe2, 0x7f, 0xbc, 0x00, 0x5d, 0xa5, 0x31, 0xef, 0xc6, + 0x48, 0xee, 0xdb, 0xcc, 0xe0, 0xf1, 0x56, 0xf5, 0xd4, 0xca, 0x45, 0xa1, + 0x59, 0xb5, 0xe4, 0xd7, 0x60, 0x9c, 0x57, 0xe0, 0xa7, 0x5a, 0xf2, 0x35, + 0x1e, 0xa0, 0x22, 0xdb, 0x5e, 0x1c, 0x0c, 0x61, 0xbd, 0xa1, 0xc5, 0x7b, + 0x9f, 0x69, 0xf2, 0xd5, 0x95, 0xe2, 0xbc, 0x52, 0xb9, 0x1d, 0x9c, 0x2c, + 0xda, 0xb6, 0x73, 0x75, 0x4a, 0x84, 0xe5, 0x94, 0xb8, 0x19, 0x4d, 0xdd, + 0x70, 0xbd, 0x7f, 0x4c, 0xb9, 0x17, 0x6a, 0x58, 0x16, 0x89, 0x22, 0x44, + 0x37, 0x57, 0x55, 0x26, 0x42, 0xe3, 0xb7, 0xe5, 0xc7, 0x2b, 0x40, 0x0c, + 0xe9, 0xe4, 0x7f, 0x52, 0x75, 0xdf, 0x06, 0xc9, 0xfb, 0x01, 0x44, 0x34, + 0xac, 0x20, 0x3c, 0xb4, 0xbe, 0x2b, 0x3e, 0xef, 0x85, 0x38, 0x96, 0x5b, + 0x9b, 0x1e, 0x25, 0x86, 0x18, 0x4c, 0xa4, 0x06, 0x70, 0x06, 0x6a, 0xc8, + 0x4b, 0x6f, 0x5f, 0xc4, 0x05, 0x1f, 0x03, 0x62, 0x30, 0x11, 0x61, 0xbc, + 0xc1, 0x40, 0x31, 0x66, 0xdc, 0x64, 0xf0, 0x4f, 0x6b, 0xb9, 0xec, 0xc8, + 0x29, 0x30, 0x82, 0x01, 0xa4, 0x30, 0x82, 0x01, 0x49, 0xa0, 0x03, 0x02, + 0x01, 0x02, 0x02, 0x14, 0x62, 0x4d, 0x11, 0x9c, 0xcf, 0x5d, 0xe5, 0x71, + 0xa2, 0x82, 0xd9, 0x8f, 0xe0, 0x04, 0xb8, 0x5f, 0x0e, 0x4d, 0x07, 0xad, + 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, + 0x30, 0x27, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, + 0x08, 0x61, 0x74, 0x74, 0x61, 0x63, 0x6b, 0x65, 0x72, 0x31, 0x12, 0x30, + 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x09, 0x75, 0x6e, 0x74, 0x72, + 0x75, 0x73, 0x74, 0x65, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x36, 0x30, + 0x34, 0x32, 0x31, 0x31, 0x31, 0x31, 0x36, 0x32, 0x38, 0x5a, 0x17, 0x0d, + 0x33, 0x36, 0x30, 0x34, 0x31, 0x38, 0x31, 0x31, 0x31, 0x36, 0x32, 0x38, + 0x5a, 0x30, 0x27, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x0c, 0x08, 0x61, 0x74, 0x74, 0x61, 0x63, 0x6b, 0x65, 0x72, 0x31, 0x12, + 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x09, 0x75, 0x6e, 0x74, + 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, + 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xae, 0xdb, 0xf7, + 0x3b, 0x7e, 0x82, 0x88, 0xfc, 0x1a, 0xfb, 0x86, 0x56, 0x83, 0x03, 0xdd, + 0x05, 0x14, 0x79, 0x51, 0x0f, 0x3c, 0x86, 0x85, 0x2d, 0xeb, 0x18, 0x17, + 0x20, 0x3b, 0x37, 0x6f, 0x7f, 0x78, 0x19, 0x3b, 0xf6, 0x71, 0xad, 0xc9, + 0x65, 0x81, 0x7e, 0xe0, 0xa9, 0x29, 0xdd, 0xfd, 0xf0, 0xff, 0x04, 0x7d, + 0x5a, 0x59, 0xd6, 0x6c, 0xe2, 0xde, 0xc5, 0xd5, 0xb6, 0x1f, 0x69, 0xd9, + 0x33, 0xa3, 0x53, 0x30, 0x51, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, + 0x04, 0x16, 0x04, 0x14, 0xf7, 0xab, 0x3f, 0x49, 0xcf, 0x7d, 0x48, 0x9c, + 0x04, 0x49, 0x1a, 0xac, 0x8f, 0x26, 0x16, 0x09, 0xa8, 0x2a, 0x74, 0xf5, + 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, + 0x14, 0xf7, 0xab, 0x3f, 0x49, 0xcf, 0x7d, 0x48, 0x9c, 0x04, 0x49, 0x1a, + 0xac, 0x8f, 0x26, 0x16, 0x09, 0xa8, 0x2a, 0x74, 0xf5, 0x30, 0x0f, 0x06, + 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, + 0x01, 0xff, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, + 0x03, 0x02, 0x03, 0x49, 0x00, 0x30, 0x46, 0x02, 0x21, 0x00, 0x8d, 0xbf, + 0x36, 0xe5, 0x51, 0x9a, 0xde, 0xf4, 0x7f, 0xbf, 0xbd, 0x7f, 0x71, 0x66, + 0xc1, 0x67, 0xfa, 0x71, 0x0d, 0x79, 0xc6, 0x60, 0x3a, 0x6c, 0xeb, 0x43, + 0xc3, 0xf2, 0x5e, 0xe8, 0x74, 0xb6, 0x02, 0x21, 0x00, 0xfa, 0xdb, 0x40, + 0x47, 0x72, 0xf0, 0x15, 0x52, 0xc1, 0x78, 0x11, 0x6b, 0x76, 0xc5, 0x1f, + 0xcf, 0xb6, 0x09, 0x6d, 0x8f, 0xcb, 0x92, 0x2f, 0x1b, 0x3c, 0xc3, 0x28, + 0x48, 0x61, 0x0f, 0x60, 0x71, 0x31, 0x81, 0xa8, 0x30, 0x81, 0xa5, 0x02, + 0x01, 0x01, 0x30, 0x3f, 0x30, 0x27, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x0c, 0x08, 0x61, 0x74, 0x74, 0x61, 0x63, 0x6b, 0x65, + 0x72, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x09, + 0x75, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x02, 0x14, 0x62, + 0x4d, 0x11, 0x9c, 0xcf, 0x5d, 0xe5, 0x71, 0xa2, 0x82, 0xd9, 0x8f, 0xe0, + 0x04, 0xb8, 0x5f, 0x0e, 0x4d, 0x07, 0xad, 0x30, 0x0b, 0x06, 0x09, 0x60, + 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x30, 0x0a, 0x06, 0x08, + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x04, 0x46, 0x30, 0x44, + 0x02, 0x20, 0x22, 0x4a, 0x99, 0xb1, 0xbc, 0xa9, 0xee, 0x24, 0x60, 0x81, + 0xb9, 0x64, 0xba, 0x86, 0x00, 0xae, 0xb5, 0xd7, 0xb8, 0x72, 0xb9, 0x8c, + 0xb3, 0xe7, 0x78, 0x29, 0xdb, 0xa8, 0x27, 0xf7, 0x30, 0xf0, 0x02, 0x20, + 0x19, 0x2d, 0xd3, 0x17, 0x9a, 0xc1, 0xf9, 0xd2, 0x63, 0x92, 0x8e, 0x78, + 0xcc, 0xa4, 0x0b, 0x91, 0x12, 0xa5, 0xb2, 0xbc, 0x35, 0x87, 0x8e, 0x33, + 0xa7, 0xe0, 0x5e, 0xab, 0x95, 0xb2, 0x2a, 0xf4 + }; + PKCS7* p7 = NULL; + X509_STORE* store = NULL; + X509* caCert = NULL; + WOLFSSL_BIO* caBio = NULL; + const byte* p = forgedSignedData; + const char* ca = "./certs/ca-cert.pem"; + + /* Load the same CA into the trust store that the attacker bundled at + * cert[0] in the forged message. */ + ExpectNotNull(caBio = BIO_new_file(ca, "r")); + ExpectNotNull(caCert = PEM_read_bio_X509(caBio, NULL, 0, NULL)); + ExpectNotNull(store = X509_STORE_new()); + ExpectIntEQ(X509_STORE_add_cert(store, caCert), 1); + + /* Parse the forged message. d2i_PKCS7 internally runs + * wc_PKCS7_VerifySignedData, which must NOT accept the attacker's + * signature under any bundled cert other than the one named by the + * signerInfo sid. Since the sid names the attacker cert (which does + * not chain to the trusted CA), the parse may succeed but verification + * against the trust store must fail. */ + ExpectNotNull(p7 = d2i_PKCS7(NULL, &p, (int)sizeof(forgedSignedData))); + + /* PKCS7_verify() MUST fail: the only certificate in the trust store + * is the wolfSSL CA - it is bundled at cert[0] but did NOT sign this + * message. The actual signer (the attacker's self-signed cert at + * cert[1]) cannot chain to any trust anchor. */ + ExpectIntEQ(PKCS7_verify(p7, NULL, store, NULL, NULL, 0), + WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); + + PKCS7_free(p7); + X509_STORE_free(store); + X509_free(caCert); + BIO_free(caBio); +#endif + return EXPECT_RESULT(); +} + +/* Exercise the SignerInfo-sid binding enforcement end-to-end. + * + * For both supported sid encodings (v1 = IssuerAndSerialNumber, v3 = + * SubjectKeyIdentifier), this builds a valid CMS SignedData message with + * two certificates in the bundle: + * cert[0] = ca-cert (extra, non-signing) + * cert[1] = server-cert (actual signer) + * and checks that: + * - parsing + signature verification succeeds, + * - chain validation against a trust store containing ca-cert succeeds, + * - PKCS7_get0_signers() returns the *signer* (server-cert), not the + * extra cert at cert[0] - which would be the pre-fix behavior and the + * core of the signer-identity forgery bug. */ +int test_wolfSSL_PKCS7_verify_sid_binding(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_ALL) && defined(HAVE_PKCS7) && !defined(NO_BIO) && \ + !defined(NO_FILESYSTEM) && !defined(NO_RSA) + const char* signerCertFile = "./certs/server-cert.pem"; + const char* signerKeyFile = "./certs/server-key.pem"; + const char* caFile = "./certs/ca-cert.pem"; + const byte content[] = "sid-binding test content"; + /* Build both variants: default v1 (IssuerAndSerialNumber) and v3 + * (SubjectKeyIdentifier). */ + const int sidTypes[2] = { CMS_ISSUER_AND_SERIAL_NUMBER, CMS_SKID }; + int variant; + + BIO* signerCertBio = NULL; + BIO* caBio = NULL; + X509* signerCertX509 = NULL; + X509* caX509 = NULL; + byte* signerCertDer = NULL; + byte* caDer = NULL; + byte* signerKey = NULL; + int signerCertDerSz = 0; + int caDerSz = 0; + size_t signerKeySz = 0; + XFILE keyFile = XBADFILE; + WC_RNG rng; + int rngInited = 0; + + /* ---- Load signer cert + key and the CA cert. ---- */ + ExpectNotNull(signerCertBio = BIO_new_file(signerCertFile, "r")); + ExpectNotNull(signerCertX509 = PEM_read_bio_X509(signerCertBio, NULL, 0, + NULL)); + ExpectIntGT(signerCertDerSz = i2d_X509(signerCertX509, &signerCertDer), 0); + + ExpectNotNull(caBio = BIO_new_file(caFile, "r")); + ExpectNotNull(caX509 = PEM_read_bio_X509(caBio, NULL, 0, NULL)); + ExpectIntGT(caDerSz = i2d_X509(caX509, &caDer), 0); + + /* Slurp the DER private key straight from a PEM->DER round-trip via + * wc_KeyPemToDer. The test only needs the bytes in a form + * wc_PKCS7_EncodeSignedData can consume. */ + { + long filePemLen = 0; + byte* keyPem = NULL; + int derLen = 0; + + ExpectTrue((keyFile = XFOPEN(signerKeyFile, "rb")) != XBADFILE); + if (keyFile != XBADFILE) { + (void)XFSEEK(keyFile, 0, XSEEK_END); + filePemLen = XFTELL(keyFile); + (void)XFSEEK(keyFile, 0, XSEEK_SET); + ExpectIntGT(filePemLen, 0); + keyPem = (byte*)XMALLOC((size_t)filePemLen, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + ExpectNotNull(keyPem); + if (keyPem != NULL) { + ExpectIntEQ(XFREAD(keyPem, 1, (size_t)filePemLen, keyFile), + (size_t)filePemLen); + /* First call sizes the output buffer. */ + derLen = wc_KeyPemToDer(keyPem, (word32)filePemLen, NULL, 0, + NULL); + ExpectIntGT(derLen, 0); + if (derLen > 0) { + signerKey = (byte*)XMALLOC((size_t)derLen, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + ExpectNotNull(signerKey); + if (signerKey != NULL) { + derLen = wc_KeyPemToDer(keyPem, (word32)filePemLen, + signerKey, (word32)derLen, + NULL); + ExpectIntGT(derLen, 0); + signerKeySz = (size_t)derLen; + } + } + } + XFREE(keyPem, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFCLOSE(keyFile); + keyFile = XBADFILE; + } + } + + ExpectIntEQ(wc_InitRng(&rng), 0); + if (EXPECT_SUCCESS()) + rngInited = 1; + + for (variant = 0; variant < 2; variant++) { + wc_PKCS7* p7Enc = NULL; + byte encoded[4096]; + int encodedSz = 0; + PKCS7* p7Ver = NULL; + X509_STORE* store = NULL; + const byte* encodedPtr = NULL; + STACK_OF(X509)* signers = NULL; + X509* reportedSigner = NULL; + byte* reportedSignerDer = NULL; + int reportedSignerDerSz = 0; + X509* caForStore = NULL; + BIO* caForStoreBio = NULL; + + /* ---- Encode: signer=server-cert, extra bundle cert=ca. ---- */ + ExpectNotNull(p7Enc = wc_PKCS7_New(HEAP_HINT, INVALID_DEVID)); + ExpectIntEQ(wc_PKCS7_Init(p7Enc, HEAP_HINT, INVALID_DEVID), 0); + ExpectIntEQ(wc_PKCS7_InitWithCert(p7Enc, signerCertDer, + (word32)signerCertDerSz), 0); + /* wc_PKCS7_AddCertificate prepends to the cert list - the encoded + * SET therefore ends up [ca, signer], putting the actual signer + * at index 1 and exercising the sid-selection path (cert[0] is + * NOT the signer and must be skipped). */ + ExpectIntEQ(wc_PKCS7_AddCertificate(p7Enc, caDer, (word32)caDerSz), 0); + + if (p7Enc != NULL) { + p7Enc->content = (byte*)content; + p7Enc->contentSz = (word32)sizeof(content); + p7Enc->encryptOID = RSAk; + p7Enc->hashOID = SHA256h; + p7Enc->privateKey = signerKey; + p7Enc->privateKeySz = (word32)signerKeySz; + p7Enc->rng = &rng; + } + + ExpectIntEQ(wc_PKCS7_SetSignerIdentifierType(p7Enc, sidTypes[variant]), + 0); + + ExpectIntGT((encodedSz = wc_PKCS7_EncodeSignedData(p7Enc, encoded, + sizeof(encoded))), + 0); + wc_PKCS7_Free(p7Enc); + p7Enc = NULL; + + /* ---- Parse + verify through the OpenSSL compat layer. ---- */ + encodedPtr = encoded; + ExpectNotNull(p7Ver = d2i_PKCS7(NULL, &encodedPtr, encodedSz)); + + /* Trust store holds only ca-cert. Reload it rather than reusing + * caX509, since X509_STORE_free takes ownership-like semantics. */ + ExpectNotNull(caForStoreBio = BIO_new_file(caFile, "r")); + ExpectNotNull(caForStore = PEM_read_bio_X509(caForStoreBio, NULL, 0, + NULL)); + ExpectNotNull(store = X509_STORE_new()); + ExpectIntEQ(X509_STORE_add_cert(store, caForStore), 1); + + ExpectIntEQ(PKCS7_verify(p7Ver, NULL, store, NULL, NULL, 0), 1); + + /* Snapshot the singleCert / verifyCert pointers and sizes after + * PKCS7_verify has finished re-parsing the message. A buggy + * implementation that passes &p7->pkcs7.singleCert (or verifyCert) + * directly to wolfSSL_d2i_X509 permanently advances the struct + * field, which corrupts it for any subsequent use - producing a + * heap-OOB read on the next call since the size isn't advanced. + * These pointers must stay exactly where they are across repeated + * get0_signers calls. */ + if (p7Ver != NULL) { + wc_PKCS7* wcP7 = &((WOLFSSL_PKCS7*)p7Ver)->pkcs7; + byte* singleBefore = wcP7->singleCert; + word32 singleSzBefore = wcP7->singleCertSz; + byte* verifyBefore = wcP7->verifyCert; + word32 verifySzBefore = wcP7->verifyCertSz; + int i; + + /* Call get0_signers repeatedly. Each invocation must return + * the correct cert and must not mutate singleCert/verifyCert. + * Three iterations so the "second call reads past the end" + * pattern (the exact OOB the reporter hit) is exercised. */ + for (i = 0; i < 3; i++) { + ExpectNotNull(signers = PKCS7_get0_signers(p7Ver, NULL, 0)); + ExpectIntEQ(sk_X509_num(signers), 1); + ExpectNotNull(reportedSigner = sk_X509_value(signers, 0)); + ExpectIntGT(reportedSignerDerSz = i2d_X509(reportedSigner, + &reportedSignerDer), 0); + /* DER-compare: reportedSigner must equal server-cert and + * must NOT equal ca-cert (the pre-fix signer-confusion + * outcome). */ + ExpectIntEQ(reportedSignerDerSz, signerCertDerSz); + if (reportedSignerDer != NULL && signerCertDer != NULL) { + ExpectIntEQ(XMEMCMP(reportedSignerDer, signerCertDer, + (size_t)signerCertDerSz), 0); + if (reportedSignerDerSz == caDerSz) { + ExpectIntNE(XMEMCMP(reportedSignerDer, caDer, + (size_t)caDerSz), 0); + } + } + XFREE(reportedSignerDer, NULL, DYNAMIC_TYPE_OPENSSL); + reportedSignerDer = NULL; + sk_X509_pop_free(signers, NULL); + signers = NULL; + + /* Struct fields must survive every call unchanged. */ + ExpectPtrEq(wcP7->singleCert, singleBefore); + ExpectIntEQ(wcP7->singleCertSz, singleSzBefore); + ExpectPtrEq(wcP7->verifyCert, verifyBefore); + ExpectIntEQ(wcP7->verifyCertSz, verifySzBefore); + } + } + + PKCS7_free(p7Ver); + X509_STORE_free(store); + X509_free(caForStore); + BIO_free(caForStoreBio); + } + + if (rngInited) + wc_FreeRng(&rng); + + XFREE(signerKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(signerCertDer, NULL, DYNAMIC_TYPE_OPENSSL); + XFREE(caDer, NULL, DYNAMIC_TYPE_OPENSSL); + X509_free(signerCertX509); + X509_free(caX509); + BIO_free(signerCertBio); + BIO_free(caBio); +#endif + return EXPECT_RESULT(); +} + int test_wolfSSL_PKCS7_SIGNED_new(void) { EXPECT_DECLS; diff --git a/tests/api/test_ossl_p7p12.h b/tests/api/test_ossl_p7p12.h index 58aa9dd12a..6704ab51ed 100644 --- a/tests/api/test_ossl_p7p12.h +++ b/tests/api/test_ossl_p7p12.h @@ -27,6 +27,8 @@ int test_wolfssl_PKCS7(void); int test_wolfSSL_PKCS7_certs(void); int test_wolfSSL_PKCS7_sign(void); +int test_wolfSSL_PKCS7_verify_signer_forgery(void); +int test_wolfSSL_PKCS7_verify_sid_binding(void); int test_wolfSSL_PKCS7_SIGNED_new(void); int test_wolfSSL_PEM_write_bio_PKCS7(void); int test_wolfSSL_PEM_write_bio_encryptedKey(void); @@ -38,6 +40,8 @@ int test_wolfSSL_PKCS12(void); TEST_DECL_GROUP("ossl_p7", test_wolfssl_PKCS7), \ TEST_DECL_GROUP("ossl_p7", test_wolfSSL_PKCS7_certs), \ TEST_DECL_GROUP("ossl_p7", test_wolfSSL_PKCS7_sign), \ + TEST_DECL_GROUP("ossl_p7", test_wolfSSL_PKCS7_verify_signer_forgery), \ + TEST_DECL_GROUP("ossl_p7", test_wolfSSL_PKCS7_verify_sid_binding), \ TEST_DECL_GROUP("ossl_p7", test_wolfSSL_PKCS7_SIGNED_new), \ TEST_DECL_GROUP("ossl_p7", test_wolfSSL_PEM_write_bio_PKCS7), \ TEST_DECL_GROUP("ossl_p7", test_wolfSSL_PEM_write_bio_encryptedKey), \ diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index 5d1a25bb31..2c1c3a80f0 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -97,6 +97,7 @@ typedef enum { /* holds information about the signers */ struct PKCS7SignerInfo { int version; + int sidType; /* CMS_ISSUER_AND_SERIAL_NUMBER or CMS_SKID */ byte *sid; word32 sidSz; }; @@ -4292,6 +4293,94 @@ int wc_PKCS7_SetEccSignRawDigestCb(wc_PKCS7* pkcs7, CallbackEccSignRawDigest cb) #endif /* HAVE_ECC */ +#if !defined(NO_RSA) || defined(HAVE_ECC) +/* Check whether the given decoded certificate matches the SignerIdentifier + * (sid) field of the currently parsed SignerInfo. Per RFC 5652 Section 5.3, + * the sid selects which certificate's public key must be used to verify the + * signature. Returns 1 on match, 0 on no match or when the sid is not + * available for comparison. */ +static int wc_PKCS7_CertMatchesSignerInfo(wc_PKCS7* pkcs7, DecodedCert* dCert) +{ + PKCS7SignerInfo* signerInfo; + + if (pkcs7 == NULL || dCert == NULL) + return 0; + + signerInfo = pkcs7->signerInfo; + if (signerInfo == NULL || signerInfo->sid == NULL || + signerInfo->sidSz == 0) { + /* No SID parsed, cannot perform an identity binding check. */ + return 0; + } + + if (signerInfo->sidType == CMS_ISSUER_AND_SERIAL_NUMBER) { + /* IssuerAndSerialNumber: SID blob stores the content of the outer + * SEQUENCE (issuer Name followed by INTEGER serialNumber). */ + word32 idx = 0; + byte sidIssuerHash[KEYID_SIZE]; + WC_DECLARE_VAR(sidSerial, mp_int, 1, pkcs7->heap); + WC_DECLARE_VAR(certSerial, mp_int, 1, pkcs7->heap); + int cmp; + int match = 0; + + if (GetNameHash_ex(signerInfo->sid, &idx, sidIssuerHash, + (int)signerInfo->sidSz, dCert->signatureOID) < 0) { + return 0; + } + if (XMEMCMP(sidIssuerHash, dCert->issuerHash, KEYID_SIZE) != 0) + return 0; + + WC_ALLOC_VAR_EX(sidSerial, mp_int, 1, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER, + { return 0; }); + WC_ALLOC_VAR_EX(certSerial, mp_int, 1, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER, + { WC_FREE_VAR_EX(sidSerial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + return 0; }); + + if (mp_init(sidSerial) != MP_OKAY) { + WC_FREE_VAR_EX(sidSerial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + WC_FREE_VAR_EX(certSerial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + return 0; + } + if (mp_init(certSerial) != MP_OKAY) { + mp_clear(sidSerial); + WC_FREE_VAR_EX(sidSerial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + WC_FREE_VAR_EX(certSerial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + return 0; + } + + if (GetInt(sidSerial, signerInfo->sid, &idx, signerInfo->sidSz) == 0 && + mp_read_unsigned_bin(certSerial, dCert->serial, + (word32)dCert->serialSz) == MP_OKAY) { + cmp = mp_cmp(sidSerial, certSerial); + if (cmp == MP_EQ) + match = 1; + } + + mp_clear(sidSerial); + mp_clear(certSerial); + WC_FREE_VAR_EX(sidSerial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + WC_FREE_VAR_EX(certSerial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + return match; + } + else if (signerInfo->sidType == CMS_SKID) { + /* SubjectKeyIdentifier: SID blob is the raw SKID octet string + * content. Normalize the same way the certificate side does so + * that comparisons between SHA-1 SKIDs and other lengths match. */ + byte sidKid[KEYID_SIZE]; + + if (GetHashId(signerInfo->sid, (int)signerInfo->sidSz, sidKid, + HashIdAlg(dCert->signatureOID)) != 0) { + return 0; + } + if (XMEMCMP(sidKid, dCert->extSubjKeyId, KEYID_SIZE) == 0) + return 1; + return 0; + } + + return 0; +} +#endif /* !NO_RSA || HAVE_ECC */ + #ifndef NO_RSA /* returns size of signature put into out, negative on error */ @@ -4371,6 +4460,31 @@ static int wc_PKCS7_RsaVerify(wc_PKCS7* pkcs7, byte* sig, int sigSz, continue; } + /* If the SignerInfo sid was parsed, only try the certificate whose + * identity matches it. This binds the verifying public key to the + * signer identity advertised in the CMS message and prevents signer + * confusion when multiple certificates are embedded. */ + if (pkcs7->signerInfo != NULL && pkcs7->signerInfo->sid != NULL && + !wc_PKCS7_CertMatchesSignerInfo(pkcs7, dCert)) { + FreeDecodedCert(dCert); + wc_FreeRsaKey(key); + continue; + } + + /* Defense in depth: the sid-matched cert must actually carry an + * RSA-family key before we feed its SPKI to the RSA key decoder. + * Rejecting here avoids depending on wc_RsaPublicKeyDecode to reject + * wrong-type SPKIs. */ + if (dCert->keyOID != RSAk + #ifdef WC_RSA_PSS + && dCert->keyOID != RSAPSSk + #endif + ) { + FreeDecodedCert(dCert); + wc_FreeRsaKey(key); + continue; + } + if (wc_RsaPublicKeyDecode(dCert->publicKey, &scratch, key, dCert->pubKeySize) < 0) { WOLFSSL_MSG("ASN RSA key decode error"); @@ -4481,6 +4595,24 @@ static int wc_PKCS7_RsaPssVerify(wc_PKCS7* pkcs7, byte* sig, int sigSz, continue; } + /* Only try the certificate identified by the SignerInfo sid (see + * matching comment in wc_PKCS7_RsaVerify). */ + if (pkcs7->signerInfo != NULL && pkcs7->signerInfo->sid != NULL && + !wc_PKCS7_CertMatchesSignerInfo(pkcs7, dCert)) { + FreeDecodedCert(dCert); + wc_FreeRsaKey(key); + continue; + } + + /* Defense in depth: reject non-RSA SPKIs before key decode. RSA + * rsaEncryption certs (keyOID=RSAk) are accepted for PSS signatures + * per RFC 8017 - a RSASSA-PSS cert is not required. */ + if (dCert->keyOID != RSAk && dCert->keyOID != RSAPSSk) { + FreeDecodedCert(dCert); + wc_FreeRsaKey(key); + continue; + } + pkSz = dCert->pubKeySize; if (pkSz > (MAX_RSA_INT_SZ + MAX_RSA_E_SZ)) pkSz = (MAX_RSA_INT_SZ + MAX_RSA_E_SZ); @@ -4646,6 +4778,22 @@ static int wc_PKCS7_EcdsaVerify(wc_PKCS7* pkcs7, byte* sig, int sigSz, continue; } + /* Only try the certificate identified by the SignerInfo sid (see + * matching comment in wc_PKCS7_RsaVerify). */ + if (pkcs7->signerInfo != NULL && pkcs7->signerInfo->sid != NULL && + !wc_PKCS7_CertMatchesSignerInfo(pkcs7, dCert)) { + FreeDecodedCert(dCert); + wc_ecc_free(key); + continue; + } + + /* Defense in depth: reject non-ECDSA SPKIs before key decode. */ + if (dCert->keyOID != ECDSAk) { + FreeDecodedCert(dCert); + wc_ecc_free(key); + continue; + } + if (wc_EccPublicKeyDecode(dCert->publicKey, &idx, key, dCert->pubKeySize) < 0) { WOLFSSL_MSG("ASN ECC key decode error"); @@ -5359,11 +5507,16 @@ static int wc_PKCS7_ParseSignerInfo(wc_PKCS7* pkcs7, byte* in, word32 inSz, ret = ASN_PARSE_E; if (ret == 0) { + pkcs7->signerInfo->sidType = CMS_ISSUER_AND_SERIAL_NUMBER; ret = wc_PKCS7_SignerInfoSetSID(pkcs7, in + idx, length); idx += (word32)length; } } else if (ret == 0 && version == 3) { + /* Default: SignerInfo version 3 carries SubjectKeyIdentifier. + * May be overridden below if the parser instead finds a + * SEQUENCE (IssuerAndSerialNumber fallback). */ + pkcs7->signerInfo->sidType = CMS_SKID; /* Get the sequence of SubjectKeyIdentifier */ if (idx + 1 > inSz) ret = BUFFER_E; @@ -5406,6 +5559,12 @@ static int wc_PKCS7_ParseSignerInfo(wc_PKCS7* pkcs7, byte* in, word32 inSz, if (ret == 0 && GetSequence(in, &idx, &length, inSz) < 0) ret = ASN_PARSE_E; + + if (ret == 0) { + /* v3 carrying IssuerAndSerialNumber fallback */ + pkcs7->signerInfo->sidType = + CMS_ISSUER_AND_SERIAL_NUMBER; + } } } From 97b82b50873e16feb90b9c911424d3ed547ee36e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Tue, 21 Apr 2026 18:33:45 +0200 Subject: [PATCH 112/167] Add nonce length validation for PKCS#7 --- wolfcrypt/src/pkcs7.c | 45 ++++++++++++++++++++++++++++++++++ wolfssl/wolfcrypt/wc_encrypt.h | 3 +++ 2 files changed, 48 insertions(+) diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index 2c1c3a80f0..3b34dd970c 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -14726,6 +14726,11 @@ int wc_PKCS7_DecodeAuthEnvelopedData(wc_PKCS7* pkcs7, byte* in, break; } pkiMsgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length: inSz; + + /* Restore encOID across WANT_READ re-entries so the nonce + * length validation below always sees the content-cipher + * algorithm parsed in AUTHENV_3. */ + wc_PKCS7_StreamGetVar(pkcs7, &encOID, &blockKeySz, NULL); #endif /* get length of optional parameter sequence */ if (ret == 0 && GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) { @@ -14743,6 +14748,46 @@ int wc_PKCS7_DecodeAuthEnvelopedData(wc_PKCS7* pkcs7, byte* in, ret = ASN_PARSE_E; } + /* Enforce algorithm-specific nonce length bounds at the parser + * layer so malformed lengths (notably zero-length, which would + * catastrophically break AEAD uniqueness on HW backends that + * skip their own checks) cannot reach the cipher engine. + * - AES-GCM in CMS: RFC 5084 Sec. 3.2 mandates a 12-octet IV. + * - AES-CCM: RFC 3610 Sec. 2.3 requires 7..13 octets. + * Any other encOID here is a parser-state invariant violation. */ + if (ret == 0) { + int nonceMin = 0, nonceMax = 0; + switch (encOID) { + #ifdef HAVE_AESGCM + case AES128GCMb: + case AES192GCMb: + case AES256GCMb: + nonceMin = GCM_NONCE_MID_SZ; + nonceMax = GCM_NONCE_MID_SZ; + break; + #endif + #ifdef HAVE_AESCCM + case AES128CCMb: + case AES192CCMb: + case AES256CCMb: + nonceMin = CCM_NONCE_MIN_SZ; + nonceMax = CCM_NONCE_MAX_SZ; + break; + #endif + default: + WOLFSSL_MSG( + "AuthEnvelopedData unexpected content cipher"); + ret = ALGO_ID_E; + break; + } + if (ret == 0 && + (nonceSz < nonceMin || nonceSz > nonceMax)) { + WOLFSSL_MSG( + "AuthEnvelopedData nonce length invalid for cipher"); + ret = ASN_PARSE_E; + } + } + if (ret == 0) { XMEMCPY(nonce, &pkiMsg[idx], (word32)nonceSz); idx += (word32)nonceSz; diff --git a/wolfssl/wolfcrypt/wc_encrypt.h b/wolfssl/wolfcrypt/wc_encrypt.h index da11b53922..7f1c48b636 100644 --- a/wolfssl/wolfcrypt/wc_encrypt.h +++ b/wolfssl/wolfcrypt/wc_encrypt.h @@ -73,6 +73,9 @@ #ifndef CCM_NONCE_MIN_SZ #define CCM_NONCE_MIN_SZ 7 #endif + #ifndef CCM_NONCE_MAX_SZ + #define CCM_NONCE_MAX_SZ 13 + #endif #endif From 22d14413311a6d0bb55221a2e4c9759f9530651a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Thu, 23 Apr 2026 10:19:36 +0200 Subject: [PATCH 113/167] Bounds-check the RecipientInfo SET length in wc_PKCS7_ParseToRecipientInfoSet() --- tests/api/test_pkcs7.c | 66 ++++++++++++++++++++++++++++++++++++++++++ tests/api/test_pkcs7.h | 4 ++- wolfcrypt/src/pkcs7.c | 37 +++++++++++++++++++++++ 3 files changed, 106 insertions(+), 1 deletion(-) diff --git a/tests/api/test_pkcs7.c b/tests/api/test_pkcs7.c index a22fd9e10e..69b4631605 100644 --- a/tests/api/test_pkcs7.c +++ b/tests/api/test_pkcs7.c @@ -2711,6 +2711,72 @@ int test_wc_PKCS7_DecodeEnvelopedData_stream(void) } /* END test_wc_PKCS7_DecodeEnvelopedData_stream() */ +/* + * Regression test: a PKCS#7 EnvelopedData with a forged RecipientInfo SET + * length (parsed via GetSet_ex with NO_USER_CHECK) must not drive an + * uncapped heap allocation through wc_PKCS7_GrowStream(). The decoder + * must reject the oversized allocation rather than attempting it. + */ +int test_wc_PKCS7_DecodeEnvelopedData_forgedRecipientSetLen(void) +{ + EXPECT_DECLS; +#if defined(HAVE_PKCS7) && !defined(NO_RSA) && !defined(NO_PKCS7_STREAM) + /* Crafted ContentInfo/EnvelopedData header. All lengths use the + * 4-byte long form for clarity. The RecipientInfo SET length is + * forged to 0x01000001 (16 MB + 1), which exceeds the default + * WOLFSSL_PKCS7_MAX_STREAM_ALLOC cap and should be rejected before + * any allocation succeeds. The body after the SET header is never + * consumed because the decoder fails at the GrowStream() cap. */ + static const byte forged[] = { + /* ContentInfo SEQUENCE, body length 0x01000021 */ + 0x30, 0x84, 0x01, 0x00, 0x00, 0x21, + /* OID 1.2.840.113549.1.7.3 (id-envelopedData) */ + 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, + 0x01, 0x07, 0x03, + /* [0] EXPLICIT content, body length 0x01000016 */ + 0xA0, 0x84, 0x01, 0x00, 0x00, 0x16, + /* EnvelopedData SEQUENCE, body length 0x01000010 */ + 0x30, 0x84, 0x01, 0x00, 0x00, 0x10, + /* version INTEGER 0 */ + 0x02, 0x01, 0x00, + /* Forged RecipientInfo SET header: length = 0x01000001 */ + 0x31, 0x84, 0x01, 0x00, 0x00, 0x01, + /* Padding so that header-parsing states can buffer their + * required lookahead without returning WC_PKCS7_WANT_READ_E. + * These bytes are never interpreted. */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + }; + PKCS7* pkcs7 = NULL; + byte out[32]; + int ret; + + ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId)); + ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, (byte*)client_cert_der_2048, + sizeof_client_cert_der_2048), 0); + ExpectIntEQ(wc_PKCS7_SetKey(pkcs7, (byte*)client_key_der_2048, + sizeof_client_key_der_2048), 0); + + ret = wc_PKCS7_DecodeEnvelopedData(pkcs7, (byte*)forged, + (word32)sizeof(forged), out, (word32)sizeof(out)); + /* Must NOT return WC_PKCS7_WANT_READ_E (which would imply the + * oversized allocation succeeded and the decoder is waiting for + * the around 16 MB of SET body). Must NOT return 0 / positive length. + * Expected: BUFFER_E from the GrowStream cap. */ + ExpectIntEQ(ret, WC_NO_ERR_TRACE(BUFFER_E)); + + wc_PKCS7_Free(pkcs7); +#endif + return EXPECT_RESULT(); +} /* END test_wc_PKCS7_DecodeEnvelopedData_forgedRecipientSetLen() */ + + /* * Testing wc_PKCS7_DecodeEnvelopedData with streaming */ diff --git a/tests/api/test_pkcs7.h b/tests/api/test_pkcs7.h index e1c71c911d..f4aed161da 100644 --- a/tests/api/test_pkcs7.h +++ b/tests/api/test_pkcs7.h @@ -65,6 +65,7 @@ int test_wc_PKCS7_SetOriEncryptCtx(void); int test_wc_PKCS7_SetOriDecryptCtx(void); int test_wc_PKCS7_DecodeCompressedData(void); int test_wc_PKCS7_DecodeEnvelopedData_multiple_recipients(void); +int test_wc_PKCS7_DecodeEnvelopedData_forgedRecipientSetLen(void); int test_wc_PKCS7_VerifySignedData_PKCS7ContentSeq(void); int test_wc_PKCS7_VerifySignedData_IndefLenOOB(void); @@ -129,7 +130,8 @@ int test_wc_PKCS7_VerifySignedData_IndefLenOOB(void); TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_DecodeOneSymmetricKey), \ TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_SetOriEncryptCtx), \ TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_SetOriDecryptCtx), \ - TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_DecodeEnvelopedData_multiple_recipients) + TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_DecodeEnvelopedData_multiple_recipients), \ + TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_DecodeEnvelopedData_forgedRecipientSetLen) #define TEST_PKCS7_SIGNED_ENCRYPTED_DATA_DECLS \ TEST_DECL_GROUP("pkcs7_sed", test_wc_PKCS7_signed_enveloped) diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index 3b34dd970c..666890b608 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -113,6 +113,17 @@ struct PKCS7SignerInfo { #ifndef NO_PKCS7_STREAM +/* Hard upper bound on a single PKCS7 streaming buffer allocation. Guards + * wc_PKCS7_GrowStream against attacker-controlled ASN.1 lengths that were + * parsed with NO_USER_CHECK and would otherwise drive allocations up to + * around 2GB (e.g. via a forged RecipientInfo SET length). 16 MB is well above + * any legitimate RecipientInfo / encoded-attribute size but small enough + * that a forged length fails allocation on constrained targets and is + * rejected on larger ones. */ +#ifndef WOLFSSL_PKCS7_MAX_STREAM_ALLOC + #define WOLFSSL_PKCS7_MAX_STREAM_ALLOC (16 * 1024 * 1024) +#endif + #define MAX_PKCS7_STREAM_BUFFER 256 struct PKCS7State { byte* tmpCert; @@ -274,6 +285,16 @@ static void wc_PKCS7_FreeStream(wc_PKCS7* pkcs7) static int wc_PKCS7_GrowStream(wc_PKCS7* pkcs7, word32 newSz) { byte* pt; + + /* Guard against attacker-controlled ASN.1 lengths reaching this + * allocation. Several callers parse lengths with NO_USER_CHECK and + * pass them here unvalidated (e.g. wc_PKCS7_ParseToRecipientInfoSet + * on a forged RecipientInfo SET header). */ + if (newSz > WOLFSSL_PKCS7_MAX_STREAM_ALLOC) { + WOLFSSL_MSG("PKCS7 streaming allocation exceeds maximum"); + return BUFFER_E; + } + pt = (byte*)XMALLOC(newSz, pkcs7->heap, DYNAMIC_TYPE_PKCS7); if (pt == NULL) { return MEMORY_E; @@ -13096,6 +13117,22 @@ static int wc_PKCS7_ParseToRecipientInfoSet(wc_PKCS7* pkcs7, byte* in, NO_USER_CHECK) < 0) ret = ASN_PARSE_E; + /* GetSet_ex is called with NO_USER_CHECK, which skips the + * (idx + length > maxIdx) bounds check in GetLength_ex. In + * non-streaming mode, validate the SET length against the + * remaining input buffer; in streaming mode the length flows + * into pkcs7->stream->expected and then wc_PKCS7_GrowStream, + * where it is capped by WOLFSSL_PKCS7_MAX_STREAM_ALLOC. */ + if (ret == 0 && length < 0) + ret = ASN_PARSE_E; + #ifdef NO_PKCS7_STREAM + if (ret == 0 && + (*idx > pkiMsgSz || + (word32)length > pkiMsgSz - *idx)) { + ret = ASN_PARSE_E; + } + #endif + if (ret < 0) break; From 6c5de29758f2763e3d0c2dc71d32324cea725add Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Mon, 20 Apr 2026 13:01:25 +0200 Subject: [PATCH 114/167] Fix ECC validation regression --- tests/api/test_ecc.c | 52 ++++++++++++++++++++++++++++++++++++++++++++ tests/api/test_ecc.h | 2 ++ wolfcrypt/src/ecc.c | 3 ++- 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/tests/api/test_ecc.c b/tests/api/test_ecc.c index b0d32d4b8c..f70882a76a 100644 --- a/tests/api/test_ecc.c +++ b/tests/api/test_ecc.c @@ -772,6 +772,58 @@ int test_wc_ecc_import_x963(void) return EXPECT_RESULT(); } /* END wc_ecc_import_x963 */ +/* + * testing wc_ecc_import_x963() rejects an off-curve public point. + * + * Regression coverage for the invalid-curve attack: the legacy wrapper + * wc_ecc_import_x963_ex (called by wc_ecc_import_x963()) must pass untrusted=1 + * to wc_ecc_import_x963_ex2 so that ECIES, PKCS#7 KARI, and EVP ECDH callers + * validate that the imported point actually lies on the curve. Without that, + * an attacker can feed a point from a weak twist and leak the victim's private + * scalar modulo small primes (Biehl-Meyer-Mueller). + */ +int test_wc_ecc_import_x963_off_curve(void) +{ + EXPECT_DECLS; +#if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_IMPORT) && \ + !defined(NO_ECC256) && !defined(NO_ECC_SECP) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION_GE(7,0)) && !defined(HAVE_SELFTEST) + ecc_key pubKey; + /* Uncompressed X9.63 P-256 point: 0x04 || Gx || Gy with the last byte + * of Gy flipped by 1. Gx/Gy are the NIST P-256 generator coordinates; + * modifying a single bit of Gy produces a point that is not on the + * curve, so wc_ecc_import_x963 must reject it. */ + static const byte offCurveX963[] = { + 0x04, + 0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, 0x47, + 0xF8, 0xBC, 0xE6, 0xE5, 0x63, 0xA4, 0x40, 0xF2, + 0x77, 0x03, 0x7D, 0x81, 0x2D, 0xEB, 0x33, 0xA0, + 0xF4, 0xA1, 0x39, 0x45, 0xD8, 0x98, 0xC2, 0x96, + 0x4F, 0xE3, 0x42, 0xE2, 0xFE, 0x1A, 0x7F, 0x9B, + 0x8E, 0xE7, 0xEB, 0x4A, 0x7C, 0x0F, 0x9E, 0x16, + 0x2B, 0xCE, 0x33, 0x57, 0x6B, 0x31, 0x5E, 0xCE, + 0xCB, 0xB6, 0x40, 0x68, 0x37, 0xBF, 0x51, 0xF4 + }; + + XMEMSET(&pubKey, 0, sizeof(ecc_key)); + + ExpectIntEQ(wc_ecc_init(&pubKey), 0); + + /* Importing an off-curve point must fail. wc_ecc_import_x963() calls + * wc_ecc_import_x963_ex() which ultimately calls wc_ecc_import_x963_ex2() + * with the required untrusted=1 flag. */ + ExpectIntNE(wc_ecc_import_x963(offCurveX963, (word32)sizeof(offCurveX963), + &pubKey), 0); + + wc_ecc_free(&pubKey); + +#ifdef FP_ECC + wc_ecc_fp_free(); +#endif +#endif + return EXPECT_RESULT(); +} /* END test_wc_ecc_import_x963_off_curve */ + /* * testing wc_ecc_import_private_key() */ diff --git a/tests/api/test_ecc.h b/tests/api/test_ecc.h index 8b13eeb00d..95f6f8b93b 100644 --- a/tests/api/test_ecc.h +++ b/tests/api/test_ecc.h @@ -39,6 +39,7 @@ int test_wc_ecc_shared_secret(void); int test_wc_ecc_export_x963(void); int test_wc_ecc_export_x963_ex(void); int test_wc_ecc_import_x963(void); +int test_wc_ecc_import_x963_off_curve(void); int test_wc_ecc_import_private_key(void); int test_wc_ecc_export_private_only(void); int test_wc_ecc_rs_to_sig(void); @@ -76,6 +77,7 @@ int test_wc_EccPrivateKeyToDer(void); TEST_DECL_GROUP("ecc", test_wc_ecc_export_x963), \ TEST_DECL_GROUP("ecc", test_wc_ecc_export_x963_ex), \ TEST_DECL_GROUP("ecc", test_wc_ecc_import_x963), \ + TEST_DECL_GROUP("ecc", test_wc_ecc_import_x963_off_curve), \ TEST_DECL_GROUP("ecc", test_wc_ecc_import_private_key), \ TEST_DECL_GROUP("ecc", test_wc_ecc_export_private_only), \ TEST_DECL_GROUP("ecc", test_wc_ecc_rs_to_sig), \ diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 573a690140..cd7089f393 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -11226,7 +11226,8 @@ int wc_ecc_import_x963_ex2(const byte* in, word32 inLen, ecc_key* key, int wc_ecc_import_x963_ex(const byte* in, word32 inLen, ecc_key* key, int curve_id) { - return wc_ecc_import_x963_ex2(in, inLen, key, curve_id, 0); + /* treat as untrusted: validate the point is on the curve */ + return wc_ecc_import_x963_ex2(in, inLen, key, curve_id, 1); } WOLFSSL_ABI From 72c7d12cfb575f0382effd3bf7e77883312e9c70 Mon Sep 17 00:00:00 2001 From: JacobBarthelmeh Date: Thu, 23 Apr 2026 16:23:07 -0600 Subject: [PATCH 115/167] exclude the trust anchor from prospective certification path with pathlen check --- tests/api.c | 9 +++++++++ wolfcrypt/src/asn.c | 17 ++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/tests/api.c b/tests/api.c index 4c15bfccc2..e9b43d8276 100644 --- a/tests/api.c +++ b/tests/api.c @@ -21763,6 +21763,15 @@ static int test_PathLenSelfIssued(void) cm), WC_NO_ERR_TRACE(ASN_PATHLEN_INV_E)); wc_FreeDecodedCert(&decodedCert); + /* Step 6: Parse the trust anchor itself as a chain cert. + * A peer is allowed to include the root in the chain it sends. + * Per RFC 5280 6.1 the trust anchor is not part of the prospective + * certification path, so its own pathLen=0 must not fire against + * itself. */ + wc_InitDecodedCert(&decodedCert, rootDer, (word32)rootDerSz, NULL); + ExpectIntEQ(wc_ParseCert(&decodedCert, CHAIN_CERT_TYPE, VERIFY, cm), 0); + wc_FreeDecodedCert(&decodedCert); + wolfSSL_CertManagerFree(cm); wc_ecc_free(&entityKey); wc_ecc_free(&icaKey); diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index cbd2a9901b..176e39c2fd 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -22527,7 +22527,22 @@ int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm, * max_path_length, but the issuer's constraint still * applies. A self-issued cert from a CA with maxPathLen=0 * cannot act as an intermediate CA. */ - if (cert->ca->maxPathLen == 0) { + if (cert->publicKey != NULL && + cert->ca->publicKey != NULL && + cert->pubKeySize > 0 && + cert->pubKeySize == cert->ca->pubKeySize && + XMEMCMP(cert->publicKey, cert->ca->publicKey, + cert->pubKeySize) == 0) { + /* Exclude the trust anchor itself from step (l). Per + * RFC 5280 6.1, when the trust anchor is supplied as a + * self-signed certificate it "is not included as part + * of the prospective certification path" */ + + /* Trust anchor: honor issuer's constraint */ + cert->maxPathLen = (word16)min(cert->ca->maxPathLen, + cert->maxPathLen); + } + else if (cert->ca->maxPathLen == 0) { cert->maxPathLen = 0; if (verify != NO_VERIFY) { WOLFSSL_MSG("\tSelf-issued cert, maxPathLen is 0"); From 29f674e5b606897d4127e094d5185589c81d3a6e Mon Sep 17 00:00:00 2001 From: JacobBarthelmeh Date: Fri, 24 Apr 2026 00:38:52 -0600 Subject: [PATCH 116/167] avoid glitch hardening false positive byte collision with small messages and adjust test case --- src/internal.c | 8 +++++--- src/tls13.c | 8 ++++---- tests/api/test_tls13.c | 38 +++++++++++++++++++++----------------- 3 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/internal.c b/src/internal.c index 70584590f1..4af743278d 100644 --- a/src/internal.c +++ b/src/internal.c @@ -20682,9 +20682,10 @@ static WC_INLINE int Encrypt(WOLFSSL* ssl, byte* out, const byte* input, } #ifdef WOLFSSL_CIPHER_TEXT_CHECK - if (ssl->specs.bulk_cipher_algorithm != wolfssl_cipher_null) { + if (ssl->specs.bulk_cipher_algorithm != wolfssl_cipher_null && + sz >= sizeof(ssl->encrypt.sanityCheck)) { XMEMCPY(ssl->encrypt.sanityCheck, input, - min(sz, sizeof(ssl->encrypt.sanityCheck))); + sizeof(ssl->encrypt.sanityCheck)); } #endif @@ -20771,8 +20772,9 @@ static WC_INLINE int Encrypt(WOLFSSL* ssl, byte* out, const byte* input, { #ifdef WOLFSSL_CIPHER_TEXT_CHECK if (ssl->specs.bulk_cipher_algorithm != wolfssl_cipher_null && + sz >= sizeof(ssl->encrypt.sanityCheck) && XMEMCMP(out, ssl->encrypt.sanityCheck, - min(sz, sizeof(ssl->encrypt.sanityCheck))) == 0) { + sizeof(ssl->encrypt.sanityCheck)) == 0) { WOLFSSL_MSG("Encrypt sanity check failed! Glitch?"); WOLFSSL_ERROR_VERBOSE(ENCRYPT_ERROR); diff --git a/src/tls13.c b/src/tls13.c index 824ad08b69..80e0f570c0 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -2639,9 +2639,9 @@ static int EncryptTls13(WOLFSSL* ssl, byte* output, const byte* input, #ifdef WOLFSSL_CIPHER_TEXT_CHECK if (ssl->specs.bulk_cipher_algorithm != wolfssl_cipher_null && - dataSz > 0) { + dataSz >= sizeof(ssl->encrypt.sanityCheck)) { XMEMCPY(ssl->encrypt.sanityCheck, input, - min(dataSz, sizeof(ssl->encrypt.sanityCheck))); + sizeof(ssl->encrypt.sanityCheck)); } #endif @@ -2825,9 +2825,9 @@ static int EncryptTls13(WOLFSSL* ssl, byte* output, const byte* input, #ifdef WOLFSSL_CIPHER_TEXT_CHECK if (ssl->specs.bulk_cipher_algorithm != wolfssl_cipher_null && - dataSz > 0 && + dataSz >= sizeof(ssl->encrypt.sanityCheck) && XMEMCMP(output, ssl->encrypt.sanityCheck, - min(dataSz, sizeof(ssl->encrypt.sanityCheck))) == 0) { + sizeof(ssl->encrypt.sanityCheck)) == 0) { WOLFSSL_MSG("EncryptTls13 sanity check failed! Glitch?"); return ENCRYPT_ERROR; diff --git a/tests/api/test_tls13.c b/tests/api/test_tls13.c index e6302d9e37..194ea6e432 100644 --- a/tests/api/test_tls13.c +++ b/tests/api/test_tls13.c @@ -4590,7 +4590,7 @@ int test_tls13_empty_record_limit(void) struct test_memio_ctx test_ctx; WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; WOLFSSL *ssl_c = NULL, *ssl_s = NULL; - int recSz; + int recSz = 0; /* Send exactly WOLFSSL_MAX_EMPTY_RECORDS to pin the boundary check. * The Nth record increments the counter to N, and `N >= N` triggers * the error. Sending one more would let a `>=` -> `>` mutation survive @@ -4608,16 +4608,18 @@ int test_tls13_empty_record_limit(void) ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); - /* Consume any post-handshake messages (e.g. NewSessionTicket). */ - wolfSSL_read(ssl_c, buf, sizeof(buf)); - test_memio_clear_buffer(&test_ctx, 0); - test_memio_clear_buffer(&test_ctx, 1); + if (EXPECT_SUCCESS()) { + /* Consume any post-handshake messages (e.g. NewSessionTicket). */ + wolfSSL_read(ssl_c, buf, sizeof(buf)); + test_memio_clear_buffer(&test_ctx, 0); + test_memio_clear_buffer(&test_ctx, 1); - /* Get the size of an encrypted zero-length app data record. */ - recSz = BuildTls13Message(ssl_c, NULL, 0, NULL, 0, - application_data, 0, 1, 0); - ExpectIntGT(recSz, 0); - ExpectIntLE(recSz, (int)sizeof(rec)); + /* Get the size of an encrypted zero-length app data record. */ + recSz = BuildTls13Message(ssl_c, NULL, 0, NULL, 0, + application_data, 0, 1, 0); + ExpectIntGT(recSz, 0); + ExpectIntLE(recSz, (int)sizeof(rec)); + } /* Build all empty records into one contiguous buffer. */ if (EXPECT_SUCCESS()) { @@ -4664,15 +4666,17 @@ int test_tls13_empty_record_limit(void) ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); - wolfSSL_read(ssl_c, buf, sizeof(buf)); - test_memio_clear_buffer(&test_ctx, 0); - test_memio_clear_buffer(&test_ctx, 1); + if (EXPECT_SUCCESS()) { + wolfSSL_read(ssl_c, buf, sizeof(buf)); + test_memio_clear_buffer(&test_ctx, 0); + test_memio_clear_buffer(&test_ctx, 1); - recSz = BuildTls13Message(ssl_c, NULL, 0, NULL, 0, - application_data, 0, 1, 0); - ExpectIntGT(recSz, 0); + recSz = BuildTls13Message(ssl_c, NULL, 0, NULL, 0, + application_data, 0, 1, 0); + ExpectIntGT(recSz, 0); + } - { + if (EXPECT_SUCCESS()) { int emptyBefore = WOLFSSL_MAX_EMPTY_RECORDS - 1; int emptyAfter = WOLFSSL_MAX_EMPTY_RECORDS - 1; int dataRecSz; From 412c428b0a9ae58d8a341f5836ed9819a8f728db Mon Sep 17 00:00:00 2001 From: Eric Blankenhorn Date: Tue, 14 Apr 2026 11:48:56 -0500 Subject: [PATCH 117/167] Fix TLS ext bounds checking --- src/tls.c | 107 +++++++++++++++++++++++++++---- src/tls13.c | 4 ++ tests/api.c | 139 +++++++++++++++++++++++++++++++++++++++++ tests/api/test_tls13.c | 44 ++++++++----- wolfcrypt/src/aes.c | 9 ++- wolfcrypt/test/test.c | 108 ++++++++++++++++++++++++++++++++ wolfssl/internal.h | 19 ++++-- 7 files changed, 393 insertions(+), 37 deletions(-) diff --git a/src/tls.c b/src/tls.c index ed8267469d..996edafbbc 100644 --- a/src/tls.c +++ b/src/tls.c @@ -6504,7 +6504,7 @@ static int TLSX_SessionTicket_Parse(WOLFSSL* ssl, const byte* input, return ret; } -WOLFSSL_LOCAL SessionTicket* TLSX_SessionTicket_Create(word32 lifetime, +WOLFSSL_TEST_VIS SessionTicket* TLSX_SessionTicket_Create(word32 lifetime, byte* data, word16 size, void* heap) { SessionTicket* ticket = (SessionTicket*)XMALLOC(sizeof(SessionTicket), @@ -6525,7 +6525,7 @@ WOLFSSL_LOCAL SessionTicket* TLSX_SessionTicket_Create(word32 lifetime, return ticket; } -WOLFSSL_LOCAL void TLSX_SessionTicket_Free(SessionTicket* ticket, void* heap) +WOLFSSL_TEST_VIS void TLSX_SessionTicket_Free(SessionTicket* ticket, void* heap) { if (ticket) { XFREE(ticket->data, heap, DYNAMIC_TYPE_TLSX); @@ -14879,9 +14879,27 @@ static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType, { int ret = 0; TLSX* extension; - word16 length = 0; + /* Use a word32 accumulator so that an extension whose contribution + * pushes the running total past 0xFFFF is detected rather than + * silently wrapped (the TLS extensions block length prefix on the + * wire is a 2-byte field). Callees that take a word16* accumulator + * are invoked via a per-iteration shim (`cbShim`) and their delta + * is added back into the word32 total. + * + * MAINTAINER NOTE: do NOT pass &length to any *_GET_SIZE function + * that expects a `word16*` out-parameter -- that would be a type + * mismatch (UB) and would silently bypass the overflow detection + * below. When adding a new extension case, either: + * - use `length += FOO_GET_SIZE(...)` when the helper returns a + * word16 by value, or + * - use the cbShim pattern: `cbShim = 0; ret = FOO_GET_SIZE(..., + * &cbShim); length += cbShim;` + */ + word32 length = 0; + word16 cbShim = 0; byte isRequest = (msgType == client_hello || msgType == certificate_request); + (void)cbShim; while ((extension = list)) { list = extension->next; @@ -14965,23 +14983,31 @@ static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType, #endif #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) case TLSX_ENCRYPT_THEN_MAC: - ret = ETM_GET_SIZE(msgType, &length); + cbShim = 0; + ret = ETM_GET_SIZE(msgType, &cbShim); + length += cbShim; break; #endif /* HAVE_ENCRYPT_THEN_MAC */ #if defined(WOLFSSL_TLS13) || !defined(WOLFSSL_NO_TLS12) || !defined(NO_OLD_TLS) #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) case TLSX_PRE_SHARED_KEY: + cbShim = 0; ret = PSK_GET_SIZE((PreSharedKey*)extension->data, msgType, - &length); + &cbShim); + length += cbShim; break; #ifdef WOLFSSL_TLS13 case TLSX_PSK_KEY_EXCHANGE_MODES: - ret = PKM_GET_SIZE((byte)extension->val, msgType, &length); + cbShim = 0; + ret = PKM_GET_SIZE((byte)extension->val, msgType, &cbShim); + length += cbShim; break; #ifdef WOLFSSL_CERT_WITH_EXTERN_PSK case TLSX_CERT_WITH_EXTERN_PSK: - ret = PSK_WITH_CERT_GET_SIZE(msgType, &length); + cbShim = 0; + ret = PSK_WITH_CERT_GET_SIZE(msgType, &cbShim); + length += cbShim; break; #endif #endif @@ -14993,22 +15019,30 @@ static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType, #ifdef WOLFSSL_TLS13 case TLSX_SUPPORTED_VERSIONS: - ret = SV_GET_SIZE(extension->data, msgType, &length); + cbShim = 0; + ret = SV_GET_SIZE(extension->data, msgType, &cbShim); + length += cbShim; break; case TLSX_COOKIE: - ret = CKE_GET_SIZE((Cookie*)extension->data, msgType, &length); + cbShim = 0; + ret = CKE_GET_SIZE((Cookie*)extension->data, msgType, &cbShim); + length += cbShim; break; #ifdef WOLFSSL_EARLY_DATA case TLSX_EARLY_DATA: - ret = EDI_GET_SIZE(msgType, &length); + cbShim = 0; + ret = EDI_GET_SIZE(msgType, &cbShim); + length += cbShim; break; #endif #ifdef WOLFSSL_POST_HANDSHAKE_AUTH case TLSX_POST_HANDSHAKE_AUTH: - ret = PHA_GET_SIZE(msgType, &length); + cbShim = 0; + ret = PHA_GET_SIZE(msgType, &cbShim); + length += cbShim; break; #endif @@ -15061,12 +15095,26 @@ static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType, break; } + /* Early exit: stop accumulating as soon as the running total + * cannot possibly fit the 2-byte wire length. Check *before* + * marking the extension as processed so the semaphore is not + * left in an inconsistent state on the error path. */ + if (length > WOLFSSL_MAX_16BIT) { + WOLFSSL_MSG("TLSX_GetSize extension length exceeds word16"); + return BUFFER_E; + } + /* marks the extension as processed so ctx level */ /* extensions don't overlap with ssl level ones. */ TURN_ON(semaphore, TLSX_ToSemaphore((word16)extension->type)); } - *pLength += length; + if ((word32)*pLength + length > WOLFSSL_MAX_16BIT) { + WOLFSSL_MSG("TLSX_GetSize total extensions length exceeds word16"); + return BUFFER_E; + } + + *pLength += (word16)length; return ret; } @@ -15079,6 +15127,7 @@ static int TLSX_Write(TLSX* list, byte* output, byte* semaphore, TLSX* extension; word16 offset = 0; word16 length_offset = 0; + word32 prevOffset; byte isRequest = (msgType == client_hello || msgType == certificate_request); @@ -15093,6 +15142,10 @@ static int TLSX_Write(TLSX* list, byte* output, byte* semaphore, if (!IS_OFF(semaphore, TLSX_ToSemaphore((word16)extension->type))) continue; /* skip! */ + /* Snapshot offset to detect word16 wrap within this iteration; + * see matching comment in TLSX_GetSize. */ + prevOffset = offset; + /* writes extension type. */ c16toa((word16)extension->type, output + offset); offset += HELLO_EXT_TYPE_SZ + OPAQUE16_LEN; @@ -15326,9 +15379,24 @@ static int TLSX_Write(TLSX* list, byte* output, byte* semaphore, /* if we encountered an error propagate it */ if (ret != 0) break; + + if (offset <= prevOffset) { + WOLFSSL_MSG("TLSX_Write extension length exceeds word16"); + return BUFFER_E; + } } - *pOffset += offset; + /* Only validate and commit the aggregate offset when the loop + * completed without error; on the error path, leave *pOffset + * unchanged and return the original failure reason so callers + * see the real error instead of a masking BUFFER_E. */ + if (ret == 0) { + if ((word32)*pOffset + (word32)offset > WOLFSSL_MAX_16BIT) { + WOLFSSL_MSG("TLSX_Write total extensions length exceeds word16"); + return BUFFER_E; + } + *pOffset += offset; + } return ret; } @@ -16432,6 +16500,13 @@ int TLSX_GetRequestSize(WOLFSSL* ssl, byte msgType, word32* pLength) } #endif + /* The TLS extensions block length prefix is a 2-byte field, so any + * accumulated total above 0xFFFF must be rejected rather than silently + * truncating and producing a short, malformed handshake message. */ + if (length > (word16)(WOLFSSL_MAX_16BIT - OPAQUE16_LEN)) { + WOLFSSL_MSG("TLSX_GetRequestSize extensions exceed word16"); + return BUFFER_E; + } if (length) length += OPAQUE16_LEN; /* for total length storage. */ @@ -16635,6 +16710,12 @@ int TLSX_WriteRequest(WOLFSSL* ssl, byte* output, byte msgType, word32* pOffset) #endif #endif + /* Wrap detection for the TLSX_Write calls above is handled inside + * TLSX_Write itself: any iteration that would push the local word16 + * offset past 0xFFFF returns BUFFER_E so we never reach here with a + * truncated value. The TLS extensions block length prefix on the + * wire is a 2-byte field, matching this invariant. */ + if (offset > OPAQUE16_LEN || msgType != client_hello) c16toa(offset - OPAQUE16_LEN, output); /* extensions length */ diff --git a/src/tls13.c b/src/tls13.c index de666c866e..80a1c2c1a5 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -3279,6 +3279,10 @@ int BuildTls13Message(WOLFSSL* ssl, byte* output, int outSz, const byte* input, WOLFSSL_ENTER("BuildTls13Message"); + if (ssl == NULL) { + return BAD_FUNC_ARG; + } + #ifdef WOLFSSL_ASYNC_CRYPT ret = WC_NO_PENDING_E; if (asyncOkay) { diff --git a/tests/api.c b/tests/api.c index 2b259d54ab..95ca8344c2 100644 --- a/tests/api.c +++ b/tests/api.c @@ -10578,6 +10578,144 @@ static int test_tls_ext_duplicate(void) return EXPECT_RESULT(); } +/* Regression test: TLSX extension size accumulation must not silently wrap + * the internal word16 accumulator. Prior to the fix, a single extension + * whose size (plus the 4-byte header) pushes the running total past 0xFFFF + * caused TLSX_GetSize / TLSX_Write to return a truncated length, which + * in turn led to undersized buffer writes. The on-wire extensions block + * length is a 2-byte field per RFC 8446 Section 4.2, so the correct + * behavior is to return BUFFER_E rather than wrap. */ +static int test_tls_ext_word16_overflow(void) +{ + EXPECT_DECLS; +#if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_CLIENT) && \ + !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + SessionTicket* ticket = NULL; + byte* big = NULL; + /* Size chosen so that 4 (ext header) + size > 0xFFFF. */ + const word16 bigSz = 0xFFFE; + word32 length = 0; + + big = (byte*)XMALLOC(bigSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + ExpectNotNull(big); + if (big != NULL) + XMEMSET(big, 0xA5, bigSz); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* Build an oversized SessionTicket extension directly on the ssl + * extension list. Going via the public API is not enough here because + * wolfSSL_set_SessionTicket clamps to word16 without creating the + * TLSX entry; the TLSX path is what exercises the accumulator. */ + if (EXPECT_SUCCESS()) { + ticket = TLSX_SessionTicket_Create(0, big, bigSz, ssl->heap); + ExpectNotNull(ticket); + } + if (EXPECT_SUCCESS()) { + ExpectIntEQ(TLSX_UseSessionTicket(&ssl->extensions, ticket, ssl->heap), + WOLFSSL_SUCCESS); + /* TLSX_UseSessionTicket takes ownership on success. */ + ticket = NULL; + } + + /* TLSX_GetRequestSize must refuse to encode: 4-byte ext header + + * 0xFFFE payload + 2-byte block length prefix = 0x10004, which does + * not fit in a word16 wire length. Expect BUFFER_E, not a silently + * wrapped small value. */ + if (EXPECT_SUCCESS()) { + int ret = TLSX_GetRequestSize(ssl, client_hello, &length); + ExpectIntEQ(ret, BUFFER_E); + } + + if (ticket != NULL) + TLSX_SessionTicket_Free(ticket, ssl->heap); + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); + XFREE(big, NULL, DYNAMIC_TYPE_TMP_BUFFER); + ssl = NULL; + ctx = NULL; + big = NULL; + + /* Boundary case: construct a SessionTicket extension sized so that the + * total extensions length in TLSX_GetRequestSize is exactly + * WOLFSSL_MAX_16BIT - OPAQUE16_LEN (0xFFFD) *before* the OPAQUE16_LEN + * block-prefix adjustment, which must succeed. This pins the `>` + * comparison in the overflow check -- mutating it to `>=` would + * incorrectly reject this valid case and fail this test. */ + { + WOLFSSL_CTX* ctx2 = NULL; + WOLFSSL* ssl2 = NULL; + SessionTicket* ticket2 = NULL; + byte* buf = NULL; + word32 baseLen = 0; + word32 baseInternal = 0; + word32 tickSz = 0; + /* TLSX_GetRequestSize rejects when internal sum > 0xFFFD. */ + const word32 target = (word32)WOLFSSL_MAX_16BIT - (word32)OPAQUE16_LEN; + /* Session ticket extension contributes: type (2) + len (2) + size. */ + const word32 extHdr = (word32)HELLO_EXT_TYPE_SZ + + (word32)OPAQUE16_LEN; + int ret; + + ExpectNotNull(ctx2 = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl2 = wolfSSL_new(ctx2)); + + /* Measure baseline length with no session ticket extension. The + * returned value already includes the 2-byte block-length prefix + * when nonzero; strip it to get the raw internal sum. */ + if (EXPECT_SUCCESS()) { + baseLen = 0; + ret = TLSX_GetRequestSize(ssl2, client_hello, &baseLen); + ExpectIntEQ(ret, 0); + baseInternal = (baseLen > 0) + ? baseLen - (word32)OPAQUE16_LEN : 0; + } + + /* Target: baseInternal + extHdr + tickSz == 0xFFFD. */ + if (EXPECT_SUCCESS() && baseInternal + extHdr < target) { + tickSz = target - baseInternal - extHdr; + } + + if (EXPECT_SUCCESS() && tickSz > 0 && tickSz <= WOLFSSL_MAX_16BIT) { + buf = (byte*)XMALLOC(tickSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + ExpectNotNull(buf); + if (buf != NULL) + XMEMSET(buf, 0x5A, tickSz); + } + + if (EXPECT_SUCCESS() && buf != NULL) { + ticket2 = TLSX_SessionTicket_Create(0, buf, (word16)tickSz, + ssl2->heap); + ExpectNotNull(ticket2); + } + if (EXPECT_SUCCESS() && ticket2 != NULL) { + ExpectIntEQ(TLSX_UseSessionTicket(&ssl2->extensions, ticket2, + ssl2->heap), WOLFSSL_SUCCESS); + ticket2 = NULL; + } + + /* Exact boundary: internal sum == 0xFFFD must succeed, and the + * final returned length is 0xFFFD + OPAQUE16_LEN == 0xFFFF. */ + if (EXPECT_SUCCESS()) { + word32 lenBoundary = 0; + ret = TLSX_GetRequestSize(ssl2, client_hello, &lenBoundary); + ExpectIntEQ(ret, 0); + ExpectIntEQ(lenBoundary, (word32)WOLFSSL_MAX_16BIT); + } + + if (ticket2 != NULL) + TLSX_SessionTicket_Free(ticket2, ssl2->heap); + wolfSSL_free(ssl2); + wolfSSL_CTX_free(ctx2); + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + } +#endif + return EXPECT_RESULT(); +} + /* Test TLS connection abort when legacy version field indicates TLS 1.3 or * higher. Based on test_tls_ext_duplicate() but with legacy version modified @@ -37373,6 +37511,7 @@ TEST_CASE testCases[] = { TEST_DECL(test_wolfSSL_SCR_Reconnect), TEST_DECL(test_wolfSSL_SCR_check_enabled), TEST_DECL(test_tls_ext_duplicate), + TEST_DECL(test_tls_ext_word16_overflow), TEST_DECL(test_tls_bad_legacy_version), #if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) #if defined(HAVE_IO_TESTS_DEPENDENCIES) diff --git a/tests/api/test_tls13.c b/tests/api/test_tls13.c index 194ea6e432..ba12b7e368 100644 --- a/tests/api/test_tls13.c +++ b/tests/api/test_tls13.c @@ -4637,14 +4637,18 @@ int test_tls13_empty_record_limit(void) } /* Inject all records as a single message. */ - ExpectIntEQ(test_memio_inject_message(&test_ctx, 0, (const char*)allRecs, - recSz * numRecs), 0); + if (EXPECT_SUCCESS()) { + ExpectIntEQ(test_memio_inject_message(&test_ctx, 0, + (const char*)allRecs, recSz * numRecs), 0); + } /* The server's wolfSSL_read should fail with EMPTY_RECORD_LIMIT_E. */ - ExpectIntEQ(wolfSSL_read(ssl_s, buf, sizeof(buf)), - WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)); - ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR), - WC_NO_ERR_TRACE(EMPTY_RECORD_LIMIT_E)); + if (EXPECT_SUCCESS()) { + ExpectIntEQ(wolfSSL_read(ssl_s, buf, sizeof(buf)), + WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)); + ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR), + WC_NO_ERR_TRACE(EMPTY_RECORD_LIMIT_E)); + } XFREE(allRecs, NULL, DYNAMIC_TYPE_TMP_BUFFER); allRecs = NULL; @@ -4679,17 +4683,19 @@ int test_tls13_empty_record_limit(void) if (EXPECT_SUCCESS()) { int emptyBefore = WOLFSSL_MAX_EMPTY_RECORDS - 1; int emptyAfter = WOLFSSL_MAX_EMPTY_RECORDS - 1; - int dataRecSz; + int dataRecSz = 0; byte dataRec[128]; byte payload[1] = { 'a' }; - int totalSz; + int totalSz = 0; - dataRecSz = BuildTls13Message(ssl_c, NULL, 0, NULL, 1, - application_data, 0, 1, 0); - ExpectIntGT(dataRecSz, 0); - - totalSz = recSz * (emptyBefore + emptyAfter) + dataRecSz; if (EXPECT_SUCCESS()) { + dataRecSz = BuildTls13Message(ssl_c, NULL, 0, NULL, 1, + application_data, 0, 1, 0); + ExpectIntGT(dataRecSz, 0); + } + + if (EXPECT_SUCCESS()) { + totalSz = recSz * (emptyBefore + emptyAfter) + dataRecSz; allRecs = (byte*)XMALLOC((size_t)totalSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); ExpectNotNull(allRecs); @@ -4725,15 +4731,19 @@ int test_tls13_empty_record_limit(void) rec, (size_t)recSz); } - ExpectIntEQ(test_memio_inject_message(&test_ctx, 0, - (const char*)allRecs, totalSz), 0); + if (EXPECT_SUCCESS()) { + ExpectIntEQ(test_memio_inject_message(&test_ctx, 0, + (const char*)allRecs, totalSz), 0); + } } /* wolfSSL_read should return the 1-byte payload. The counter resets * on the non-empty record so neither batch of (limit - 1) empties * triggers the error. */ - ExpectIntEQ(wolfSSL_read(ssl_s, buf, sizeof(buf)), 1); - ExpectIntEQ(buf[0], 'a'); + if (EXPECT_SUCCESS()) { + ExpectIntEQ(wolfSSL_read(ssl_s, buf, sizeof(buf)), 1); + ExpectIntEQ(buf[0], 'a'); + } XFREE(allRecs, NULL, DYNAMIC_TYPE_TMP_BUFFER); wolfSSL_free(ssl_c); diff --git a/wolfcrypt/src/aes.c b/wolfcrypt/src/aes.c index 72c1df4946..0e5304c2ea 100644 --- a/wolfcrypt/src/aes.c +++ b/wolfcrypt/src/aes.c @@ -16852,6 +16852,11 @@ int wc_AesEaxDecryptAuth(const byte* key, word32 keySz, byte* out, return BAD_FUNC_ARG; } + if (authTagSz < WOLFSSL_MIN_AUTH_TAG_SZ + || authTagSz > WC_AES_BLOCK_SIZE) { + return BAD_FUNC_ARG; + } + #if defined(WOLFSSL_SMALL_STACK) if ((eax = (AesEax *)XMALLOC(sizeof(AesEax), NULL, @@ -17201,8 +17206,8 @@ int wc_AesEaxDecryptFinal(AesEax* eax, byte authTag[WC_AES_BLOCK_SIZE]; #endif - if (eax == NULL || authIn == NULL || authInSz == 0 || - authInSz > WC_AES_BLOCK_SIZE) { + if (eax == NULL || authIn == NULL || authInSz > WC_AES_BLOCK_SIZE + || authInSz < WOLFSSL_MIN_AUTH_TAG_SZ) { return BAD_FUNC_ARG; } diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 1d6eb27822..c765b530e9 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -19518,6 +19518,114 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aes_eax_test(void) } } + + /* Regression test: wc_AesEaxDecryptAuth must reject authTagSz below + * WOLFSSL_MIN_AUTH_TAG_SZ (including zero), otherwise an attacker could + * bypass tag verification by supplying an empty tag. */ +#if WOLFSSL_MIN_AUTH_TAG_SZ > 0 + { + byte zero_ct[16]; + byte zero_pt[16]; + byte zero_tag[16]; + XMEMSET(zero_ct, 0, sizeof(zero_ct)); + XMEMSET(zero_tag, 0, sizeof(zero_tag)); + + ret = wc_AesEaxDecryptAuth(vectors[0].key, + (word32)vectors[0].key_length, + zero_pt, + zero_ct, (word32)sizeof(zero_ct), + vectors[0].iv, + (word32)vectors[0].iv_length, + zero_tag, 0, + vectors[0].aad, + (word32)vectors[0].aad_length); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) { + return WC_TEST_RET_ENC_EC(ret); + } + +#if WOLFSSL_MIN_AUTH_TAG_SZ > 1 + ret = wc_AesEaxDecryptAuth(vectors[0].key, + (word32)vectors[0].key_length, + zero_pt, + zero_ct, (word32)sizeof(zero_ct), + vectors[0].iv, + (word32)vectors[0].iv_length, + zero_tag, WOLFSSL_MIN_AUTH_TAG_SZ - 1, + vectors[0].aad, + (word32)vectors[0].aad_length); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) { + return WC_TEST_RET_ENC_EC(ret); + } +#endif + + /* Upper bound: authTagSz > WC_AES_BLOCK_SIZE must be rejected. + * Pins the '>' operator in the validation against mutation to '>=' + * and prevents an over-read of the caller-supplied tag buffer. */ + ret = wc_AesEaxDecryptAuth(vectors[0].key, + (word32)vectors[0].key_length, + zero_pt, + zero_ct, (word32)sizeof(zero_ct), + vectors[0].iv, + (word32)vectors[0].iv_length, + zero_tag, WC_AES_BLOCK_SIZE + 1, + vectors[0].aad, + (word32)vectors[0].aad_length); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) { + return WC_TEST_RET_ENC_EC(ret); + } + + /* Direct incremental-API coverage: wc_AesEaxDecryptFinal must also + * reject authInSz of zero and below WOLFSSL_MIN_AUTH_TAG_SZ. The + * one-shot API above is a separate code path. Heap-allocate the + * AesEax context to keep stack usage within Linux kernel limits. */ + { + AesEax *eax = (AesEax *)XMALLOC(sizeof(*eax), HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER); + if (eax == NULL) { + return WC_TEST_RET_ENC_NC; + } + XMEMSET(eax, 0, sizeof(*eax)); + ret = wc_AesEaxInit(eax, + vectors[0].key, (word32)vectors[0].key_length, + vectors[0].iv, (word32)vectors[0].iv_length, + vectors[0].aad, + (word32)vectors[0].aad_length); + if (ret != 0) { + XFREE(eax, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + return WC_TEST_RET_ENC_EC(ret); + } + + ret = wc_AesEaxDecryptFinal(eax, zero_tag, 0); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) { + wc_AesEaxFree(eax); + XFREE(eax, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + return WC_TEST_RET_ENC_EC(ret); + } + +#if WOLFSSL_MIN_AUTH_TAG_SZ > 1 + ret = wc_AesEaxDecryptFinal(eax, zero_tag, + WOLFSSL_MIN_AUTH_TAG_SZ - 1); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) { + wc_AesEaxFree(eax); + XFREE(eax, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + return WC_TEST_RET_ENC_EC(ret); + } +#endif + + /* Upper bound: authInSz > WC_AES_BLOCK_SIZE must be rejected. */ + ret = wc_AesEaxDecryptFinal(eax, zero_tag, WC_AES_BLOCK_SIZE + 1); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) { + wc_AesEaxFree(eax); + XFREE(eax, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + return WC_TEST_RET_ENC_EC(ret); + } + + wc_AesEaxFree(eax); + XFREE(eax, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + } + } +#endif /* WOLFSSL_MIN_AUTH_TAG_SZ > 0 */ + return 0; } diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 9e89e64b0b..d8fff147fe 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -3189,9 +3189,13 @@ WOLFSSL_LOCAL int TLSX_SupportExtensions(WOLFSSL* ssl); WOLFSSL_LOCAL int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isRequest); #if defined(WOLFSSL_TLS13) || !defined(NO_WOLFSSL_CLIENT) -WOLFSSL_LOCAL int TLSX_GetRequestSize(WOLFSSL* ssl, byte msgType, +#ifdef WOLFSSL_API_PREFIX_MAP + #define TLSX_GetRequestSize wolfSSL_TLSX_GetRequestSize + #define TLSX_WriteRequest wolfSSL_TLSX_WriteRequest +#endif +WOLFSSL_TEST_VIS int TLSX_GetRequestSize(WOLFSSL* ssl, byte msgType, word32* pLength); -WOLFSSL_LOCAL int TLSX_WriteRequest(WOLFSSL* ssl, byte* output, +WOLFSSL_TEST_VIS int TLSX_WriteRequest(WOLFSSL* ssl, byte* output, byte msgType, word32* pOffset); #endif @@ -3597,11 +3601,16 @@ typedef struct TicketEncCbCtx { #endif /* !WOLFSSL_NO_DEF_TICKET_ENC_CB && !NO_WOLFSSL_SERVER */ -WOLFSSL_LOCAL int TLSX_UseSessionTicket(TLSX** extensions, +#ifdef WOLFSSL_API_PREFIX_MAP + #define TLSX_UseSessionTicket wolfSSL_TLSX_UseSessionTicket + #define TLSX_SessionTicket_Create wolfSSL_TLSX_SessionTicket_Create + #define TLSX_SessionTicket_Free wolfSSL_TLSX_SessionTicket_Free +#endif +WOLFSSL_TEST_VIS int TLSX_UseSessionTicket(TLSX** extensions, SessionTicket* ticket, void* heap); -WOLFSSL_LOCAL SessionTicket* TLSX_SessionTicket_Create(word32 lifetime, +WOLFSSL_TEST_VIS SessionTicket* TLSX_SessionTicket_Create(word32 lifetime, byte* data, word16 size, void* heap); -WOLFSSL_LOCAL void TLSX_SessionTicket_Free(SessionTicket* ticket, void* heap); +WOLFSSL_TEST_VIS void TLSX_SessionTicket_Free(SessionTicket* ticket, void* heap); #endif /* HAVE_SESSION_TICKET */ From 08fd7bde58017de46f7e4788ba7ae14498248297 Mon Sep 17 00:00:00 2001 From: kaleb-himes Date: Tue, 24 Mar 2026 04:21:04 -0600 Subject: [PATCH 118/167] PQ FIPS v7.0.0 Phase 2 & 3: All changes Implement peer review feedback --- .wolfssl_known_macro_extras | 2 + IDE/WIN10/wolfssl-fips.vcxproj | 6 + configure.ac | 840 +++- doc/dox_comments/header_files/random.h | 237 + doc/dox_comments/header_files/wc_slhdsa.h | 793 ++++ src/include.am | 391 +- src/tls.c | 6 + tests/api.c | 2 - tests/api/test_hash.c | 26 +- tests/api/test_mldsa.c | 5112 +++++++++++++++++++++ tests/api/test_mldsa.h | 4 + tests/api/test_mlkem.c | 23 +- tests/api/test_random.c | 143 + tests/api/test_random.h | 4 +- wolfcrypt/benchmark/benchmark.c | 567 ++- wolfcrypt/benchmark/benchmark.h | 7 + wolfcrypt/src/asn.c | 18 + wolfcrypt/src/dh.c | 5 + wolfcrypt/src/dilithium.c | 167 +- wolfcrypt/src/ecc.c | 6 + wolfcrypt/src/error.c | 24 + wolfcrypt/src/evp.c | 46 +- wolfcrypt/src/ext_lms.c | 28 + wolfcrypt/src/ext_mlkem.c | 6 + wolfcrypt/src/hash.c | 388 +- wolfcrypt/src/hmac.c | 164 + wolfcrypt/src/random.c | 1733 ++++++- wolfcrypt/src/rng_bank.c | 57 +- wolfcrypt/src/rsa.c | 149 +- wolfcrypt/src/sha256.c | 2 + wolfcrypt/src/sha3.c | 1 + wolfcrypt/src/sha512.c | 4 + wolfcrypt/src/wc_lms.c | 252 +- wolfcrypt/src/wc_lms_impl.c | 827 +++- wolfcrypt/src/wc_mlkem.c | 52 + wolfcrypt/src/wc_port.c | 19 + wolfcrypt/src/wc_slhdsa.c | 1866 ++++++-- wolfcrypt/src/wc_xmss.c | 5 + wolfcrypt/src/wolfentropy.c | 69 +- wolfcrypt/test/test.c | 1013 +++- wolfssl/wolfcrypt/aes.h | 7 + wolfssl/wolfcrypt/dilithium.h | 6 + wolfssl/wolfcrypt/error-crypt.h | 16 +- wolfssl/wolfcrypt/fips_test.h | 8 +- wolfssl/wolfcrypt/lms.h | 64 + wolfssl/wolfcrypt/random.h | 202 +- wolfssl/wolfcrypt/rsa.h | 9 + wolfssl/wolfcrypt/settings.h | 2 +- wolfssl/wolfcrypt/wc_lms.h | 101 +- wolfssl/wolfcrypt/wc_slhdsa.h | 290 +- 50 files changed, 14675 insertions(+), 1094 deletions(-) create mode 100644 doc/dox_comments/header_files/wc_slhdsa.h diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 6efadcab07..9b16dcd495 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -733,6 +733,7 @@ WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC WOLFSSL_DILITHIUM_SIGN_SMALL_MEM_PRECALC_A WOLFSSL_DILITHIUM_SMALL_MEM_POLY64 WOLFSSL_DISABLE_EARLY_SANITY_CHECKS +WOLFSSL_DRBG_SHA256 WOLFSSL_DTLS_DISALLOW_FUTURE WOLFSSL_DTLS_RECORDS_CAN_SPAN_DATAGRAMS WOLFSSL_DTLS_RESEND_ONLY_TIMEOUT @@ -1133,3 +1134,4 @@ ssize_t sun versal wc_Tls13_HKDF_Expand_Label +WOLFSSL_NO_LMS_SHAKE256_256 diff --git a/IDE/WIN10/wolfssl-fips.vcxproj b/IDE/WIN10/wolfssl-fips.vcxproj index eac076eb3a..721bf088ef 100644 --- a/IDE/WIN10/wolfssl-fips.vcxproj +++ b/IDE/WIN10/wolfssl-fips.vcxproj @@ -318,6 +318,12 @@ + + + + + + diff --git a/configure.ac b/configure.ac index 09a763d542..dc7cc30ab4 100644 --- a/configure.ac +++ b/configure.ac @@ -623,10 +623,8 @@ AS_CASE([$ENABLED_FIPS], DEF_SP_MATH="yes" DEF_FAST_MATH="no" ], - # Should always remain one ahead of the latest so as not to be confused with - # the latest - [ready],[ - FIPS_VERSION="ready" + [v7],[ + FIPS_VERSION="v7" HAVE_FIPS_VERSION=7 HAVE_FIPS_VERSION_MAJOR=7 HAVE_FIPS_VERSION_MINOR=0 @@ -635,9 +633,21 @@ AS_CASE([$ENABLED_FIPS], DEF_SP_MATH="yes" DEF_FAST_MATH="no" ], - [dev],[ + # Should always remain one ahead of the latest so as not to be confused with + # the latest + [ready|v7-ready],[ + FIPS_VERSION="ready" + HAVE_FIPS_VERSION=8 + HAVE_FIPS_VERSION_MAJOR=8 + HAVE_FIPS_VERSION_MINOR=0 + HAVE_FIPS_VERSION_PATCH=0 + ENABLED_FIPS="yes" + DEF_SP_MATH="yes" + DEF_FAST_MATH="no" + ], + [dev|v7-dev],[ FIPS_VERSION="dev" - HAVE_FIPS_VERSION_MAJOR=7 + HAVE_FIPS_VERSION_MAJOR=8 HAVE_FIPS_VERSION_MINOR=0 HAVE_FIPS_VERSION_PATCH=0 ENABLED_FIPS="yes" @@ -645,14 +655,14 @@ AS_CASE([$ENABLED_FIPS], ], [lean-aesgcm|lean-aesgcm-ready|lean-aesgcm-dev],[ FIPS_VERSION="$ENABLED_FIPS" - HAVE_FIPS_VERSION_MAJOR=7 + HAVE_FIPS_VERSION_MAJOR=8 HAVE_FIPS_VERSION_MINOR=0 HAVE_FIPS_VERSION_PATCH=0 ENABLED_FIPS="yes" ], [ AS_IF([test "$ENABLED_FIPS" = "yes"],[ENABLED_FIPS="(unset)"],[ENABLED_FIPS=\"$ENABLED_FIPS\"]) - AC_MSG_ERROR([Invalid value for --enable-fips $ENABLED_FIPS (main options: v1, v2, v5, v6, ready, dev, rand, lean-aesgcm, no, disabled)]) + AC_MSG_ERROR([Invalid value for --enable-fips $ENABLED_FIPS (main options: v1, v2, v5, v6, v7, ready, dev, rand, lean-aesgcm, no, disabled)]) ]) if test -z "$HAVE_FIPS_VERSION_MAJOR" @@ -1828,39 +1838,6 @@ do esac done -if test "$ENABLED_DILITHIUM" != "no" -then - AM_CFLAGS="$AM_CFLAGS -DHAVE_DILITHIUM" - - if test "$ENABLED_MLDSA44" = ""; then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_DSA_44" - fi - if test "$ENABLED_MLDSA65" = ""; then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_DSA_65" - fi - if test "$ENABLED_MLDSA87" = ""; then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_DSA_87" - fi - if test "$ENABLED_DILITHIUM_MAKE_KEY" = "no"; then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DILITHIUM_NO_MAKE_KEY" - fi - if test "$ENABLED_DILITHIUM_SIGN" = "no"; then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DILITHIUM_NO_SIGN" - fi - if test "$ENABLED_DILITHIUM_VERIFY" = "no"; then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DILITHIUM_NO_VERIFY" - fi - - if test "$ENABLED_LIBOQS" = "no"; then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_DILITHIUM" - AM_CCASFLAGS="$AM_CCASFLAGS -DWOLFSSL_WC_DILITHIUM" - test "$enable_sha3" = "" && enable_sha3=yes - test "$enable_shake128" = "" && enable_shake128=yes - test "$enable_shake256" = "" && enable_shake256=yes - fi - ENABLED_CERTS=yes -fi - # XMSS ENABLED_WC_XMSS=no AC_ARG_ENABLE([xmss], @@ -1940,19 +1917,6 @@ AC_ARG_WITH([libxmss], [XMSS_ROOT=""] ) -if test "$ENABLED_XMSS" != "no" -then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_XMSS" - - # Use hash-sigs XMSS lib if enabled. - if test "$ENABLED_LIBXMSS" = "yes"; then - ENABLED_WC_XMSS=no - else - ENABLED_WC_XMSS=yes - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_XMSS" - fi -fi - # LMS ENABLED_WC_LMS=no AC_ARG_ENABLE([lms], @@ -1980,6 +1944,9 @@ do sha256-192) AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_LMS_SHA256_192" ;; + shake256) + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_LMS_SHAKE256" + ;; *) AC_MSG_ERROR([Invalid choice for LMS []: $ENABLED_LMS.]) break;; @@ -2054,19 +2021,6 @@ AC_ARG_WITH([liblms], ] ) -if test "$ENABLED_LMS" != "no" -then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_LMS" - - # Use hash-sigs LMS lib if enabled. - if test "$ENABLED_LIBLMS" = "yes"; then - ENABLED_WC_LMS=no - else - ENABLED_WC_LMS=yes - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_LMS" - fi -fi - # SLH-DSA ENABLED_SLHDSA=yes AC_ARG_ENABLE([slhdsa], @@ -2121,59 +2075,50 @@ do no-f) AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_FAST" ;; + sha2) + SLHDSA_SHA2=yes + SLHDSA_PARAM_SHA2_128S=yes + SLHDSA_PARAM_SHA2_128F=yes + SLHDSA_PARAM_SHA2_192S=yes + SLHDSA_PARAM_SHA2_192F=yes + SLHDSA_PARAM_SHA2_256S=yes + SLHDSA_PARAM_SHA2_256F=yes + ;; + sha2-128s) + SLHDSA_SHA2=yes + SLHDSA_PARAM_SHA2_128S=yes + ;; + sha2-128f) + SLHDSA_SHA2=yes + SLHDSA_PARAM_SHA2_128F=yes + ;; + sha2-192s) + SLHDSA_SHA2=yes + SLHDSA_PARAM_SHA2_192S=yes + ;; + sha2-192f) + SLHDSA_SHA2=yes + SLHDSA_PARAM_SHA2_192F=yes + ;; + sha2-256s) + SLHDSA_SHA2=yes + SLHDSA_PARAM_SHA2_256S=yes + ;; + sha2-256f) + SLHDSA_SHA2=yes + SLHDSA_PARAM_SHA2_256F=yes + ;; + no-sha2-s) + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL" + ;; + no-sha2-f) + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST" + ;; *) AC_MSG_ERROR([Invalid choice for SLH-DSA []: $ENABLED_SLHDSA.]) break;; esac done - -if test "$ENABLED_SLHDSA" != "no" -then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_SLHDSA" - AM_CCASFLAGS="$AM_CCASFLAGS -DWOLFSSL_HAVE_SLHDSA" - - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_SLHDSA" - - if test "$SLHDSA_PARAM_128S" = "yes" - then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_128S" - else - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_128S" - fi - if test "$SLHDSA_PARAM_128F" = "yes" - then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_128F" - else - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_128F" - fi - if test "$SLHDSA_PARAM_192S" = "yes" - then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_192S" - else - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_192S" - fi - if test "$SLHDSA_PARAM_192F" = "yes" - then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_192F" - else - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_192F" - fi - if test "$SLHDSA_PARAM_256S" = "yes" - then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_256S" - else - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_256S" - fi - if test "$SLHDSA_PARAM_256F" = "yes" - then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_256F" - else - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_256F" - fi - - enable_shake256=yes -fi - # SINGLE THREADED AC_ARG_ENABLE([singlethreaded], [AS_HELP_STRING([--enable-singlethreaded],[Enable wolfSSL single threaded (default: disabled)])], @@ -4557,6 +4502,17 @@ AC_ARG_ENABLE([shake128], [ ENABLED_SHAKE128=$SHAKE_DEFAULT ] ) +# MLKEM requires SHAKE128. Force-enable when MLKEM is enabled. +if test "$ENABLED_MLKEM" != "no" +then + if test "$ENABLED_SHAKE128" = "no" + then + AC_MSG_NOTICE([MLKEM enabled (not explicitly disabled); overriding --disable-shake128 to enable SHAKE128]) + ENABLED_SHAKE128=yes + enable_shake128=yes + fi +fi + # SHAKE256 AC_ARG_ENABLE([shake256], [AS_HELP_STRING([--enable-shake256],[Enable wolfSSL SHAKE256 support (default: disabled)])], @@ -4564,6 +4520,17 @@ AC_ARG_ENABLE([shake256], [ ENABLED_SHAKE256=$SHAKE_DEFAULT ] ) +# MLKEM requires SHAKE256. Force-enable when MLKEM is enabled. +if test "$ENABLED_MLKEM" != "no" +then + if test "$ENABLED_SHAKE256" = "no" + then + AC_MSG_NOTICE([MLKEM enabled (not explicitly disabled); overriding --disable-shake256 to enable SHAKE256]) + ENABLED_SHAKE256=yes + enable_shake256=yes + fi +fi + # SHA512 AC_ARG_ENABLE([sha512], [AS_HELP_STRING([--enable-sha512],[Enable wolfSSL SHA-512 support (default: enabled)])], @@ -4589,6 +4556,25 @@ then AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SHA512" fi +# SHA-256 Hash DRBG (SP 800-90A) -- sub-option of hashdrbg +AC_ARG_ENABLE([sha256-drbg], + [AS_HELP_STRING([--enable-sha256-drbg],[Enable SHA-256 Hash DRBG (default: enabled)])], + [ ENABLED_SHA256_DRBG=$enableval ], + [ ENABLED_SHA256_DRBG=yes ] + ) + +# SHA-512 Hash DRBG (SP 800-90A) -- sub-option of hashdrbg +AC_ARG_ENABLE([sha512-drbg], + [AS_HELP_STRING([--enable-sha512-drbg],[Enable SHA-512 Hash DRBG (default: enabled)])], + [ ENABLED_SHA512_DRBG=$enableval ], + [ ENABLED_SHA512_DRBG=yes ] + ) + +# SHA-512 DRBG requires SHA-512 +if test "$ENABLED_SHA512" != "yes" +then + ENABLED_SHA512_DRBG=no +fi # SHA384 AC_ARG_ENABLE([sha384], @@ -6132,12 +6118,12 @@ AC_ARG_ENABLE([aeskeywrap], # FIPS feature and macro setup AS_CASE([$FIPS_VERSION], - [v6|ready|dev],[ # FIPS 140-3 SRTP-KDF + [v7|ready|dev],[ # FIPS 140-3 PQ-FS AS_IF([test "$FIPS_VERSION" = "dev"], ENABLED_FIPS_DEV=yes [AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_FIPS_DEV"]) - AS_IF([test "$FIPS_VERSION" = "ready"], + AS_IF([test "$FIPS_VERSION" = "ready" || test "$FIPS_VERSION" = "v7"], ENABLED_FIPS_READY=yes [AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_FIPS_READY"]) @@ -6253,8 +6239,248 @@ AS_CASE([$FIPS_VERSION], (test "$FIPS_VERSION" != "dev" || test "$enable_sha512" != "no")], [ENABLED_SHA512="yes"; AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SHA512 -DWOLFSSL_SHA384"]) - # SHA512-224 and SHA512-256 are SHA-2 algorithms not in our FIPS algorithm list - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NOSHA512_224 -DWOLFSSL_NOSHA512_256" + # SHA512-224 and SHA512-256 enabled for FIPS v7+ (needed for ML-DSA + # HashML-DSA ACVP test vectors with SHA2-512/224 and SHA2-512/256) + + # Shake128 because we're testing SHAKE256 + AS_IF([test "x$ENABLED_SHAKE128" = "xno" && + (test "$FIPS_VERSION" != "dev" || test "$enable_shake128" != "no")], + [ENABLED_SHAKE128="yes"]) + + # Shake256 mandated for ED448 + AS_IF([test "x$ENABLED_SHAKE256" = "xno" && + (test "$FIPS_VERSION" != "dev" || test "$enable_shake256" != "no")], + [ENABLED_SHAKE256="yes"]) + +# Aes section + AS_IF([test "$ENABLED_AESCCM" != "yes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_aesccm" != "no")], + [ENABLED_AESCCM="yes"; AM_CFLAGS="$AM_CFLAGS -DHAVE_AESCCM"]) + + AS_IF([test "$ENABLED_AESCTR" != "yes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_aesctr" != "no")], + [ENABLED_AESCTR="yes"; AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_AES_COUNTER"]) + + AS_IF([test "$ENABLED_CMAC" != "yes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_cmac" != "no")], + [ENABLED_CMAC="yes"; AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_CMAC"]) + + AS_IF([test "$ENABLED_AESGCM" = "no" && + (test "$FIPS_VERSION" != "dev" || test "$enable_aesgcm" != "no")], + [ENABLED_AESGCM="yes"; AM_CFLAGS="$AM_CFLAGS -DHAVE_AESGCM"; AM_CCASFLAGS="$AM_CCASFLAGS -DHAVE_AESGCM"]) + + AS_IF([test "$ENABLED_AESGCM_STREAM" != "yes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_aesgcm_stream" != "no")], + [ENABLED_AESGCM_STREAM="yes"]) + + AS_IF([test "x$ENABLED_AESOFB" = "xno" && + (test "$FIPS_VERSION" != "dev" || test "$enable_aesofb" != "no")], + [ENABLED_AESOFB="yes"; AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_AES_OFB"]) + + AS_IF([test "x$ENABLED_AESCFB" = "xno" && + (test "$FIPS_VERSION" != "dev" || test "$enable_aescfb" != "no")], + [ENABLED_AESCFB="yes"; AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_AES_CFB"]) + + AS_IF([test "x$ENABLED_AESXTS" = "xno" && + (test "$FIPS_VERSION" != "dev" || test "$enable_aesxts" != "no")], + [ENABLED_AESXTS="yes"; AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_AES_XTS"]) + AS_IF([test "x$ENABLED_AESXTS" = "xyes" && test "x$ENABLED_AESNI" = "xyes"], + [AM_CCASFLAGS="$AM_CCASFLAGS -DWOLFSSL_AES_XTS"]) + + AS_IF([test "x$ENABLED_AESXTS_STREAM" = "xno" && + (test "$FIPS_VERSION" != "dev" || test "$enable_aesxts_stream" != "no")], + [ENABLED_AESXTS_STREAM="yes"]) + + AS_IF([(test "$ENABLED_AESCCM" != "no" && test "$HAVE_AESCCM_PORT" != "yes") || + (test "$ENABLED_AESCTR" != "no" && test "$HAVE_AESCTR_PORT" != "yes") || + (test "$ENABLED_AESGCM" != "no" && test "$HAVE_AESGCM_PORT" != "yes") || + (test "$ENABLED_AESOFB" != "no" && test "$HAVE_AESOFB_PORT" != "yes")], + [AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_AES_DIRECT -DHAVE_AES_ECB"]) + + AS_IF([test "x$ENABLED_AESKEYWRAP" != "xyes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_aeskeywrap" != "no")], + [ENABLED_AESKEYWRAP="yes"; AM_CFLAGS="$AM_CFLAGS -DHAVE_AES_KEYWRAP"]) + +# Post-Quantum section + AS_IF([test "$ENABLED_MLKEM" != "yes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_mlkem" != "no")], + [ENABLED_MLKEM="yes" + ENABLED_MLKEM512="yes" + ENABLED_MLKEM768="yes" + ENABLED_MLKEM1024="yes" + ENABLED_MLKEM_MAKE_KEY="yes" + ENABLED_MLKEM_ENCAPSULATE="yes" + ENABLED_MLKEM_DECAPSULATE="yes"]) + + AS_IF([test "$ENABLED_DILITHIUM" != "yes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_dilithium" != "no")], + [ENABLED_DILITHIUM="yes" + ENABLED_MLDSA44="yes" + ENABLED_MLDSA65="yes" + ENABLED_MLDSA87="yes" + ENABLED_DILITHIUM_MAKE_KEY="yes" + ENABLED_DILITHIUM_SIGN="yes" + ENABLED_DILITHIUM_VERIFY="yes"]) + + AS_IF([test "$ENABLED_XMSS" != "yes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_xmss" != "no")], + [ENABLED_XMSS="yes"]) + + AS_IF([test "$ENABLED_LMS" != "yes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_lms" != "no")], + [ENABLED_LMS="yes"]) + # LMS: enable SHA-256/192 and SHAKE256 parameter sets for FIPS v7 + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_LMS_SHA256_192 -DWOLFSSL_LMS_SHAKE256" + + AS_IF([test "$ENABLED_SLHDSA" != "yes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_slhdsa" != "no")], + [ENABLED_SLHDSA="yes" + SLHDSA_PARAM_128S="yes" + SLHDSA_PARAM_128F="yes" + SLHDSA_PARAM_192S="yes" + SLHDSA_PARAM_192F="yes" + SLHDSA_PARAM_256S="yes" + SLHDSA_PARAM_256F="yes" + SLHDSA_SHA2="yes" + SLHDSA_PARAM_SHA2_128S="yes" + SLHDSA_PARAM_SHA2_128F="yes" + SLHDSA_PARAM_SHA2_192S="yes" + SLHDSA_PARAM_SHA2_192F="yes" + SLHDSA_PARAM_SHA2_256S="yes" + SLHDSA_PARAM_SHA2_256F="yes"]) + +# SHA-256 DRBG -- cannot be disabled at build time in FIPS mode + AS_IF([test "$enable_sha256_drbg" = "no"], + [AC_MSG_WARN([Can not disable SHA256-DRBG at build time in FIPS mode, disable at run-time with wc_Sha256Drbg_Disable() or wc_Sha256Drbg_Disable_fips()])]) + ENABLED_SHA256_DRBG="yes" + +# SHA-512 DRBG -- cannot be disabled at build time in FIPS mode + AS_IF([test "$enable_sha512_drbg" = "no"], + [AC_MSG_WARN([Can not disable SHA512-DRBG at build time in FIPS mode, disable it at run-time with wc_Sha512Drbg_Disable() or wc_Sha512Drbg_Disable_fips()])]) + ENABLED_SHA512_DRBG="yes" + +# Old TLS requires MD5 + HMAC, which is not allowed under FIPS 140-3 + AS_IF([test "$ENABLED_OLD_TLS" != "no"], + [AC_MSG_WARN([Forcing off oldtls for FIPS ${FIPS_VERSION}.]) + ENABLED_OLD_TLS="no"; AM_CFLAGS="$AM_CFLAGS -DNO_OLD_TLS"]) + + ], + + [v6],[ # FIPS 140-3 SRTP-KDF (frozen) + + AM_CFLAGS="$AM_CFLAGS \ + -DHAVE_FIPS \ + -DHAVE_FIPS_VERSION=$HAVE_FIPS_VERSION \ + -DHAVE_FIPS_VERSION_MAJOR=$HAVE_FIPS_VERSION_MAJOR \ + -DHAVE_FIPS_VERSION_MINOR=$HAVE_FIPS_VERSION_MINOR \ + -DHAVE_FIPS_VERSION_PATCH=$HAVE_FIPS_VERSION_PATCH \ + -DHAVE_ECC_CDH \ + -DWC_RSA_NO_PADDING \ + -DECC_USER_CURVES \ + -DHAVE_ECC384 \ + -DHAVE_ECC521 \ + -DWOLFSSL_VALIDATE_FFC_IMPORT \ + -DHAVE_FFDHE_Q \ + -DHAVE_FFDHE_3072 \ + -DHAVE_FFDHE_4096 \ + -DHAVE_FFDHE_6144 \ + -DHAVE_FFDHE_8192" + + # KCAPI API does not support custom k for sign, don't force enable ECC key sizes and don't use seed callback + AS_IF([test "x$ENABLED_KCAPI_ECC" = "xno"], + [AM_CFLAGS="$AM_CFLAGS \ + -DWC_RNG_SEED_CB \ + -DWOLFSSL_ECDSA_SET_K \ + -DWOLFSSL_VALIDATE_ECC_IMPORT \ + -DWOLFSSL_VALIDATE_ECC_KEYGEN \ + -DHAVE_ECC192 \ + -DHAVE_ECC224 \ + -DHAVE_ECC256"]) + + DEFAULT_MAX_CLASSIC_ASYM_KEY_BITS=8192 +# optimizations section + +# protocol section + AS_IF([test "$ENABLED_WOLFSSH" != "yes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_ssh" != "no")], + [enable_ssh="yes"]) + + AS_IF([test "$ENABLED_HKDF" != "yes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_hkdf" != "no")], + [ENABLED_HKDF="yes"; AM_CFLAGS="$AM_CFLAGS -DHAVE_HKDF"]) + + AS_IF([test "x$ENABLED_PWDBASED" = "xno" && + (test "$FIPS_VERSION" != "dev" || test "$enable_pwdbased" != "no")], + [ENABLED_PWDBASED="yes"; AM_CFLAGS="$AM_CFLAGS -DHAVE_PBKDF2 -DHAVE_AESGCM"]) + + AS_IF([test "x$ENABLED_SRTP" = "xno" && + (test "$FIPS_VERSION" != "dev" || test "$enable_srtp" != "no")], + [ENABLED_SRTP="yes"]) + AS_IF([test "x$ENABLED_SRTP_KDF" = "xno" && + (test "$FIPS_VERSION" != "dev" || test "$enable_srtp_kdf" != "no")], + [ENABLED_SRTP_KDF="yes"]) + +# public key section + AS_IF([test "$ENABLED_KEYGEN" != "yes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_keygen" != "no")], + [ENABLED_KEYGEN="yes"; AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_KEY_GEN"]) + +# AS_IF([test "$ENABLED_COMPKEY" != "yes" && +# (test "$FIPS_VERSION" != "dev" || test "$enable_compkey" != "yes")], +# [ENABLED_COMPKEY="yes"]) + + AS_IF([test "$ENABLED_RSAPSS" != "yes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_rsapss" != "no")], + [ENABLED_RSAPSS="yes"; AM_CFLAGS="$AM_CFLAGS -DWC_RSA_PSS"]) + + AS_IF([test "$ENABLED_ECC" != "yes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_ecc" != "no")], + [ENABLED_ECC="yes"; AM_CFLAGS="$AM_CFLAGS -DHAVE_ECC -DTFM_ECC256" + AS_IF([test "$ENABLED_ECC_SHAMIR" = "yes"], + [AM_CFLAGS="$AM_CFLAGS -DECC_SHAMIR"])]) + + AS_IF([test "$ENABLED_ED25519" = "no" && + (test "$FIPS_VERSION" != "dev" || test "$enable_ed25519" != "no")], + [ENABLED_ED25519="yes"; AM_CFLAGS="$AM_CFLAGS -DHAVE_ED25519 -DHAVE_ED25519_KEY_IMPORT"]) + + AS_IF([test "$ENABLED_CURVE25519" != "no" && + (test "$FIPS_VERSION" != "dev" || test "$enable_curve25519" = "")], + [ENABLED_CURVE25519="no"; AM_CFLAGS="$AM_CFLAGS"]) + + AS_IF([test "x$ENABLED_ED448" != "xyes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_ed448" != "no")], + [ENABLED_ED448="yes"; AM_CFLAGS="$AM_CFLAGS -DHAVE_ED448 -DHAVE_ED448_KEY_IMPORT"]) + + AS_IF([test "$ENABLED_CURVE448" != "no" && + (test "$FIPS_VERSION" != "dev" || test "$enable_curve448" = "")], + [ENABLED_CURVE448="no"; AM_CFLAGS="$AM_CFLAGS"]) + + AS_IF([test "x$ENABLED_ED25519_STREAM" != "xyes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_ed25519_stream" != "no")], + [ENABLED_ED25519_STREAM="yes"]) + AS_IF([test "x$ENABLED_ED448_STREAM" != "xyes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_ed448_stream" != "no")], + [ENABLED_ED448_STREAM="yes"]) + + AS_IF([test "x$ENABLED_ECCCUSTCURVES" != "xno" && + test "$FIPS_VERSION" != "dev"], + [AC_MSG_WARN([Forcing off ecccustcurves for FIPS ${FIPS_VERSION}.]) + ENABLED_ECCCUSTCURVES="no"]) + +# Hashing section + AS_IF([test "x$ENABLED_SHA3" != "xyes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_sha3" != "no")], + [ENABLED_SHA3="yes"; AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SHA3"]) + + AS_IF([test "$ENABLED_SHA224" != "yes" && + (test "$FIPS_VERSION" != "dev" || test "$enable_sha224" != "no")], + [ENABLED_SHA224="yes"; AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SHA224"]) + + AS_IF([test "$ENABLED_SHA512" = "no" && + (test "$FIPS_VERSION" != "dev" || test "$enable_sha512" != "no")], + [ENABLED_SHA512="yes"; AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SHA512 -DWOLFSSL_SHA384"]) + + # SHA512-224 and SHA512-256 are needed for HashML-DSA (FIPS 204) # Shake128 because we're testing SHAKE256 AS_IF([test "x$ENABLED_SHAKE128" = "xno" && @@ -6990,6 +7216,10 @@ then AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_EXTRA_PQC_HYBRIDS" fi +# Selftest uses its own random.c which doesn't support SHA-512 DRBG +# or runtime DRBG disable/enable APIs +AS_IF([test "x$ENABLED_SELFTEST" = "xyes"], + [ENABLED_SHA512_DRBG=no]) AS_IF([test "x$ENABLED_AESXTS" = "xyes"], [AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_AES_XTS -DWOLFSSL_AES_DIRECT"]) @@ -7096,6 +7326,21 @@ then AM_CFLAGS="$AM_CFLAGS -DWC_SRTP_KDF -DHAVE_AES_ECB -DWOLFSSL_AES_DIRECT" fi +# ML-KEM and Dilithium require SHA-3 and SHAKE -- force them on before flag +# processing so that the correct -D flags are emitted. +if test "$ENABLED_MLKEM" != "no" && test "$ENABLED_LIBOQS" = "no" +then + ENABLED_SHA3=yes + ENABLED_SHAKE128=yes + ENABLED_SHAKE256=yes +fi +if test "$ENABLED_DILITHIUM" != "no" && test "$ENABLED_LIBOQS" = "no" +then + ENABLED_SHA3=yes + ENABLED_SHAKE128=yes + ENABLED_SHAKE256=yes +fi + # Set SHA-3 flags if test "$ENABLED_SHA3" != "no" then @@ -7134,6 +7379,305 @@ else AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_SHAKE256" fi +# MLKEM CFLAG processing (after FIPS section for sandwich pattern) +if test "$ENABLED_MLKEM" != "no" +then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_MLKEM" + # Use liboqs if specified. + if test "$ENABLED_LIBOQS" = "no"; then + ENABLED_WC_MLKEM=yes + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_MLKEM" + AM_CCASFLAGS="$AM_CCASFLAGS -DWOLFSSL_WC_MLKEM" + fi + + if test "$ENABLED_ORIGINAL" = "yes"; then + # FIPS 203 (ML-KEM) and Kyber use different implicit rejection. + # Kyber mode must not be used in FIPS v7+ builds. + AS_IF([test "$HAVE_FIPS_VERSION" -ge 7], + [AC_MSG_ERROR([Kyber (--enable-mlkem=original) is not compatible with FIPS v7+. Use ML-KEM (FIPS 203) instead.])]) + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_MLKEM_KYBER" + if test "$ENABLED_MLKEM512" = ""; then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_KYBER512" + fi + if test "$ENABLED_MLKEM768" = ""; then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_KYBER768" + fi + if test "$ENABLED_MLKEM1024" = ""; then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_KYBER1024" + fi + if test "$ENABLED_ML_KEM" = "unset"; then + ENABLED_ML_KEM=no + fi + fi + if test "$ENABLED_ML_KEM" = "unset"; then + ENABLED_ML_KEM=yes + fi + if test "$ENABLED_ML_KEM" = "yes"; then + if test "$ENABLED_MLKEM512" = ""; then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_KEM_512" + fi + if test "$ENABLED_MLKEM768" = ""; then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_KEM_768" + fi + if test "$ENABLED_MLKEM1024" = ""; then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_KEM_1024" + fi + else + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_KEM" + fi + if test "$ENABLED_MLKEM_MAKE_KEY" = "no"; then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_MLKEM_NO_MAKE_KEY" + fi + if test "$ENABLED_MLKEM_ENCAPSULATE" = "no"; then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_MLKEM_NO_ENCAPSULATE" + fi + if test "$ENABLED_MLKEM_DECAPSULATE" = "no"; then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_MLKEM_NO_DECAPSULATE" + fi + + if test "$ENABLED_WC_MLKEM" = "yes" + then + test "$enable_sha3" = "" && enable_sha3=yes + test "$enable_shake128" = "" && enable_shake128=yes + test "$enable_shake256" = "" && enable_shake256=yes + fi +fi + +AC_ARG_ENABLE([tls-mlkem-standalone], + [AS_HELP_STRING([--enable-tls-mlkem-standalone],[Enable ML-KEM as standalone TLS key exchange (non-hybrid) (default: disabled)])], + [ ENABLED_MLKEM_STANDALONE=$enableval ], + [ ENABLED_MLKEM_STANDALONE=no ] + ) + +AS_IF([ test "$ENABLED_MLKEM_STANDALONE" = "yes" && test "$ENABLED_ML_KEM" = "no" ],[AC_MSG_ERROR([ML-KEM as standalone TLS key exchange (non-hybrid) requires ML-KEM.])]) +if test "$ENABLED_MLKEM_STANDALONE" != "yes" +then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_TLS_NO_MLKEM_STANDALONE" +fi + +AC_ARG_ENABLE([pqc-hybrids], + [AS_HELP_STRING([--enable-pqc-hybrids],[Enable PQ/T hybrid combinations (default: enabled)])], + [ ENABLED_PQC_HYBRIDS=$enableval ], + [ ENABLED_PQC_HYBRIDS=yes ] + ) + +if test "$ENABLED_PQC_HYBRIDS" = "yes" +then + if test "$ENABLED_ML_KEM" = "no" || test "$ENABLED_MLKEM" = "no" + then + ENABLED_PQC_HYBRIDS=no + elif test "$ENABLED_MLKEM768" = "" && test "$ENABLED_MLKEM1024" = ""; then + AC_MSG_NOTICE([PQC hybrid combinations require either ML-KEM 768 or ML-KEM 1024, but both disabled.]) + ENABLED_PQC_HYBRIDS=no + else + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_PQC_HYBRIDS" + fi +fi + +if test "$ENABLED_ML_KEM" != "no" && test "$ENABLED_MLKEM" != "no" +then + if test "$ENABLED_PQC_HYBRIDS" = "no" && test "$ENABLED_MLKEM_STANDALONE" = "no" && test "$ENABLED_CRYPTONLY" = "no" + then + AC_MSG_ERROR([Both hybrid PQ/T and standalone ML-KEM are disabled, so no PQC hybrid combinations will be available.]) + fi +fi + +# Extra PQ/T Hybrid combinations +AC_ARG_ENABLE([extra-pqc-hybrids], + [AS_HELP_STRING([--enable-extra-pqc-hybrids],[Enable extra PQ/T hybrid combinations (default: disabled)])], + [ ENABLED_EXTRA_PQC_HYBRIDS=$enableval ], + [ ENABLED_EXTRA_PQC_HYBRIDS=no ] + ) + +if test "$ENABLED_EXTRA_PQC_HYBRIDS" = "yes" +then + AS_IF([ test "$ENABLED_EXPERIMENTAL" != "yes" ],[ AC_MSG_ERROR([extra-pqc-hybrids requires --enable-experimental.]) ]) + AS_IF([ test "$ENABLED_ML_KEM" = "no" ],[ AC_MSG_ERROR([extra-pqc-hybrids requires ML-KEM.]) ]) + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_EXTRA_PQC_HYBRIDS" +fi + +# Dilithium CFLAG processing (after FIPS section for sandwich pattern) +if test "$ENABLED_DILITHIUM" != "no" +then + AM_CFLAGS="$AM_CFLAGS -DHAVE_DILITHIUM" + + if test "$ENABLED_MLDSA44" = ""; then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_DSA_44" + fi + if test "$ENABLED_MLDSA65" = ""; then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_DSA_65" + fi + if test "$ENABLED_MLDSA87" = ""; then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_DSA_87" + fi + if test "$ENABLED_DILITHIUM_MAKE_KEY" = "no"; then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DILITHIUM_NO_MAKE_KEY" + fi + if test "$ENABLED_DILITHIUM_SIGN" = "no"; then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DILITHIUM_NO_SIGN" + fi + if test "$ENABLED_DILITHIUM_VERIFY" = "no"; then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DILITHIUM_NO_VERIFY" + fi + + if test "$ENABLED_LIBOQS" = "no"; then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_DILITHIUM" + AM_CCASFLAGS="$AM_CCASFLAGS -DWOLFSSL_WC_DILITHIUM" + test "$enable_sha3" = "" && enable_sha3=yes + test "$enable_shake128" = "" && enable_shake128=yes + test "$enable_shake256" = "" && enable_shake256=yes + fi + ENABLED_CERTS=yes +fi + +# XMSS CFLAG processing (after FIPS section for sandwich pattern) +if test "$ENABLED_XMSS" != "no" +then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_XMSS" + + # Use hash-sigs XMSS lib if enabled. + if test "$ENABLED_LIBXMSS" = "yes"; then + ENABLED_WC_XMSS=no + else + ENABLED_WC_XMSS=yes + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_XMSS" + fi +fi + +# LMS CFLAG processing (after FIPS section for sandwich pattern) +if test "$ENABLED_LMS" != "no" +then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_LMS" + + # Use hash-sigs LMS lib if enabled. + if test "$ENABLED_LIBLMS" = "yes"; then + ENABLED_WC_LMS=no + else + ENABLED_WC_LMS=yes + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_LMS" + fi +fi + +# SLH-DSA CFLAG processing (after FIPS section for sandwich pattern) +if test "$ENABLED_SLHDSA" != "no" +then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_SLHDSA" + AM_CCASFLAGS="$AM_CCASFLAGS -DWOLFSSL_HAVE_SLHDSA" + + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_SLHDSA" + + if test "$SLHDSA_PARAM_128S" = "yes" + then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_128S" + else + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_128S" + fi + if test "$SLHDSA_PARAM_128F" = "yes" + then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_128F" + else + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_128F" + fi + if test "$SLHDSA_PARAM_192S" = "yes" + then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_192S" + else + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_192S" + fi + if test "$SLHDSA_PARAM_192F" = "yes" + then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_192F" + else + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_192F" + fi + if test "$SLHDSA_PARAM_256S" = "yes" + then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_256S" + else + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_256S" + fi + if test "$SLHDSA_PARAM_256F" = "yes" + then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_256F" + else + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_256F" + fi + + # SHA2 parameter set support + if test "$SLHDSA_SHA2" = "yes" + then + # Dependency checks for SHA2 SLH-DSA + if test "$ENABLED_SHA256" = "no" + then + AC_MSG_ERROR([SLH-DSA SHA2 requires SHA-256 (--enable-sha256)]) + fi + if test "$ENABLED_SHA512" = "no" + then + AC_MSG_ERROR([SLH-DSA SHA2 requires SHA-512 (--enable-sha512)]) + fi + if test "$ENABLED_HMAC" = "no" + then + AC_MSG_ERROR([SLH-DSA SHA2 requires HMAC (--enable-hmac)]) + fi + + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_SHA2" + + if test "$SLHDSA_PARAM_SHA2_128S" = "yes" + then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_SHA2_128S" + else + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_SHA2_128S" + fi + if test "$SLHDSA_PARAM_SHA2_128F" = "yes" + then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_SHA2_128F" + else + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_SHA2_128F" + fi + if test "$SLHDSA_PARAM_SHA2_192S" = "yes" + then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_SHA2_192S" + else + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_SHA2_192S" + fi + if test "$SLHDSA_PARAM_SHA2_192F" = "yes" + then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_SHA2_192F" + else + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_SHA2_192F" + fi + if test "$SLHDSA_PARAM_SHA2_256S" = "yes" + then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_SHA2_256S" + else + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_SHA2_256S" + fi + if test "$SLHDSA_PARAM_SHA2_256F" = "yes" + then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_SHA2_256F" + else + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SLHDSA_PARAM_NO_SHA2_256F" + fi + fi + + # SLH-DSA requires SHAKE-256 (and SHA-3 as its dependency). + # This runs after the SHAKE256 flags section, so we must set both the + # ENABLED variable and emit the CFLAGS ourselves. + if test "$ENABLED_SHAKE256" = "no" || test "$ENABLED_SHAKE256" = "" + then + ENABLED_SHAKE256=yes + if test "$ENABLED_SHA3" = "no" + then + ENABLED_SHA3=yes + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SHA3" + fi + # Remove -DWOLFSSL_NO_SHAKE256 if it was already added and add the + # positive define. + AM_CFLAGS=$(echo "$AM_CFLAGS" | sed 's/-DWOLFSSL_NO_SHAKE256//g') + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SHAKE256" + fi +fi + # set POLY1305 default POLY1305_DEFAULT=yes @@ -7248,27 +7792,60 @@ then AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_PUF_TEST" fi -# Hash DRBG +# Hash DRBG (master switch for all Hash DRBGs) AC_ARG_ENABLE([hashdrbg], [AS_HELP_STRING([--enable-hashdrbg],[Enable Hash DRBG support (default: enabled)])], [ ENABLED_HASHDRBG=$enableval ], [ ENABLED_HASHDRBG=yes ] ) +# If hashdrbg is explicitly disabled, force both sub-options off +if test "x$ENABLED_HASHDRBG" = "xno" +then + ENABLED_SHA256_DRBG=no + ENABLED_SHA512_DRBG=no +fi + +# If both sub-options are off, treat hashdrbg as off +if test "x$ENABLED_SHA256_DRBG" != "xyes" && test "x$ENABLED_SHA512_DRBG" != "xyes" +then + ENABLED_HASHDRBG=no +fi + +# FIPS override: Hash DRBG is mandatory +if test "x$ENABLED_HASHDRBG" != "xyes" && test "x$ENABLED_FIPS" = "xyes" && test "x$ENABLED_KCAPI" = "xno" +then + if test "$enable_hashdrbg" = "no" + then + AC_MSG_WARN([SHA256-DRBG required in FIPS build]) + fi + ENABLED_HASHDRBG=yes + ENABLED_SHA256_DRBG=yes +fi + +# SHA-512 DRBG and runtime DRBG disable/enable APIs are v7+ only +if test "x$ENABLED_FIPS" = "xyes" && test $HAVE_FIPS_VERSION -lt 7 +then + ENABLED_SHA512_DRBG=no +fi + +# Set Hash DRBG compiler flags if test "x$ENABLED_HASHDRBG" = "xyes" then AM_CFLAGS="$AM_CFLAGS -DHAVE_HASHDRBG" -else - # turn on Hash DRBG if FIPS is on (don't force on for KCAPI) - if test "x$ENABLED_FIPS" = "xyes" && test "x$ENABLED_KCAPI" = "xno" + if test "x$ENABLED_SHA256_DRBG" != "xyes" then - AM_CFLAGS="$AM_CFLAGS -DHAVE_HASHDRBG" - ENABLED_HASHDRBG=yes - else - AM_CFLAGS="$AM_CFLAGS -DWC_NO_HASHDRBG" + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_SHA256_DRBG" fi + if test "x$ENABLED_SHA512_DRBG" = "xyes" + then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DRBG_SHA512" + fi +else + AM_CFLAGS="$AM_CFLAGS -DWC_NO_HASHDRBG" fi + # MemUse Entropy (AKA wolfEntropy) if test "x$ENABLED_ENTROPY_MEMUSE" != "xno" then @@ -10860,6 +11437,11 @@ AS_IF([test "x$ENABLED_MAXSTRENGTH" = "xyes" && \ test "x$ENABLED_LEANPSK" = "xyes"], [AC_MSG_ERROR([Cannot use Max Strength and Lean PSK at the same time.])]) +AS_IF([test "x$ENABLED_CRYPTONLY" = "xno" && \ + test "x$ENABLED_PSK" = "xno" && \ + test "x$ENABLED_ASN" = "xno"], + [AC_MSG_ERROR([please enable psk if disabling asn.])]) + AS_IF([test "x$ENABLED_OCSP" = "xyes" && \ test "x$ENABLED_ASN" = "xno"], [AC_MSG_ERROR([please enable asn if enabling ocsp.])]) @@ -11625,6 +12207,8 @@ AM_CONDITIONAL([BUILD_FIPS_V5],[test "$HAVE_FIPS_VERSION" = 5]) AM_CONDITIONAL([BUILD_FIPS_V5_PLUS],[test "$HAVE_FIPS_VERSION" -ge 5]) AM_CONDITIONAL([BUILD_FIPS_V6],[test $HAVE_FIPS_VERSION = 6]) AM_CONDITIONAL([BUILD_FIPS_V6_PLUS],[test $HAVE_FIPS_VERSION -ge 6]) +AM_CONDITIONAL([BUILD_FIPS_V7],[test $HAVE_FIPS_VERSION = 7]) +AM_CONDITIONAL([BUILD_FIPS_V7_PLUS],[test $HAVE_FIPS_VERSION -ge 7]) AM_CONDITIONAL([BUILD_SIPHASH],[test "x$ENABLED_SIPHASH" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_CMAC],[test "x$ENABLED_CMAC" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_SHE],[test "x$ENABLED_SHE" = "xstandard" || test "x$ENABLED_SHE" = "xextended" || test "x$ENABLED_USERSETTINGS" = "xyes"]) @@ -12115,6 +12699,8 @@ echo " * certgencache: $ENABLED_certgencache" echo " * CHACHA: $ENABLED_CHACHA" echo " * XCHACHA: $ENABLED_XCHACHA" echo " * Hash DRBG: $ENABLED_HASHDRBG" +echo " * SHA-256 Hash DRBG: $ENABLED_SHA256_DRBG" +echo " * SHA-512 Hash DRBG: $ENABLED_SHA512_DRBG" echo " * MmemUse Entropy:" echo " * (AKA: wolfEntropy): $ENABLED_ENTROPY_MEMUSE" echo " * PWDBASED: $ENABLED_PWDBASED" diff --git a/doc/dox_comments/header_files/random.h b/doc/dox_comments/header_files/random.h index ead9011d46..fa870a927e 100644 --- a/doc/dox_comments/header_files/random.h +++ b/doc/dox_comments/header_files/random.h @@ -583,3 +583,240 @@ int wc_Entropy_Get(int bits, unsigned char* entropy, word32 len); \sa wc_Entropy_Get */ int wc_Entropy_OnDemandTest(void); + +/*! + \ingroup Random + + \brief Runs the SHA-512 Hash_DRBG Known Answer Test (KAT) per + SP 800-90A. Instantiates a SHA-512 DRBG with seedA, optionally + reseeds with seedB, generates output, and compares against known + test vectors. Available when WOLFSSL_DRBG_SHA512 is defined. + + \return 0 On success + \return BAD_FUNC_ARG If seedA or output is NULL, or if reseed is + set and seedB is NULL + \return -1 Test failed + + \param reseed Non-zero to test reseeding + \param seedA Initial entropy seed + \param seedASz Size of seedA in bytes + \param seedB Reseed entropy (required if reseed is set) + \param seedBSz Size of seedB in bytes + \param output Buffer to receive generated output + \param outputSz Size of output in bytes + + _Example_ + \code + byte output[WC_SHA512_DIGEST_SIZE * 4]; + const byte seedA[] = { ... }; + const byte seedB[] = { ... }; + + ret = wc_RNG_HealthTest_SHA512(0, seedA, sizeof(seedA), NULL, 0, + output, sizeof(output)); + if (ret != 0) + return -1; + + ret = wc_RNG_HealthTest_SHA512(1, seedA, sizeof(seedA), + seedB, sizeof(seedB), + output, sizeof(output)); + if (ret != 0) + return -1; + \endcode + + \sa wc_RNG_HealthTest + \sa wc_RNG_HealthTest_SHA512_ex +*/ +int wc_RNG_HealthTest_SHA512(int reseed, const byte* seedA, word32 seedASz, + const byte* seedB, word32 seedBSz, + byte* output, word32 outputSz); + +/*! + \ingroup Random + + \brief Extended SHA-512 Hash_DRBG health test with nonce, + personalization string, and additional input support. Suitable + for full ACVP / CAVP test vector validation. Available when + WOLFSSL_DRBG_SHA512 is defined. + + \return 0 On success + \return BAD_FUNC_ARG If required params are NULL + \return -1 Test failed + + \param reseed Non-zero to test reseeding + \param nonce Nonce buffer (can be NULL) + \param nonceSz Nonce size + \param persoString Personalization string (can be NULL) + \param persoStringSz Personalization string size + \param seedA Initial entropy seed + \param seedASz Initial seed size + \param seedB Reseed entropy (required if reseed is set) + \param seedBSz Reseed size + \param additionalA Additional input for first generate (can be NULL) + \param additionalASz Additional input A size + \param additionalB Additional input for second generate (can be NULL) + \param additionalBSz Additional input B size + \param output Output buffer + \param outputSz Output size + \param heap Heap hint (can be NULL) + \param devId Device ID (INVALID_DEVID for software) + + _Example_ + \code + byte output[WC_SHA512_DIGEST_SIZE * 4]; + const byte seedA[] = { ... }; + const byte nonce[] = { ... }; + + int ret = wc_RNG_HealthTest_SHA512_ex(0, nonce, sizeof(nonce), + NULL, 0, + seedA, sizeof(seedA), + NULL, 0, + NULL, 0, NULL, 0, + output, sizeof(output), + NULL, INVALID_DEVID); + \endcode + + \sa wc_RNG_HealthTest_SHA512 + \sa wc_RNG_HealthTest_ex +*/ +int wc_RNG_HealthTest_SHA512_ex(int reseed, const byte* nonce, word32 nonceSz, + const byte* persoString, word32 persoStringSz, + const byte* seedA, word32 seedASz, + const byte* seedB, word32 seedBSz, + const byte* additionalA, word32 additionalASz, + const byte* additionalB, word32 additionalBSz, + byte* output, word32 outputSz, + void* heap, int devId); + +/*! + \ingroup Random + + \brief Disables the SHA-256 Hash_DRBG at runtime. When disabled, + newly initialized WC_RNG instances will not use the SHA-256 DRBG. + If the SHA-512 DRBG is enabled (WOLFSSL_DRBG_SHA512), new RNG + instances will use SHA-512 instead. Requires HAVE_HASHDRBG. + + \return 0 On success + + _Example_ + \code + wc_Sha256Drbg_Disable(); + // New WC_RNG instances will now use SHA-512 DRBG if available + WC_RNG rng; + wc_InitRng(&rng); + \endcode + + \sa wc_Sha256Drbg_Enable + \sa wc_Sha256Drbg_IsDisabled + \sa wc_Sha512Drbg_Disable +*/ +int wc_Sha256Drbg_Disable(void); + +/*! + \ingroup Random + + \brief Re-enables the SHA-256 Hash_DRBG at runtime after a prior + call to wc_Sha256Drbg_Disable(). Requires HAVE_HASHDRBG. + + \return 0 On success + + _Example_ + \code + wc_Sha256Drbg_Disable(); + // ... use SHA-512 DRBG only ... + wc_Sha256Drbg_Enable(); + // New WC_RNG instances can use SHA-256 DRBG again + \endcode + + \sa wc_Sha256Drbg_Disable + \sa wc_Sha256Drbg_IsDisabled +*/ +int wc_Sha256Drbg_Enable(void); + +/*! + \ingroup Random + + \brief Returns whether the SHA-256 Hash_DRBG is currently disabled. + Requires HAVE_HASHDRBG. + + \return 1 SHA-256 DRBG is disabled + \return 0 SHA-256 DRBG is enabled (not disabled) + + _Example_ + \code + if (wc_Sha256Drbg_IsDisabled()) { + printf("SHA-256 DRBG is off\n"); + } + \endcode + + \sa wc_Sha256Drbg_Disable + \sa wc_Sha256Drbg_Enable +*/ +int wc_Sha256Drbg_IsDisabled(void); + +/*! + \ingroup Random + + \brief Disables the SHA-512 Hash_DRBG at runtime. When disabled, + newly initialized WC_RNG instances will not use the SHA-512 DRBG. + If the SHA-256 DRBG is still enabled, new RNG instances will fall + back to SHA-256. Available when WOLFSSL_DRBG_SHA512 is defined. + Requires HAVE_HASHDRBG. + + \return 0 On success + + _Example_ + \code + wc_Sha512Drbg_Disable(); + // New WC_RNG instances will now use SHA-256 DRBG + WC_RNG rng; + wc_InitRng(&rng); + \endcode + + \sa wc_Sha512Drbg_Enable + \sa wc_Sha512Drbg_IsDisabled + \sa wc_Sha256Drbg_Disable +*/ +int wc_Sha512Drbg_Disable(void); + +/*! + \ingroup Random + + \brief Re-enables the SHA-512 Hash_DRBG at runtime after a prior + call to wc_Sha512Drbg_Disable(). Available when WOLFSSL_DRBG_SHA512 + is defined. Requires HAVE_HASHDRBG. + + \return 0 On success + + _Example_ + \code + wc_Sha512Drbg_Disable(); + // ... use SHA-256 DRBG only ... + wc_Sha512Drbg_Enable(); + // New WC_RNG instances can use SHA-512 DRBG again + \endcode + + \sa wc_Sha512Drbg_Disable + \sa wc_Sha512Drbg_IsDisabled +*/ +int wc_Sha512Drbg_Enable(void); + +/*! + \ingroup Random + + \brief Returns whether the SHA-512 Hash_DRBG is currently disabled. + Available when WOLFSSL_DRBG_SHA512 is defined. Requires HAVE_HASHDRBG. + + \return 1 SHA-512 DRBG is disabled + \return 0 SHA-512 DRBG is enabled (not disabled) + + _Example_ + \code + if (wc_Sha512Drbg_IsDisabled()) { + printf("SHA-512 DRBG is off\n"); + } + \endcode + + \sa wc_Sha512Drbg_Disable + \sa wc_Sha512Drbg_Enable +*/ +int wc_Sha512Drbg_IsDisabled(void); diff --git a/doc/dox_comments/header_files/wc_slhdsa.h b/doc/dox_comments/header_files/wc_slhdsa.h new file mode 100644 index 0000000000..a520d153b2 --- /dev/null +++ b/doc/dox_comments/header_files/wc_slhdsa.h @@ -0,0 +1,793 @@ +/*! + \ingroup SLH_DSA + + \brief Initializes an SLH-DSA key object with the specified parameter set. + Must be called before any other SLH-DSA operation. Use wc_SlhDsaKey_Free() + to release resources when done. + + SLH-DSA (FIPS 205) is a stateless hash-based digital signature algorithm. + Parameter sets control the hash function (SHAKE or SHA2), security level + (128, 192, 256), and speed/size tradeoff (s = small signatures, + f = fast signing). + + \return 0 on success. + \return BAD_FUNC_ARG if key is NULL or param is invalid. + + \param [in,out] key Pointer to the SlhDsaKey to initialize. + \param [in] param Parameter set to use. One of: SLHDSA_SHAKE128S, + SLHDSA_SHAKE128F, SLHDSA_SHAKE192S, SLHDSA_SHAKE192F, SLHDSA_SHAKE256S, + SLHDSA_SHAKE256F, SLHDSA_SHA2_128S, SLHDSA_SHA2_128F, SLHDSA_SHA2_192S, + SLHDSA_SHA2_192F, SLHDSA_SHA2_256S, SLHDSA_SHA2_256F. + \param [in] heap Pointer to heap hint for dynamic memory allocation. + May be NULL. + \param [in] devId Device identifier for hardware crypto callbacks. + Use INVALID_DEVID for software-only. + + _Example_ + \code + SlhDsaKey key; + int ret; + + ret = wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID); + if (ret != 0) { + // error initializing key + } + // ... use key ... + wc_SlhDsaKey_Free(&key); + \endcode + + \sa wc_SlhDsaKey_Free + \sa wc_SlhDsaKey_MakeKey +*/ +int wc_SlhDsaKey_Init(SlhDsaKey* key, enum SlhDsaParam param, + void* heap, int devId); + +/*! + \ingroup SLH_DSA + + \brief Frees resources associated with an SLH-DSA key object. + + \param [in,out] key Pointer to the SlhDsaKey to free. May be NULL. + + _Example_ + \code + SlhDsaKey key; + wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID); + // ... use key ... + wc_SlhDsaKey_Free(&key); + \endcode + + \sa wc_SlhDsaKey_Init +*/ +void wc_SlhDsaKey_Free(SlhDsaKey* key); + +/*! + \ingroup SLH_DSA + + \brief Generates a new SLH-DSA key pair using the RNG for randomness. + The key must have been initialized with wc_SlhDsaKey_Init() first. + + \return 0 on success. + \return BAD_FUNC_ARG if key or rng is NULL, or key is not initialized. + + \param [in,out] key Pointer to an initialized SlhDsaKey. + \param [in] rng Pointer to an initialized WC_RNG. + + _Example_ + \code + SlhDsaKey key; + WC_RNG rng; + int ret; + + wc_InitRng(&rng); + wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID); + ret = wc_SlhDsaKey_MakeKey(&key, &rng); + if (ret != 0) { + // error generating key + } + \endcode + + \sa wc_SlhDsaKey_Init + \sa wc_SlhDsaKey_MakeKeyWithRandom +*/ +int wc_SlhDsaKey_MakeKey(SlhDsaKey* key, WC_RNG* rng); + +/*! + \ingroup SLH_DSA + + \brief Generates an SLH-DSA key pair from caller-provided seed material. + This is the deterministic key generation interface — given the same seeds, + the same key pair is produced. + + \return 0 on success. + \return BAD_FUNC_ARG if key or any seed pointer is NULL, or lengths + do not match the parameter set's n value. + + \param [in,out] key Pointer to an initialized SlhDsaKey. + \param [in] sk_seed Secret key seed (n bytes). + \param [in] sk_seed_len Length of sk_seed. + \param [in] sk_prf Secret key PRF seed (n bytes). + \param [in] sk_prf_len Length of sk_prf. + \param [in] pk_seed Public key seed (n bytes). + \param [in] pk_seed_len Length of pk_seed. + + _Example_ + \code + SlhDsaKey key; + byte sk_seed[16], sk_prf[16], pk_seed[16]; // n=16 for 128-bit params + int ret; + + // fill seeds with known values (e.g. from NIST test vectors) + wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID); + ret = wc_SlhDsaKey_MakeKeyWithRandom(&key, + sk_seed, sizeof(sk_seed), + sk_prf, sizeof(sk_prf), + pk_seed, sizeof(pk_seed)); + \endcode + + \sa wc_SlhDsaKey_MakeKey +*/ +int wc_SlhDsaKey_MakeKeyWithRandom(SlhDsaKey* key, + const byte* sk_seed, word32 sk_seed_len, + const byte* sk_prf, word32 sk_prf_len, + const byte* pk_seed, word32 pk_seed_len); + +/*! + \ingroup SLH_DSA + + \brief Signs a message using the SLH-DSA external (pure) interface with + deterministic randomness. This is FIPS 205 Algorithm 22 with opt_rand set + to PK.seed. The message M is wrapped internally as + M' = 0x00 || len(ctx) || ctx || M before signing. + + \return 0 on success. + \return BAD_FUNC_ARG if key, msg, sig, or sigSz is NULL. + \return BUFFER_E if the output buffer is too small. + + \param [in] key Pointer to a private SlhDsaKey. + \param [in] ctx Context string for domain separation. May be NULL if + ctxSz is 0. + \param [in] ctxSz Length of the context string (0-255). + \param [in] msg Pointer to the message to sign. + \param [in] msgSz Length of the message. + \param [out] sig Buffer to receive the signature. + \param [in,out] sigSz On input, size of sig buffer. On output, actual + signature length. + + _Example_ + \code + SlhDsaKey key; + byte sig[WC_SLHDSA_MAX_SIG_LEN]; + word32 sigSz = sizeof(sig); + byte msg[] = "Hello World!"; + int ret; + + // key already generated via wc_SlhDsaKey_MakeKey() + ret = wc_SlhDsaKey_SignDeterministic(&key, NULL, 0, + msg, sizeof(msg), sig, &sigSz); + \endcode + + \sa wc_SlhDsaKey_SignWithRandom + \sa wc_SlhDsaKey_Sign + \sa wc_SlhDsaKey_Verify +*/ +int wc_SlhDsaKey_SignDeterministic(SlhDsaKey* key, const byte* ctx, + byte ctxSz, const byte* msg, word32 msgSz, byte* sig, word32* sigSz); + +/*! + \ingroup SLH_DSA + + \brief Signs a message using the SLH-DSA external (pure) interface with + caller-provided additional randomness. This is FIPS 205 Algorithm 22 with + an explicit opt_rand value. + + \return 0 on success. + \return BAD_FUNC_ARG if key, msg, sig, sigSz, or addRnd is NULL. + + \param [in] key Pointer to a private SlhDsaKey. + \param [in] ctx Context string. May be NULL if ctxSz is 0. + \param [in] ctxSz Length of the context string (0-255). + \param [in] msg Pointer to the message to sign. + \param [in] msgSz Length of the message. + \param [out] sig Buffer to receive the signature. + \param [in,out] sigSz On input, size of sig buffer. On output, actual + signature length. + \param [in] addRnd Additional randomness (n bytes, where n is the + parameter set's security parameter). + + _Example_ + \code + SlhDsaKey key; + byte sig[WC_SLHDSA_MAX_SIG_LEN]; + word32 sigSz = sizeof(sig); + byte msg[] = "Hello World!"; + byte addRnd[16]; // n=16 for 128-bit params + int ret; + + wc_RNG_GenerateBlock(&rng, addRnd, sizeof(addRnd)); + ret = wc_SlhDsaKey_SignWithRandom(&key, NULL, 0, + msg, sizeof(msg), sig, &sigSz, addRnd); + \endcode + + \sa wc_SlhDsaKey_SignDeterministic + \sa wc_SlhDsaKey_Sign +*/ +int wc_SlhDsaKey_SignWithRandom(SlhDsaKey* key, const byte* ctx, + byte ctxSz, const byte* msg, word32 msgSz, byte* sig, word32* sigSz, + const byte* addRnd); + +/*! + \ingroup SLH_DSA + + \brief Signs a message using the SLH-DSA external (pure) interface with + RNG-provided randomness. This is the general-purpose signing function + that uses the WC_RNG for opt_rand. + + \return 0 on success. + \return BAD_FUNC_ARG if key, msg, sig, sigSz, or rng is NULL. + + \param [in] key Pointer to a private SlhDsaKey. + \param [in] ctx Context string. May be NULL if ctxSz is 0. + \param [in] ctxSz Length of the context string (0-255). + \param [in] msg Pointer to the message to sign. + \param [in] msgSz Length of the message. + \param [out] sig Buffer to receive the signature. + \param [in,out] sigSz On input, size of sig buffer. On output, actual + signature length. + \param [in] rng Pointer to an initialized WC_RNG. + + _Example_ + \code + SlhDsaKey key; + WC_RNG rng; + byte sig[WC_SLHDSA_MAX_SIG_LEN]; + word32 sigSz = sizeof(sig); + byte msg[] = "Hello World!"; + int ret; + + ret = wc_SlhDsaKey_Sign(&key, NULL, 0, + msg, sizeof(msg), sig, &sigSz, &rng); + \endcode + + \sa wc_SlhDsaKey_SignDeterministic + \sa wc_SlhDsaKey_Verify +*/ +int wc_SlhDsaKey_Sign(SlhDsaKey* key, const byte* ctx, + byte ctxSz, const byte* msg, word32 msgSz, byte* sig, word32* sigSz, + WC_RNG* rng); + +/*! + \ingroup SLH_DSA + + \brief Verifies an SLH-DSA signature over a message using the external + (pure) interface. This is FIPS 205 Algorithm 23. The message is wrapped + internally as M' = 0x00 || len(ctx) || ctx || M before verification. + + \return 0 on success (signature valid). + \return BAD_FUNC_ARG if key, msg, or sig is NULL. + \return SIG_VERIFY_E if the signature is invalid. + + \param [in] key Pointer to a public SlhDsaKey. + \param [in] ctx Context string. May be NULL if ctxSz is 0. + \param [in] ctxSz Length of the context string (0-255). + \param [in] msg Pointer to the message to verify. + \param [in] msgSz Length of the message. + \param [in] sig Pointer to the signature to verify. + \param [in] sigSz Length of the signature. + + _Example_ + \code + SlhDsaKey key; + byte sig[...]; // previously generated signature + word32 sigSz; + byte msg[] = "Hello World!"; + int ret; + + ret = wc_SlhDsaKey_Verify(&key, NULL, 0, + msg, sizeof(msg), sig, sigSz); + if (ret == 0) { + // signature is valid + } + \endcode + + \sa wc_SlhDsaKey_Sign + \sa wc_SlhDsaKey_SignDeterministic +*/ +int wc_SlhDsaKey_Verify(SlhDsaKey* key, const byte* ctx, + byte ctxSz, const byte* msg, word32 msgSz, const byte* sig, + word32 sigSz); + +/*! + \ingroup SLH_DSA + + \brief Signs using the SLH-DSA internal interface with deterministic + randomness. Unlike the external interface, M' is provided directly by + the caller — no 0x00||len(ctx)||ctx||M wrapping is performed. This + corresponds to FIPS 205 Algorithm 19 (slh_sign_internal) with opt_rand + set to PK.seed. + + Use this when the CAVP test framework or protocol layer has already + constructed M'. + + \return 0 on success. + \return BAD_FUNC_ARG if key, mprime, sig, or sigSz is NULL. + + \param [in] key Pointer to a private SlhDsaKey. + \param [in] mprime Pointer to the pre-constructed M' message. + \param [in] mprimeSz Length of M'. + \param [out] sig Buffer to receive the signature. + \param [in,out] sigSz On input, size of sig buffer. On output, actual + signature length. + + _Example_ + \code + SlhDsaKey key; + byte sig[WC_SLHDSA_MAX_SIG_LEN]; + word32 sigSz = sizeof(sig); + byte mprime[] = { ... }; // pre-constructed M' + int ret; + + ret = wc_SlhDsaKey_SignMsgDeterministic(&key, + mprime, sizeof(mprime), sig, &sigSz); + \endcode + + \sa wc_SlhDsaKey_SignMsgWithRandom + \sa wc_SlhDsaKey_VerifyMsg + \sa wc_SlhDsaKey_SignDeterministic +*/ +int wc_SlhDsaKey_SignMsgDeterministic(SlhDsaKey* key, + const byte* mprime, word32 mprimeSz, byte* sig, word32* sigSz); + +/*! + \ingroup SLH_DSA + + \brief Signs using the SLH-DSA internal interface with caller-provided + additional randomness. M' is provided directly — no wrapping is performed. + This corresponds to FIPS 205 Algorithm 19 (slh_sign_internal) with an + explicit opt_rand value. + + \return 0 on success. + \return BAD_FUNC_ARG if key, mprime, sig, sigSz, or addRnd is NULL. + + \param [in] key Pointer to a private SlhDsaKey. + \param [in] mprime Pointer to the pre-constructed M' message. + \param [in] mprimeSz Length of M'. + \param [out] sig Buffer to receive the signature. + \param [in,out] sigSz On input, size of sig buffer. On output, actual + signature length. + \param [in] addRnd Additional randomness (n bytes). + + _Example_ + \code + SlhDsaKey key; + byte sig[WC_SLHDSA_MAX_SIG_LEN]; + word32 sigSz = sizeof(sig); + byte mprime[] = { ... }; + byte addRnd[16]; + int ret; + + wc_RNG_GenerateBlock(&rng, addRnd, sizeof(addRnd)); + ret = wc_SlhDsaKey_SignMsgWithRandom(&key, + mprime, sizeof(mprime), sig, &sigSz, addRnd); + \endcode + + \sa wc_SlhDsaKey_SignMsgDeterministic + \sa wc_SlhDsaKey_VerifyMsg +*/ +int wc_SlhDsaKey_SignMsgWithRandom(SlhDsaKey* key, + const byte* mprime, word32 mprimeSz, byte* sig, word32* sigSz, + const byte* addRnd); + +/*! + \ingroup SLH_DSA + + \brief Verifies an SLH-DSA signature using the internal interface. M' is + provided directly — no wrapping is performed. This corresponds to FIPS 205 + Algorithm 20 (slh_verify_internal). + + \return 0 on success (signature valid). + \return BAD_FUNC_ARG if key, mprime, or sig is NULL. + \return SIG_VERIFY_E if the signature is invalid. + + \param [in] key Pointer to a public SlhDsaKey. + \param [in] mprime Pointer to the pre-constructed M' message. + \param [in] mprimeSz Length of M'. + \param [in] sig Pointer to the signature to verify. + \param [in] sigSz Length of the signature. + + _Example_ + \code + SlhDsaKey key; + byte sig[...]; // previously generated signature + word32 sigSz; + byte mprime[] = { ... }; + int ret; + + ret = wc_SlhDsaKey_VerifyMsg(&key, + mprime, sizeof(mprime), sig, sigSz); + if (ret == 0) { + // signature is valid + } + \endcode + + \sa wc_SlhDsaKey_SignMsgDeterministic + \sa wc_SlhDsaKey_Verify +*/ +int wc_SlhDsaKey_VerifyMsg(SlhDsaKey* key, const byte* mprime, + word32 mprimeSz, const byte* sig, word32 sigSz); + +/*! + \ingroup SLH_DSA + + \brief Signs a pre-hashed message using the SLH-DSA external (HashSLH-DSA) + interface with deterministic randomness. The message is hashed with the + specified hash algorithm, then signed per FIPS 205 Algorithm 22 with the + pre-hash domain separator (0x01). + + \return 0 on success. + \return BAD_FUNC_ARG if key, msg, sig, or sigSz is NULL, or hashType + is unsupported. + + \param [in] key Pointer to a private SlhDsaKey. + \param [in] ctx Context string. May be NULL if ctxSz is 0. + \param [in] ctxSz Length of the context string (0-255). + \param [in] msg Pointer to the message to hash and sign. + \param [in] msgSz Length of the message. + \param [in] hashType Hash algorithm to use for pre-hashing. Supported: + WC_HASH_TYPE_SHA256, WC_HASH_TYPE_SHA384, WC_HASH_TYPE_SHA512, + WC_HASH_TYPE_SHAKE128, WC_HASH_TYPE_SHAKE256, WC_HASH_TYPE_SHA3_224, + WC_HASH_TYPE_SHA3_256, WC_HASH_TYPE_SHA3_384, WC_HASH_TYPE_SHA3_512. + \param [out] sig Buffer to receive the signature. + \param [in,out] sigSz On input, size of sig buffer. On output, actual + signature length. + + _Example_ + \code + SlhDsaKey key; + byte sig[WC_SLHDSA_MAX_SIG_LEN]; + word32 sigSz = sizeof(sig); + byte msg[] = "Hello World!"; + int ret; + + ret = wc_SlhDsaKey_SignHashDeterministic(&key, NULL, 0, + msg, sizeof(msg), WC_HASH_TYPE_SHA256, sig, &sigSz); + \endcode + + \sa wc_SlhDsaKey_SignHashWithRandom + \sa wc_SlhDsaKey_SignHash + \sa wc_SlhDsaKey_VerifyHash +*/ +int wc_SlhDsaKey_SignHashDeterministic(SlhDsaKey* key, + const byte* ctx, byte ctxSz, const byte* msg, word32 msgSz, + enum wc_HashType hashType, byte* sig, word32* sigSz); + +/*! + \ingroup SLH_DSA + + \brief Signs a pre-hashed message using the SLH-DSA external (HashSLH-DSA) + interface with caller-provided additional randomness. + + \return 0 on success. + \return BAD_FUNC_ARG if key, msg, sig, sigSz, or addRnd is NULL. + + \param [in] key Pointer to a private SlhDsaKey. + \param [in] ctx Context string. May be NULL if ctxSz is 0. + \param [in] ctxSz Length of the context string (0-255). + \param [in] msg Pointer to the message to hash and sign. + \param [in] msgSz Length of the message. + \param [in] hashType Hash algorithm to use for pre-hashing. + \param [out] sig Buffer to receive the signature. + \param [in,out] sigSz On input, size of sig buffer. On output, actual + signature length. + \param [in] addRnd Additional randomness (n bytes). + + \sa wc_SlhDsaKey_SignHashDeterministic + \sa wc_SlhDsaKey_VerifyHash +*/ +int wc_SlhDsaKey_SignHashWithRandom(SlhDsaKey* key, + const byte* ctx, byte ctxSz, const byte* msg, word32 msgSz, + enum wc_HashType hashType, byte* sig, word32* sigSz, byte* addRnd); + +/*! + \ingroup SLH_DSA + + \brief Signs a pre-hashed message using the SLH-DSA external (HashSLH-DSA) + interface with RNG-provided randomness. + + \return 0 on success. + \return BAD_FUNC_ARG if key, msg, sig, sigSz, or rng is NULL. + + \param [in] key Pointer to a private SlhDsaKey. + \param [in] ctx Context string. May be NULL if ctxSz is 0. + \param [in] ctxSz Length of the context string (0-255). + \param [in] msg Pointer to the message to hash and sign. + \param [in] msgSz Length of the message. + \param [in] hashType Hash algorithm to use for pre-hashing. + \param [out] sig Buffer to receive the signature. + \param [in,out] sigSz On input, size of sig buffer. On output, actual + signature length. + \param [in] rng Pointer to an initialized WC_RNG. + + \sa wc_SlhDsaKey_SignHashDeterministic + \sa wc_SlhDsaKey_VerifyHash +*/ +int wc_SlhDsaKey_SignHash(SlhDsaKey* key, const byte* ctx, + byte ctxSz, const byte* msg, word32 msgSz, enum wc_HashType hashType, + byte* sig, word32* sigSz, WC_RNG* rng); + +/*! + \ingroup SLH_DSA + + \brief Verifies an SLH-DSA signature over a pre-hashed message + (HashSLH-DSA). The message is hashed with the specified hash algorithm + before verification. + + \return 0 on success (signature valid). + \return BAD_FUNC_ARG if key, msg, or sig is NULL. + \return SIG_VERIFY_E if the signature is invalid. + + \param [in] key Pointer to a public SlhDsaKey. + \param [in] ctx Context string. May be NULL if ctxSz is 0. + \param [in] ctxSz Length of the context string (0-255). + \param [in] msg Pointer to the message to hash and verify. + \param [in] msgSz Length of the message. + \param [in] hashType Hash algorithm used for pre-hashing. Must match the + hash used during signing. + \param [in] sig Pointer to the signature to verify. + \param [in] sigSz Length of the signature. + + _Example_ + \code + SlhDsaKey key; + byte sig[...]; + word32 sigSz; + byte msg[] = "Hello World!"; + int ret; + + ret = wc_SlhDsaKey_VerifyHash(&key, NULL, 0, + msg, sizeof(msg), WC_HASH_TYPE_SHA256, sig, sigSz); + if (ret == 0) { + // signature is valid + } + \endcode + + \sa wc_SlhDsaKey_SignHashDeterministic + \sa wc_SlhDsaKey_Verify +*/ +int wc_SlhDsaKey_VerifyHash(SlhDsaKey* key, const byte* ctx, + byte ctxSz, const byte* msg, word32 msgSz, enum wc_HashType hashType, + const byte* sig, word32 sigSz); + +/*! + \ingroup SLH_DSA + + \brief Imports an SLH-DSA private key from a raw byte buffer. The buffer + must contain the full private key (4*n bytes: SK.seed || SK.prf || + PK.seed || PK.root). After import, the key can be used for signing. + + \return 0 on success. + \return BAD_FUNC_ARG if key or in is NULL, or inLen does not match the + expected private key size for the parameter set. + + \param [in,out] key Pointer to an initialized SlhDsaKey. + \param [in] in Buffer containing the raw private key bytes. + \param [in] inLen Length of the input buffer. + + _Example_ + \code + SlhDsaKey key; + byte privKey[...]; // 4*n bytes + int ret; + + wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID); + ret = wc_SlhDsaKey_ImportPrivate(&key, privKey, sizeof(privKey)); + \endcode + + \sa wc_SlhDsaKey_ExportPrivate + \sa wc_SlhDsaKey_ImportPublic +*/ +int wc_SlhDsaKey_ImportPrivate(SlhDsaKey* key, const byte* in, + word32 inLen); + +/*! + \ingroup SLH_DSA + + \brief Imports an SLH-DSA public key from a raw byte buffer. The buffer + must contain PK.seed || PK.root (2*n bytes). After import, the key can + be used for verification. + + \return 0 on success. + \return BAD_FUNC_ARG if key or in is NULL, or inLen does not match the + expected public key size. + + \param [in,out] key Pointer to an initialized SlhDsaKey. + \param [in] in Buffer containing the raw public key bytes. + \param [in] inLen Length of the input buffer. + + _Example_ + \code + SlhDsaKey key; + byte pubKey[...]; // 2*n bytes + int ret; + + wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID); + ret = wc_SlhDsaKey_ImportPublic(&key, pubKey, sizeof(pubKey)); + \endcode + + \sa wc_SlhDsaKey_ExportPublic + \sa wc_SlhDsaKey_ImportPrivate +*/ +int wc_SlhDsaKey_ImportPublic(SlhDsaKey* key, const byte* in, + word32 inLen); + +/*! + \ingroup SLH_DSA + + \brief Checks the consistency of an SLH-DSA key. For a key with both + private and public components, verifies that the public key matches the + private key. + + \return 0 on success (key is valid). + \return BAD_FUNC_ARG if key is NULL. + + \param [in] key Pointer to the SlhDsaKey to check. + + \sa wc_SlhDsaKey_MakeKey + \sa wc_SlhDsaKey_ImportPrivate +*/ +int wc_SlhDsaKey_CheckKey(SlhDsaKey* key); + +/*! + \ingroup SLH_DSA + + \brief Exports the private key from an SLH-DSA key object into a raw + byte buffer (4*n bytes). + + \return 0 on success. + \return BAD_FUNC_ARG if key, out, or outLen is NULL. + \return BUFFER_E if the output buffer is too small. + + \param [in] key Pointer to the SlhDsaKey containing a private key. + \param [out] out Buffer to receive the raw private key bytes. + \param [in,out] outLen On input, size of out buffer. On output, bytes + written. + + _Example_ + \code + SlhDsaKey key; + byte privKey[4 * 32]; // 4*n for 256-bit params + word32 privKeySz = sizeof(privKey); + int ret; + + ret = wc_SlhDsaKey_ExportPrivate(&key, privKey, &privKeySz); + \endcode + + \sa wc_SlhDsaKey_ImportPrivate + \sa wc_SlhDsaKey_ExportPublic +*/ +int wc_SlhDsaKey_ExportPrivate(SlhDsaKey* key, byte* out, + word32* outLen); + +/*! + \ingroup SLH_DSA + + \brief Exports the public key from an SLH-DSA key object into a raw + byte buffer (2*n bytes: PK.seed || PK.root). + + \return 0 on success. + \return BAD_FUNC_ARG if key, out, or outLen is NULL. + \return BUFFER_E if the output buffer is too small. + + \param [in] key Pointer to the SlhDsaKey containing a public key. + \param [out] out Buffer to receive the raw public key bytes. + \param [in,out] outLen On input, size of out buffer. On output, bytes + written. + + _Example_ + \code + SlhDsaKey key; + byte pubKey[2 * 32]; + word32 pubKeySz = sizeof(pubKey); + int ret; + + ret = wc_SlhDsaKey_ExportPublic(&key, pubKey, &pubKeySz); + \endcode + + \sa wc_SlhDsaKey_ImportPublic + \sa wc_SlhDsaKey_ExportPrivate +*/ +int wc_SlhDsaKey_ExportPublic(SlhDsaKey* key, byte* out, + word32* outLen); + +/*! + \ingroup SLH_DSA + + \brief Returns the private key size in bytes for the key's parameter set. + + \return Private key size in bytes (4*n) on success. + \return BAD_FUNC_ARG if key is NULL or not initialized. + + \param [in] key Pointer to an initialized SlhDsaKey. + + \sa wc_SlhDsaKey_PublicSize + \sa wc_SlhDsaKey_SigSize + \sa wc_SlhDsaKey_PrivateSizeFromParam +*/ +int wc_SlhDsaKey_PrivateSize(SlhDsaKey* key); + +/*! + \ingroup SLH_DSA + + \brief Returns the public key size in bytes for the key's parameter set. + + \return Public key size in bytes (2*n) on success. + \return BAD_FUNC_ARG if key is NULL or not initialized. + + \param [in] key Pointer to an initialized SlhDsaKey. + + \sa wc_SlhDsaKey_PrivateSize + \sa wc_SlhDsaKey_SigSize + \sa wc_SlhDsaKey_PublicSizeFromParam +*/ +int wc_SlhDsaKey_PublicSize(SlhDsaKey* key); + +/*! + \ingroup SLH_DSA + + \brief Returns the signature size in bytes for the key's parameter set. + + \return Signature size in bytes on success. + \return BAD_FUNC_ARG if key is NULL or not initialized. + + \param [in] key Pointer to an initialized SlhDsaKey. + + \sa wc_SlhDsaKey_PrivateSize + \sa wc_SlhDsaKey_PublicSize + \sa wc_SlhDsaKey_SigSizeFromParam +*/ +int wc_SlhDsaKey_SigSize(SlhDsaKey* key); + +/*! + \ingroup SLH_DSA + + \brief Returns the private key size in bytes for the given parameter set + without needing an initialized key object. + + \return Private key size in bytes (4*n) on success. + \return BAD_FUNC_ARG if param is invalid. + + \param [in] param The SLH-DSA parameter set. + + \sa wc_SlhDsaKey_PrivateSize +*/ +int wc_SlhDsaKey_PrivateSizeFromParam(enum SlhDsaParam param); + +/*! + \ingroup SLH_DSA + + \brief Returns the public key size in bytes for the given parameter set + without needing an initialized key object. + + \return Public key size in bytes (2*n) on success. + \return BAD_FUNC_ARG if param is invalid. + + \param [in] param The SLH-DSA parameter set. + + \sa wc_SlhDsaKey_PublicSize +*/ +int wc_SlhDsaKey_PublicSizeFromParam(enum SlhDsaParam param); + +/*! + \ingroup SLH_DSA + + \brief Returns the signature size in bytes for the given parameter set + without needing an initialized key object. + + \return Signature size in bytes on success. + \return BAD_FUNC_ARG if param is invalid. + + \param [in] param The SLH-DSA parameter set. + + \sa wc_SlhDsaKey_SigSize +*/ +int wc_SlhDsaKey_SigSizeFromParam(enum SlhDsaParam param); diff --git a/src/include.am b/src/include.am index 09610bcfdf..0ac8d62602 100644 --- a/src/include.am +++ b/src/include.am @@ -439,7 +439,7 @@ src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/fips.c \ src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wolfcrypt_last.c endif BUILD_FIPS_V5 -if BUILD_FIPS_V6_PLUS +if BUILD_FIPS_V6 # FIPS 140-3 SRTP-KDF first file src_libwolfssl@LIBSUFFIX@_la_SOURCES += \ wolfcrypt/src/wolfcrypt_first.c @@ -782,7 +782,390 @@ src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/fips.c \ # fips last file src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wolfcrypt_last.c -endif BUILD_FIPS_V6_PLUS +endif BUILD_FIPS_V6 + +if BUILD_FIPS_V7_PLUS +# FIPS 140-3 v7.0.0+ first file +src_libwolfssl@LIBSUFFIX@_la_SOURCES += \ + wolfcrypt/src/wolfcrypt_first.c + +src_libwolfssl@LIBSUFFIX@_la_SOURCES += \ + wolfcrypt/src/hmac.c \ + wolfcrypt/src/random.c + +if BUILD_MEMUSE +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wolfentropy.c +endif + +if BUILD_RNG_BANK +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/rng_bank.c +endif + +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/kdf.c + +if BUILD_RSA +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/rsa.c +endif + +if BUILD_ECC +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/ecc.c +endif + +if BUILD_AES +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/aes.c + +if BUILD_ARMASM +src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(LEGACY_ARMASM_AES_C) +endif BUILD_ARMASM + +if BUILD_ARMASM_NEON +if BUILD_ARMASM_INLINE +src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(NEW_ARMASM_AES_ASM_C) +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-aes-asm_c.c +else +src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(NEW_ARMASM_AES_ASM_S) +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-aes-asm.S +endif !BUILD_ARMASM_INLINE +else +if BUILD_ARMASM +if BUILD_ARMASM_INLINE +if BUILD_ARM_NONTHUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-aes-asm_c.c +endif +if BUILD_ARM_THUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-aes-asm_c.c +endif +else +if BUILD_ARM_NONTHUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-aes-asm.S +endif +if BUILD_ARM_THUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-aes-asm.S +endif +endif !BUILD_ARMASM_INLINE +endif BUILD_ARMASM +endif !BUILD_ARMASM_NEON +endif BUILD_AES + +if BUILD_AESNI +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/aes_asm.S +if BUILD_X86_ASM +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/aes_gcm_x86_asm.S +else +if BUILD_AESGCM +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/aes_gcm_asm.S +endif +if BUILD_AESXTS +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/aes_xts_asm.S +endif +endif +endif + +if BUILD_SHA +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sha.c +endif + +if BUILD_ARMASM_NEON +src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(ARMASM_SHA256_C) +src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(LEGACY_ARMASM_SHA256_C) +if BUILD_ARMASM_INLINE +src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(NEW_ARMASM_SHA256_ASM_C) +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-sha256-asm_c.c +else +src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(NEW_ARMASM_SHA256_ASM_S) +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-sha256-asm.S +endif !BUILD_ARMASM_INLINE +else +if BUILD_ARMASM +src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(ARMASM_SHA256_C) +src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(LEGACY_ARMASM_SHA256_C) +if BUILD_ARMASM_INLINE +if BUILD_ARM_NONTHUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-sha256-asm_c.c +endif +if BUILD_ARM_THUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-sha256-asm_c.c +endif +else +if BUILD_ARM_NONTHUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-sha256-asm.S +endif +if BUILD_ARM_THUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-sha256-asm.S +endif +endif !BUILD_ARMASM_INLINE +else +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sha256.c +if BUILD_INTELASM +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sha256_asm.S +endif BUILD_INTELASM +endif !BUILD_ARMASM +endif !BUILD_ARMASM_NEON + +if BUILD_RISCV_ASM +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/riscv/riscv-64-sha256.c +endif BUILD_RISCV_ASM + +if BUILD_PPC32_ASM +if BUILD_PPC32_ASM_INLINE +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/ppc32/ppc32-sha256-asm_c.c +else +if BUILD_PPC32_ASM_INLINE_REG +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/ppc32/ppc32-sha256-asm_cr.c +else +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/ppc32/ppc32-sha256-asm.S +endif !BUILD_PPC32_ASM_INLINE_REG +endif !BUILD_PPC32_ASM_INLINE +endif BUILD_PPC32_ASM + +if BUILD_SHA512 +if BUILD_RISCV_ASM +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/riscv/riscv-64-sha512.c +else + +if !BUILD_FIPS_V5 +if !BUILD_FIPS_V6 +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sha512.c +endif !BUILD_FIPS_V6 +endif !BUILD_FIPS_V5 + +if BUILD_ARMASM_NEON +src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(LEGACY_ARMASM_SHA512_C) +if BUILD_ARMASM_INLINE +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-sha512-asm_c.c +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-sha512-asm_c.c +else +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-sha512-asm.S +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-sha512-asm.S +endif !BUILD_ARMASM_INLINE +else +if BUILD_ARMASM +src_libwolfssl@LIBSUFFIX@_la_SOURCES += $(LEGACY_ARMASM_SHA512_C) +if BUILD_ARMASM_INLINE +if BUILD_ARM_NONTHUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-sha512-asm_c.c +endif +if BUILD_ARM_THUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-sha512-asm_c.c +endif +else +if BUILD_ARM_NONTHUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-sha512-asm.S +endif +if BUILD_ARM_THUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-sha512-asm.S +endif +endif !BUILD_ARMASM_INLINE +else + +if BUILD_FIPS_V5 +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sha512.c +else +if BUILD_FIPS_V6 +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sha512.c +endif BUILD_FIPS_V6 +endif !BUILD_FIPS_V5 + +if BUILD_INTELASM +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sha512_asm.S +endif BUILD_INTELASM +endif !BUILD_ARMASM +endif !BUILD_ARMASM_NEON +endif !BUILD_RISCV_ASM +endif BUILD_SHA512 + +if BUILD_SHA3 +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sha3.c +if BUILD_ARMASM_NEON +if BUILD_ARMASM_INLINE +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-sha3-asm_c.c +else +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-sha3-asm.S +endif !BUILD_ARMASM_INLINE +endif BUILD_ARMASM_NEON +if BUILD_ARMASM +if BUILD_ARMASM_INLINE +if BUILD_ARM_NONTHUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-sha3-asm_c.c +endif +if BUILD_ARM_THUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-sha3-asm_c.c +endif +else +if BUILD_ARM_NONTHUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-sha3-asm.S +endif +if BUILD_ARM_THUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-sha3-asm.S +endif +endif !BUILD_ARMASM_INLINE +endif BUILD_ARMASM +if BUILD_RISCV_ASM +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/riscv/riscv-64-sha3.c +endif BUILD_RISCV_ASM +if BUILD_INTELASM +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sha3_asm.S +endif +endif + +if BUILD_DH +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/dh.c +endif + +if BUILD_CMAC +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/cmac.c +endif + +if BUILD_CURVE448 +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/curve448.c +endif + +if BUILD_ED448 +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/ed448.c +endif + +if BUILD_CURVE25519 +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/curve25519.c +endif + +if BUILD_ED25519 +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/ed25519.c +endif + +if BUILD_ARMASM +if BUILD_ARMASM_NEON +if BUILD_ARMASM_INLINE +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-curve25519_c.c +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-curve25519_c.c +else +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-curve25519.S +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-curve25519.S +endif !BUILD_ARMASM_INLINE +else +if BUILD_ARMASM_INLINE +if BUILD_ARM_NONTHUMB +if BUILD_ARM_32 +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-curve25519_c.c +endif +if BUILD_ARM_64 +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-curve25519_c.c +endif +endif +if BUILD_ARM_THUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-curve25519_c.c +endif +else +if BUILD_ARM_NONTHUMB +if BUILD_ARM_32 +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-curve25519.S +endif +if BUILD_ARM_64 +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-curve25519.S +endif +endif +if BUILD_ARM_THUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-curve25519.S +endif +endif !BUILD_ARMASM_INLINE +endif !BUILD_ARMASM_NEON +endif BUILD_ARMASM + +if BUILD_PWDBASED +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/pwdbased.c +endif BUILD_PWDBASED + +if BUILD_SP +if BUILD_SP_C32 +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sp_c32.c +endif +if BUILD_SP_C64 +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sp_c64.c +endif + +if BUILD_SP_X86_64 +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sp_x86_64.c +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sp_x86_64_asm.S +endif +if !BUILD_FIPS_V2 +if BUILD_SP_ARM32 +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sp_arm32.c +endif +endif +if BUILD_SP_ARM_THUMB +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sp_armthumb.c +endif +if !BUILD_FIPS_V2 +if BUILD_SP_ARM64 +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sp_arm64.c +endif +endif +if BUILD_SP_ARM_CORTEX +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sp_cortexm.c +endif +endif BUILD_SP + +# PQ Algorithms (FIPS v7.0.0+) +if BUILD_WC_MLKEM +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_mlkem.c +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_mlkem_poly.c +if BUILD_ARMASM +if BUILD_ARM_THUMB +if BUILD_ARMASM_INLINE +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-mlkem-asm_c.c +else +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/thumb2-mlkem-asm.S +endif !BUILD_ARMASM_INLINE +else +if BUILD_ARMASM_INLINE +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-mlkem-asm_c.c +else +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-32-mlkem-asm.S +endif !BUILD_ARMASM_INLINE +endif !BUILD_ARM_THUMB +endif BUILD_ARMASM +if !BUILD_X86_ASM +if BUILD_INTELASM +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_mlkem_asm.S +endif +endif +if BUILD_ARMASM_NEON +if BUILD_ARMASM_INLINE +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-mlkem-asm_c.c +else +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/arm/armv8-mlkem-asm.S +endif !BUILD_ARMASM_INLINE +endif BUILD_ARMASM_NEON +endif + +if BUILD_DILITHIUM +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/dilithium.c +if !BUILD_X86_ASM +if BUILD_INTELASM +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_mldsa_asm.S +endif BUILD_INTELASM +endif !BUILD_X86_ASM +endif + +if BUILD_WC_LMS +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_lms.c +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_lms_impl.c +endif + +if BUILD_WC_XMSS +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_xmss.c +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_xmss_impl.c +endif + +if BUILD_WC_SLHDSA +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_slhdsa.c +endif + +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/fips.c \ + wolfcrypt/src/fips_test.c + +# fips last file +src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wolfcrypt_last.c +endif BUILD_FIPS_V7_PLUS endif BUILD_FIPS @@ -1401,6 +1784,7 @@ if BUILD_SAKKE src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sakke.c endif +if !BUILD_FIPS_V7_PLUS if BUILD_WC_MLKEM src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_mlkem.c src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_mlkem_poly.c @@ -1451,10 +1835,13 @@ if BUILD_WC_XMSS src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_xmss.c src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_xmss_impl.c endif +endif !BUILD_FIPS_V7_PLUS +if !BUILD_FIPS_V7_PLUS if BUILD_WC_SLHDSA src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/wc_slhdsa.c endif +endif !BUILD_FIPS_V7_PLUS if !BUILD_FIPS_V6_PLUS if BUILD_CURVE25519 diff --git a/src/tls.c b/src/tls.c index ed8267469d..b1cd707404 100644 --- a/src/tls.c +++ b/src/tls.c @@ -8892,7 +8892,9 @@ static int TLSX_KeyShare_GenPqcKeyClient(WOLFSSL *ssl, KeyShareEntry* kse) #ifndef WOLFSSL_TLSX_PQC_MLKEM_STORE_OBJ if (ret == 0) { + PRIVATE_KEY_UNLOCK(); ret = wc_KyberKey_EncodePrivateKey(kem, privKey, privSz); + PRIVATE_KEY_LOCK(); } #endif @@ -9975,7 +9977,9 @@ static int TLSX_KeyShare_ProcessPqcClient_ex(WOLFSSL* ssl, ret = BAD_FUNC_ARG; } if (ret == 0) { + PRIVATE_KEY_UNLOCK(); ret = wc_KyberKey_DecodePrivateKey(kem, keyShareEntry->privKey, privSz); + PRIVATE_KEY_LOCK(); } #endif @@ -9984,8 +9988,10 @@ static int TLSX_KeyShare_ProcessPqcClient_ex(WOLFSSL* ssl, ret = BUFFER_E; } if (ret == 0) { + PRIVATE_KEY_UNLOCK(); ret = wc_KyberKey_Decapsulate(kem, ssOutput, keyShareEntry->ke, ctSz); + PRIVATE_KEY_LOCK(); if (ret != 0) { WOLFSSL_MSG("wc_KyberKey decapsulation failure."); ret = BAD_FUNC_ARG; diff --git a/tests/api.c b/tests/api.c index 2b259d54ab..72febe7329 100644 --- a/tests/api.c +++ b/tests/api.c @@ -28101,8 +28101,6 @@ static int error_test(void) {63, 63}, #endif { -9, WC_SPAN1_FIRST_E + 1 }, - { -124, -124 }, - { -167, -169 }, { -300, -300 }, { -335, -336 }, { -346, -349 }, diff --git a/tests/api/test_hash.c b/tests/api/test_hash.c index f6a968670a..2c24a85f9a 100644 --- a/tests/api/test_hash.c +++ b/tests/api/test_hash.c @@ -68,6 +68,12 @@ static const enum wc_HashType supportedHash[] = { WC_HASH_TYPE_SHA3_256, WC_HASH_TYPE_SHA3_384, WC_HASH_TYPE_SHA3_512, +#if defined(WOLFSSL_SHAKE128) + WC_HASH_TYPE_SHAKE128, +#endif +#if defined(WOLFSSL_SHAKE256) + WC_HASH_TYPE_SHAKE256, +#endif #endif #ifdef WOLFSSL_SM3 WC_HASH_TYPE_SM3, @@ -126,14 +132,14 @@ static const enum wc_HashType notCompiledHash[] = { WC_HASH_TYPE_NONE /* Dummy value to ensure list is non-zero. */ }; static const int notCompiledHashLen = (sizeof(notCompiledHash) / - sizeof(enum wc_HashType)) - 1; + sizeof(notCompiledHash[0])) - 1; static const int notSupportedHash[] = { WC_HASH_TYPE_NONE, WC_HASH_TYPE_MAX + 1 }; static const int notSupportedHashLen = (sizeof(notSupportedHash) / - sizeof(enum wc_HashType)); + sizeof(notSupportedHash[0])); static const enum wc_HashType sizeSupportedHash[] = { #if !defined(NO_MD5) && !defined(NO_SHA) @@ -150,11 +156,17 @@ static const enum wc_HashType sizeSupportedHash[] = { #endif #ifdef HAVE_BLAKE2S WC_HASH_TYPE_BLAKE2S, +#endif +#if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128) + WC_HASH_TYPE_SHAKE128, +#endif +#if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256) + WC_HASH_TYPE_SHAKE256, #endif WC_HASH_TYPE_NONE /* Dummy value to ensure list is non-zero. */ }; static const int sizeSupportedHashLen = (sizeof(sizeSupportedHash) / - sizeof(enum wc_HashType)) - 1; + sizeof(sizeSupportedHash[0])) - 1; static const enum wc_HashType sizeNotCompiledHash[] = { #if defined(NO_MD5) || defined(NO_SHA) WC_HASH_TYPE_MD5_SHA, @@ -171,18 +183,22 @@ static const enum wc_HashType sizeNotCompiledHash[] = { #ifndef HAVE_BLAKE2S WC_HASH_TYPE_BLAKE2S, #endif +#if !defined(WOLFSSL_SHA3) || !defined(WOLFSSL_SHAKE128) WC_HASH_TYPE_SHAKE128, +#endif +#if !defined(WOLFSSL_SHA3) || !defined(WOLFSSL_SHAKE256) WC_HASH_TYPE_SHAKE256, +#endif WC_HASH_TYPE_NONE /* Dummy value to ensure list is non-zero. */ }; static const int sizeNotCompiledHashLen = (sizeof(sizeNotCompiledHash) / - sizeof(enum wc_HashType)) - 1; + sizeof(sizeNotCompiledHash[0])) - 1; static const int sizeNotSupportedHash[] = { WC_HASH_TYPE_NONE, WC_HASH_TYPE_MAX + 1 }; static const int sizeNotSupportedHashLen = (sizeof(sizeNotSupportedHash) / - sizeof(enum wc_HashType)); + sizeof(sizeNotSupportedHash[0])); #endif /* NO_HASH_WRAPPER */ int test_wc_HashInit(void) diff --git a/tests/api/test_mldsa.c b/tests/api/test_mldsa.c index 9ebd027b96..ce924d7b2c 100644 --- a/tests/api/test_mldsa.c +++ b/tests/api/test_mldsa.c @@ -554,6 +554,8 @@ int test_wc_dilithium(void) ExpectIntEQ(wc_InitRng(&rng), 0); #endif + PRIVATE_KEY_UNLOCK(); + ExpectIntEQ(wc_dilithium_init(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_dilithium_init_ex(NULL, NULL, INVALID_DEVID), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); wc_dilithium_free(NULL); @@ -674,6 +676,8 @@ int test_wc_dilithium(void) WC_NO_ERR_TRACE(BAD_FUNC_ARG)); #endif + PRIVATE_KEY_LOCK(); + wc_dilithium_free(key); #if !defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) || \ !defined(WOLFSSL_DILITHIUM_NO_SIGN) @@ -844,6 +848,8 @@ int test_wc_dilithium_sign(void) ExpectIntEQ(wc_InitRng(&rng), 0); ExpectIntEQ(wc_dilithium_init(key), 0); + PRIVATE_KEY_UNLOCK(); + #ifndef WOLFSSL_NO_ML_DSA_44 ExpectIntEQ(wc_dilithium_set_level(key, WC_ML_DSA_44), 0); #elif !defined(WOLFSSL_NO_ML_DSA_65) @@ -957,6 +963,8 @@ int test_wc_dilithium_sign(void) #endif wc_dilithium_free(importKey); + PRIVATE_KEY_LOCK(); + wc_dilithium_free(key); wc_FreeRng(&rng); @@ -1330,6 +1338,8 @@ int test_wc_dilithium_check_key(void) ExpectIntEQ(wc_InitRng(&rng), 0); + PRIVATE_KEY_UNLOCK(); + ExpectIntEQ(wc_dilithium_check_key(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_dilithium_init(checkKey), 0); @@ -1416,6 +1426,8 @@ int test_wc_dilithium_check_key(void) pubCheckKey[48] ^= 0x80; } + PRIVATE_KEY_LOCK(); + wc_dilithium_free(checkKey); wc_FreeRng(&rng); @@ -3019,6 +3031,8 @@ int test_wc_dilithium_der(void) ExpectIntEQ(wc_InitRng(&rng), 0); ExpectIntEQ(wc_dilithium_init(key), 0); + PRIVATE_KEY_UNLOCK(); + ExpectIntEQ(wc_Dilithium_PublicKeyToDer(key, der, DILITHIUM_MAX_DER_SIZE, 0), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wc_Dilithium_PublicKeyToDer(key, der, DILITHIUM_MAX_DER_SIZE, @@ -3170,6 +3184,7 @@ int test_wc_dilithium_der(void) idx = 0; ExpectIntEQ(wc_Dilithium_PrivateKeyDecode(der, &idx, key, len), 0); + PRIVATE_KEY_LOCK(); wc_dilithium_free(key); wc_FreeRng(&rng); @@ -12425,6 +12440,9 @@ int test_wc_dilithium_sig_kats(void) } ExpectIntEQ(wc_dilithium_init_ex(key, NULL, INVALID_DEVID), 0); + + PRIVATE_KEY_UNLOCK(); + #ifndef WOLFSSL_NO_ML_DSA_44 ExpectIntEQ(wc_dilithium_set_level(key, WC_ML_DSA_44), 0); ExpectIntEQ(wc_dilithium_import_private(sk_44, (word32)sizeof(sk_44), key), @@ -12456,6 +12474,8 @@ int test_wc_dilithium_sig_kats(void) ExpectIntEQ(XMEMCMP(sig, sig_87, sizeof(sig_87)), 0); #endif + PRIVATE_KEY_LOCK(); + wc_dilithium_free(key); XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif @@ -16619,6 +16639,7 @@ int test_wc_dilithium_sign_ctx_kats(void) XMEMSET(key, 0, sizeof(*key)); } + PRIVATE_KEY_UNLOCK(); #ifndef WOLFSSL_NO_ML_DSA_44 /* ML-DSA-44: empty context (ctx=NULL, ctxLen=0) */ ExpectIntEQ(wc_dilithium_init_ex(key, NULL, INVALID_DEVID), 0); @@ -16694,6 +16715,7 @@ int test_wc_dilithium_sign_ctx_kats(void) wc_dilithium_free(key); #endif /* !WOLFSSL_NO_ML_DSA_87 */ + PRIVATE_KEY_LOCK(); XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif /* HAVE_DILITHIUM && WOLFSSL_WC_DILITHIUM && !WOLFSSL_DILITHIUM_NO_SIGN */ @@ -24522,6 +24544,5092 @@ int test_wc_dilithium_verify_kats(void) return EXPECT_RESULT(); } +/* Known-answer tests for the ML-DSA externalMu sign API + * (wc_dilithium_sign_mu_with_seed). Vectors are the deterministic + * externalMu groups from the ACVP v7.0.0 known-vector set. + * + * Note: this file is userspace-only (tests/unit.test); it is not built into + * libwolfssl.ko, so the large per-paramSet vectors do not need the chunking + * treatment used in wolfcrypt/src/fips_test.c. The arrays are static const + * and live in .rodata, not on the stack. */ +int test_wc_dilithium_sign_mu_kats(void) +{ + EXPECT_DECLS; +#if defined(HAVE_DILITHIUM) && defined(WOLFSSL_WC_DILITHIUM) && \ + !defined(WOLFSSL_DILITHIUM_NO_SIGN) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + dilithium_key* key = NULL; + word32 sigLen; + byte* sig = NULL; + /* FIPS 204 Section 3.7: deterministic ML-DSA fixes rnd to 32 zero + * bytes. Our ACVP "deterministic" vectors were generated with that + * convention, so passing zeroSeed reproduces them byte-for-byte. */ + static const byte zeroSeed[DILITHIUM_RND_SZ] = { 0 }; + + /* ML-DSA-44 externalMu: deterministic, tcId 91 + * Source: kh-fork-fips/wolfACVP/v7.0.0-known/ + * ML-DSA-sigGen-request.json. Deterministic mode + * uses rnd = 0^32 per FIPS 204 Section 3.7. */ + static const byte sk_44_mu[] = { + 0x81, 0xf5, 0x5d, 0xba, 0xcc, 0x51, 0xeb, 0xde, + 0x5c, 0x5a, 0x25, 0x8c, 0x14, 0xf5, 0x54, 0xfb, + 0x3a, 0x93, 0xe1, 0x6c, 0x78, 0x3a, 0x7e, 0x8c, + 0x60, 0x8e, 0x6e, 0xbd, 0xd2, 0x35, 0x2f, 0x20, + 0x0c, 0x59, 0x00, 0x71, 0xd2, 0x3d, 0xdc, 0xb8, + 0x0a, 0x7e, 0xc0, 0xc0, 0xbc, 0x31, 0x16, 0x91, + 0xe3, 0xec, 0xef, 0x93, 0xfc, 0x4e, 0xd1, 0x1e, + 0xe2, 0xda, 0xa6, 0xf7, 0xdc, 0x26, 0xc2, 0x68, + 0x0c, 0xbd, 0xe1, 0x97, 0x9a, 0x62, 0x1e, 0x46, + 0xe0, 0x5f, 0x0e, 0x88, 0x43, 0xe4, 0xa7, 0x20, + 0x42, 0xaf, 0xef, 0xd9, 0x05, 0x75, 0xfe, 0x6d, + 0x11, 0x73, 0x7a, 0xa5, 0xd9, 0x5c, 0x56, 0x3c, + 0xff, 0xfb, 0x1a, 0x4e, 0x97, 0x3e, 0xd5, 0x04, + 0xdc, 0x25, 0x9f, 0xf0, 0xdd, 0xb2, 0xc7, 0xf4, + 0x29, 0x32, 0x07, 0x7e, 0xb7, 0x63, 0x60, 0x93, + 0x65, 0xbd, 0xe7, 0xf8, 0x7b, 0xf7, 0x75, 0x48, + 0x1a, 0xa6, 0x4c, 0x99, 0x88, 0x88, 0x0c, 0x27, + 0x4e, 0xcb, 0x44, 0x48, 0xa4, 0x44, 0x90, 0x4c, + 0x48, 0x31, 0x1a, 0x42, 0x8a, 0x1a, 0x89, 0x25, + 0xa2, 0x18, 0x4c, 0x4a, 0xb0, 0x00, 0xc0, 0x26, + 0x46, 0x9c, 0xa2, 0x85, 0x00, 0x16, 0x00, 0xdc, + 0x48, 0x0e, 0x24, 0xa3, 0x2c, 0x24, 0x34, 0x05, + 0x03, 0x07, 0x52, 0x83, 0xb6, 0x88, 0x10, 0x43, + 0x2a, 0x02, 0xc0, 0x10, 0x10, 0x24, 0x71, 0x44, + 0x92, 0x00, 0x54, 0x46, 0x12, 0x99, 0x36, 0x09, + 0x4c, 0x96, 0x40, 0x59, 0x22, 0x92, 0x09, 0xc7, + 0x84, 0x91, 0xc4, 0x01, 0x01, 0x86, 0x69, 0x59, + 0x20, 0x42, 0x21, 0xa2, 0x84, 0x90, 0x26, 0x40, + 0xe4, 0x26, 0x6c, 0xd3, 0x22, 0x66, 0x50, 0x00, + 0x12, 0x61, 0x90, 0x85, 0x4a, 0x10, 0x28, 0x00, + 0xb0, 0x6d, 0xda, 0xa2, 0x69, 0x12, 0x44, 0x05, + 0xa2, 0x48, 0x05, 0x0b, 0xb6, 0x0c, 0x0a, 0xa8, + 0x31, 0x5a, 0x20, 0x0d, 0xe4, 0xc6, 0x0c, 0xa3, + 0xb6, 0x41, 0x8b, 0x38, 0x66, 0x11, 0xa5, 0x4d, + 0x0a, 0x23, 0x28, 0xd9, 0x40, 0x8c, 0x08, 0xb5, + 0x4c, 0x41, 0x28, 0x32, 0x5b, 0x80, 0x48, 0xa3, + 0x42, 0x70, 0x22, 0x82, 0x09, 0x48, 0x36, 0x4d, + 0xdb, 0x90, 0x81, 0x53, 0xa2, 0x0d, 0x01, 0x91, + 0x6c, 0x8c, 0x80, 0x29, 0x19, 0xc3, 0x51, 0x1a, + 0xa9, 0x50, 0x14, 0x26, 0x81, 0x4c, 0x26, 0x10, + 0x0c, 0x33, 0x60, 0x1c, 0x45, 0x30, 0x0c, 0x20, + 0x52, 0x9a, 0x32, 0x65, 0xda, 0x10, 0x11, 0x12, + 0x28, 0x84, 0xcb, 0x96, 0x05, 0x09, 0xa4, 0x90, + 0xc2, 0x48, 0x2c, 0x60, 0x30, 0x0a, 0x60, 0x20, + 0x66, 0x59, 0x16, 0x69, 0x82, 0x00, 0x8a, 0x21, + 0x98, 0x25, 0x09, 0x37, 0x69, 0xd1, 0xb4, 0x64, + 0x8b, 0x98, 0x0c, 0x19, 0x22, 0x4c, 0x4a, 0x28, + 0x28, 0xda, 0xb8, 0x25, 0x64, 0x92, 0x44, 0x22, + 0x39, 0x80, 0x88, 0x24, 0x91, 0x24, 0x49, 0x50, + 0x90, 0x44, 0x20, 0x9a, 0xc2, 0x64, 0x1b, 0x27, + 0x0c, 0x1a, 0x27, 0x69, 0x8b, 0x10, 0x00, 0x82, + 0x06, 0x72, 0x91, 0x36, 0x90, 0x84, 0x30, 0x0d, + 0xc8, 0x86, 0x60, 0x51, 0xc4, 0x41, 0x9a, 0x02, + 0x06, 0x61, 0x46, 0x05, 0xc4, 0xc4, 0x11, 0xa1, + 0x84, 0x2c, 0x51, 0xb4, 0x41, 0xc2, 0x36, 0x86, + 0xc2, 0x30, 0x2d, 0xd3, 0xa0, 0x10, 0xe3, 0xb8, + 0x64, 0x92, 0x98, 0x28, 0x8b, 0x98, 0x6d, 0xca, + 0xa6, 0x44, 0xc8, 0x32, 0x31, 0x08, 0x28, 0x4d, + 0xc9, 0x36, 0x4c, 0xca, 0x28, 0x21, 0x01, 0x45, + 0x01, 0x64, 0xa6, 0x09, 0xd1, 0x06, 0x8c, 0x08, + 0x95, 0x70, 0x90, 0x16, 0x50, 0x0a, 0x13, 0x28, + 0x0c, 0xc6, 0x01, 0x12, 0xa2, 0x2d, 0x18, 0xb0, + 0x8d, 0x1b, 0x92, 0x4c, 0x62, 0x82, 0x25, 0xa3, + 0x94, 0x88, 0x1a, 0x92, 0x65, 0x13, 0xa3, 0x88, + 0x01, 0x45, 0x72, 0x1a, 0x85, 0x8c, 0x08, 0x39, + 0x44, 0x59, 0x06, 0x31, 0x90, 0x02, 0x4d, 0x43, + 0x44, 0x52, 0x41, 0x48, 0x81, 0x89, 0x04, 0x04, + 0x0b, 0x30, 0x40, 0x23, 0x45, 0x89, 0x1c, 0x97, + 0x40, 0x60, 0x94, 0x50, 0x00, 0x87, 0x10, 0x48, + 0xa6, 0x2d, 0x12, 0xb7, 0x11, 0x19, 0xb9, 0x8c, + 0x20, 0x02, 0x0c, 0x44, 0xc8, 0x61, 0x62, 0x12, + 0x82, 0x44, 0x08, 0x04, 0x41, 0x80, 0x65, 0x51, + 0xc8, 0x90, 0xd0, 0xb2, 0x88, 0x09, 0x03, 0x81, + 0x18, 0x00, 0x4d, 0x0c, 0x17, 0x69, 0x11, 0x97, + 0x4c, 0x21, 0xa9, 0x31, 0xcb, 0x30, 0x11, 0xc3, + 0x94, 0x45, 0xe4, 0x44, 0x84, 0xc1, 0x14, 0x50, + 0x88, 0x36, 0x4a, 0x99, 0x00, 0x6e, 0x54, 0x30, + 0x25, 0x0b, 0x88, 0x49, 0x60, 0x00, 0x71, 0xd3, + 0x14, 0x8a, 0x02, 0x28, 0x48, 0x60, 0x22, 0x30, + 0x4a, 0x30, 0x91, 0x93, 0x34, 0x72, 0x84, 0x80, + 0x20, 0xc8, 0x38, 0x2c, 0xc9, 0xa2, 0x04, 0x1c, + 0x80, 0x88, 0x1c, 0xc6, 0x2d, 0xe0, 0x00, 0x46, + 0x50, 0x84, 0x0d, 0x5b, 0xb2, 0x0d, 0x21, 0x47, + 0x92, 0x23, 0x24, 0x6a, 0x93, 0x48, 0x2a, 0x44, + 0x40, 0x69, 0x0b, 0x91, 0x6c, 0x98, 0xa4, 0x4d, + 0x5c, 0xa2, 0x71, 0x49, 0x00, 0x04, 0x9b, 0x42, + 0x12, 0x0c, 0x49, 0x2d, 0x9c, 0x18, 0x65, 0x4c, + 0x90, 0x09, 0x4b, 0x24, 0x51, 0x4a, 0xa6, 0x68, + 0x00, 0x25, 0x08, 0x90, 0x48, 0x6a, 0xc1, 0x80, + 0x60, 0x8b, 0x24, 0x4a, 0x64, 0x40, 0x52, 0x18, + 0x38, 0x42, 0x22, 0x24, 0x89, 0x11, 0x97, 0x85, + 0x03, 0xa7, 0x4d, 0xe2, 0x44, 0x4c, 0x08, 0x36, + 0x68, 0xa3, 0x24, 0x52, 0xa2, 0x22, 0x05, 0x62, + 0x84, 0x01, 0x10, 0x81, 0x04, 0xd9, 0x40, 0x70, + 0x91, 0x02, 0x40, 0x1b, 0x90, 0x09, 0x21, 0x03, + 0x22, 0xcb, 0x86, 0x09, 0x51, 0x04, 0x12, 0x89, + 0xb6, 0x24, 0x54, 0x28, 0x84, 0x1c, 0x38, 0x49, + 0x01, 0x23, 0x10, 0x04, 0x35, 0x80, 0x19, 0x22, + 0x09, 0x11, 0xa9, 0x4c, 0x43, 0x12, 0x06, 0x84, + 0x48, 0x29, 0x42, 0xb6, 0x49, 0x08, 0x20, 0x42, + 0x88, 0xb4, 0x50, 0x43, 0x46, 0x69, 0x1a, 0x01, + 0x22, 0x08, 0x05, 0x6e, 0x52, 0xa4, 0x8d, 0x49, + 0x82, 0x68, 0x1a, 0x39, 0x30, 0x99, 0x94, 0x44, + 0x0b, 0xa9, 0x2d, 0xdb, 0x98, 0x31, 0xa2, 0x04, + 0x48, 0x04, 0x06, 0x2e, 0xc0, 0x32, 0x2d, 0xca, + 0x40, 0x61, 0x10, 0xb0, 0x04, 0xd0, 0x22, 0x0a, + 0x63, 0x18, 0x0a, 0xd3, 0xa8, 0x10, 0x54, 0x48, + 0x62, 0xa3, 0x94, 0x20, 0x90, 0x20, 0x82, 0x42, + 0x38, 0x45, 0x21, 0x39, 0x86, 0x1b, 0xb9, 0x48, + 0x22, 0x05, 0x85, 0xcb, 0x24, 0x2e, 0x54, 0xb8, + 0x6c, 0xa2, 0xb4, 0x69, 0x1b, 0x80, 0x50, 0x8b, + 0xa4, 0x8d, 0x53, 0x14, 0x2c, 0x48, 0x28, 0x6c, + 0x56, 0x34, 0x6c, 0x84, 0xe9, 0x9a, 0x33, 0x27, + 0x7c, 0xee, 0x77, 0x2e, 0x7f, 0x86, 0x62, 0x2f, + 0x1e, 0xfe, 0x52, 0x01, 0x02, 0x20, 0x4d, 0x28, + 0xa7, 0xa7, 0x34, 0xa0, 0x9a, 0xae, 0x7c, 0xfb, + 0x82, 0x0e, 0xe5, 0xef, 0xb9, 0x99, 0xbb, 0xa4, + 0x37, 0x62, 0xed, 0x43, 0xe0, 0x51, 0x41, 0x43, + 0xc3, 0xeb, 0xba, 0x95, 0xbf, 0x60, 0x45, 0xc8, + 0x5f, 0x1d, 0xa9, 0xb1, 0x8d, 0x1f, 0xf8, 0x3c, + 0xe4, 0x3c, 0xb4, 0x98, 0xae, 0x2f, 0xfe, 0xbb, + 0x25, 0x9c, 0xad, 0xaa, 0x9e, 0x4e, 0x39, 0x6a, + 0xc3, 0x73, 0x66, 0x5a, 0xc3, 0x37, 0x4c, 0x5a, + 0x17, 0x58, 0x4e, 0x01, 0x5b, 0xe6, 0x62, 0xd1, + 0xf1, 0x90, 0xd2, 0x49, 0x25, 0xf2, 0x8d, 0x4c, + 0x9c, 0xb4, 0x93, 0xea, 0x5e, 0x20, 0x11, 0xc7, + 0x1a, 0x3e, 0xe7, 0xb4, 0x82, 0x64, 0x35, 0xa4, + 0xe9, 0x9a, 0x5c, 0xfd, 0xba, 0x1e, 0x3f, 0xd0, + 0xe6, 0x04, 0x4f, 0x84, 0x14, 0x2f, 0x96, 0x58, + 0x56, 0x59, 0xb9, 0x78, 0x7f, 0x6b, 0x69, 0xb5, + 0x7f, 0x36, 0x10, 0x24, 0x9a, 0x6a, 0x9d, 0x98, + 0x0a, 0x6e, 0x56, 0x81, 0xcf, 0x8d, 0x77, 0xa2, + 0xe4, 0x58, 0x29, 0x17, 0x6b, 0x3e, 0x3b, 0x15, + 0x14, 0x65, 0x4f, 0xb8, 0x8e, 0xa7, 0x29, 0xe4, + 0x20, 0x20, 0x01, 0xa4, 0x93, 0xe9, 0x57, 0x55, + 0xae, 0x29, 0xed, 0xfa, 0x5f, 0x3e, 0x7f, 0x33, + 0x92, 0xee, 0x6e, 0xdc, 0xae, 0x5f, 0x1b, 0xb0, + 0xf2, 0x6c, 0xf7, 0x71, 0x17, 0xc7, 0xc3, 0x47, + 0xe6, 0xfc, 0xd4, 0x4d, 0x7e, 0x53, 0x5b, 0x6d, + 0xf0, 0xfb, 0xf8, 0x1f, 0xf0, 0x6e, 0x14, 0xce, + 0xd3, 0x42, 0x0e, 0x3e, 0x73, 0x51, 0x5f, 0x4c, + 0xd4, 0xde, 0x30, 0xad, 0xc2, 0x67, 0x26, 0x16, + 0x51, 0x47, 0xf7, 0x42, 0xa6, 0xb1, 0x08, 0x1a, + 0xf7, 0x8f, 0xf4, 0xc6, 0x23, 0x44, 0xdc, 0xac, + 0x44, 0xfe, 0xb9, 0x74, 0x25, 0x7f, 0x13, 0xc7, + 0x3a, 0xb7, 0xc2, 0xb6, 0xa2, 0x54, 0x53, 0x7f, + 0x04, 0x5e, 0x59, 0x4e, 0x53, 0xa1, 0x39, 0x2a, + 0xb9, 0x2b, 0x70, 0x01, 0x8f, 0x87, 0x37, 0xfb, + 0xf2, 0x24, 0xc1, 0x2b, 0x6d, 0xc1, 0x0e, 0xaf, + 0x61, 0x7a, 0x36, 0x01, 0xf8, 0xcb, 0xdd, 0xef, + 0x3a, 0x13, 0x34, 0xf7, 0xf3, 0xa8, 0xc9, 0xfa, + 0x84, 0x4a, 0xef, 0x65, 0xa5, 0xd7, 0x74, 0xce, + 0xef, 0x7f, 0x99, 0x23, 0x82, 0x60, 0xfb, 0x86, + 0xd7, 0xba, 0x2e, 0x4a, 0x15, 0x72, 0x56, 0x7a, + 0x9c, 0x9c, 0x28, 0x7d, 0xcc, 0xc2, 0xf1, 0x58, + 0x58, 0x6b, 0x4e, 0x08, 0x15, 0x0c, 0x9c, 0x12, + 0x55, 0xcc, 0xbd, 0xb8, 0xe4, 0x98, 0xbd, 0x36, + 0x00, 0xf0, 0xa1, 0x9e, 0x27, 0x4b, 0x68, 0xf5, + 0x02, 0xaa, 0x69, 0xcc, 0x42, 0xc3, 0x02, 0x0c, + 0xf2, 0x46, 0x26, 0x35, 0x13, 0x71, 0x3f, 0xc0, + 0x6e, 0x93, 0x1d, 0x82, 0x82, 0xdd, 0x73, 0x90, + 0xde, 0xba, 0x08, 0x5c, 0x25, 0x91, 0x10, 0x2b, + 0xc8, 0xa9, 0xad, 0xe6, 0x2f, 0xe5, 0x67, 0xb8, + 0x95, 0x5a, 0x72, 0xfb, 0xd7, 0x1c, 0x24, 0x71, + 0xab, 0xb5, 0x47, 0x66, 0xe9, 0x60, 0x9e, 0xe0, + 0x53, 0xb1, 0xb8, 0x02, 0x19, 0x94, 0x0c, 0x30, + 0x55, 0x89, 0x3c, 0x6f, 0xb6, 0x89, 0xd7, 0xe4, + 0xeb, 0x8d, 0xfa, 0xd8, 0x49, 0xe3, 0x3c, 0xfd, + 0xf2, 0xaa, 0x26, 0xc4, 0xb5, 0x34, 0x3c, 0xc0, + 0x5a, 0x73, 0xbf, 0x59, 0x0e, 0x8d, 0x13, 0x9c, + 0x88, 0x5b, 0x72, 0xf3, 0xb1, 0x1a, 0xb2, 0x28, + 0x44, 0x16, 0x4b, 0x1a, 0xf2, 0x3d, 0x14, 0x80, + 0x7c, 0x33, 0x09, 0x82, 0x4c, 0x13, 0xc7, 0xf2, + 0xce, 0xa7, 0x9d, 0xa3, 0x6c, 0x4c, 0xd7, 0x96, + 0x03, 0xa2, 0x69, 0x57, 0x51, 0x97, 0x03, 0x98, + 0xa6, 0xe3, 0x36, 0x47, 0x27, 0xb1, 0xf9, 0xd7, + 0x0a, 0x24, 0x6e, 0x53, 0x88, 0xe3, 0xcd, 0x25, + 0x49, 0x59, 0xa6, 0x71, 0xed, 0x42, 0x34, 0x10, + 0x94, 0x68, 0xad, 0x39, 0x4b, 0x28, 0xe3, 0x3b, + 0x4f, 0xc5, 0x01, 0xaf, 0xa3, 0x72, 0xd7, 0x88, + 0x52, 0x93, 0xd2, 0xcf, 0xb3, 0xd6, 0xa9, 0x22, + 0x92, 0x74, 0xd5, 0x85, 0xb0, 0x59, 0x26, 0x49, + 0xb0, 0x10, 0x11, 0x08, 0x68, 0x61, 0xc9, 0x04, + 0xb5, 0xf3, 0x66, 0x42, 0xc2, 0xa9, 0xda, 0x39, + 0x35, 0x61, 0xde, 0x56, 0x86, 0x45, 0xe7, 0x4e, + 0xb5, 0xa0, 0x25, 0xd4, 0x3b, 0x07, 0x95, 0x21, + 0x1a, 0x4a, 0x86, 0xeb, 0x78, 0x1e, 0xf8, 0x08, + 0x3f, 0x8d, 0xa3, 0x1f, 0x93, 0xb0, 0x03, 0x21, + 0x5e, 0x12, 0xa8, 0x23, 0x76, 0xde, 0x14, 0x65, + 0x98, 0xd0, 0x45, 0x58, 0x56, 0xbb, 0x4f, 0x25, + 0xba, 0xe0, 0x04, 0x4d, 0x2e, 0x63, 0x40, 0x2e, + 0x0d, 0x8f, 0x8f, 0xaa, 0xb1, 0x5e, 0xe7, 0x95, + 0xe4, 0xa9, 0x9e, 0x0f, 0xe7, 0xf4, 0x78, 0x43, + 0x01, 0x42, 0x34, 0xf4, 0xb5, 0x3b, 0xea, 0x6b, + 0xcf, 0x5f, 0x24, 0x6d, 0xd5, 0xcf, 0x85, 0x59, + 0x0b, 0x1a, 0xf1, 0xee, 0x97, 0x09, 0x7e, 0x4d, + 0x2a, 0xe4, 0x52, 0x45, 0xdf, 0xd2, 0xe0, 0xc1, + 0xdf, 0x3f, 0xaa, 0x85, 0xb0, 0xc8, 0xb4, 0x52, + 0x7a, 0x75, 0xcd, 0xd1, 0xe0, 0xe0, 0x17, 0x57, + 0x8b, 0x82, 0x62, 0x81, 0xa7, 0x60, 0x8e, 0x85, + 0xee, 0x10, 0xdd, 0x16, 0x16, 0x72, 0x39, 0x1f, + 0x53, 0x7a, 0xa4, 0x29, 0x65, 0x7c, 0x14, 0x70, + 0xa0, 0x3d, 0xe9, 0xa6, 0xe0, 0x85, 0x29, 0xe8, + 0x95, 0x4e, 0x19, 0x8d, 0xdc, 0xe8, 0x3b, 0x6b, + 0x9d, 0xe8, 0xab, 0xda, 0x23, 0x03, 0x76, 0xdd, + 0x79, 0x2f, 0x04, 0x08, 0xbe, 0x48, 0x91, 0x89, + 0x01, 0x82, 0x2c, 0x3d, 0xd6, 0x93, 0x32, 0xbc, + 0xff, 0x34, 0x3c, 0xb1, 0x8f, 0x9c, 0xd4, 0xde, + 0x5d, 0x59, 0x3a, 0xf9, 0xe6, 0x09, 0xa0, 0x1d, + 0x8a, 0x3d, 0x5a, 0x68, 0x2b, 0x45, 0x80, 0x7a, + 0xdc, 0xd2, 0x57, 0x93, 0xeb, 0x76, 0x15, 0x33, + 0x3e, 0xdd, 0x3b, 0xbf, 0x28, 0x10, 0x21, 0xe3, + 0xd6, 0x83, 0xc4, 0x8f, 0xec, 0x9b, 0x5f, 0x85, + 0xef, 0xe9, 0x2f, 0xda, 0x21, 0x64, 0x66, 0x91, + 0x33, 0x06, 0x71, 0xf6, 0xe7, 0x23, 0x98, 0xb1, + 0xa8, 0x26, 0xa4, 0xc8, 0x38, 0xc6, 0x9e, 0xc3, + 0x34, 0x22, 0x2f, 0x8e, 0xcc, 0xc1, 0x5b, 0xe5, + 0x84, 0x09, 0x8f, 0x35, 0xa4, 0xc3, 0x5f, 0x7e, + 0xd3, 0x0d, 0x5c, 0x46, 0x58, 0x77, 0x75, 0x74, + 0x6f, 0xeb, 0xc6, 0xe0, 0xb1, 0xf4, 0x47, 0xdd, + 0x79, 0x6a, 0xef, 0x1e, 0x73, 0xd7, 0x74, 0x70, + 0xf7, 0x13, 0x72, 0x07, 0x34, 0x96, 0x4b, 0x1f, + 0xff, 0xb9, 0x77, 0x8c, 0x13, 0x88, 0x86, 0x83, + 0x4d, 0xc8, 0x49, 0x74, 0xd9, 0xa4, 0x56, 0x7d, + 0x7b, 0xa0, 0x7d, 0x8f, 0x11, 0x08, 0x9b, 0xc0, + 0x25, 0xc9, 0xa3, 0xa8, 0x32, 0xfd, 0x84, 0xaa, + 0xda, 0x11, 0x76, 0x86, 0x7e, 0xa2, 0x4b, 0x40, + 0xe4, 0x0c, 0x5b, 0x2b, 0x60, 0x8a, 0x49, 0x37, + 0x7d, 0xb0, 0xad, 0x35, 0x26, 0x17, 0xb4, 0x0a, + 0x5d, 0x4e, 0x58, 0xd2, 0xe2, 0x61, 0xca, 0x8f, + 0x98, 0x0d, 0x83, 0xcc, 0x90, 0xb1, 0x0b, 0x8a, + 0x45, 0x8d, 0xa9, 0x87, 0x21, 0x0c, 0x62, 0xf6, + 0x4b, 0xfd, 0xba, 0xba, 0x73, 0x17, 0x0e, 0x45, + 0x9d, 0x86, 0xe3, 0xa1, 0x10, 0xad, 0x90, 0x01, + 0xd6, 0x79, 0x09, 0xfe, 0xe2, 0xe3, 0xca, 0x00, + 0xcb, 0xa2, 0xe5, 0xa0, 0xe3, 0x52, 0x6e, 0x6e, + 0x5a, 0x92, 0xa5, 0x43, 0x61, 0x1e, 0xf1, 0x63, + 0x17, 0x85, 0xd8, 0x8a, 0x24, 0x4e, 0xec, 0xdf, + 0x48, 0xe3, 0x8b, 0x89, 0x53, 0x8b, 0x94, 0x02, + 0x6e, 0x35, 0xdf, 0xe0, 0xaf, 0x0c, 0x6a, 0xc2, + 0x1d, 0x0a, 0xf6, 0x5e, 0xae, 0xf1, 0xbd, 0xd8, + 0x9f, 0x04, 0xf4, 0x76, 0x62, 0x14, 0xd7, 0x8d, + 0x4e, 0x21, 0x21, 0x9e, 0x5a, 0x8c, 0xb5, 0x1a, + 0x28, 0x8e, 0xdb, 0xbc, 0x53, 0x78, 0x45, 0x08, + 0x0f, 0x5b, 0x12, 0x2d, 0xdf, 0x70, 0xb4, 0x0c, + 0x81, 0x3b, 0x2b, 0xf1, 0x77, 0x7b, 0x70, 0xa4, + 0x98, 0x42, 0xcc, 0x04, 0x22, 0xf8, 0xbb, 0x08, + 0xfa, 0x75, 0x99, 0x65, 0x15, 0x61, 0x51, 0xa3, + 0x29, 0xb9, 0x7d, 0x12, 0x33, 0xdc, 0xf6, 0xb7, + 0xf1, 0x7e, 0x59, 0xe5, 0x09, 0xad, 0x07, 0x9c, + 0x6d, 0xbc, 0x94, 0xfc, 0xdd, 0xdc, 0x76, 0x3a, + 0xc1, 0xe6, 0xcf, 0x40, 0xf7, 0xb5, 0xea, 0x4d, + 0x71, 0xbc, 0x7e, 0xb5, 0x97, 0x11, 0xbd, 0x40, + 0x75, 0xf6, 0xb7, 0xc8, 0xb1, 0xe5, 0xf0, 0x2c, + 0x66, 0xfa, 0x40, 0x87, 0xe6, 0xd9, 0x71, 0x4a, + 0xeb, 0x55, 0x2a, 0x94, 0x22, 0x71, 0x79, 0xb3, + 0xac, 0x1a, 0x4c, 0x4e, 0xba, 0x97, 0x20, 0xf8, + 0x78, 0x31, 0x27, 0x30, 0x2f, 0x8b, 0x16, 0xe1, + 0xf7, 0x88, 0x7d, 0xbf, 0x8d, 0x33, 0x35, 0xcf, + 0xa2, 0xe6, 0x2c, 0x6b, 0x3c, 0x49, 0x4d, 0x77, + 0x9d, 0x63, 0xfb, 0xb3, 0x41, 0x9d, 0x25, 0x76, + 0xc7, 0x11, 0xcb, 0xc6, 0xa7, 0x23, 0x86, 0xc6, + 0xe8, 0x82, 0x7a, 0x88, 0x33, 0x8a, 0x0b, 0x2e, + 0x61, 0x41, 0x67, 0xe0, 0x27, 0x74, 0xbf, 0x61, + 0x4e, 0xd4, 0x0f, 0x75, 0xa7, 0x5b, 0x71, 0x96, + 0x22, 0x55, 0x38, 0x86, 0x4a, 0x41, 0x04, 0x42, + 0x28, 0xda, 0xdd, 0xac, 0x4b, 0x86, 0xe4, 0x20, + 0x41, 0x7f, 0x84, 0x51, 0x79, 0xa1, 0xf4, 0x36, + 0x02, 0x2c, 0x0d, 0x74, 0xc8, 0x67, 0xdc, 0x25, + 0xdc, 0x84, 0x6b, 0x71, 0xee, 0xc0, 0x79, 0xa1, + 0x4c, 0x2a, 0xa6, 0xbb, 0x0f, 0x11, 0xf4, 0x59, + 0xbb, 0x65, 0x7d, 0xe7, 0x32, 0x52, 0x1c, 0x4f, + 0xc7, 0x51, 0x30, 0x39, 0xd4, 0x80, 0x24, 0x99, + 0x09, 0x13, 0x5a, 0x08, 0xdf, 0xde, 0xb0, 0xd4, + 0xce, 0x25, 0x53, 0xb9, 0xb4, 0x1e, 0x53, 0x01, + 0x90, 0xf5, 0x6d, 0x52, 0xcc, 0x52, 0x39, 0x12, + 0xc7, 0x1b, 0x34, 0x20, 0x13, 0x28, 0x9a, 0x0e, + 0x1f, 0x24, 0xe3, 0x9d, 0x37, 0x3e, 0x20, 0xdb, + 0x9a, 0x19, 0x88, 0xf6, 0xbd, 0x64, 0x97, 0xbb, + 0x02, 0x1f, 0x14, 0xb6, 0xc6, 0x30, 0x72, 0x2d, + 0xff, 0x04, 0xd3, 0x20, 0xb9, 0x77, 0x74, 0x68, + 0x2e, 0x1c, 0x09, 0x93, 0x05, 0x58, 0xeb, 0x8f, + 0x9c, 0x91, 0x12, 0x20, 0x8b, 0xd2, 0x51, 0xa3, + 0x93, 0xea, 0xdb, 0xef, 0x6c, 0x2f, 0xd5, 0xf2, + 0x56, 0x52, 0xd4, 0xab, 0x3f, 0x38, 0x4b, 0x7c, + 0xe1, 0x07, 0x8b, 0x41, 0x55, 0x53, 0x55, 0x32, + 0x5f, 0x0c, 0x2e, 0xcd, 0xe2, 0xf2, 0x27, 0x3f, + 0x82, 0xe3, 0xa6, 0x21, 0x57, 0xad, 0x4e, 0x77, + 0xb4, 0x37, 0x73, 0xc8, 0x14, 0x15, 0xc5, 0x78, + 0x2f, 0xaf, 0xce, 0xbf, 0x98, 0xf1, 0x51, 0xde, + 0xd8, 0xfc, 0x77, 0x8e, 0x4f, 0xa9, 0xa6, 0x3a, + 0xc2, 0xf5, 0xbe, 0x6c, 0x88, 0x77, 0x8f, 0xd7, + 0x2e, 0xda, 0xae, 0xf0, 0x4a, 0xc6, 0x81, 0x73, + 0x0e, 0x63, 0x5e, 0x50, 0x13, 0xd2, 0x6f, 0x4a, + 0x6a, 0x23, 0x1a, 0x58, 0x8d, 0xa4, 0xc8, 0xe4, + 0x20, 0xec, 0x5d, 0x0d, 0x5b, 0x5d, 0x76, 0x66, + 0x56, 0xf8, 0xa8, 0xf2, 0x3d, 0x2f, 0xd3, 0xb2, + 0x20, 0xb6, 0x12, 0x9d, 0x37, 0x89, 0x28, 0xe5, + 0x36, 0xdf, 0x13, 0x73, 0x38, 0x4e, 0x25, 0x7b, + 0x33, 0xb7, 0xc8, 0x4b, 0x39, 0x7e, 0x74, 0x9f, + 0xe5, 0xbb, 0x8c, 0x6f, 0x94, 0x62, 0x27, 0xbb, + 0x9c, 0xd4, 0x1b, 0xb5, 0xcc, 0x0c, 0x5f, 0x16, + 0xc2, 0x96, 0xd0, 0xdf, 0x81, 0xdd, 0x21, 0x3a, + 0xf0, 0x42, 0x11, 0xe3, 0xb5, 0x6f, 0x1b, 0xc6, + 0x23, 0xd1, 0x13, 0x23, 0x42, 0x3b, 0xb6, 0xa0, + 0x75, 0x1c, 0x45, 0x98, 0x78, 0x94, 0xa0, 0xbb, + 0xba, 0xf9, 0x04, 0xe8, 0x48, 0x3d, 0x12, 0x23, + 0xf4, 0x96, 0x8f, 0x4b, 0xbb, 0x94, 0x96, 0x89, + 0x25, 0x7b, 0x3b, 0xfe, 0x30, 0x6b, 0x7b, 0x96, + 0xfa, 0xe9, 0x23, 0xc9, 0xdb, 0xa8, 0xe6, 0xbc, + 0x4a, 0x72, 0x7e, 0x41, 0xb1, 0x96, 0x01, 0x09, + 0x26, 0x42, 0x8c, 0xc3, 0x4e, 0x05, 0xd3, 0x73, + 0xa7, 0xb1, 0xdb, 0xd0, 0xc0, 0x9c, 0x8a, 0x24, + 0xfc, 0x82, 0x68, 0x98, 0xff, 0x0f, 0xd6, 0x62, + 0x56, 0xbe, 0x42, 0xa3, 0xca, 0xd1, 0xc8, 0x3f, + 0xab, 0xd9, 0xd6, 0x3f, 0xbf, 0x9d, 0x98, 0x66, + 0x25, 0x0a, 0x26, 0x46, 0xef, 0xf8, 0x0c, 0xf5, + 0xfb, 0xcc, 0x5e, 0x70, 0x57, 0xa9, 0x50, 0xe7, + 0x8b, 0xf8, 0xc9, 0xe0, 0x41, 0x4d, 0x0b, 0x96, + 0x25, 0xf0, 0x94, 0x17, 0x70, 0x13, 0x50, 0xfd + }; + static const byte mu_44[] = { + 0xe7, 0x8a, 0xe8, 0x1f, 0xbf, 0xc8, 0xef, 0x71, + 0x9a, 0xf1, 0xae, 0xca, 0xc8, 0xea, 0x9a, 0x9b, + 0x19, 0x42, 0x4d, 0x15, 0xf1, 0x41, 0x8e, 0xaf, + 0xd7, 0xa7, 0x6f, 0x6a, 0xed, 0x00, 0x78, 0x25, + 0x2a, 0x1f, 0xdb, 0x9e, 0x0c, 0x6f, 0x00, 0x52, + 0x33, 0x59, 0xf6, 0x8a, 0x30, 0xe9, 0xc1, 0x58, + 0xf1, 0x67, 0x4f, 0x1d, 0x34, 0x59, 0xb8, 0xc3, + 0x29, 0xf4, 0x8f, 0xbf, 0x1a, 0x22, 0xca, 0x91 + }; + static const byte sig_44_mu[] = { + 0xa3, 0xf1, 0xe8, 0xd7, 0xf3, 0x38, 0x9e, 0x08, + 0x0e, 0xe3, 0x00, 0xa9, 0xf7, 0x71, 0x03, 0x70, + 0x3e, 0x28, 0xc7, 0x3c, 0xd4, 0xec, 0x3d, 0x62, + 0xba, 0xf5, 0x9c, 0x1b, 0x86, 0xd9, 0x0c, 0xe0, + 0xde, 0x85, 0xe0, 0x85, 0xc1, 0x7c, 0x1a, 0xe8, + 0x42, 0x7c, 0xb5, 0x37, 0x2b, 0x88, 0x69, 0x0c, + 0xe7, 0xee, 0x5a, 0xec, 0xed, 0xce, 0xc0, 0x1a, + 0x35, 0x88, 0xee, 0x15, 0xa6, 0x10, 0x83, 0x4d, + 0x61, 0xc1, 0x1a, 0x7d, 0xe8, 0xcb, 0xa3, 0x54, + 0x7a, 0x3c, 0x43, 0xba, 0x26, 0xef, 0x54, 0x62, + 0x33, 0x2d, 0x4a, 0x2f, 0x43, 0x07, 0x6c, 0x1e, + 0x2a, 0x6f, 0x76, 0x9e, 0x6b, 0x74, 0x24, 0x17, + 0x06, 0xa8, 0x1f, 0x5d, 0x8a, 0x59, 0x30, 0x9f, + 0x97, 0xbd, 0x8c, 0x55, 0x0c, 0xa6, 0xc2, 0xbf, + 0x34, 0x0a, 0x36, 0x6f, 0xe5, 0x52, 0x55, 0x25, + 0xb3, 0x15, 0x9e, 0x4c, 0xba, 0x16, 0x72, 0x50, + 0xf1, 0x0a, 0x45, 0xb1, 0x65, 0xb5, 0x06, 0x14, + 0x1a, 0x24, 0x10, 0xeb, 0xe1, 0x5b, 0xa3, 0x3b, + 0x01, 0xdc, 0xd0, 0x18, 0xf7, 0xcd, 0x02, 0x15, + 0xd5, 0x82, 0x76, 0x52, 0x1d, 0x60, 0x16, 0x08, + 0xbf, 0x44, 0x51, 0x0a, 0xb2, 0xd4, 0x68, 0x99, + 0xc6, 0x9c, 0x97, 0xf5, 0x37, 0x1c, 0xd1, 0x27, + 0xcf, 0xe8, 0x33, 0x2f, 0x81, 0x14, 0xd5, 0xa6, + 0x9a, 0x9c, 0x61, 0xc0, 0x91, 0x6a, 0x5a, 0x63, + 0x39, 0x11, 0x9d, 0x35, 0x33, 0x98, 0xf6, 0x2c, + 0x78, 0xba, 0x4c, 0x6b, 0x7f, 0x3c, 0x71, 0x64, + 0x5b, 0x29, 0xf7, 0xdc, 0x3d, 0x25, 0x45, 0xed, + 0x30, 0xc1, 0xb5, 0x3e, 0x18, 0x51, 0xa7, 0x06, + 0x6d, 0x24, 0xc2, 0x43, 0x55, 0x91, 0xab, 0x4c, + 0xdd, 0xbd, 0x54, 0xb0, 0x48, 0x0e, 0x87, 0x75, + 0xdb, 0x31, 0x3c, 0x70, 0x61, 0x92, 0xd8, 0xed, + 0xbe, 0x18, 0xe7, 0xd3, 0xc4, 0xbe, 0xd5, 0x5e, + 0x46, 0xf5, 0xf4, 0x14, 0xc5, 0xba, 0xb6, 0x4f, + 0x23, 0x97, 0x13, 0x6e, 0x6a, 0x86, 0x76, 0x6a, + 0x20, 0x3f, 0x46, 0x38, 0xa9, 0x5d, 0x33, 0xf7, + 0x14, 0x6f, 0xc5, 0x3f, 0x4f, 0x5b, 0xe4, 0xf2, + 0x78, 0x34, 0x23, 0x88, 0xdf, 0xb9, 0xf1, 0xd9, + 0x3e, 0x1f, 0x30, 0x94, 0xfb, 0x99, 0x32, 0xb9, + 0x76, 0xda, 0x97, 0x52, 0xbd, 0x73, 0xd8, 0x33, + 0x44, 0x3f, 0xfc, 0x9b, 0x75, 0xe0, 0x04, 0xa3, + 0x37, 0x0c, 0xd4, 0x48, 0x9f, 0x72, 0xc0, 0xd5, + 0xba, 0xe6, 0x5f, 0x93, 0x0d, 0x07, 0x82, 0xbb, + 0x6c, 0x06, 0xeb, 0x9f, 0x6a, 0xe4, 0x9f, 0x29, + 0x25, 0xac, 0x22, 0xc3, 0x50, 0x53, 0x3e, 0xa8, + 0x32, 0x5e, 0x55, 0xde, 0x86, 0x42, 0x63, 0x7e, + 0xc4, 0x40, 0x12, 0x42, 0xb5, 0x5a, 0xc4, 0x2f, + 0xe4, 0xa3, 0xe7, 0x13, 0xbf, 0x1f, 0x3b, 0x9c, + 0x3a, 0xab, 0xa9, 0xa8, 0x34, 0x52, 0x1f, 0xee, + 0xb2, 0x75, 0xe7, 0x25, 0xac, 0x8c, 0x4f, 0x34, + 0x8e, 0xb6, 0x29, 0x43, 0xf4, 0x37, 0x04, 0xe5, + 0x58, 0xde, 0xf0, 0xd2, 0x72, 0x1e, 0xb4, 0xc2, + 0x17, 0xe7, 0x97, 0xa9, 0x9d, 0x26, 0xfa, 0x68, + 0x21, 0x3c, 0x8c, 0xea, 0xa2, 0x9e, 0x3a, 0x18, + 0x6e, 0x79, 0x2b, 0x83, 0x24, 0x2c, 0xf2, 0x46, + 0x07, 0x19, 0x39, 0x45, 0x47, 0x50, 0x96, 0x5a, + 0xa2, 0x57, 0x62, 0x24, 0x72, 0xbb, 0x95, 0x65, + 0xbb, 0x22, 0x33, 0x83, 0x51, 0x10, 0x99, 0x6c, + 0x21, 0xa4, 0x82, 0x41, 0xc9, 0x2d, 0xa3, 0xa2, + 0xd9, 0xee, 0xc1, 0x03, 0x27, 0x92, 0x33, 0x4e, + 0x2d, 0x6f, 0x54, 0x86, 0x76, 0x7d, 0xd8, 0xc4, + 0x45, 0xdf, 0xe1, 0xa7, 0xb0, 0xeb, 0xa8, 0x56, + 0x5f, 0x89, 0x99, 0xa2, 0x78, 0xb4, 0x96, 0xe4, + 0x56, 0xd2, 0xea, 0x56, 0x2e, 0xf8, 0x93, 0x04, + 0x9c, 0x5f, 0xf2, 0x70, 0x6e, 0x8e, 0x5f, 0x17, + 0xd4, 0x91, 0x75, 0x63, 0x39, 0xdc, 0x67, 0xd7, + 0x7f, 0x30, 0x4d, 0x2d, 0x4b, 0x87, 0xea, 0xf9, + 0x78, 0xff, 0x0a, 0xb3, 0xab, 0x9d, 0xad, 0xb3, + 0x52, 0x9b, 0xea, 0x8c, 0x7f, 0xa9, 0xe6, 0x63, + 0x8c, 0xe5, 0x70, 0x34, 0x9f, 0xf2, 0x0d, 0x90, + 0x72, 0x32, 0x89, 0x64, 0x2c, 0x65, 0x14, 0xb1, + 0x44, 0xf7, 0x46, 0x36, 0xd2, 0xd8, 0xd7, 0x84, + 0x4a, 0xab, 0x08, 0xc4, 0x9b, 0xb7, 0x6b, 0x14, + 0xbe, 0x37, 0x59, 0xec, 0x6f, 0x0f, 0x16, 0x99, + 0x75, 0x6e, 0x00, 0xbe, 0x8a, 0x7f, 0x31, 0xe3, + 0xec, 0x59, 0x71, 0x32, 0xa4, 0x0b, 0xde, 0x96, + 0x9a, 0x36, 0xe2, 0x8f, 0x60, 0x16, 0x2c, 0x23, + 0x47, 0x37, 0x91, 0x3e, 0x30, 0x2d, 0x36, 0x97, + 0x96, 0x40, 0xa8, 0x37, 0x98, 0x64, 0x9f, 0xfc, + 0x86, 0x82, 0x6d, 0x6a, 0x8c, 0x2e, 0xf5, 0x35, + 0x12, 0x91, 0xcb, 0x5e, 0x52, 0x31, 0x11, 0x3d, + 0x67, 0x23, 0x9f, 0x4f, 0x53, 0x0c, 0xf9, 0xd0, + 0xbb, 0x8a, 0x3b, 0xb3, 0xf4, 0x00, 0x12, 0x7b, + 0x73, 0x1b, 0x96, 0x0c, 0x56, 0x90, 0x80, 0x3c, + 0x6c, 0x44, 0x23, 0xc3, 0xd4, 0xac, 0x53, 0x22, + 0x10, 0x70, 0xf0, 0x44, 0xe9, 0xbb, 0x1a, 0xa3, + 0xf2, 0x1b, 0x0e, 0x39, 0x43, 0xea, 0x2c, 0x05, + 0xf7, 0x41, 0x5d, 0x48, 0x7d, 0xb1, 0x4b, 0xfc, + 0xcf, 0x76, 0x86, 0x57, 0xcd, 0x42, 0xdf, 0xd1, + 0xcc, 0x89, 0xf1, 0x23, 0x8e, 0xe8, 0xe4, 0x91, + 0xf6, 0x94, 0xc6, 0x9e, 0x51, 0x6a, 0x4a, 0x66, + 0x84, 0xcd, 0xfc, 0xa1, 0xb7, 0x3b, 0x5c, 0xf9, + 0xb2, 0x4c, 0x00, 0x49, 0x8d, 0xc2, 0x79, 0xc2, + 0xf9, 0xe0, 0xcc, 0x1b, 0xd7, 0xd8, 0xa8, 0x98, + 0xa9, 0xc7, 0x13, 0x14, 0x9d, 0x8a, 0x9c, 0xc1, + 0xd9, 0x95, 0x52, 0x51, 0x55, 0xfc, 0x3a, 0x1d, + 0x71, 0x8f, 0x23, 0x6a, 0x4a, 0xc2, 0x8b, 0x1e, + 0xac, 0x4b, 0x2f, 0xaa, 0x22, 0xd3, 0xfe, 0xce, + 0x30, 0x36, 0x4b, 0xa0, 0xe6, 0x3b, 0x38, 0x53, + 0xec, 0xd8, 0x76, 0x41, 0xc8, 0x24, 0xa4, 0xe6, + 0x59, 0x7a, 0xd1, 0x6d, 0x34, 0xb4, 0x6a, 0x40, + 0xdd, 0xa5, 0xd5, 0x86, 0x45, 0xcc, 0x72, 0xcd, + 0x82, 0xb5, 0x9a, 0x38, 0x69, 0x1b, 0xf4, 0x53, + 0xb0, 0xdb, 0x90, 0x3e, 0xc7, 0x0b, 0x66, 0x93, + 0x93, 0x52, 0xd3, 0x80, 0x93, 0x9f, 0xde, 0x39, + 0xdb, 0x7b, 0xae, 0xbb, 0x8e, 0xfd, 0xd9, 0xfc, + 0x54, 0xf6, 0x41, 0xc5, 0x38, 0x09, 0x16, 0xbd, + 0x1b, 0x21, 0xed, 0xbe, 0x33, 0xc4, 0xb1, 0xbd, + 0x77, 0x88, 0x05, 0x06, 0x09, 0x4c, 0x41, 0xda, + 0xb7, 0x17, 0x70, 0xf0, 0x3e, 0x44, 0x2f, 0xa3, + 0x0c, 0x55, 0x65, 0xc4, 0xc0, 0x0d, 0x34, 0x82, + 0xb1, 0x54, 0xb4, 0xff, 0x39, 0xe2, 0x68, 0x67, + 0x72, 0x7b, 0xd8, 0x60, 0x4e, 0x61, 0x48, 0xdc, + 0x65, 0x02, 0xf7, 0x28, 0x82, 0xf2, 0xb8, 0xf5, + 0x87, 0x5e, 0x91, 0x7c, 0xea, 0xd4, 0xef, 0xaf, + 0xee, 0x24, 0x8d, 0xab, 0xfb, 0x8d, 0xab, 0x59, + 0xaa, 0x85, 0xfa, 0x52, 0x6a, 0x96, 0xcf, 0x08, + 0x60, 0x47, 0x2d, 0xe3, 0xdf, 0xad, 0x6f, 0x75, + 0xbd, 0x15, 0x99, 0xb0, 0x9c, 0x75, 0xf3, 0x91, + 0x36, 0x1a, 0xcf, 0x84, 0x78, 0xf5, 0x33, 0x3a, + 0x78, 0x51, 0x40, 0x87, 0x47, 0x88, 0x56, 0xc0, + 0x8c, 0x1f, 0xc2, 0x94, 0x52, 0xe6, 0x18, 0xd9, + 0xe6, 0x0a, 0x9b, 0xd4, 0xa5, 0x3a, 0xea, 0x35, + 0x49, 0xae, 0xfe, 0xcb, 0xc1, 0x7c, 0x99, 0x9c, + 0x29, 0x38, 0x83, 0x3b, 0xbe, 0xc9, 0x4d, 0x33, + 0x16, 0xca, 0x9a, 0x72, 0xfa, 0x07, 0x9f, 0x72, + 0xba, 0x11, 0x13, 0x06, 0x38, 0xf3, 0xc3, 0x0c, + 0xd7, 0x79, 0xee, 0x3b, 0xcf, 0x9a, 0xe8, 0xbb, + 0x26, 0x03, 0x22, 0x75, 0xf9, 0x78, 0xb0, 0x4a, + 0x65, 0xa8, 0x9f, 0x95, 0xd6, 0xd9, 0xb3, 0x7b, + 0xe0, 0x59, 0xd1, 0x71, 0x25, 0xce, 0x60, 0xc1, + 0x50, 0x3e, 0x2e, 0xd5, 0xab, 0xf7, 0xd3, 0x27, + 0xd3, 0xc7, 0x9b, 0xc4, 0xd3, 0x57, 0x82, 0x10, + 0xa4, 0xef, 0x20, 0x20, 0xf5, 0x8b, 0xa0, 0x0c, + 0x08, 0xec, 0xf0, 0x39, 0x02, 0xe4, 0xe6, 0xd9, + 0x52, 0x7e, 0x76, 0x73, 0x48, 0x5d, 0x15, 0x86, + 0xc4, 0x28, 0xee, 0x6e, 0x5c, 0x47, 0xd4, 0x52, + 0xfd, 0xd0, 0xba, 0x3c, 0xec, 0x59, 0x93, 0x01, + 0x04, 0xa9, 0x1f, 0xf5, 0x73, 0xeb, 0x18, 0xf7, + 0x48, 0x57, 0x20, 0xcd, 0xa5, 0x67, 0xcc, 0x9f, + 0x9c, 0x18, 0xb7, 0xcf, 0xf2, 0x55, 0xf2, 0x08, + 0x8d, 0x40, 0x3f, 0xaa, 0xb5, 0x83, 0xf2, 0x85, + 0x33, 0x8a, 0x0f, 0xd2, 0x25, 0x10, 0x30, 0xda, + 0x5a, 0xd3, 0x39, 0xb1, 0xc0, 0x9c, 0x01, 0xef, + 0x8e, 0x81, 0x4b, 0x0d, 0x00, 0x21, 0x06, 0xd0, + 0xcf, 0x1b, 0x9a, 0xea, 0x49, 0xaa, 0xaa, 0xa8, + 0x08, 0x7b, 0x01, 0x3c, 0x96, 0x65, 0xe9, 0x0b, + 0x74, 0x44, 0x36, 0x25, 0x26, 0x08, 0xc7, 0xac, + 0x16, 0x15, 0x38, 0xbb, 0xfe, 0xac, 0x0c, 0x86, + 0x6a, 0xce, 0x71, 0x2c, 0xea, 0xfa, 0xbd, 0xda, + 0x5c, 0xd2, 0x51, 0x71, 0xfe, 0xe2, 0x13, 0xae, + 0x33, 0x8d, 0xfa, 0xfa, 0x80, 0x1c, 0x7b, 0xe8, + 0xb2, 0x79, 0xa7, 0x4a, 0xbc, 0x68, 0x72, 0xdb, + 0x5a, 0x45, 0x33, 0x73, 0x24, 0xb1, 0xa4, 0xe0, + 0x24, 0x29, 0x1c, 0xb3, 0x6a, 0x16, 0xa0, 0xf6, + 0x04, 0x50, 0x25, 0xdc, 0x21, 0x20, 0xec, 0xf0, + 0x3d, 0x46, 0x0c, 0x55, 0x53, 0x7d, 0xff, 0xde, + 0x1f, 0x4d, 0xcb, 0x42, 0xd6, 0xee, 0x14, 0x66, + 0xb5, 0xf2, 0x2f, 0x3e, 0x47, 0xd5, 0x46, 0x45, + 0xa5, 0xc8, 0xba, 0x5b, 0x7e, 0xbd, 0x7a, 0xc6, + 0x64, 0x2e, 0xdb, 0x3f, 0x01, 0x1e, 0x89, 0xe3, + 0x48, 0xdd, 0x44, 0xa2, 0x7b, 0xeb, 0x1a, 0x57, + 0x10, 0xd4, 0x02, 0x08, 0x50, 0x2d, 0xdf, 0xfd, + 0x4b, 0x00, 0xba, 0xed, 0x1c, 0xdc, 0x10, 0x5a, + 0xa3, 0x75, 0xce, 0xae, 0xff, 0xa8, 0xb3, 0x75, + 0x5a, 0xbc, 0x13, 0x2e, 0xeb, 0x20, 0x13, 0xfc, + 0xe4, 0x4d, 0xa8, 0x01, 0xa1, 0x6d, 0xef, 0x73, + 0xf2, 0x8c, 0x7b, 0xd9, 0x37, 0xb1, 0xe3, 0x28, + 0x71, 0x70, 0xeb, 0xfe, 0x4a, 0x4f, 0xaf, 0x6a, + 0xe1, 0x3a, 0xdf, 0x05, 0x27, 0x4d, 0x7a, 0x90, + 0xb1, 0x00, 0x16, 0x8b, 0x5d, 0x59, 0x38, 0x94, + 0xfc, 0x88, 0x1f, 0x00, 0xdc, 0x01, 0xf5, 0x02, + 0x3b, 0x1d, 0x8e, 0x34, 0xa6, 0xe9, 0x86, 0x72, + 0x7b, 0x97, 0x01, 0x6e, 0x75, 0xf0, 0xdd, 0xb0, + 0x2a, 0xed, 0x68, 0x22, 0xc7, 0x0d, 0xdf, 0x52, + 0x1b, 0x81, 0xf9, 0x8f, 0x74, 0x18, 0x36, 0xec, + 0x7d, 0xe7, 0x68, 0x7e, 0x8c, 0xc3, 0x58, 0xdc, + 0xc9, 0x04, 0xa0, 0x55, 0x87, 0xc7, 0xaa, 0xad, + 0x2e, 0x63, 0xc9, 0x94, 0x2b, 0x19, 0x30, 0x4c, + 0x35, 0xa2, 0x63, 0xc5, 0x8e, 0x80, 0xe9, 0x92, + 0xbe, 0xce, 0x2a, 0x12, 0x97, 0x84, 0xc9, 0x31, + 0x08, 0x97, 0x3b, 0xec, 0xd3, 0x1d, 0x92, 0x79, + 0x14, 0x4b, 0x25, 0x2c, 0x60, 0x30, 0xe6, 0x16, + 0x60, 0x7e, 0xfb, 0x1b, 0x97, 0x83, 0xd5, 0xbf, + 0xcf, 0x88, 0x1a, 0xf3, 0x15, 0xdc, 0x51, 0x71, + 0xed, 0xf8, 0xe0, 0xed, 0xc4, 0x45, 0xb4, 0x96, + 0xf9, 0xd0, 0x25, 0xa7, 0xf8, 0xd9, 0xe4, 0x41, + 0xd4, 0xb9, 0x04, 0x70, 0x02, 0x60, 0xeb, 0x17, + 0xa8, 0x10, 0x4e, 0xe8, 0xdb, 0x6c, 0x20, 0x7f, + 0x41, 0x63, 0x01, 0x6d, 0xa8, 0x40, 0x82, 0x30, + 0x67, 0x4c, 0x87, 0x54, 0x6f, 0x19, 0x95, 0x4a, + 0xa6, 0x46, 0x43, 0x8e, 0xb3, 0xfd, 0x86, 0xf0, + 0xc5, 0x3e, 0x67, 0x8c, 0xb6, 0x6f, 0x8a, 0x15, + 0x01, 0x35, 0xf0, 0x7b, 0x67, 0x65, 0x0d, 0x69, + 0x65, 0xb8, 0x3f, 0x30, 0xcb, 0x10, 0xb3, 0x02, + 0x08, 0x8e, 0xef, 0x9c, 0x50, 0x90, 0x4f, 0x85, + 0x23, 0xb5, 0xfa, 0x75, 0xc2, 0x70, 0x9b, 0x33, + 0xf9, 0xeb, 0x69, 0x33, 0xfb, 0xbe, 0x67, 0x87, + 0x5e, 0x9f, 0x79, 0x54, 0x8b, 0xb4, 0x27, 0xf1, + 0xd7, 0x77, 0xdd, 0x32, 0x9a, 0xea, 0x7b, 0x97, + 0x7e, 0x10, 0xb1, 0x49, 0xf2, 0x45, 0xef, 0x47, + 0xa6, 0x3f, 0x34, 0xdf, 0x0e, 0x6c, 0xed, 0x5d, + 0x1f, 0x80, 0x71, 0x00, 0x3e, 0x9c, 0x6f, 0x37, + 0x60, 0x2d, 0xd7, 0xb1, 0x63, 0xb1, 0xf8, 0x0f, + 0xc6, 0xdf, 0x99, 0xff, 0x5c, 0x1a, 0x37, 0x0e, + 0x48, 0xba, 0x33, 0xa8, 0x2a, 0xad, 0x04, 0xae, + 0x14, 0xb8, 0x9d, 0x9b, 0x7d, 0xe6, 0x1a, 0xd5, + 0x8a, 0x55, 0xfb, 0x21, 0x27, 0xc8, 0xd5, 0xc7, + 0x41, 0xb1, 0x73, 0xa1, 0xe6, 0x3f, 0x08, 0x68, + 0x35, 0xf5, 0xb2, 0x85, 0xa8, 0x3a, 0xed, 0xe5, + 0x0e, 0x3a, 0x3d, 0x2c, 0x87, 0x5d, 0x6e, 0xc7, + 0x66, 0x4e, 0xcf, 0x00, 0x04, 0x15, 0xd9, 0x78, + 0x65, 0x77, 0x08, 0x79, 0xb3, 0x6b, 0x47, 0xea, + 0x45, 0x67, 0xe5, 0x95, 0x42, 0xde, 0x07, 0xd6, + 0x6e, 0x41, 0x01, 0x18, 0x37, 0xf9, 0xb5, 0x55, + 0x3c, 0xb0, 0x6c, 0xdd, 0xfe, 0x33, 0x5b, 0x53, + 0x03, 0x88, 0x42, 0xae, 0xfd, 0xbe, 0x02, 0xf3, + 0xd5, 0x32, 0x95, 0x4c, 0x5c, 0x4b, 0xb8, 0x9b, + 0x54, 0x93, 0x3f, 0x50, 0x99, 0xfc, 0x31, 0x5a, + 0xbc, 0x13, 0x9c, 0x73, 0x65, 0x33, 0x01, 0xe0, + 0x04, 0xb7, 0x91, 0xf5, 0x2a, 0x0b, 0xd4, 0xb2, + 0xbf, 0xf6, 0x55, 0x2c, 0xa5, 0xd9, 0x7e, 0x13, + 0x88, 0x80, 0x78, 0xfb, 0xde, 0xb9, 0x92, 0x3e, + 0x0d, 0x58, 0xdf, 0x5e, 0xaf, 0x29, 0xf1, 0x60, + 0x3b, 0xb9, 0xcf, 0x48, 0x7d, 0x87, 0x62, 0x4e, + 0x49, 0x46, 0x26, 0x38, 0x33, 0x63, 0xc0, 0x31, + 0x58, 0x03, 0xf1, 0xa0, 0xd8, 0x1c, 0xf2, 0xc2, + 0x1f, 0x1e, 0x91, 0x34, 0x55, 0xeb, 0xbb, 0x13, + 0xea, 0x7e, 0x66, 0xaf, 0x12, 0x43, 0x4c, 0x0f, + 0x79, 0x57, 0x22, 0xd0, 0x84, 0x80, 0x23, 0xf5, + 0x32, 0x3a, 0x53, 0x69, 0x91, 0x89, 0x8c, 0x84, + 0x9a, 0x8d, 0xc3, 0xd8, 0xf6, 0x87, 0x89, 0x9c, + 0x5c, 0x1d, 0xd8, 0x63, 0x26, 0xfa, 0x37, 0xbc, + 0x9e, 0x36, 0x75, 0x59, 0x81, 0xcc, 0xbb, 0xa3, + 0xa1, 0x2d, 0x9d, 0x59, 0xe7, 0x1c, 0x8c, 0xff, + 0x61, 0x44, 0x65, 0x92, 0x9f, 0xae, 0x1e, 0x55, + 0xff, 0xb8, 0x1f, 0xf9, 0xb3, 0xd4, 0x8e, 0x03, + 0x23, 0xe9, 0x49, 0x1d, 0x74, 0x71, 0x71, 0x98, + 0x59, 0xee, 0xf8, 0x7e, 0xf3, 0x6e, 0x0c, 0x9c, + 0x87, 0xd4, 0xa1, 0x2e, 0xee, 0xac, 0x24, 0x11, + 0xac, 0xe1, 0xc4, 0x5b, 0x0f, 0x40, 0x83, 0xb8, + 0xfd, 0x0b, 0x36, 0xff, 0xf5, 0xfc, 0x38, 0x55, + 0x71, 0x51, 0xfd, 0x15, 0x86, 0x6f, 0x2d, 0xe1, + 0xf5, 0xff, 0xcb, 0xdd, 0x27, 0x0b, 0x9d, 0x74, + 0x50, 0x5c, 0x4f, 0x7a, 0x4d, 0x32, 0x0d, 0x58, + 0x9f, 0x48, 0xc3, 0x60, 0xfe, 0x86, 0xf0, 0x4f, + 0xfd, 0x98, 0xfd, 0x4f, 0xd2, 0xd0, 0xe5, 0xcb, + 0x57, 0xab, 0xab, 0x54, 0xc8, 0xb5, 0x2e, 0x45, + 0x84, 0xa5, 0xa7, 0x69, 0x4d, 0xfe, 0xa2, 0x94, + 0x0e, 0xdf, 0xe6, 0x3a, 0xa9, 0x89, 0xe5, 0xaf, + 0x11, 0x8e, 0x72, 0xe0, 0xbb, 0x04, 0xdd, 0xe9, + 0x39, 0x38, 0x81, 0xd9, 0x72, 0xc7, 0x38, 0x66, + 0x3e, 0xe2, 0x90, 0xb9, 0x69, 0x2a, 0xe1, 0x4b, + 0x93, 0x45, 0x77, 0x72, 0x8c, 0x98, 0x12, 0x18, + 0xeb, 0x07, 0x77, 0xe8, 0x8b, 0x12, 0x4a, 0xbd, + 0xe3, 0x0c, 0x0b, 0x3b, 0xe9, 0x3a, 0x24, 0xe4, + 0x7a, 0x82, 0x94, 0x88, 0x6d, 0xbf, 0x37, 0x3a, + 0x62, 0xf8, 0x1e, 0x13, 0xa7, 0x08, 0xfd, 0x26, + 0xbd, 0x0b, 0xb3, 0xef, 0x04, 0x2a, 0x56, 0x8f, + 0xa1, 0x1c, 0xbc, 0xa5, 0x7a, 0x14, 0x0e, 0xf3, + 0xe8, 0x7e, 0x44, 0x54, 0x90, 0x54, 0x9c, 0xf8, + 0xe3, 0x39, 0xcd, 0xa1, 0x45, 0x2d, 0x6c, 0xfb, + 0x2a, 0x5d, 0x13, 0x91, 0xb2, 0x25, 0xf8, 0xe7, + 0x1c, 0x4e, 0x63, 0xb0, 0x1b, 0xdf, 0xdd, 0xcb, + 0x63, 0x1c, 0x30, 0xa8, 0x50, 0x35, 0xdd, 0x48, + 0x63, 0xad, 0xd8, 0x89, 0xbd, 0xf3, 0xf3, 0x1d, + 0x03, 0x5f, 0x8b, 0xe1, 0xdf, 0xa5, 0x0b, 0x04, + 0x80, 0x70, 0x4d, 0xac, 0x2f, 0x88, 0xd3, 0x7e, + 0x45, 0x7a, 0x4e, 0x19, 0xbd, 0xa9, 0xaa, 0x21, + 0x91, 0xc4, 0x7d, 0x8e, 0x1a, 0xcf, 0x20, 0x4d, + 0x30, 0x0c, 0x07, 0x82, 0xd1, 0x0b, 0x01, 0x3a, + 0x6f, 0x91, 0x37, 0x3e, 0xe6, 0x43, 0xf5, 0xe3, + 0x1e, 0xce, 0x75, 0x3f, 0x1d, 0x3c, 0x65, 0xdb, + 0x39, 0x89, 0xa7, 0x4b, 0x30, 0x4e, 0x37, 0xd5, + 0xcc, 0xf5, 0x5a, 0xb1, 0x45, 0x86, 0x44, 0x6c, + 0xea, 0x2f, 0xdb, 0xfe, 0xe9, 0x2e, 0x12, 0x4c, + 0x47, 0x15, 0x08, 0x58, 0x59, 0x9f, 0x6a, 0x05, + 0x24, 0xa8, 0x46, 0x71, 0xd6, 0x65, 0xd5, 0x79, + 0x1b, 0x6c, 0x3b, 0xf3, 0x59, 0x6b, 0x6d, 0x6a, + 0xa9, 0x75, 0xe7, 0x6b, 0x53, 0xbd, 0x63, 0x81, + 0x45, 0x7f, 0x59, 0xc3, 0xfb, 0x98, 0xc5, 0x2f, + 0xe2, 0x17, 0x0f, 0x0a, 0xad, 0xfe, 0xf4, 0x30, + 0x6e, 0x10, 0xf4, 0x25, 0x90, 0x4f, 0x50, 0xb3, + 0xca, 0xc9, 0x1a, 0x47, 0xf2, 0x75, 0xa2, 0x86, + 0xff, 0xd9, 0xfc, 0xae, 0x77, 0xaa, 0xa6, 0x03, + 0xd2, 0x07, 0x21, 0x65, 0x4e, 0x2e, 0x0b, 0x00, + 0x48, 0x8b, 0x27, 0xd0, 0x28, 0x96, 0xa4, 0x00, + 0x04, 0xcf, 0x63, 0x38, 0xc9, 0x55, 0xd6, 0x0d, + 0x49, 0x03, 0xfb, 0x68, 0xde, 0x43, 0x24, 0x5f, + 0x4e, 0x40, 0xfa, 0x1e, 0xf2, 0x19, 0x72, 0xa4, + 0x00, 0x32, 0xdb, 0x1c, 0xbc, 0xc3, 0x66, 0x62, + 0x7e, 0x39, 0x1f, 0x6d, 0x17, 0xeb, 0x32, 0x6e, + 0x4d, 0x20, 0x71, 0xd8, 0x90, 0x41, 0x5c, 0xc3, + 0x04, 0x14, 0x1c, 0x37, 0x40, 0x49, 0x54, 0x57, + 0x67, 0x6d, 0x71, 0x77, 0x85, 0x87, 0xc4, 0xd9, + 0xe4, 0xee, 0x12, 0x1e, 0x22, 0x42, 0x66, 0x6d, + 0x72, 0x7a, 0xa4, 0xc6, 0xcf, 0xed, 0xef, 0x02, + 0x08, 0x0f, 0x14, 0x67, 0xbb, 0xc2, 0xca, 0xeb, + 0x00, 0x01, 0x24, 0x37, 0x3f, 0x4f, 0x5f, 0x70, + 0x73, 0x76, 0xb9, 0xbb, 0xcc, 0xde, 0xe2, 0xeb, + 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x12, 0x1f, 0x28, 0x39 + }; + + /* ML-DSA-65 externalMu: deterministic, tcId 121 + * Source: kh-fork-fips/wolfACVP/v7.0.0-known/ + * ML-DSA-sigGen-request.json. Deterministic mode + * uses rnd = 0^32 per FIPS 204 Section 3.7. */ + static const byte sk_65_mu[] = { + 0xba, 0xba, 0x6c, 0x1f, 0x57, 0xed, 0x64, 0x1c, + 0x3b, 0x7e, 0xba, 0x49, 0xe3, 0x81, 0x5b, 0xf9, + 0x78, 0x1d, 0x6e, 0x49, 0x46, 0x2e, 0x2e, 0x22, + 0x50, 0xad, 0x46, 0x7c, 0x1c, 0x82, 0x8d, 0xce, + 0xd9, 0x4b, 0x82, 0xc8, 0xe8, 0x1c, 0x0a, 0x30, + 0xa1, 0xe7, 0x5b, 0xb2, 0xdf, 0xb9, 0xd1, 0x3f, + 0x47, 0xf4, 0x31, 0x44, 0x18, 0x99, 0x88, 0xa9, + 0x59, 0x92, 0x82, 0x91, 0xf0, 0xdc, 0xa2, 0xbf, + 0x97, 0x26, 0x7f, 0xf3, 0x70, 0x64, 0x16, 0x41, + 0x35, 0xf9, 0xcd, 0x4b, 0x81, 0x19, 0x13, 0x83, + 0xc3, 0xc7, 0x05, 0x8c, 0xae, 0x1e, 0x2b, 0x4d, + 0xad, 0x15, 0x0c, 0x40, 0x5b, 0x41, 0xe9, 0x5f, + 0xf2, 0x26, 0xbc, 0x8e, 0x65, 0x7d, 0xbe, 0xb1, + 0x19, 0x8a, 0x7e, 0x3b, 0x73, 0x81, 0x65, 0x2e, + 0x15, 0xab, 0xe8, 0x74, 0x44, 0x3e, 0xb2, 0xf9, + 0x51, 0x72, 0xea, 0x55, 0x02, 0xde, 0x9e, 0x8b, + 0x61, 0x84, 0x83, 0x82, 0x82, 0x64, 0x31, 0x73, + 0x56, 0x52, 0x72, 0x13, 0x42, 0x68, 0x73, 0x76, + 0x26, 0x04, 0x56, 0x61, 0x82, 0x42, 0x06, 0x74, + 0x31, 0x80, 0x87, 0x32, 0x36, 0x34, 0x43, 0x16, + 0x58, 0x58, 0x42, 0x35, 0x24, 0x52, 0x20, 0x37, + 0x20, 0x30, 0x21, 0x20, 0x17, 0x37, 0x23, 0x10, + 0x71, 0x56, 0x02, 0x35, 0x22, 0x20, 0x61, 0x10, + 0x82, 0x83, 0x46, 0x43, 0x47, 0x68, 0x36, 0x15, + 0x06, 0x14, 0x27, 0x25, 0x82, 0x32, 0x22, 0x37, + 0x05, 0x63, 0x17, 0x45, 0x11, 0x18, 0x37, 0x88, + 0x51, 0x73, 0x02, 0x37, 0x57, 0x21, 0x73, 0x86, + 0x62, 0x57, 0x10, 0x13, 0x35, 0x50, 0x64, 0x71, + 0x87, 0x47, 0x34, 0x44, 0x70, 0x32, 0x41, 0x24, + 0x80, 0x77, 0x08, 0x78, 0x72, 0x16, 0x71, 0x43, + 0x82, 0x86, 0x22, 0x64, 0x24, 0x61, 0x16, 0x08, + 0x84, 0x56, 0x21, 0x57, 0x01, 0x07, 0x27, 0x66, + 0x01, 0x20, 0x50, 0x02, 0x08, 0x18, 0x58, 0x18, + 0x27, 0x44, 0x52, 0x30, 0x60, 0x46, 0x37, 0x88, + 0x47, 0x76, 0x84, 0x04, 0x28, 0x00, 0x08, 0x66, + 0x04, 0x33, 0x12, 0x35, 0x80, 0x00, 0x51, 0x51, + 0x72, 0x72, 0x76, 0x13, 0x17, 0x56, 0x36, 0x61, + 0x74, 0x34, 0x68, 0x26, 0x16, 0x65, 0x71, 0x71, + 0x23, 0x62, 0x32, 0x33, 0x23, 0x32, 0x83, 0x28, + 0x31, 0x36, 0x60, 0x17, 0x61, 0x52, 0x10, 0x76, + 0x34, 0x71, 0x16, 0x76, 0x28, 0x14, 0x62, 0x28, + 0x84, 0x65, 0x41, 0x10, 0x81, 0x53, 0x06, 0x44, + 0x60, 0x26, 0x67, 0x51, 0x63, 0x26, 0x68, 0x23, + 0x66, 0x67, 0x50, 0x25, 0x11, 0x65, 0x34, 0x86, + 0x27, 0x13, 0x70, 0x47, 0x46, 0x00, 0x72, 0x85, + 0x55, 0x32, 0x71, 0x10, 0x43, 0x37, 0x03, 0x23, + 0x85, 0x51, 0x40, 0x67, 0x85, 0x13, 0x74, 0x85, + 0x35, 0x55, 0x73, 0x82, 0x78, 0x40, 0x74, 0x71, + 0x04, 0x16, 0x33, 0x84, 0x06, 0x47, 0x66, 0x87, + 0x40, 0x11, 0x63, 0x34, 0x03, 0x67, 0x10, 0x01, + 0x44, 0x63, 0x12, 0x75, 0x36, 0x43, 0x58, 0x32, + 0x05, 0x83, 0x24, 0x54, 0x45, 0x77, 0x41, 0x30, + 0x65, 0x86, 0x82, 0x48, 0x77, 0x73, 0x77, 0x62, + 0x18, 0x38, 0x64, 0x61, 0x65, 0x38, 0x21, 0x88, + 0x14, 0x51, 0x51, 0x30, 0x54, 0x45, 0x62, 0x17, + 0x02, 0x22, 0x15, 0x80, 0x53, 0x58, 0x15, 0x63, + 0x75, 0x42, 0x47, 0x64, 0x64, 0x48, 0x62, 0x10, + 0x57, 0x64, 0x04, 0x50, 0x60, 0x85, 0x72, 0x43, + 0x62, 0x71, 0x66, 0x24, 0x77, 0x03, 0x17, 0x26, + 0x65, 0x30, 0x31, 0x74, 0x58, 0x11, 0x35, 0x66, + 0x32, 0x53, 0x76, 0x51, 0x58, 0x32, 0x08, 0x07, + 0x35, 0x74, 0x05, 0x27, 0x30, 0x42, 0x52, 0x16, + 0x65, 0x63, 0x60, 0x63, 0x01, 0x36, 0x60, 0x71, + 0x16, 0x75, 0x56, 0x76, 0x76, 0x86, 0x41, 0x20, + 0x07, 0x38, 0x65, 0x20, 0x86, 0x72, 0x15, 0x11, + 0x65, 0x56, 0x76, 0x87, 0x01, 0x65, 0x33, 0x20, + 0x08, 0x12, 0x35, 0x06, 0x58, 0x80, 0x76, 0x31, + 0x83, 0x75, 0x83, 0x81, 0x72, 0x77, 0x62, 0x21, + 0x70, 0x66, 0x16, 0x83, 0x85, 0x48, 0x14, 0x66, + 0x58, 0x51, 0x83, 0x53, 0x82, 0x34, 0x48, 0x61, + 0x42, 0x00, 0x67, 0x82, 0x22, 0x87, 0x37, 0x60, + 0x86, 0x43, 0x18, 0x31, 0x02, 0x75, 0x25, 0x55, + 0x01, 0x56, 0x37, 0x55, 0x50, 0x30, 0x37, 0x86, + 0x45, 0x68, 0x68, 0x07, 0x34, 0x54, 0x48, 0x01, + 0x33, 0x67, 0x84, 0x86, 0x82, 0x45, 0x13, 0x22, + 0x61, 0x42, 0x36, 0x16, 0x47, 0x70, 0x23, 0x88, + 0x66, 0x62, 0x24, 0x65, 0x43, 0x44, 0x64, 0x04, + 0x73, 0x45, 0x33, 0x14, 0x66, 0x51, 0x07, 0x00, + 0x61, 0x00, 0x31, 0x23, 0x08, 0x88, 0x61, 0x54, + 0x14, 0x18, 0x47, 0x46, 0x02, 0x53, 0x56, 0x17, + 0x44, 0x13, 0x67, 0x14, 0x52, 0x02, 0x20, 0x62, + 0x10, 0x35, 0x18, 0x50, 0x41, 0x87, 0x73, 0x85, + 0x11, 0x23, 0x42, 0x77, 0x40, 0x40, 0x30, 0x10, + 0x74, 0x13, 0x17, 0x22, 0x84, 0x74, 0x23, 0x62, + 0x24, 0x01, 0x21, 0x78, 0x04, 0x16, 0x14, 0x64, + 0x06, 0x88, 0x42, 0x67, 0x17, 0x41, 0x30, 0x48, + 0x22, 0x16, 0x66, 0x45, 0x10, 0x23, 0x57, 0x67, + 0x50, 0x00, 0x51, 0x88, 0x04, 0x76, 0x55, 0x82, + 0x06, 0x72, 0x81, 0x30, 0x13, 0x45, 0x00, 0x65, + 0x44, 0x68, 0x87, 0x03, 0x14, 0x85, 0x68, 0x14, + 0x85, 0x82, 0x03, 0x24, 0x23, 0x05, 0x04, 0x74, + 0x72, 0x10, 0x74, 0x14, 0x27, 0x71, 0x75, 0x33, + 0x82, 0x48, 0x17, 0x07, 0x20, 0x83, 0x47, 0x52, + 0x63, 0x84, 0x60, 0x16, 0x06, 0x31, 0x18, 0x75, + 0x06, 0x38, 0x81, 0x87, 0x34, 0x23, 0x06, 0x54, + 0x84, 0x00, 0x57, 0x43, 0x14, 0x63, 0x86, 0x85, + 0x31, 0x76, 0x44, 0x64, 0x58, 0x31, 0x01, 0x17, + 0x35, 0x44, 0x43, 0x00, 0x77, 0x87, 0x54, 0x82, + 0x00, 0x40, 0x37, 0x68, 0x16, 0x33, 0x37, 0x42, + 0x70, 0x44, 0x00, 0x67, 0x42, 0x61, 0x80, 0x10, + 0x18, 0x81, 0x48, 0x30, 0x40, 0x10, 0x73, 0x43, + 0x00, 0x74, 0x53, 0x60, 0x84, 0x21, 0x64, 0x37, + 0x01, 0x20, 0x07, 0x43, 0x77, 0x66, 0x55, 0x87, + 0x54, 0x24, 0x75, 0x32, 0x03, 0x54, 0x55, 0x46, + 0x30, 0x18, 0x26, 0x32, 0x30, 0x01, 0x07, 0x13, + 0x78, 0x50, 0x26, 0x17, 0x67, 0x15, 0x12, 0x35, + 0x85, 0x66, 0x11, 0x88, 0x18, 0x03, 0x37, 0x62, + 0x76, 0x24, 0x83, 0x01, 0x72, 0x54, 0x62, 0x75, + 0x31, 0x52, 0x48, 0x87, 0x20, 0x56, 0x30, 0x14, + 0x81, 0x48, 0x03, 0x23, 0x01, 0x38, 0x00, 0x35, + 0x10, 0x33, 0x74, 0x21, 0x73, 0x50, 0x07, 0x07, + 0x02, 0x24, 0x35, 0x55, 0x02, 0x80, 0x77, 0x58, + 0x14, 0x75, 0x75, 0x46, 0x85, 0x42, 0x57, 0x16, + 0x45, 0x20, 0x00, 0x67, 0x74, 0x54, 0x25, 0x53, + 0x30, 0x24, 0x84, 0x41, 0x17, 0x54, 0x16, 0x34, + 0x25, 0x23, 0x56, 0x87, 0x75, 0x07, 0x54, 0x30, + 0x64, 0x58, 0x21, 0x61, 0x36, 0x20, 0x20, 0x73, + 0x58, 0x33, 0x27, 0x24, 0x58, 0x55, 0x30, 0x08, + 0x46, 0x66, 0x34, 0x10, 0x83, 0x63, 0x13, 0x64, + 0x45, 0x17, 0x03, 0x76, 0x13, 0x52, 0x58, 0x84, + 0x13, 0x17, 0x36, 0x66, 0x28, 0x88, 0x31, 0x24, + 0x35, 0x78, 0x82, 0x48, 0x54, 0x20, 0x43, 0x13, + 0x25, 0x21, 0x08, 0x87, 0x05, 0x43, 0x25, 0x21, + 0x47, 0x76, 0x04, 0x27, 0x21, 0x66, 0x81, 0x42, + 0x13, 0x24, 0x82, 0x40, 0x61, 0x05, 0x41, 0x30, + 0x40, 0x71, 0x84, 0x56, 0x52, 0x68, 0x67, 0x13, + 0x41, 0x87, 0x38, 0x33, 0x86, 0x72, 0x70, 0x42, + 0x34, 0x25, 0x78, 0x83, 0x37, 0x02, 0x28, 0x72, + 0x70, 0x46, 0x37, 0x08, 0x47, 0x62, 0x76, 0x63, + 0x54, 0x21, 0x82, 0x52, 0x60, 0x52, 0x02, 0x83, + 0x45, 0x47, 0x04, 0x30, 0x37, 0x83, 0x87, 0x16, + 0x15, 0x25, 0x43, 0x70, 0x67, 0x35, 0x32, 0x32, + 0x01, 0x62, 0x44, 0x36, 0x01, 0x10, 0x03, 0x30, + 0x74, 0x60, 0x14, 0x38, 0x58, 0x11, 0x38, 0x23, + 0x87, 0x65, 0x53, 0x27, 0x53, 0x33, 0x28, 0x08, + 0x55, 0x63, 0x52, 0x88, 0x28, 0x83, 0x54, 0x33, + 0x04, 0x11, 0x50, 0x80, 0x28, 0x88, 0x62, 0x66, + 0x55, 0x80, 0x80, 0x65, 0x01, 0x76, 0x80, 0x77, + 0x10, 0x22, 0x01, 0x38, 0x01, 0x43, 0x27, 0x03, + 0x28, 0x41, 0x73, 0x78, 0x03, 0x16, 0x48, 0x74, + 0x73, 0x82, 0x16, 0x50, 0x10, 0x06, 0x82, 0x74, + 0x42, 0x32, 0x17, 0x26, 0x04, 0x17, 0x47, 0x61, + 0x67, 0x32, 0x21, 0x15, 0x40, 0x31, 0x55, 0x14, + 0x08, 0x55, 0x63, 0x13, 0x36, 0x70, 0x14, 0x63, + 0x68, 0x83, 0x22, 0x62, 0x17, 0x77, 0x88, 0x61, + 0x85, 0x65, 0x40, 0x65, 0x21, 0x84, 0x82, 0x00, + 0x02, 0x72, 0x06, 0x04, 0x87, 0x74, 0x76, 0x68, + 0x68, 0x20, 0x68, 0x87, 0x84, 0x57, 0x24, 0x81, + 0x40, 0x25, 0x27, 0x60, 0x11, 0x02, 0x84, 0x84, + 0x31, 0x55, 0x82, 0x11, 0x20, 0x01, 0x43, 0x07, + 0x10, 0x71, 0x74, 0x85, 0x14, 0x82, 0x13, 0x36, + 0x61, 0x00, 0x61, 0x20, 0x31, 0x57, 0x53, 0x74, + 0x65, 0x12, 0x71, 0x83, 0x24, 0x17, 0x00, 0x72, + 0x13, 0x22, 0x63, 0x64, 0x42, 0x50, 0x38, 0x14, + 0x70, 0x26, 0x30, 0x17, 0x53, 0x07, 0x70, 0x36, + 0x38, 0x88, 0x58, 0x03, 0x83, 0x01, 0x75, 0x38, + 0x67, 0x45, 0x75, 0x22, 0x22, 0x06, 0x80, 0x06, + 0x23, 0x31, 0x65, 0x88, 0x05, 0x85, 0x42, 0x23, + 0x66, 0x42, 0x75, 0x86, 0x07, 0x16, 0x65, 0x81, + 0x12, 0x62, 0x75, 0x86, 0x42, 0x48, 0x18, 0x73, + 0x17, 0x75, 0x30, 0x54, 0x26, 0x83, 0x51, 0x73, + 0x27, 0x34, 0x87, 0x82, 0x42, 0x73, 0x30, 0x28, + 0x73, 0x60, 0x43, 0x81, 0x78, 0x80, 0x08, 0x74, + 0x38, 0x43, 0x36, 0x33, 0x15, 0x38, 0x78, 0x87, + 0x68, 0x28, 0x53, 0x71, 0x54, 0x03, 0x52, 0x26, + 0x30, 0x63, 0x04, 0x73, 0x64, 0x42, 0x71, 0x44, + 0x44, 0x21, 0x14, 0x74, 0x37, 0x42, 0x45, 0x64, + 0x12, 0x48, 0x03, 0x04, 0x17, 0x22, 0x46, 0x50, + 0x82, 0x35, 0x67, 0x80, 0x26, 0x10, 0x58, 0x84, + 0x07, 0x72, 0x72, 0x08, 0x05, 0x47, 0x47, 0x60, + 0x65, 0x70, 0x68, 0x47, 0x02, 0x51, 0x86, 0x82, + 0x25, 0x10, 0x35, 0x62, 0x67, 0x46, 0x71, 0x10, + 0x47, 0x83, 0x24, 0x73, 0x25, 0x73, 0x41, 0x14, + 0x54, 0x42, 0x58, 0x25, 0x16, 0x68, 0x65, 0x25, + 0x36, 0x40, 0x00, 0x12, 0x16, 0x08, 0x24, 0x61, + 0x60, 0x38, 0x04, 0x72, 0x01, 0x37, 0x25, 0x17, + 0x66, 0x55, 0x84, 0x77, 0x74, 0x47, 0x24, 0x00, + 0x38, 0x01, 0x08, 0x63, 0x62, 0x75, 0x16, 0x80, + 0x57, 0x06, 0x48, 0x14, 0x60, 0x37, 0x20, 0x65, + 0x23, 0x63, 0x57, 0x14, 0x60, 0x12, 0x78, 0x08, + 0x53, 0x05, 0x43, 0x32, 0x57, 0x22, 0x18, 0x08, + 0x64, 0x07, 0x44, 0x33, 0x55, 0x45, 0x54, 0x55, + 0x77, 0x63, 0x58, 0x52, 0x13, 0x85, 0x42, 0x00, + 0x36, 0x02, 0x38, 0x82, 0x78, 0x06, 0x08, 0x20, + 0x68, 0x88, 0x13, 0x81, 0x14, 0x57, 0x55, 0x81, + 0x67, 0x86, 0x02, 0x70, 0x56, 0x03, 0x13, 0x74, + 0x37, 0x20, 0x86, 0x26, 0x84, 0x76, 0x22, 0x74, + 0x65, 0x67, 0x44, 0x37, 0x84, 0x40, 0x34, 0x37, + 0x46, 0x38, 0x11, 0x40, 0x57, 0x40, 0x03, 0x37, + 0x33, 0x18, 0x14, 0x44, 0x76, 0x83, 0x57, 0x01, + 0x33, 0x55, 0x00, 0x64, 0x01, 0x81, 0x06, 0x43, + 0x00, 0x46, 0x31, 0x77, 0x16, 0x35, 0x66, 0x74, + 0xc1, 0x70, 0xea, 0xb7, 0xdc, 0x3a, 0x0c, 0xfc, + 0xa4, 0xda, 0x07, 0x46, 0x3d, 0x88, 0xcb, 0x05, + 0x72, 0xd1, 0xe1, 0x07, 0x8e, 0x1d, 0xb7, 0xd1, + 0x7b, 0xf0, 0x2c, 0x97, 0x12, 0xf1, 0xc5, 0xf1, + 0xab, 0xc4, 0x56, 0xf9, 0xdf, 0xf2, 0xd9, 0x22, + 0x8c, 0xc1, 0xeb, 0x76, 0x5a, 0xac, 0x28, 0x08, + 0x09, 0xbe, 0x3a, 0x26, 0xd7, 0x1c, 0x4e, 0x25, + 0x18, 0x91, 0xc8, 0x93, 0xea, 0x65, 0xf4, 0x67, + 0x33, 0xba, 0xfc, 0x22, 0xda, 0x34, 0x7a, 0x2b, + 0x1b, 0xb6, 0x95, 0xd1, 0xc9, 0x42, 0x50, 0x19, + 0x6f, 0xa3, 0x0f, 0x71, 0xdd, 0xd9, 0xd7, 0xbd, + 0xc8, 0x0a, 0x29, 0xf8, 0x1c, 0x68, 0xd0, 0xb0, + 0x3e, 0xa3, 0xe3, 0x24, 0x2d, 0x83, 0xc8, 0xfe, + 0x2a, 0xb2, 0x58, 0xd4, 0x5e, 0xff, 0xf2, 0x3c, + 0x39, 0x9a, 0x6e, 0xdc, 0xb4, 0x17, 0xe4, 0x64, + 0xc4, 0xb1, 0x94, 0xa0, 0x36, 0x6f, 0x65, 0x10, + 0x13, 0x88, 0x9b, 0x1d, 0x57, 0x7a, 0x21, 0xc5, + 0x54, 0xac, 0x98, 0x94, 0xed, 0xc4, 0x7c, 0xaa, + 0x44, 0x6a, 0xd0, 0xa4, 0x88, 0x8b, 0xf9, 0x14, + 0xaa, 0xd2, 0x0a, 0xc2, 0xaa, 0xc6, 0x59, 0x5e, + 0xbc, 0xe5, 0x91, 0xe1, 0x82, 0xf5, 0x38, 0x1b, + 0xc1, 0xd8, 0x95, 0x3c, 0x78, 0x68, 0x22, 0x49, + 0x9a, 0xb8, 0xfa, 0x68, 0xdb, 0x2b, 0xdd, 0x90, + 0x74, 0x6e, 0x94, 0x4b, 0xc6, 0x93, 0xcc, 0x27, + 0x95, 0x80, 0xc1, 0xf9, 0xe0, 0x7a, 0x38, 0x24, + 0xf5, 0x25, 0xdf, 0x53, 0xd1, 0xda, 0x7f, 0x3e, + 0x96, 0x3d, 0x3d, 0xbe, 0xca, 0xdb, 0xde, 0xef, + 0x93, 0xb1, 0x47, 0x4a, 0x6f, 0x3c, 0x3e, 0xa6, + 0xff, 0x2e, 0x8a, 0xb4, 0x0c, 0xbb, 0xfe, 0xc1, + 0xcd, 0x25, 0xbf, 0x76, 0xc3, 0x07, 0xfb, 0x09, + 0x7f, 0x2d, 0x24, 0x29, 0x26, 0xc4, 0x0b, 0x08, + 0xb5, 0xad, 0x9a, 0x14, 0x85, 0x9e, 0x75, 0xbf, + 0xe7, 0x61, 0xbf, 0x61, 0xd5, 0x1f, 0xda, 0xb0, + 0xaf, 0xd5, 0xaa, 0x64, 0x6b, 0x25, 0xf7, 0x9d, + 0xbc, 0x3e, 0xf5, 0x17, 0x19, 0xcc, 0x04, 0x43, + 0xe2, 0x07, 0x8a, 0xa9, 0x72, 0xa5, 0xc0, 0x51, + 0xad, 0xc7, 0x46, 0xa4, 0x11, 0xe8, 0x91, 0x65, + 0xe9, 0xec, 0x0e, 0x36, 0x7f, 0xc4, 0x67, 0x6c, + 0xd6, 0x50, 0x3d, 0x6c, 0xa2, 0x22, 0xde, 0x5f, + 0xc0, 0xc7, 0x55, 0x97, 0xbe, 0xcf, 0x1e, 0x3d, + 0x42, 0xae, 0x7f, 0x62, 0xd6, 0x06, 0xac, 0x43, + 0x10, 0x90, 0x0f, 0x75, 0x19, 0xbb, 0x62, 0x4d, + 0xae, 0xd6, 0x8c, 0xf0, 0x1b, 0xe0, 0x60, 0xb5, + 0x2a, 0x3c, 0x46, 0xc9, 0xbb, 0x4b, 0xac, 0x78, + 0x82, 0xb3, 0xda, 0x72, 0xe1, 0x8e, 0x2d, 0xec, + 0x6c, 0xc6, 0x20, 0x1a, 0xa3, 0x2b, 0xc3, 0x57, + 0x01, 0xb6, 0xdd, 0x09, 0x66, 0x45, 0xdf, 0x30, + 0x62, 0xdd, 0xfb, 0x33, 0xef, 0x03, 0xb0, 0xb4, + 0x9d, 0x82, 0xfd, 0xb0, 0x67, 0x9f, 0x97, 0x84, + 0xc6, 0xd5, 0x74, 0x01, 0x8b, 0x38, 0x62, 0x76, + 0xf0, 0xba, 0x10, 0x95, 0xf7, 0x9c, 0x0c, 0xd5, + 0xcd, 0x64, 0xdd, 0xbc, 0xa7, 0x98, 0x99, 0x10, + 0x7f, 0x09, 0x9a, 0x33, 0x88, 0x54, 0xab, 0x07, + 0xbd, 0xab, 0xf2, 0xb6, 0x11, 0x38, 0x32, 0x3c, + 0x59, 0xe2, 0x7a, 0x7a, 0x60, 0xf1, 0xa1, 0xb4, + 0xca, 0x72, 0x7d, 0xc9, 0xfa, 0x64, 0x5f, 0x1f, + 0x34, 0x7f, 0x3d, 0x91, 0xa9, 0x11, 0xbd, 0x5c, + 0xe3, 0x26, 0xa8, 0x08, 0x1a, 0x07, 0xbe, 0xf5, + 0x8d, 0x72, 0x3f, 0x1a, 0x1a, 0xc9, 0xbc, 0x04, + 0xd3, 0xb5, 0x03, 0xc0, 0x72, 0x35, 0x46, 0xba, + 0x95, 0xf7, 0xbd, 0x43, 0xdd, 0x4d, 0x60, 0xef, + 0x1a, 0x27, 0x9a, 0xa2, 0x67, 0xd0, 0xbe, 0xb3, + 0x89, 0xe6, 0xc0, 0xd1, 0xb5, 0x49, 0x94, 0xb2, + 0x4e, 0x5c, 0xde, 0xc7, 0x55, 0x25, 0x87, 0x57, + 0xa5, 0xc3, 0x50, 0x05, 0x7c, 0x06, 0xc8, 0x04, + 0x11, 0x05, 0x12, 0x7c, 0x18, 0x80, 0x41, 0xbd, + 0xf3, 0x2a, 0x6f, 0x38, 0xe8, 0x12, 0x9f, 0xc3, + 0xcf, 0x49, 0x3d, 0x19, 0xa8, 0xbe, 0xba, 0xeb, + 0x9d, 0x80, 0x22, 0xef, 0xb5, 0xe8, 0x58, 0x9c, + 0x2f, 0x43, 0xb8, 0xda, 0xa1, 0x7c, 0xbf, 0x5e, + 0xb7, 0x80, 0x4d, 0x30, 0xb0, 0x98, 0xc1, 0x4a, + 0xb1, 0x2e, 0xa0, 0xd8, 0x0d, 0x26, 0xb6, 0xff, + 0xa1, 0x6b, 0x51, 0x97, 0x51, 0x39, 0x77, 0x5f, + 0xa3, 0x9c, 0x62, 0xd6, 0xe3, 0x72, 0x46, 0xa9, + 0x6b, 0x49, 0xa0, 0xc2, 0xf9, 0xf3, 0x09, 0x7f, + 0xac, 0x5b, 0x3b, 0x8e, 0x77, 0xa0, 0x01, 0xc1, + 0x65, 0x54, 0xfc, 0xe3, 0x07, 0x62, 0x14, 0xa3, + 0x84, 0x1f, 0x8e, 0x27, 0x22, 0xeb, 0xee, 0x8f, + 0xf2, 0xed, 0xab, 0x97, 0x19, 0x4f, 0x28, 0xa2, + 0x58, 0x9a, 0x01, 0xf5, 0xdd, 0x3c, 0xb7, 0x9b, + 0xdf, 0x9d, 0x78, 0x46, 0x70, 0x8c, 0x0b, 0xae, + 0x7d, 0x9c, 0x29, 0x4a, 0x12, 0x5c, 0x59, 0xa1, + 0x6e, 0x61, 0xb4, 0x80, 0x88, 0x52, 0x94, 0x37, + 0x17, 0xf6, 0xe6, 0xf2, 0x84, 0xb6, 0xa2, 0x23, + 0xc0, 0xa5, 0xfd, 0xc9, 0x3a, 0xd6, 0x08, 0x9d, + 0xd3, 0xd2, 0x74, 0xa1, 0x3d, 0xc9, 0x05, 0xeb, + 0x6d, 0x06, 0xb5, 0x37, 0x2a, 0xe5, 0x31, 0x3c, + 0x4f, 0xcd, 0xfe, 0x07, 0xb3, 0x2c, 0x51, 0xae, + 0x10, 0x02, 0x51, 0x9d, 0xd7, 0x25, 0x66, 0x74, + 0xd6, 0x11, 0x6c, 0x95, 0xc1, 0x92, 0x5f, 0x6c, + 0xd7, 0x45, 0x53, 0x0f, 0xef, 0xed, 0xd6, 0xde, + 0xa2, 0xfc, 0x24, 0xff, 0x5e, 0xda, 0x4b, 0x8d, + 0x3c, 0x54, 0xe4, 0x37, 0xa7, 0xfc, 0xbb, 0xaf, + 0x50, 0x80, 0x7a, 0x04, 0x25, 0x9a, 0x88, 0x40, + 0x1e, 0xf8, 0xf1, 0x0f, 0x68, 0x87, 0x84, 0xc3, + 0xd1, 0x8d, 0x4f, 0x2e, 0x5d, 0x4e, 0x8d, 0xc0, + 0xed, 0xc5, 0x96, 0xd7, 0x30, 0x07, 0x2e, 0x5e, + 0xfd, 0x84, 0x70, 0xf2, 0xb5, 0x60, 0xd1, 0x9d, + 0xcd, 0xce, 0xc8, 0x47, 0xfa, 0x8e, 0x9a, 0x6d, + 0x3f, 0x11, 0x8c, 0x4d, 0x32, 0xb2, 0xa5, 0xc6, + 0x79, 0xe6, 0x34, 0x32, 0x18, 0x15, 0xc0, 0xd5, + 0x11, 0xb6, 0xc4, 0x8d, 0xc0, 0x21, 0x39, 0xf2, + 0x49, 0x1d, 0x11, 0x6a, 0x04, 0x7d, 0xa5, 0xe7, + 0x12, 0xd3, 0x39, 0x4d, 0x90, 0x04, 0x04, 0x50, + 0xc0, 0x45, 0xbd, 0x03, 0xfd, 0xd5, 0x65, 0x3e, + 0x92, 0xef, 0x18, 0x88, 0x38, 0x8f, 0x76, 0x66, + 0x15, 0x53, 0x2e, 0x90, 0x14, 0xe5, 0xa8, 0x4c, + 0xbb, 0x85, 0x57, 0x47, 0x60, 0x3c, 0x3e, 0x75, + 0x24, 0x4d, 0xe5, 0x86, 0xd0, 0xb0, 0x40, 0x97, + 0x7b, 0xd1, 0x44, 0x23, 0xe3, 0x5a, 0x12, 0xe1, + 0x14, 0x96, 0x7e, 0x30, 0x4b, 0xe0, 0xe2, 0x67, + 0xb8, 0x7e, 0x02, 0xfb, 0xf4, 0x90, 0x13, 0x2c, + 0x19, 0xdc, 0xba, 0xc3, 0x06, 0x72, 0xb8, 0x9b, + 0xbe, 0x3d, 0x7f, 0x6c, 0xfc, 0xab, 0xc7, 0x9d, + 0xe3, 0xa8, 0x9c, 0x17, 0x31, 0x79, 0x6a, 0x8b, + 0xe3, 0x1a, 0x12, 0x08, 0x92, 0x6a, 0x01, 0x71, + 0x0e, 0x61, 0x81, 0xb3, 0x8f, 0x58, 0x6a, 0xd6, + 0x47, 0xf5, 0x09, 0x96, 0x1a, 0x0a, 0x33, 0xeb, + 0x0b, 0xc6, 0xf3, 0x9d, 0x0e, 0x82, 0x18, 0x28, + 0xf2, 0x71, 0xe9, 0xa4, 0x39, 0x81, 0x16, 0x32, + 0x54, 0x29, 0xa0, 0xa1, 0x19, 0xb3, 0x46, 0xd9, + 0xc8, 0x14, 0x29, 0xf0, 0x09, 0x40, 0x50, 0xef, + 0xf2, 0x70, 0x86, 0x55, 0x11, 0xb8, 0xa5, 0xa8, + 0x06, 0xa8, 0xbf, 0xda, 0xeb, 0xbd, 0xe4, 0x41, + 0x7c, 0xd7, 0xb9, 0xc3, 0x3b, 0x30, 0xa5, 0x2e, + 0x3f, 0x95, 0x9d, 0xdc, 0xe6, 0x0b, 0xf6, 0xee, + 0xf7, 0x22, 0x51, 0x30, 0xe9, 0x42, 0xa7, 0xe9, + 0x5a, 0x7f, 0xf4, 0xb5, 0x4f, 0x14, 0x86, 0xdf, + 0x1e, 0x07, 0x23, 0x7a, 0xa2, 0x3a, 0x01, 0xfd, + 0x3c, 0x05, 0xef, 0x02, 0x20, 0x2a, 0x39, 0xa8, + 0x20, 0x21, 0xd8, 0xa3, 0xca, 0x55, 0xbd, 0xaa, + 0xcf, 0x72, 0x99, 0xfd, 0x7a, 0x87, 0xc2, 0x2c, + 0x38, 0x42, 0xfa, 0xba, 0xbd, 0xd6, 0xd9, 0x44, + 0x74, 0x6f, 0xf2, 0xa7, 0x9c, 0x46, 0x29, 0x2a, + 0x25, 0x3b, 0xbf, 0x80, 0xc3, 0xdd, 0x0b, 0x62, + 0x24, 0xf5, 0x15, 0xa3, 0x0c, 0x7d, 0x5b, 0x72, + 0xb9, 0xf3, 0x40, 0x07, 0x2d, 0x31, 0x79, 0x16, + 0x82, 0x76, 0xe4, 0x35, 0xb2, 0x33, 0xcf, 0x29, + 0x4d, 0x0e, 0x6c, 0x9f, 0x38, 0xf6, 0x5b, 0x5b, + 0x7c, 0x56, 0x34, 0x02, 0x6b, 0xb8, 0x97, 0x4f, + 0x5d, 0x6e, 0x2a, 0x29, 0x7c, 0x32, 0xad, 0xe3, + 0xc1, 0x94, 0xe5, 0x86, 0xd7, 0x55, 0xe6, 0xe9, + 0xef, 0xf9, 0xf7, 0x56, 0x36, 0x72, 0xcb, 0xa6, + 0x6f, 0xfe, 0x51, 0x74, 0xe3, 0x37, 0x2d, 0x8c, + 0xf8, 0x61, 0x71, 0x27, 0x18, 0x6b, 0xc7, 0x2c, + 0xfe, 0xe9, 0x10, 0x0e, 0x40, 0x14, 0x02, 0x4a, + 0x52, 0x64, 0xa7, 0x05, 0xb2, 0x4e, 0xc5, 0x09, + 0x88, 0xdc, 0x30, 0x8a, 0xa8, 0x09, 0x8a, 0x19, + 0x00, 0x67, 0x8c, 0xf6, 0xef, 0x2d, 0x47, 0xea, + 0x3e, 0x15, 0xdb, 0x2d, 0x6d, 0x6c, 0x97, 0x2c, + 0xd1, 0x90, 0x2b, 0x41, 0x2a, 0xf4, 0x3e, 0x46, + 0x54, 0x92, 0xf7, 0x71, 0x03, 0x48, 0xc4, 0x62, + 0xf5, 0xd0, 0x4d, 0x62, 0xa9, 0x48, 0xcd, 0x2e, + 0x4b, 0xc3, 0xf3, 0x5d, 0xaa, 0xff, 0x72, 0x99, + 0xb7, 0x4e, 0xa1, 0xfa, 0xe6, 0x23, 0xb5, 0x42, + 0x07, 0x4a, 0xd2, 0x85, 0x52, 0xe9, 0x4f, 0xcc, + 0x04, 0x9e, 0x8c, 0x40, 0xb8, 0xe8, 0xa0, 0x59, + 0x57, 0x75, 0x9c, 0x4c, 0x22, 0x67, 0x62, 0xda, + 0xeb, 0x97, 0x92, 0x72, 0xa9, 0x07, 0x46, 0x99, + 0x1f, 0x74, 0xda, 0xac, 0xd9, 0x29, 0x5c, 0x03, + 0xee, 0xd0, 0x94, 0xe7, 0x3a, 0x59, 0x5c, 0x29, + 0x36, 0x56, 0x6c, 0x77, 0x7d, 0x0c, 0x2d, 0x06, + 0x64, 0xa0, 0xf6, 0x07, 0x62, 0x34, 0xb7, 0x72, + 0xc1, 0xa3, 0xf0, 0xe8, 0x72, 0x3d, 0xca, 0x25, + 0x7f, 0x30, 0x67, 0x4c, 0x48, 0x56, 0x28, 0xf6, + 0x0c, 0x24, 0x32, 0xc8, 0xca, 0xaa, 0x76, 0x75, + 0x59, 0xc1, 0x37, 0x43, 0x5c, 0x88, 0x15, 0xad, + 0xa5, 0xd6, 0x07, 0xf3, 0x3b, 0x22, 0x87, 0x64, + 0xfe, 0xf5, 0xdb, 0xa3, 0xd4, 0xe7, 0xca, 0x9a, + 0xaf, 0x9d, 0xf5, 0x5a, 0x99, 0x6f, 0x74, 0x1e, + 0x46, 0x67, 0x3b, 0x37, 0x6e, 0x03, 0xd7, 0x45, + 0xfc, 0xff, 0xa9, 0xf5, 0xae, 0xb3, 0x43, 0x57, + 0x65, 0xc8, 0x03, 0x1a, 0x0d, 0xc7, 0x4a, 0x76, + 0xcf, 0x8b, 0x55, 0x24, 0x1d, 0x1d, 0x91, 0x55, + 0x50, 0x10, 0x64, 0x89, 0x45, 0xcd, 0x5e, 0x64, + 0xaf, 0x42, 0x80, 0xb6, 0x49, 0x7b, 0xc5, 0x1f, + 0xa8, 0x00, 0xb2, 0x97, 0x98, 0x71, 0x1d, 0x96, + 0x73, 0xb7, 0x59, 0xb7, 0x2d, 0xb6, 0x1a, 0xf1, + 0x36, 0xba, 0x39, 0x80, 0x06, 0x7e, 0xa3, 0x1d, + 0x68, 0x88, 0x52, 0x32, 0xf2, 0x5c, 0x6a, 0xc1, + 0x48, 0x22, 0xc1, 0xce, 0x53, 0x50, 0xf1, 0xac, + 0x6d, 0xd5, 0xc0, 0xa8, 0x35, 0x52, 0x68, 0xc6, + 0xc7, 0xaf, 0xfc, 0x95, 0xa2, 0x66, 0xcc, 0xfc, + 0x8c, 0xee, 0x30, 0x53, 0xa9, 0xb4, 0xac, 0x39, + 0xc7, 0x6c, 0x94, 0xa4, 0x70, 0xf6, 0x54, 0xa3, + 0x83, 0x7b, 0xee, 0x43, 0x79, 0x60, 0x22, 0xe2, + 0x90, 0x80, 0xcf, 0xc2, 0x5a, 0x58, 0xd2, 0x48, + 0x0a, 0x4f, 0x7a, 0xa5, 0x93, 0x35, 0x1c, 0x19, + 0x58, 0x0c, 0xf3, 0x72, 0xb8, 0xb1, 0x45, 0xba, + 0x42, 0xd0, 0x82, 0xc5, 0x25, 0xa0, 0xff, 0xa6, + 0x52, 0x71, 0xba, 0xea, 0x91, 0x64, 0x70, 0x51, + 0xc6, 0x33, 0xee, 0x46, 0x03, 0xcd, 0x29, 0x63, + 0x4e, 0x82, 0x8d, 0xde, 0x8d, 0xa6, 0xd5, 0x44, + 0x9d, 0x29, 0x8c, 0xa5, 0x92, 0xa5, 0x79, 0xd7, + 0x1b, 0x9d, 0xa1, 0xba, 0xca, 0xdc, 0x8e, 0x06, + 0xbe, 0xd2, 0x87, 0x6a, 0x47, 0x3a, 0xf4, 0x57, + 0x2f, 0x21, 0xd6, 0x45, 0x1d, 0x3b, 0x59, 0xf0, + 0x44, 0x61, 0x5e, 0xf4, 0xf8, 0x05, 0x9e, 0x33, + 0x0b, 0x95, 0x79, 0x72, 0x7d, 0xde, 0x52, 0x9b, + 0x0f, 0x91, 0xc3, 0x3c, 0xcb, 0x92, 0x3d, 0xad, + 0x87, 0x33, 0x35, 0xb6, 0x65, 0xaf, 0xbb, 0x2a, + 0x3f, 0xac, 0x43, 0xa5, 0x34, 0x96, 0x46, 0xfc, + 0xb2, 0x91, 0x13, 0xe9, 0x01, 0xbf, 0x27, 0x0b, + 0xb8, 0xec, 0x52, 0xde, 0xb3, 0xc6, 0xd7, 0x45, + 0x6b, 0x15, 0xb0, 0xd1, 0xce, 0x9a, 0x97, 0x8e, + 0x72, 0x56, 0xa7, 0xd1, 0x14, 0x97, 0xd4, 0xd1, + 0x90, 0xda, 0x17, 0x28, 0x1e, 0x77, 0xb4, 0x2f, + 0xab, 0xa9, 0xb9, 0xc0, 0x9d, 0x94, 0x11, 0x64, + 0x59, 0x09, 0x8e, 0x92, 0x37, 0xee, 0x77, 0xca, + 0xa8, 0x23, 0xb4, 0xe8, 0xe7, 0xf7, 0xe5, 0xf2, + 0x8f, 0x3b, 0xef, 0xdd, 0xc8, 0xdd, 0x7a, 0x87, + 0x70, 0x5b, 0x21, 0x46, 0x91, 0xb9, 0x5b, 0x7c, + 0x79, 0x2a, 0xda, 0x7b, 0xbe, 0x24, 0x92, 0x39, + 0x69, 0x1a, 0xdc, 0x7c, 0x27, 0x62, 0x04, 0x23, + 0x3e, 0x1c, 0x9b, 0x87, 0x74, 0x17, 0xc2, 0x11, + 0x71, 0xf8, 0x46, 0x5e, 0xbb, 0x89, 0xf2, 0xef, + 0xd9, 0x62, 0xb6, 0xa2, 0xd6, 0xfd, 0xf4, 0xe8, + 0x59, 0x22, 0xfb, 0xa8, 0x8b, 0xa6, 0xb9, 0xf7, + 0x20, 0x0f, 0x5d, 0x83, 0xd9, 0xeb, 0x9e, 0x49, + 0x07, 0xd7, 0x5c, 0xa1, 0x88, 0xb9, 0x15, 0xeb, + 0xe9, 0xb1, 0x1d, 0x88, 0x56, 0x2e, 0xa7, 0xf5, + 0xf8, 0xde, 0x51, 0x5f, 0xa7, 0xd1, 0xa3, 0xd1, + 0xa1, 0xa5, 0x9d, 0xc9, 0x53, 0xf9, 0xc9, 0xf9, + 0xa6, 0xd4, 0x22, 0x2a, 0x56, 0x08, 0x5d, 0xaa, + 0xb8, 0x9a, 0x39, 0x05, 0xdf, 0xd4, 0x5b, 0x5e, + 0x1d, 0xee, 0xe1, 0x0c, 0xf5, 0xd1, 0x18, 0x35, + 0x86, 0x3e, 0x9b, 0xcb, 0x19, 0x60, 0xeb, 0xc8, + 0x37, 0xc3, 0x05, 0x96, 0x14, 0x8f, 0x34, 0x9f, + 0xe3, 0xa9, 0xb6, 0x38, 0xad, 0xbf, 0x28, 0x63, + 0xdc, 0xa5, 0x40, 0x62, 0xb7, 0xd2, 0x02, 0x9f, + 0x2a, 0x3c, 0xa5, 0x79, 0xb0, 0x21, 0xee, 0xad, + 0x69, 0xea, 0xc2, 0xc5, 0x7d, 0x59, 0xe8, 0xdc, + 0x2f, 0xac, 0x48, 0xee, 0x9c, 0x0f, 0x9a, 0x1e, + 0xcb, 0x9c, 0x1c, 0xd3, 0x37, 0xdf, 0x40, 0x1c, + 0x73, 0x07, 0xac, 0x51, 0xeb, 0x23, 0x22, 0xf8, + 0x8e, 0xfb, 0x37, 0xf1, 0xe9, 0x1b, 0xfa, 0xac, + 0x2b, 0x9e, 0x8d, 0xeb, 0x7f, 0x76, 0xa3, 0x57, + 0x83, 0xc6, 0xef, 0xde, 0xd2, 0xc8, 0x62, 0x9b, + 0x97, 0xf0, 0x0c, 0xc0, 0x87, 0x25, 0xea, 0xf3, + 0x4f, 0x21, 0x07, 0x2d, 0x2b, 0xd5, 0x77, 0x0f, + 0x5d, 0xbc, 0xa3, 0xae, 0xab, 0x8f, 0x71, 0x9d, + 0xc6, 0x2c, 0x9d, 0x87, 0x92, 0xca, 0x70, 0x20, + 0x79, 0x49, 0x3c, 0x18, 0xea, 0x0f, 0xcc, 0x05, + 0x64, 0x3d, 0xd4, 0xb9, 0x66, 0x42, 0xf9, 0x2c, + 0xd3, 0x1c, 0x7b, 0x3d, 0x1d, 0xd0, 0x45, 0xd7, + 0x44, 0x0a, 0x57, 0xb0, 0x35, 0x79, 0x8d, 0xb5, + 0xb0, 0x80, 0xde, 0x77, 0x91, 0x9a, 0xb1, 0x45, + 0x97, 0x9b, 0x28, 0x0c, 0x6e, 0xcb, 0xd2, 0xad, + 0x63, 0x0e, 0x07, 0x5f, 0x43, 0x8b, 0x3c, 0x10, + 0xde, 0x82, 0x0d, 0xe4, 0xe4, 0x57, 0xcf, 0xb8, + 0x61, 0xce, 0x41, 0xf6, 0xe3, 0x9f, 0x3b, 0x77, + 0x27, 0x49, 0xc1, 0x08, 0xc6, 0x1d, 0x6b, 0x8f, + 0x2a, 0xb4, 0xd9, 0x54, 0x53, 0x31, 0x48, 0x3f, + 0x60, 0x9b, 0xb4, 0x38, 0x71, 0x9c, 0xf6, 0xd5, + 0x8c, 0x3e, 0xa9, 0x5a, 0xc4, 0x68, 0x68, 0x40, + 0x24, 0xde, 0xf6, 0xe5, 0x2d, 0xe9, 0x15, 0x05, + 0x82, 0x9a, 0xa3, 0xfe, 0x15, 0x5c, 0x5d, 0xdf, + 0xde, 0x49, 0xf2, 0x7c, 0x88, 0xf9, 0xb3, 0x2b, + 0x24, 0x75, 0x43, 0xda, 0x17, 0x69, 0xe0, 0x3b, + 0x3e, 0xe7, 0x65, 0x72, 0xa6, 0x4e, 0x2e, 0xec, + 0x0b, 0x84, 0x94, 0xdc, 0xf9, 0x83, 0x2c, 0x37, + 0x62, 0x19, 0x5c, 0x68, 0x44, 0xa7, 0x8d, 0xb2, + 0x27, 0xf8, 0xe9, 0x5f, 0x98, 0x90, 0xa9, 0x97, + 0xe2, 0xd4, 0x59, 0x7d, 0x40, 0xb1, 0x0c, 0x83, + 0xee, 0x26, 0xaa, 0x46, 0x35, 0x21, 0xb6, 0x89, + 0x69, 0x58, 0xd3, 0x26, 0x35, 0x36, 0x48, 0xf2, + 0xbb, 0xc0, 0x3a, 0xd6, 0x41, 0x37, 0x51, 0xe5, + 0x12, 0xf0, 0xf1, 0x77, 0x20, 0x08, 0xb8, 0x13, + 0xd7, 0x54, 0x3e, 0xcb, 0x7d, 0xa2, 0x84, 0xa9, + 0xb7, 0xd1, 0x90, 0x59, 0x0f, 0xab, 0x50, 0x1a, + 0xaa, 0xc8, 0x3f, 0xd6, 0x7c, 0xb9, 0x03, 0x12, + 0x06, 0x47, 0x3d, 0xa6, 0x3a, 0xd0, 0x81, 0x3b, + 0xbf, 0x6d, 0x4a, 0xbe, 0x53, 0xbb, 0xbe, 0x10, + 0x69, 0x38, 0x95, 0x26, 0x3e, 0x80, 0x78, 0xa7, + 0x3c, 0xf4, 0xbb, 0x74, 0xe2, 0xe7, 0x7a, 0x33, + 0xd9, 0x25, 0x61, 0x8a, 0x62, 0x3a, 0x25, 0x02, + 0x33, 0x98, 0x5a, 0x1a, 0x72, 0x6a, 0xa8, 0x87, + 0xf2, 0x12, 0x15, 0x2c, 0xa8, 0xa7, 0x8d, 0x9e, + 0xc0, 0x61, 0x77, 0x34, 0x9e, 0xeb, 0xb2, 0xf1, + 0x18, 0x4b, 0x56, 0xb4, 0xdb, 0xc7, 0xa6, 0x2b, + 0x84, 0x3a, 0x4f, 0xa0, 0x07, 0x2e, 0x7f, 0xda, + 0x3f, 0x93, 0x7e, 0x53, 0x7c, 0x8c, 0x26, 0x52, + 0xa3, 0xe2, 0x68, 0x20, 0x96, 0x74, 0xd9, 0x1c, + 0x6b, 0xe1, 0x45, 0xe0, 0x6e, 0x06, 0xa9, 0x21, + 0x9a, 0xdd, 0x0c, 0x14, 0x22, 0xda, 0xdd, 0xed, + 0x7d, 0xe7, 0x13, 0x14, 0xf9, 0x05, 0xa1, 0x52, + 0x28, 0xf1, 0xa6, 0x19, 0x31, 0xb1, 0xb8, 0x9d, + 0x05, 0x02, 0x8f, 0xa2, 0xfc, 0xc2, 0x21, 0x0c, + 0x81, 0xcf, 0x53, 0xc3, 0x59, 0x8e, 0x49, 0x2b, + 0x25, 0xa8, 0xb1, 0x6b, 0x0c, 0x01, 0x7b, 0xe2, + 0xfb, 0xa8, 0xc7, 0xcb, 0xb2, 0x17, 0x05, 0xe5, + 0x0e, 0x16, 0xaa, 0x72, 0xd6, 0xf5, 0x24, 0x7f, + 0x47, 0x33, 0x09, 0x67, 0x52, 0x44, 0x6e, 0xe4, + 0x14, 0xe4, 0xfa, 0xb2, 0x28, 0xd7, 0x1c, 0x7e, + 0xc6, 0xe9, 0x61, 0x6d, 0xd5, 0x9a, 0x9f, 0x7d, + 0x1b, 0x93, 0x7a, 0x69, 0x74, 0x4d, 0x81, 0xbb, + 0xda, 0x32, 0x40, 0x04, 0x00, 0x44, 0x9b, 0x90, + 0x5f, 0x95, 0x9d, 0x8a, 0xd4, 0xe6, 0x2f, 0x1f, + 0xb3, 0xa7, 0x75, 0xd6, 0x15, 0x5a, 0xb4, 0xd9, + 0xc8, 0xfe, 0x12, 0xca, 0xd5, 0x94, 0x48, 0x8a, + 0xe7, 0x07, 0x71, 0x8f, 0x37, 0xa9, 0x31, 0x0c, + 0xe0, 0xe2, 0x0b, 0x8b, 0x3f, 0x35, 0xb9, 0xd5, + 0x16, 0x8a, 0x38, 0xf0, 0xa1, 0x41, 0x18, 0x2d, + 0x1c, 0xc0, 0x0c, 0x67, 0x1d, 0x6a, 0x27, 0xf8, + 0xc2, 0x2f, 0xe8, 0x56, 0x68, 0x70, 0x47, 0xca, + 0xd5, 0x4d, 0xac, 0x75, 0x13, 0x09, 0x7b, 0xd8, + 0xcf, 0x5e, 0x94, 0x57, 0x8c, 0x1a, 0x38, 0x8c, + 0x30, 0x60, 0xd2, 0x9d, 0xa8, 0x4d, 0xa7, 0xb4, + 0xb2, 0x3d, 0xaa, 0x52, 0x13, 0xab, 0x92, 0x60, + 0x70, 0x36, 0xec, 0xff, 0xd9, 0x45, 0x6c, 0x7d, + 0x54, 0x2e, 0x5c, 0x8a, 0x24, 0xe8, 0xe0, 0xf7, + 0x92, 0x9a, 0xb6, 0x44, 0x08, 0x0c, 0xb9, 0xdb + }; + static const byte mu_65[] = { + 0x32, 0x6f, 0xd5, 0xf3, 0x76, 0x2b, 0xd8, 0xc1, + 0x31, 0x4b, 0x83, 0x07, 0x22, 0x5b, 0x2e, 0x6a, + 0x23, 0x08, 0x86, 0x63, 0x8d, 0x8a, 0xb4, 0xe7, + 0x8e, 0x5c, 0xff, 0xfa, 0x1c, 0xdc, 0xb9, 0x61, + 0x6f, 0x01, 0x0b, 0xb8, 0x66, 0x2d, 0x7d, 0xec, + 0x82, 0xb8, 0x00, 0xa8, 0x48, 0x77, 0x12, 0x21, + 0xea, 0x67, 0x30, 0x45, 0x21, 0x39, 0x7d, 0x3d, + 0x27, 0x3c, 0x21, 0xf4, 0x18, 0x5b, 0x79, 0x31 + }; + static const byte sig_65_mu[] = { + 0xc8, 0x39, 0x74, 0x5f, 0xbc, 0xef, 0x91, 0x4b, + 0x5e, 0x3e, 0x06, 0x86, 0xe3, 0x69, 0x57, 0xe1, + 0xf1, 0xc5, 0x6e, 0x06, 0x87, 0xf8, 0x24, 0x1c, + 0xb5, 0x38, 0x8d, 0xe3, 0x53, 0xfb, 0xe0, 0xd6, + 0x31, 0x61, 0x85, 0xa5, 0xe5, 0x86, 0x46, 0xdf, + 0xe3, 0x0e, 0xab, 0xfe, 0x06, 0x01, 0x4d, 0xa3, + 0x74, 0x1f, 0x52, 0xb9, 0x55, 0xd1, 0xf5, 0xce, + 0xac, 0x51, 0x2c, 0x3b, 0xb3, 0x64, 0xdd, 0xd3, + 0x85, 0x80, 0xd8, 0xd3, 0x64, 0x3f, 0x6f, 0xa7, + 0x3d, 0x2b, 0xc5, 0xfe, 0x29, 0x18, 0x0e, 0x8e, + 0x15, 0x5b, 0xab, 0x14, 0xcd, 0xb3, 0x3f, 0x85, + 0x4c, 0xcc, 0x0d, 0x49, 0xee, 0x1a, 0x01, 0x15, + 0xd4, 0xfe, 0xdb, 0xc8, 0x94, 0xe3, 0x84, 0x53, + 0x67, 0x26, 0x6b, 0x61, 0x2b, 0x66, 0x77, 0x9a, + 0x7d, 0xa5, 0x04, 0xf4, 0x7f, 0x4e, 0x34, 0x17, + 0x26, 0x4f, 0x31, 0x2e, 0x47, 0x38, 0x92, 0xd8, + 0xd6, 0x12, 0x69, 0xed, 0x28, 0x86, 0x25, 0xeb, + 0x29, 0x21, 0x66, 0x42, 0x53, 0x56, 0xe8, 0x5b, + 0x2d, 0x80, 0x4b, 0xf6, 0x9a, 0x41, 0x45, 0x51, + 0x71, 0xef, 0x46, 0x39, 0x6f, 0xa6, 0x95, 0x30, + 0xa4, 0xf0, 0x8f, 0xea, 0x32, 0x86, 0x05, 0x3a, + 0x9f, 0xc0, 0x0f, 0x91, 0x62, 0xd3, 0xc2, 0xe1, + 0x10, 0x1a, 0x60, 0x88, 0x6e, 0x7d, 0x7a, 0x74, + 0x51, 0x75, 0x3f, 0x8b, 0x3d, 0x1e, 0x3b, 0xcc, + 0x64, 0x90, 0xa0, 0x52, 0xe4, 0xc5, 0x3b, 0xaf, + 0x35, 0x01, 0xeb, 0xe5, 0xdb, 0xa7, 0xbf, 0x9d, + 0x2f, 0xc4, 0x37, 0x75, 0xfb, 0xbd, 0x16, 0x0e, + 0xda, 0x2f, 0x01, 0x63, 0x8b, 0x59, 0xb9, 0x9b, + 0x4f, 0x0c, 0x8b, 0x51, 0xfb, 0xf5, 0x5d, 0x6a, + 0x9d, 0xc8, 0xce, 0xaf, 0xca, 0x3f, 0x03, 0x95, + 0x1d, 0xd1, 0x26, 0xa3, 0x7c, 0x8b, 0xad, 0x92, + 0xf2, 0xe5, 0x88, 0x09, 0xeb, 0xbe, 0xff, 0x3b, + 0x4e, 0x34, 0xf8, 0x98, 0x7f, 0xf9, 0x0c, 0x7e, + 0x2c, 0x40, 0x7b, 0xc8, 0xd1, 0x21, 0x0c, 0xf6, + 0xeb, 0xba, 0x24, 0x25, 0xe2, 0x7d, 0x45, 0x92, + 0x33, 0x2b, 0xab, 0xb8, 0xd6, 0x7d, 0x91, 0x5a, + 0x36, 0xd3, 0x81, 0x4c, 0x73, 0x9c, 0x99, 0x82, + 0xcc, 0xa0, 0x1e, 0xf9, 0xd1, 0x07, 0x39, 0x31, + 0x9b, 0x3a, 0xdc, 0xb3, 0xc9, 0x3d, 0x3a, 0xb3, + 0xa1, 0x0d, 0xcd, 0x20, 0x38, 0x22, 0xa9, 0x05, + 0x74, 0xd0, 0x72, 0x32, 0x12, 0x07, 0x06, 0x7b, + 0xd3, 0xcd, 0x02, 0x1e, 0x72, 0x54, 0x6d, 0x7f, + 0xe6, 0xd2, 0x3c, 0x86, 0xed, 0x88, 0x31, 0x3c, + 0x7d, 0x21, 0x42, 0x3e, 0xbc, 0x97, 0xfd, 0x0e, + 0x75, 0xde, 0x0a, 0x3a, 0x1b, 0x32, 0x19, 0x7b, + 0x9b, 0x28, 0x0f, 0xe4, 0xf1, 0xcc, 0x77, 0xfa, + 0x81, 0x70, 0xd0, 0x6a, 0x41, 0xd3, 0xe3, 0x8b, + 0x70, 0x40, 0x30, 0x3f, 0xed, 0x5a, 0x7c, 0x7c, + 0xd4, 0x84, 0xa3, 0x36, 0x14, 0x58, 0xaa, 0xd7, + 0x9e, 0x9f, 0x64, 0x4f, 0x7b, 0x7f, 0xfd, 0x4d, + 0x6c, 0xb9, 0x1e, 0xae, 0xd0, 0x8b, 0x60, 0x61, + 0xc1, 0xe0, 0xcb, 0x14, 0xda, 0x11, 0x0d, 0xa4, + 0x4e, 0x10, 0xac, 0x59, 0x77, 0xda, 0xce, 0x8b, + 0x99, 0xcc, 0x6d, 0xf0, 0x2c, 0xd3, 0x66, 0x9a, + 0xca, 0x5a, 0x5e, 0xd6, 0x41, 0x70, 0xdf, 0x8d, + 0x17, 0x2d, 0x8e, 0xb0, 0xc5, 0x29, 0x15, 0x23, + 0x90, 0x9b, 0x21, 0xaa, 0xc3, 0xe2, 0xc1, 0x72, + 0x59, 0x20, 0xa0, 0x22, 0x49, 0x46, 0xe1, 0x68, + 0xcd, 0x58, 0x43, 0xef, 0x32, 0x20, 0xa2, 0xdd, + 0xb7, 0x4b, 0xeb, 0xfd, 0x9d, 0x87, 0x20, 0xd8, + 0x9d, 0x47, 0xf6, 0x06, 0xbb, 0x2f, 0x33, 0xee, + 0xfd, 0x01, 0x2c, 0x21, 0x41, 0x2b, 0x73, 0x7f, + 0x3b, 0x48, 0x62, 0x42, 0x76, 0xf0, 0xb3, 0x30, + 0xb2, 0x50, 0xa1, 0x00, 0xe1, 0xd6, 0x62, 0xc5, + 0xb0, 0xbb, 0x93, 0x2d, 0xda, 0xd2, 0x41, 0x14, + 0x3c, 0xbb, 0x6d, 0xee, 0xac, 0x99, 0x05, 0x0b, + 0xc0, 0x89, 0x0b, 0x6f, 0x5b, 0x04, 0x21, 0x3b, + 0x3f, 0x51, 0x25, 0xc0, 0x30, 0xc9, 0x07, 0xd6, + 0x4d, 0xec, 0x06, 0xb5, 0x14, 0x03, 0x19, 0x6e, + 0x32, 0x4f, 0xd7, 0x59, 0x32, 0x7b, 0xdb, 0x45, + 0x80, 0x6c, 0xba, 0x23, 0xba, 0x25, 0xc8, 0xf7, + 0x59, 0xf7, 0x51, 0xb3, 0x9f, 0xbe, 0xa2, 0xf9, + 0x44, 0x55, 0x3b, 0x09, 0x83, 0xab, 0x13, 0x55, + 0x6d, 0xb9, 0xeb, 0x44, 0x72, 0x9d, 0xb1, 0xed, + 0x2f, 0xfd, 0x28, 0x3b, 0xbc, 0xe6, 0xd6, 0x41, + 0xe5, 0x64, 0x1f, 0x9b, 0x8b, 0x58, 0xfd, 0x1c, + 0xe4, 0x48, 0xff, 0xa2, 0xbb, 0xa0, 0xff, 0xe7, + 0x29, 0x8b, 0xe3, 0x86, 0x10, 0xf4, 0xb1, 0xaf, + 0x06, 0xc1, 0x4b, 0x57, 0xbc, 0xc6, 0xd1, 0x83, + 0x59, 0x8e, 0x5a, 0x68, 0xa6, 0x0e, 0xce, 0xbe, + 0x65, 0x38, 0x18, 0x35, 0x20, 0x10, 0x90, 0x47, + 0x07, 0xe7, 0xb1, 0x5f, 0xb0, 0xb4, 0xe9, 0x7f, + 0x9e, 0x82, 0x49, 0x6e, 0x0c, 0xed, 0xb0, 0xc8, + 0x29, 0xea, 0xef, 0x90, 0x99, 0x61, 0xc2, 0xec, + 0xf7, 0x03, 0x8a, 0x23, 0x6b, 0x18, 0xe8, 0x60, + 0x28, 0x8a, 0x00, 0xbc, 0x3d, 0xca, 0x6e, 0x31, + 0x3f, 0x01, 0xd2, 0x26, 0xc9, 0x98, 0xf0, 0x5a, + 0x24, 0x74, 0x2b, 0x37, 0x78, 0x40, 0x06, 0x96, + 0xb2, 0xf6, 0x55, 0x96, 0xd1, 0x68, 0x7a, 0x1b, + 0x7a, 0x34, 0xbd, 0x98, 0x09, 0x9d, 0x9a, 0x39, + 0xc6, 0x25, 0x2d, 0x07, 0x92, 0xda, 0xd6, 0x5e, + 0xd9, 0x5b, 0x8d, 0x4c, 0xe0, 0x42, 0x72, 0x10, + 0x39, 0x29, 0xc6, 0x91, 0x74, 0x2c, 0x95, 0xd8, + 0x65, 0x3e, 0x7c, 0x40, 0x66, 0xcc, 0x19, 0x68, + 0x24, 0xb3, 0xa8, 0x9f, 0xf0, 0xd0, 0x65, 0xdd, + 0x02, 0x3d, 0xc4, 0xd4, 0x8c, 0xb6, 0xdf, 0xae, + 0xf9, 0xf4, 0x05, 0x76, 0x48, 0xba, 0x33, 0x7d, + 0xbd, 0x90, 0x40, 0x56, 0x95, 0x99, 0x2b, 0x13, + 0xfa, 0x79, 0x2b, 0x95, 0xd1, 0x31, 0x3c, 0x26, + 0x2c, 0xe7, 0x82, 0x87, 0xc4, 0x7e, 0x7c, 0x26, + 0x34, 0x78, 0x05, 0x5c, 0xbd, 0x0b, 0xd0, 0xa3, + 0x3d, 0x72, 0x50, 0x06, 0x49, 0x1f, 0x89, 0xc1, + 0xcf, 0xae, 0x21, 0x84, 0xb0, 0x63, 0x59, 0xca, + 0x4c, 0xe2, 0xcb, 0xb5, 0x6e, 0x5a, 0x74, 0x63, + 0x45, 0x18, 0xdb, 0x67, 0x78, 0x71, 0x13, 0x0b, + 0x4b, 0x85, 0xa0, 0x02, 0x68, 0x87, 0x6d, 0x12, + 0x2b, 0x5c, 0x3c, 0x14, 0x4b, 0x8b, 0xd0, 0x66, + 0xc2, 0x1b, 0x25, 0xf2, 0xcd, 0x19, 0xa2, 0x53, + 0x0b, 0xe3, 0x8c, 0x74, 0xdc, 0xe6, 0x33, 0x6f, + 0x1c, 0xfd, 0x29, 0x6e, 0x0b, 0x42, 0x27, 0x9d, + 0x8a, 0xce, 0x49, 0xaa, 0x02, 0x6d, 0xcf, 0x74, + 0x2b, 0xdb, 0x3a, 0x18, 0x2a, 0xf9, 0x22, 0xe3, + 0xd2, 0xdd, 0x2d, 0xa1, 0xce, 0x96, 0x82, 0xbe, + 0xfe, 0x98, 0xf5, 0x56, 0xe2, 0x7e, 0x3f, 0xeb, + 0x5a, 0x9c, 0x72, 0x7f, 0x02, 0x93, 0x3c, 0x2f, + 0x40, 0x91, 0x50, 0x5f, 0x49, 0xcc, 0x62, 0x58, + 0xdf, 0x7a, 0x81, 0x8a, 0xc9, 0xec, 0x08, 0x81, + 0x06, 0x6f, 0xbf, 0x69, 0x3a, 0x85, 0x53, 0x17, + 0x02, 0xc7, 0xee, 0xb5, 0x68, 0xe4, 0x6f, 0x5f, + 0xa1, 0xe9, 0x6c, 0x86, 0x85, 0x1f, 0x9e, 0x7b, + 0xd5, 0x15, 0xfc, 0x5c, 0x03, 0xde, 0x43, 0x64, + 0x7f, 0x36, 0x64, 0xd3, 0x2b, 0x6b, 0x6b, 0x65, + 0x52, 0x67, 0x4b, 0xd2, 0xca, 0x4d, 0x9d, 0x8b, + 0x6c, 0xe3, 0x0a, 0x71, 0x32, 0xcd, 0xb7, 0x6f, + 0xbc, 0x99, 0xa0, 0xe6, 0x3e, 0x9d, 0xa3, 0x21, + 0x03, 0x45, 0xd3, 0x0f, 0xf1, 0x04, 0x76, 0x5c, + 0xde, 0x37, 0xd0, 0x49, 0x51, 0xa7, 0xf9, 0x89, + 0x37, 0x71, 0x0e, 0x4a, 0x8e, 0x0c, 0x3c, 0x4c, + 0x3a, 0x7f, 0x55, 0xdc, 0x62, 0x47, 0x4f, 0x4e, + 0xd1, 0x72, 0xd0, 0xe1, 0x14, 0xf7, 0x24, 0xe7, + 0xfb, 0x82, 0x71, 0xa6, 0xe7, 0x40, 0xed, 0xd7, + 0x6f, 0x50, 0x6e, 0xc7, 0xc9, 0xcc, 0x14, 0xf8, + 0x1d, 0x5c, 0x49, 0xbd, 0xa7, 0x6a, 0xf3, 0xca, + 0xbe, 0xfb, 0x31, 0x8d, 0x9d, 0x64, 0x60, 0xee, + 0xd9, 0xfb, 0x0e, 0x1c, 0xd8, 0x63, 0x79, 0x03, + 0x3e, 0x93, 0xe4, 0x47, 0xa2, 0xfc, 0xc5, 0xe9, + 0xfd, 0x2f, 0xa5, 0x03, 0x55, 0xb6, 0x75, 0xed, + 0xa5, 0xc9, 0x27, 0x38, 0x04, 0xed, 0x86, 0x3f, + 0xd9, 0xcc, 0x28, 0xbc, 0xd1, 0x49, 0xe0, 0xbf, + 0x68, 0xde, 0xac, 0xff, 0xe1, 0x4d, 0xfc, 0x6b, + 0xfa, 0x63, 0x65, 0x23, 0xeb, 0xdb, 0x3a, 0x3f, + 0x11, 0xd0, 0x63, 0xa5, 0x73, 0x42, 0xbf, 0x40, + 0xf3, 0xab, 0x27, 0x18, 0x1b, 0x0b, 0x87, 0x77, + 0x13, 0x75, 0x08, 0xce, 0x63, 0x4b, 0xc6, 0x58, + 0x1a, 0x43, 0xb5, 0xd0, 0x4c, 0x29, 0x8c, 0xec, + 0x2d, 0x82, 0xc2, 0xe4, 0xaa, 0xc1, 0x3e, 0x4e, + 0x08, 0x21, 0x41, 0x20, 0xc5, 0x9f, 0x69, 0x98, + 0x1d, 0x33, 0x23, 0x4e, 0xb7, 0x6d, 0xe4, 0x2a, + 0x95, 0xb8, 0x6c, 0x39, 0xf3, 0x18, 0x01, 0x63, + 0xaa, 0x83, 0x27, 0x53, 0xd5, 0x3c, 0x37, 0xb0, + 0xda, 0x72, 0x01, 0x03, 0x85, 0x74, 0x09, 0x59, + 0x94, 0x0b, 0x10, 0x95, 0xe4, 0xad, 0x48, 0x37, + 0xcb, 0xef, 0x54, 0xe7, 0xf9, 0x8a, 0x42, 0xf8, + 0x5a, 0x56, 0xfc, 0x64, 0x92, 0xd9, 0xff, 0x75, + 0x2b, 0xee, 0x2f, 0x5d, 0x67, 0xb3, 0x98, 0x9f, + 0x20, 0x1e, 0xfe, 0x8c, 0xf2, 0x60, 0x2e, 0xcb, + 0xcd, 0x19, 0xfb, 0x31, 0x5f, 0xcf, 0xcf, 0x96, + 0x3c, 0x98, 0xe8, 0x9c, 0x3b, 0x1b, 0xf0, 0xdd, + 0x52, 0xb2, 0x9c, 0x4f, 0x83, 0x68, 0xb1, 0x42, + 0x82, 0xa4, 0x57, 0x52, 0x47, 0x0e, 0x59, 0x8c, + 0x4f, 0x76, 0x49, 0xf4, 0xc0, 0x02, 0x96, 0x10, + 0x36, 0xa0, 0x0d, 0x3d, 0x89, 0xc9, 0x1f, 0x85, + 0x96, 0x53, 0x1d, 0x89, 0xf8, 0x7a, 0xb3, 0xe4, + 0x20, 0x12, 0x65, 0x06, 0x3a, 0x89, 0xff, 0x8f, + 0x32, 0x4c, 0x81, 0x44, 0x00, 0x0a, 0xbe, 0x26, + 0x51, 0x27, 0x4b, 0x9b, 0x0d, 0x4e, 0x7c, 0xa5, + 0x71, 0xfb, 0x91, 0x08, 0x32, 0xa4, 0x82, 0xcb, + 0x9c, 0xb2, 0x0d, 0x5e, 0x22, 0xda, 0x6c, 0xd6, + 0x5f, 0xa8, 0x5b, 0xfa, 0xdc, 0x27, 0x8f, 0xa0, + 0xac, 0x58, 0xd1, 0xeb, 0xd9, 0xab, 0x2f, 0x2d, + 0xbf, 0xb7, 0x27, 0x6e, 0xfe, 0xd0, 0x54, 0x34, + 0xfe, 0x2a, 0x2f, 0x99, 0xda, 0xd2, 0xf0, 0x82, + 0x8d, 0x13, 0x72, 0x87, 0x1a, 0xa6, 0x7f, 0x9b, + 0x2b, 0x6d, 0xff, 0x8e, 0x5b, 0x23, 0xc3, 0x0a, + 0x5a, 0x5e, 0x35, 0xfa, 0xbb, 0xe0, 0xc6, 0xdc, + 0xff, 0x9f, 0x75, 0xb0, 0x27, 0xe8, 0xdd, 0x7d, + 0x1e, 0xcb, 0x61, 0x1b, 0x30, 0xe2, 0x50, 0x6a, + 0xa6, 0x0f, 0xca, 0x64, 0x74, 0x03, 0xdc, 0xe5, + 0x36, 0xdf, 0xed, 0x31, 0xa0, 0x89, 0x30, 0xb9, + 0x57, 0x3f, 0x7a, 0x2e, 0x3a, 0x3f, 0xee, 0x01, + 0x61, 0x32, 0x8a, 0xd4, 0x22, 0x01, 0x43, 0x49, + 0x60, 0x7a, 0xe2, 0x0f, 0x1c, 0x9f, 0x99, 0x88, + 0xe5, 0x84, 0x2a, 0x56, 0x56, 0x6f, 0xf7, 0x39, + 0xa7, 0xae, 0xef, 0x04, 0x4b, 0x3d, 0x9a, 0xab, + 0x2a, 0xd7, 0xd6, 0xe5, 0xc8, 0xd6, 0xe9, 0x8a, + 0x42, 0x06, 0x21, 0xb8, 0x50, 0x17, 0xf4, 0x44, + 0x09, 0x54, 0x99, 0xdd, 0x90, 0x0a, 0x50, 0x4f, + 0x5e, 0x87, 0x2e, 0xda, 0xb7, 0x18, 0xfa, 0xd4, + 0x98, 0x8e, 0x26, 0x51, 0x82, 0xfc, 0xf3, 0x88, + 0x77, 0xa0, 0xbd, 0x80, 0xc4, 0xa3, 0x07, 0x70, + 0x80, 0x91, 0xd8, 0x20, 0xf0, 0x6b, 0x01, 0xb9, + 0x89, 0xc1, 0x51, 0xcd, 0x20, 0x47, 0xd4, 0xad, + 0xd7, 0x96, 0x64, 0xe7, 0xb1, 0xbf, 0xff, 0x54, + 0xca, 0x2f, 0x04, 0x47, 0xce, 0xf8, 0x7b, 0x74, + 0x25, 0x0b, 0x15, 0xde, 0x75, 0x00, 0x61, 0xff, + 0xe4, 0x7b, 0x22, 0xf6, 0x4f, 0x45, 0x79, 0xe6, + 0xd5, 0x9e, 0xba, 0x2a, 0x6f, 0xc5, 0x21, 0x85, + 0xe8, 0x35, 0x73, 0x72, 0x1d, 0x8a, 0xcc, 0xb2, + 0x14, 0xeb, 0x7e, 0xcc, 0x4b, 0x43, 0x46, 0xb5, + 0x53, 0x51, 0x14, 0xf5, 0xb5, 0xd9, 0x76, 0x96, + 0x99, 0x8f, 0xbd, 0x6a, 0xdf, 0x36, 0x07, 0xb2, + 0xb2, 0x7b, 0xae, 0x5a, 0xf9, 0x78, 0xa7, 0x27, + 0x9a, 0x6f, 0xd5, 0xa7, 0xc4, 0x97, 0x82, 0xf2, + 0xbb, 0x4c, 0x9c, 0xe1, 0x11, 0x2c, 0x45, 0x9d, + 0x8b, 0x7f, 0x86, 0x12, 0x74, 0xc1, 0xe6, 0xe9, + 0x34, 0xba, 0x19, 0x59, 0x07, 0x18, 0xc2, 0xb3, + 0x45, 0x19, 0xe8, 0x9b, 0x97, 0xcd, 0x8a, 0xdf, + 0xb4, 0x4b, 0x8d, 0x30, 0x7b, 0xed, 0x81, 0x3f, + 0x73, 0x54, 0xc3, 0x17, 0x5c, 0xef, 0xcd, 0xf6, + 0xb6, 0xf0, 0x6b, 0xee, 0x67, 0x5e, 0x2f, 0xb8, + 0x76, 0x92, 0x20, 0x95, 0x1d, 0x50, 0x4e, 0x27, + 0x4b, 0x7f, 0xa7, 0xa6, 0x10, 0xd5, 0x28, 0x2e, + 0xd0, 0x69, 0xf7, 0x07, 0x35, 0x48, 0x7c, 0xdb, + 0xb8, 0x81, 0x91, 0x37, 0x69, 0x20, 0xd0, 0x50, + 0x1d, 0xe7, 0xa5, 0x07, 0x55, 0xd6, 0xf0, 0x8b, + 0x61, 0x0f, 0xf7, 0x19, 0xff, 0x78, 0x16, 0x70, + 0xbe, 0xae, 0xe6, 0x01, 0x56, 0x2a, 0x36, 0x47, + 0x9f, 0xd5, 0xcd, 0x96, 0x44, 0x78, 0xf6, 0x03, + 0xd4, 0x16, 0x6c, 0xc0, 0xbd, 0x30, 0xa6, 0x7a, + 0xf2, 0x35, 0x83, 0x2a, 0x74, 0x49, 0x15, 0x91, + 0xaf, 0x6c, 0x8d, 0x3a, 0xd4, 0x03, 0x68, 0xe5, + 0x0e, 0xcd, 0xfd, 0x81, 0x98, 0xb9, 0x94, 0x7f, + 0xea, 0x5f, 0xa2, 0x3d, 0x11, 0x15, 0x58, 0x97, + 0xc7, 0xa6, 0xdd, 0x90, 0x66, 0xbb, 0x3e, 0xca, + 0x33, 0x8b, 0xbf, 0x0b, 0x4c, 0x82, 0x58, 0x41, + 0xe1, 0xa3, 0x71, 0xfe, 0x92, 0x97, 0x81, 0x09, + 0xe9, 0xd1, 0x06, 0xb6, 0xea, 0x2a, 0xae, 0x31, + 0xd1, 0xe2, 0xba, 0x24, 0xaa, 0x47, 0x18, 0x63, + 0x5a, 0xcb, 0xc0, 0x86, 0xd2, 0xb3, 0x6d, 0x20, + 0x32, 0x1f, 0x84, 0xaf, 0xa2, 0x16, 0x67, 0xa4, + 0xe6, 0xf9, 0xac, 0x9a, 0x7f, 0xdc, 0x17, 0x88, + 0x12, 0xc5, 0xa0, 0x24, 0x0a, 0xca, 0x23, 0x95, + 0x03, 0xe9, 0x6e, 0x84, 0xb8, 0x12, 0x9f, 0x4e, + 0xd5, 0x60, 0x07, 0x3b, 0xcd, 0xa2, 0x28, 0x38, + 0x7f, 0x27, 0x87, 0xce, 0x01, 0x1f, 0x78, 0x66, + 0x62, 0x40, 0x97, 0x10, 0x19, 0x47, 0x5b, 0xbd, + 0x69, 0x63, 0x2b, 0x96, 0xd8, 0xa4, 0x25, 0xb1, + 0x16, 0xf8, 0xcb, 0xde, 0xee, 0xfd, 0xbf, 0x7b, + 0x0d, 0x16, 0x85, 0xb7, 0xa5, 0xe5, 0xe5, 0x4b, + 0x62, 0xc1, 0x60, 0x0f, 0x67, 0xdc, 0x42, 0x73, + 0x1d, 0x3f, 0xfb, 0x31, 0x42, 0xf5, 0x1a, 0xfb, + 0x47, 0x6b, 0x13, 0x48, 0xc8, 0x60, 0x9e, 0xf6, + 0x89, 0x7b, 0xcf, 0x34, 0x22, 0x35, 0x81, 0x7c, + 0x90, 0x0d, 0xb4, 0x47, 0x53, 0x40, 0x1d, 0x77, + 0x6f, 0xc6, 0xdf, 0x5b, 0xa3, 0xfd, 0xd8, 0x37, + 0x3e, 0xa2, 0xe4, 0x1a, 0x5c, 0x09, 0xee, 0x4b, + 0x99, 0x6b, 0x95, 0x5f, 0x4f, 0x3b, 0x4f, 0x8d, + 0xf7, 0x83, 0x2a, 0x0a, 0x15, 0x8f, 0xa8, 0xd0, + 0xf9, 0x11, 0x65, 0x24, 0xd5, 0xa8, 0x97, 0x55, + 0xd0, 0x63, 0x7c, 0x27, 0x26, 0xa5, 0x74, 0x12, + 0xa6, 0xe6, 0x00, 0xca, 0xb3, 0x00, 0xb9, 0xbe, + 0x2d, 0x58, 0xf9, 0x37, 0x6a, 0x04, 0x5c, 0x82, + 0xb5, 0x90, 0x86, 0xfc, 0x5d, 0xee, 0x24, 0xf8, + 0xd9, 0x75, 0x87, 0xf7, 0x39, 0xca, 0x0b, 0x26, + 0xf2, 0xae, 0x31, 0x57, 0x2d, 0x29, 0x53, 0x88, + 0xce, 0xdc, 0x4c, 0x3e, 0x6e, 0x23, 0x12, 0x89, + 0x0f, 0x8b, 0xcf, 0xd8, 0xd2, 0xf5, 0x1d, 0x50, + 0xd3, 0x0b, 0x50, 0x1d, 0xc1, 0xa5, 0xa1, 0x5a, + 0x78, 0x78, 0x86, 0xbb, 0xb9, 0xf1, 0xc6, 0x1c, + 0xec, 0xea, 0xa4, 0x5a, 0xf7, 0xd8, 0x9d, 0x87, + 0x35, 0x51, 0x78, 0xe7, 0x8c, 0x1c, 0x15, 0x29, + 0x54, 0xc1, 0x8f, 0x44, 0xb7, 0x5c, 0x9e, 0xe6, + 0xfd, 0xfe, 0x17, 0xc9, 0x43, 0x5a, 0xec, 0xa3, + 0x8a, 0xbd, 0xe9, 0xf5, 0xf7, 0x3d, 0xac, 0x5d, + 0x17, 0xe3, 0x2d, 0xa9, 0xb5, 0xdf, 0xc3, 0xa5, + 0x34, 0x2e, 0x49, 0xe1, 0x50, 0x90, 0xd7, 0x35, + 0x7a, 0xc6, 0x73, 0xd4, 0x4c, 0xa9, 0x4c, 0xec, + 0x16, 0x06, 0x0a, 0x39, 0xcb, 0x54, 0x97, 0x91, + 0x80, 0x5d, 0x96, 0x45, 0x29, 0x45, 0x30, 0x86, + 0xbb, 0x53, 0x2e, 0x30, 0xe1, 0x5e, 0xcb, 0x1a, + 0x03, 0x84, 0xd4, 0xd9, 0x6d, 0x14, 0xc5, 0x34, + 0x5a, 0xf7, 0xca, 0x33, 0xfe, 0x55, 0x4d, 0x9e, + 0xf0, 0x03, 0xb7, 0x47, 0xc6, 0x4f, 0x1e, 0xa0, + 0x53, 0x19, 0x8e, 0x4b, 0x8a, 0x11, 0x60, 0x50, + 0x70, 0xc5, 0xee, 0x09, 0xe1, 0xc1, 0x37, 0xf9, + 0x1b, 0xbf, 0xfc, 0x21, 0x0a, 0x4c, 0xa8, 0x6e, + 0x19, 0xba, 0x9e, 0x10, 0x09, 0x81, 0x6d, 0x00, + 0xcb, 0x24, 0x7c, 0xa4, 0xd3, 0x14, 0xb5, 0xf8, + 0x9c, 0x78, 0x2c, 0x97, 0x44, 0xd5, 0x82, 0xf1, + 0x25, 0x73, 0xa0, 0x12, 0x7a, 0x65, 0xc9, 0x08, + 0xdc, 0xda, 0x1a, 0x88, 0x5a, 0xc5, 0x5b, 0x5d, + 0x3a, 0xaf, 0x5d, 0xea, 0xe6, 0xe4, 0xfe, 0x05, + 0x06, 0x15, 0xad, 0x17, 0xfd, 0xec, 0x06, 0x0f, + 0xdb, 0xbb, 0x0e, 0x37, 0xf9, 0xc7, 0x69, 0xd0, + 0x27, 0x03, 0x65, 0xb9, 0x96, 0xe7, 0x0b, 0x04, + 0x5e, 0xdf, 0x93, 0x93, 0xa6, 0x10, 0x1e, 0x1a, + 0x90, 0x33, 0x48, 0x39, 0x0b, 0xe8, 0xd9, 0x22, + 0xbf, 0x9d, 0xf8, 0x7d, 0x1e, 0xd0, 0x79, 0xca, + 0xed, 0xa8, 0x9c, 0xc6, 0xf5, 0xa6, 0xcf, 0xa5, + 0x34, 0x76, 0x76, 0x8b, 0x9c, 0x3a, 0xa7, 0x04, + 0xc7, 0xfe, 0xb7, 0x24, 0x7c, 0x74, 0x53, 0x08, + 0xf2, 0x48, 0x6a, 0x52, 0x47, 0x8c, 0xc6, 0x86, + 0xc1, 0xae, 0x2c, 0xa0, 0xcd, 0xba, 0x4d, 0x0d, + 0x28, 0x38, 0x35, 0x83, 0xd7, 0xe1, 0x85, 0x98, + 0x2e, 0xad, 0xc3, 0x98, 0xe5, 0xb2, 0x11, 0x7b, + 0x8c, 0x87, 0xeb, 0x58, 0x1f, 0xa0, 0x95, 0x1e, + 0x62, 0x8c, 0x3b, 0xd8, 0xca, 0x23, 0x70, 0x11, + 0x9f, 0xc2, 0xa7, 0x8c, 0x7d, 0xe6, 0xe3, 0x6d, + 0x8e, 0x90, 0x8a, 0xf7, 0xab, 0x81, 0xd0, 0x09, + 0xaa, 0x49, 0x4d, 0xb7, 0xbd, 0xde, 0x29, 0x64, + 0x8e, 0x65, 0x76, 0xdb, 0x04, 0x14, 0x60, 0x99, + 0x41, 0xd8, 0x03, 0xf5, 0x43, 0x1a, 0x66, 0x55, + 0x65, 0x6b, 0x27, 0x6c, 0xe4, 0x33, 0xd5, 0x20, + 0xd2, 0xc9, 0x5d, 0x89, 0xdf, 0x44, 0xfa, 0xa6, + 0x72, 0x9e, 0x26, 0xbc, 0x78, 0x09, 0xc4, 0x22, + 0x4d, 0x9d, 0x1d, 0x48, 0xfd, 0xa2, 0xec, 0x60, + 0xef, 0xdf, 0x85, 0x5b, 0x3d, 0x04, 0x1e, 0x5d, + 0x01, 0x64, 0x76, 0x7e, 0x25, 0xda, 0x44, 0xff, + 0xf4, 0xd2, 0x8b, 0x3e, 0x7c, 0x0e, 0x87, 0x1a, + 0x04, 0xe3, 0xa1, 0xbc, 0xd3, 0x7f, 0xc2, 0x67, + 0x50, 0x29, 0x57, 0xc7, 0x57, 0xff, 0x7e, 0x94, + 0x21, 0xde, 0x66, 0xa0, 0x16, 0x55, 0xe6, 0xf9, + 0x36, 0xd9, 0xae, 0xb2, 0xc5, 0xd5, 0xf5, 0xb8, + 0x8b, 0x75, 0xbf, 0xef, 0xe6, 0xda, 0xfa, 0x40, + 0x8d, 0x21, 0xd8, 0x66, 0x6d, 0x07, 0x83, 0xf9, + 0x13, 0xa1, 0xb0, 0xb3, 0x48, 0x55, 0x35, 0x20, + 0x19, 0xb7, 0xec, 0x2a, 0x8f, 0x0c, 0xcc, 0xc7, + 0xd6, 0xfa, 0xd0, 0x5c, 0xfe, 0xaa, 0xc8, 0xa5, + 0xd2, 0xd1, 0x05, 0xa6, 0x91, 0x97, 0xc5, 0xd1, + 0x84, 0x70, 0x41, 0xd7, 0x4b, 0x55, 0x23, 0xf0, + 0x92, 0x30, 0x97, 0x2d, 0xa5, 0x72, 0x18, 0x46, + 0xf8, 0x15, 0x3e, 0xe7, 0xd7, 0x19, 0x8f, 0x17, + 0x06, 0xa2, 0x97, 0xe8, 0x39, 0xe0, 0x4d, 0x72, + 0x3a, 0x68, 0x73, 0xa4, 0x0b, 0x88, 0x86, 0x34, + 0x1d, 0xb6, 0x84, 0x99, 0x97, 0xd5, 0xb2, 0x3b, + 0x16, 0x32, 0x60, 0x3c, 0x7d, 0x61, 0x0b, 0x77, + 0xea, 0xe5, 0xa4, 0x11, 0x8b, 0xf3, 0xf4, 0x0d, + 0xc2, 0x70, 0xe9, 0x31, 0x30, 0xc2, 0x35, 0x57, + 0xfb, 0x6a, 0xae, 0x0a, 0xeb, 0x85, 0x3f, 0xb9, + 0x2c, 0x58, 0x42, 0x4d, 0x64, 0x36, 0x8a, 0x59, + 0x09, 0x60, 0xb9, 0x07, 0xfb, 0xb1, 0x76, 0xf8, + 0x1c, 0xd3, 0xf7, 0x48, 0x4c, 0xaf, 0x53, 0xe2, + 0x1a, 0x41, 0x5a, 0xbc, 0xe0, 0x7c, 0x51, 0x11, + 0x5d, 0x01, 0xc1, 0x19, 0xc8, 0xb8, 0xf8, 0xe8, + 0x79, 0x87, 0x32, 0x76, 0x6d, 0xb0, 0xa9, 0x10, + 0x7d, 0x83, 0xb6, 0xde, 0xea, 0x6d, 0x87, 0x50, + 0xa8, 0xe0, 0xd7, 0x99, 0x98, 0x46, 0x4d, 0x8e, + 0xb6, 0x43, 0x12, 0x06, 0xe0, 0xf1, 0x0a, 0x9c, + 0x6b, 0xe9, 0x17, 0x28, 0xe2, 0xa7, 0x53, 0x49, + 0xef, 0x3c, 0x68, 0x90, 0x33, 0x34, 0xb5, 0x1f, + 0x2b, 0x65, 0xea, 0x77, 0xa9, 0x61, 0xdf, 0x01, + 0xb8, 0x0c, 0xd4, 0x24, 0x46, 0xf8, 0xdd, 0x9f, + 0xe6, 0x96, 0x08, 0x90, 0x05, 0x12, 0x59, 0x07, + 0x60, 0x74, 0x2a, 0xfe, 0x1b, 0xac, 0x46, 0x86, + 0xa8, 0x83, 0x40, 0xb5, 0xa1, 0xc1, 0x28, 0xad, + 0x44, 0xba, 0x0a, 0xa7, 0x00, 0x0d, 0xed, 0x98, + 0x01, 0x1b, 0x51, 0x93, 0xa8, 0x35, 0xf4, 0x50, + 0x45, 0xfe, 0xfe, 0xad, 0x1f, 0x94, 0x73, 0xbc, + 0xca, 0x00, 0x2e, 0x6c, 0xc9, 0x59, 0x45, 0x9b, + 0x13, 0x9a, 0x4c, 0x61, 0xa5, 0xae, 0x47, 0x7c, + 0xdc, 0x05, 0xde, 0xbe, 0xf8, 0xe1, 0x3a, 0x08, + 0x75, 0x1c, 0x70, 0x9e, 0xf6, 0xec, 0x9d, 0x4c, + 0x19, 0xcb, 0x1c, 0x0a, 0x69, 0xbd, 0x14, 0x09, + 0xa3, 0x81, 0x08, 0x34, 0x54, 0x5b, 0x29, 0x13, + 0xa7, 0xc5, 0x20, 0x71, 0x31, 0xc4, 0x41, 0x40, + 0xe3, 0xff, 0x72, 0x88, 0x9d, 0x05, 0x2c, 0x4d, + 0xcb, 0xc9, 0x4b, 0xeb, 0xd6, 0xe4, 0xe0, 0x61, + 0x92, 0x3f, 0xb0, 0xe7, 0x04, 0x04, 0xa1, 0x06, + 0x83, 0xd9, 0x94, 0x8f, 0x28, 0x8d, 0xb1, 0xcc, + 0x89, 0x42, 0xd9, 0x23, 0x5b, 0x5c, 0xf1, 0x2c, + 0x9d, 0x40, 0xf0, 0xa7, 0xad, 0x99, 0x5f, 0x19, + 0xc7, 0x29, 0x6d, 0x2c, 0x23, 0x45, 0x7e, 0x46, + 0x26, 0x97, 0xb0, 0x11, 0xd7, 0x3f, 0xd2, 0xb2, + 0x02, 0x4f, 0x41, 0xc4, 0x7d, 0xbd, 0x6f, 0x51, + 0xe7, 0xdd, 0x0b, 0x41, 0x56, 0x51, 0xf0, 0x17, + 0xe3, 0x89, 0x4d, 0xed, 0xc7, 0xd4, 0x82, 0x46, + 0xbb, 0x53, 0xcf, 0x1f, 0xbf, 0x10, 0x47, 0x75, + 0x0b, 0x4f, 0xc6, 0xb8, 0xc6, 0xb4, 0x30, 0x6b, + 0x20, 0x28, 0x31, 0xa9, 0x60, 0xaf, 0x61, 0xe2, + 0xa1, 0x0d, 0x3b, 0x46, 0xda, 0xef, 0xcf, 0x41, + 0x9f, 0xe8, 0xac, 0xf3, 0x09, 0xf9, 0x39, 0xe5, + 0xaf, 0x81, 0x3c, 0x51, 0x70, 0x8b, 0x8b, 0xad, + 0x90, 0x5b, 0x29, 0x97, 0x84, 0xa6, 0x4f, 0x7a, + 0xd7, 0x9d, 0x5e, 0x23, 0xb1, 0x27, 0x06, 0x3f, + 0x6e, 0xb4, 0x7b, 0x35, 0xfc, 0xea, 0x3a, 0x6b, + 0x87, 0x54, 0x53, 0xa3, 0xd6, 0xa3, 0x9a, 0x9c, + 0x1b, 0x78, 0x07, 0x82, 0xb8, 0x50, 0x8d, 0x69, + 0x3a, 0x95, 0xe8, 0x50, 0x56, 0x1a, 0xaf, 0x06, + 0xc3, 0xe0, 0xd7, 0x1f, 0xdf, 0x61, 0xc7, 0x25, + 0xa2, 0x30, 0x3a, 0x08, 0xd6, 0xc0, 0x7d, 0x17, + 0xbb, 0x00, 0x4f, 0xf0, 0xc8, 0x96, 0x38, 0x32, + 0xa8, 0xe0, 0x87, 0x85, 0x37, 0x65, 0x3c, 0x7a, + 0xfa, 0xf4, 0xf5, 0x16, 0x17, 0xf4, 0xf1, 0x53, + 0xb4, 0x76, 0x64, 0x97, 0x53, 0xee, 0x26, 0xcc, + 0x32, 0x5c, 0x05, 0x1a, 0x33, 0x02, 0x1b, 0x66, + 0x2a, 0xd9, 0x8f, 0x54, 0xfc, 0xf1, 0xb8, 0x75, + 0x71, 0xb6, 0xce, 0xc4, 0x17, 0x5e, 0xef, 0xab, + 0xb9, 0x5f, 0xb0, 0x56, 0xc8, 0xed, 0x75, 0x2e, + 0xfc, 0x07, 0x80, 0x71, 0xa4, 0x1f, 0xa7, 0x83, + 0x6f, 0x41, 0x1e, 0x89, 0x9c, 0x91, 0x8c, 0x88, + 0xe5, 0x21, 0x0d, 0x72, 0xbe, 0x0e, 0xc3, 0xa9, + 0x5a, 0x02, 0x5d, 0xc3, 0x1f, 0x78, 0xfa, 0xef, + 0x2d, 0xd1, 0x19, 0x60, 0xe4, 0x2b, 0x3c, 0x1a, + 0x37, 0x6c, 0x8e, 0xfe, 0x5f, 0xa6, 0x6b, 0x40, + 0x79, 0x16, 0xa8, 0x60, 0x6f, 0x4f, 0x98, 0x42, + 0xd4, 0x73, 0x2b, 0xc1, 0xd1, 0x47, 0x1d, 0x79, + 0x5f, 0xb1, 0xae, 0xf3, 0xea, 0x67, 0x29, 0xc5, + 0x78, 0xb2, 0xd7, 0xa7, 0x32, 0xde, 0x40, 0x14, + 0x85, 0xd5, 0xbb, 0x2a, 0x39, 0x44, 0x4c, 0xd2, + 0x4c, 0xc1, 0xc5, 0x05, 0xc5, 0xc7, 0x26, 0xee, + 0x67, 0x5c, 0x37, 0x53, 0xc4, 0x99, 0x42, 0x60, + 0xf0, 0x7a, 0x1f, 0x21, 0x63, 0x4b, 0xf3, 0xa4, + 0x70, 0x2f, 0xd5, 0x00, 0x25, 0x65, 0x90, 0x34, + 0xa5, 0x19, 0x62, 0xdc, 0x64, 0x98, 0x46, 0x81, + 0x99, 0xa5, 0xe5, 0x28, 0x4c, 0x74, 0xe6, 0x49, + 0x21, 0x68, 0x07, 0x38, 0xa7, 0xee, 0xc5, 0x2f, + 0x01, 0x11, 0x2a, 0x6c, 0x86, 0x8c, 0x9a, 0x31, + 0x49, 0x6a, 0xd1, 0xd4, 0x01, 0x52, 0x72, 0xbb, + 0x07, 0x12, 0x54, 0x6f, 0xa5, 0xad, 0xbe, 0xf2, + 0x12, 0x7d, 0x83, 0xe5, 0x13, 0xa4, 0xdd, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0x0c, 0x10, 0x18, 0x1c, 0x1f + }; + + /* ML-DSA-87 externalMu: deterministic, tcId 151 + * Source: kh-fork-fips/wolfACVP/v7.0.0-known/ + * ML-DSA-sigGen-request.json. Deterministic mode + * uses rnd = 0^32 per FIPS 204 Section 3.7. */ + static const byte sk_87_mu[] = { + 0x89, 0x39, 0x24, 0xc8, 0xaa, 0x0a, 0xb4, 0xef, + 0x46, 0xc6, 0x5f, 0x73, 0xf9, 0xea, 0x76, 0x52, + 0xa9, 0xd5, 0x3d, 0xe7, 0x96, 0x40, 0x37, 0xd7, + 0x35, 0xd5, 0xf3, 0x13, 0xe3, 0x23, 0xbf, 0x27, + 0x64, 0x3e, 0x10, 0x7d, 0x3a, 0x19, 0xd3, 0x86, + 0x0a, 0x0c, 0x97, 0x2a, 0xaa, 0xda, 0x74, 0xb6, + 0xbd, 0x6d, 0xf2, 0xb7, 0x04, 0xa4, 0x3c, 0x83, + 0x90, 0xf3, 0xb4, 0xab, 0xc9, 0x35, 0xd1, 0xd7, + 0x60, 0x7c, 0x02, 0x01, 0x83, 0x00, 0x24, 0xa6, + 0x14, 0x85, 0xad, 0xec, 0x1f, 0x28, 0xf8, 0xd4, + 0xa1, 0x55, 0xe5, 0x9f, 0xf5, 0x75, 0x08, 0x1d, + 0x45, 0x79, 0x89, 0xbe, 0x4c, 0x9f, 0x78, 0x28, + 0x13, 0x0d, 0x73, 0x1b, 0x6d, 0xd7, 0x88, 0x39, + 0x80, 0xc8, 0x81, 0x5a, 0xf8, 0xc5, 0xd1, 0x3d, + 0x17, 0x10, 0x14, 0x94, 0xa1, 0x85, 0x02, 0xb4, + 0x06, 0xeb, 0x42, 0x9c, 0xf8, 0x4b, 0xd4, 0x3a, + 0x8c, 0xc4, 0x30, 0x83, 0xc4, 0x41, 0xd3, 0x38, + 0x81, 0xa0, 0xb4, 0x60, 0xa0, 0x30, 0x71, 0xcb, + 0x94, 0x91, 0x9a, 0x36, 0x0e, 0xe4, 0x36, 0x21, + 0x18, 0xb6, 0x4d, 0x24, 0x82, 0x04, 0x9c, 0x36, + 0x02, 0x03, 0x47, 0x0d, 0x48, 0x42, 0x0a, 0x90, + 0x80, 0x24, 0x40, 0x38, 0x71, 0x59, 0x48, 0x6e, + 0x14, 0x28, 0x90, 0x5c, 0x48, 0x12, 0x22, 0x80, + 0x80, 0x19, 0x14, 0x72, 0xd8, 0xa2, 0x09, 0xd0, + 0x10, 0x61, 0x04, 0xc8, 0x45, 0x08, 0x34, 0x85, + 0x03, 0x15, 0x66, 0x21, 0xb9, 0x6d, 0x88, 0x08, + 0x81, 0x51, 0x16, 0x32, 0x4c, 0x90, 0x91, 0x44, + 0x36, 0x70, 0xc2, 0x96, 0x60, 0x1a, 0x94, 0x61, + 0xd9, 0x06, 0x32, 0xe3, 0x20, 0x62, 0x11, 0xb0, + 0x90, 0x99, 0x02, 0x28, 0x1a, 0x10, 0x85, 0xc1, + 0x38, 0x4a, 0x01, 0x09, 0x29, 0x19, 0x22, 0x8a, + 0x20, 0xc3, 0x4c, 0x9c, 0x80, 0x85, 0x0a, 0x37, + 0x31, 0x1b, 0x95, 0x09, 0x18, 0xa1, 0x60, 0x9b, + 0x88, 0x2d, 0x04, 0xa8, 0x50, 0x22, 0x95, 0x6d, + 0x19, 0x42, 0x22, 0x19, 0x20, 0x89, 0x08, 0x49, + 0x46, 0xda, 0x96, 0x29, 0x20, 0x32, 0x84, 0x53, + 0x14, 0x4c, 0x0b, 0x92, 0x0c, 0x92, 0xa6, 0x25, + 0xe0, 0xc8, 0x30, 0xca, 0xa8, 0x40, 0x1a, 0xa9, + 0x20, 0x42, 0xa6, 0x21, 0x41, 0x04, 0x29, 0xdb, + 0xa8, 0x21, 0x23, 0x40, 0x68, 0x91, 0x12, 0x31, + 0x14, 0xb0, 0x31, 0xd8, 0x88, 0x00, 0x59, 0xb2, + 0x85, 0x12, 0xc1, 0x49, 0xa3, 0x02, 0x2a, 0x0b, + 0x01, 0x6a, 0x23, 0x13, 0x48, 0x0c, 0x92, 0x41, + 0x1a, 0xc2, 0x08, 0x21, 0xc0, 0x6c, 0x08, 0x47, + 0x4e, 0x22, 0x10, 0x26, 0xd4, 0x98, 0x24, 0x8a, + 0xc0, 0x6c, 0xcb, 0x88, 0x68, 0x60, 0x88, 0x00, + 0xc2, 0x00, 0x88, 0x40, 0x00, 0x26, 0x10, 0x10, + 0x21, 0x10, 0x05, 0x08, 0xd0, 0x86, 0x09, 0xc2, + 0x48, 0x71, 0x92, 0x36, 0x8d, 0x0b, 0x33, 0x8c, + 0x5b, 0x22, 0x82, 0x0b, 0x07, 0x31, 0x04, 0x04, + 0x10, 0xd1, 0x08, 0x40, 0x59, 0x90, 0x24, 0x5a, + 0x06, 0x46, 0x22, 0xb2, 0x0d, 0x91, 0x46, 0x2c, + 0x1b, 0x49, 0x6d, 0x59, 0x88, 0x51, 0x50, 0x36, + 0x61, 0xc4, 0xc4, 0x20, 0xe3, 0x12, 0x0a, 0x82, + 0x10, 0x0c, 0x88, 0x08, 0x00, 0xa4, 0x26, 0x45, + 0xd0, 0x14, 0x6e, 0xe4, 0xc6, 0x91, 0x99, 0x38, + 0x92, 0xe3, 0x08, 0x2a, 0x99, 0x04, 0x4a, 0x42, + 0x08, 0x41, 0x0a, 0x90, 0x80, 0xc2, 0xa8, 0x08, + 0xd2, 0xa8, 0x20, 0xa2, 0x40, 0x8c, 0x4b, 0x04, + 0x71, 0xe1, 0x92, 0x4d, 0x54, 0x34, 0x64, 0x03, + 0x03, 0x62, 0x92, 0xb4, 0x30, 0x44, 0xa8, 0x25, + 0x0b, 0x10, 0x41, 0x9a, 0x26, 0x6a, 0xd1, 0xa6, + 0x91, 0x12, 0xc7, 0x68, 0x98, 0xb8, 0x04, 0x21, + 0xb5, 0x09, 0x4a, 0x94, 0x28, 0x19, 0x36, 0x2d, + 0x09, 0x89, 0x90, 0xd9, 0x80, 0x21, 0x59, 0xb4, + 0x21, 0x80, 0x30, 0x0c, 0x08, 0xa4, 0x29, 0xcc, + 0xb4, 0x69, 0x9a, 0x28, 0x4c, 0x01, 0x40, 0x2e, + 0x1b, 0x94, 0x01, 0xd2, 0xc4, 0x70, 0x0a, 0xb3, + 0x4d, 0xd3, 0x06, 0x84, 0xa2, 0x08, 0x0e, 0x0c, + 0x14, 0x64, 0x60, 0x90, 0x6c, 0x22, 0x31, 0x60, + 0x52, 0x16, 0x31, 0xc8, 0x16, 0x8a, 0x23, 0x05, + 0x28, 0xa3, 0x16, 0x51, 0xa4, 0x04, 0x30, 0x64, + 0xb2, 0x11, 0x8c, 0x80, 0x71, 0xc1, 0x32, 0x4d, + 0x58, 0x96, 0x41, 0x02, 0x44, 0x2a, 0x9c, 0x38, + 0x40, 0x24, 0x80, 0x51, 0xa3, 0x40, 0x05, 0xa2, + 0xc2, 0x80, 0xd3, 0x34, 0x2e, 0x0b, 0x31, 0x61, + 0x21, 0x18, 0x2c, 0x51, 0x20, 0x25, 0x24, 0x92, + 0x48, 0x22, 0x04, 0x0a, 0x49, 0x22, 0x65, 0xa2, + 0x02, 0x88, 0x10, 0x86, 0x89, 0x5b, 0x94, 0x40, + 0x14, 0x33, 0x46, 0x09, 0x26, 0x66, 0xcb, 0x92, + 0x2c, 0xc1, 0x16, 0x82, 0x52, 0xc4, 0x4d, 0x01, + 0x10, 0x52, 0x5c, 0x84, 0x60, 0x4c, 0x08, 0x4c, + 0x01, 0xb5, 0x64, 0xdb, 0x82, 0x6c, 0x8b, 0xb2, + 0x8d, 0x04, 0x09, 0x90, 0x14, 0x44, 0x26, 0x0c, + 0x40, 0x81, 0xd2, 0x40, 0x28, 0xa1, 0x04, 0x6c, + 0xcb, 0x40, 0x2e, 0x14, 0xa9, 0x50, 0x23, 0x17, + 0x11, 0x41, 0xb0, 0x90, 0x08, 0x48, 0x51, 0x5a, + 0x20, 0x6e, 0x23, 0xc8, 0x05, 0x62, 0xb4, 0x2c, + 0xd2, 0x44, 0x2c, 0x14, 0x93, 0x48, 0x9b, 0x46, + 0x4a, 0x12, 0xb5, 0x0d, 0x63, 0x48, 0x00, 0xc8, + 0x10, 0x26, 0xa3, 0x14, 0x90, 0x1c, 0x48, 0x71, + 0x54, 0xc6, 0x6c, 0xdc, 0x38, 0x0d, 0x19, 0x30, + 0x6a, 0xd2, 0x44, 0x92, 0x80, 0x08, 0x51, 0xcc, + 0xc0, 0x8d, 0x1b, 0x07, 0x28, 0x12, 0xb5, 0x08, + 0x89, 0x16, 0x04, 0x08, 0xb4, 0x50, 0x5c, 0x94, + 0x11, 0x21, 0x42, 0x89, 0x21, 0xc5, 0x2c, 0x1b, + 0x12, 0x48, 0x20, 0x08, 0x69, 0x01, 0x46, 0x40, + 0xdc, 0xb2, 0x49, 0xd2, 0x98, 0x84, 0x5c, 0x04, + 0x4d, 0xa3, 0x16, 0x88, 0x8c, 0xa0, 0x44, 0xe4, + 0x92, 0x64, 0x14, 0x92, 0x88, 0x53, 0x24, 0x05, + 0x94, 0x22, 0x32, 0x14, 0x15, 0x25, 0x60, 0x18, + 0x82, 0xa4, 0xa2, 0x4d, 0x1c, 0x34, 0x46, 0x90, + 0xc4, 0x2d, 0x20, 0xb0, 0x21, 0x14, 0x31, 0x50, + 0x01, 0x39, 0x30, 0x20, 0x97, 0x8d, 0x20, 0x27, + 0x10, 0xa1, 0x10, 0x45, 0x51, 0x92, 0x00, 0x94, + 0x24, 0x10, 0x14, 0x08, 0x05, 0x24, 0x40, 0x04, + 0xc4, 0xc6, 0x11, 0x61, 0x08, 0x25, 0x08, 0xc2, + 0x21, 0xc2, 0x28, 0x4e, 0x02, 0x83, 0x61, 0x03, + 0x46, 0x46, 0x52, 0x24, 0x61, 0xa0, 0x84, 0x2c, + 0x0a, 0x40, 0x6e, 0x19, 0x49, 0x68, 0x10, 0x08, + 0x8c, 0xe3, 0x90, 0x21, 0x5b, 0xa4, 0x40, 0x8c, + 0xc0, 0x4d, 0xa4, 0xc8, 0x84, 0x4c, 0x22, 0x29, + 0x14, 0x08, 0x31, 0xa3, 0x44, 0x21, 0x24, 0x97, + 0x8c, 0x00, 0xc0, 0x09, 0x84, 0x34, 0x00, 0x8a, + 0x86, 0x88, 0x49, 0x30, 0x49, 0x58, 0x36, 0x4a, + 0x23, 0x81, 0x6d, 0x08, 0xa3, 0x89, 0xdb, 0x40, + 0x20, 0x50, 0x48, 0x02, 0x23, 0x30, 0x69, 0x18, + 0x16, 0x22, 0x42, 0x28, 0x00, 0x61, 0x82, 0x0d, + 0x0a, 0x18, 0x12, 0x5a, 0x22, 0x52, 0x19, 0x32, + 0x0c, 0x04, 0xa4, 0x11, 0x24, 0x35, 0x91, 0x02, + 0x24, 0x41, 0x02, 0x42, 0x44, 0xe2, 0x90, 0x09, + 0xe1, 0x28, 0x24, 0x18, 0xb2, 0x51, 0x1b, 0x13, + 0x86, 0x93, 0xa4, 0x8d, 0x44, 0x08, 0x04, 0x12, + 0x27, 0x08, 0x8a, 0x96, 0x50, 0x92, 0x36, 0x4d, + 0xc2, 0x32, 0x60, 0xe2, 0x98, 0x2d, 0xd1, 0x30, + 0x89, 0xe2, 0x34, 0x06, 0x19, 0xc1, 0x41, 0x00, + 0x44, 0x0d, 0x52, 0x46, 0x64, 0x20, 0xa7, 0x2d, + 0x8a, 0x88, 0x85, 0x08, 0xc8, 0x31, 0x52, 0x26, + 0x82, 0x08, 0x19, 0x01, 0x63, 0x28, 0x2a, 0xc3, + 0x08, 0x04, 0x11, 0x35, 0x20, 0x03, 0x17, 0x6d, + 0xda, 0x32, 0x06, 0x58, 0x16, 0x68, 0x0a, 0x40, + 0x0c, 0x8a, 0xa4, 0x51, 0xa0, 0x16, 0x52, 0x0a, + 0x83, 0x08, 0x90, 0xb4, 0x8c, 0x01, 0x97, 0x2c, + 0x19, 0x88, 0x00, 0x9b, 0x80, 0x68, 0x1b, 0x24, + 0x0e, 0x5c, 0x18, 0x6d, 0x1b, 0x31, 0x2d, 0x5a, + 0x24, 0x09, 0x9c, 0xa2, 0x25, 0x59, 0x26, 0x90, + 0xa0, 0xa4, 0x08, 0x93, 0x40, 0x4a, 0xd0, 0x86, + 0x4c, 0x24, 0xa2, 0x50, 0x09, 0x04, 0x12, 0x24, + 0x13, 0x65, 0x50, 0x30, 0x6a, 0x01, 0x86, 0x8c, + 0x0a, 0x97, 0x45, 0xc3, 0xc8, 0x09, 0x48, 0x40, + 0x01, 0x1a, 0x98, 0x50, 0x9b, 0x38, 0x04, 0x13, + 0xa5, 0x08, 0xe3, 0x86, 0x44, 0x24, 0x45, 0x06, + 0x82, 0x32, 0x48, 0x83, 0x22, 0x6d, 0x0b, 0x32, + 0x08, 0x08, 0x01, 0x44, 0xd9, 0x24, 0x80, 0x58, + 0xc4, 0x2c, 0x9a, 0x38, 0x01, 0x62, 0xa6, 0x28, + 0x80, 0x92, 0x01, 0x1a, 0x09, 0x2d, 0xe0, 0x06, + 0x6a, 0x64, 0x36, 0x12, 0xc2, 0x94, 0x0c, 0x0c, + 0x45, 0x4c, 0x98, 0x36, 0x8a, 0xdb, 0x26, 0x09, + 0x5c, 0x44, 0x4e, 0xa4, 0x80, 0x8c, 0x24, 0x22, + 0x86, 0x9b, 0x12, 0x32, 0xcb, 0x48, 0x84, 0x13, + 0x49, 0x52, 0x63, 0x00, 0x24, 0x8b, 0x30, 0x2d, + 0x23, 0xb8, 0x0d, 0x82, 0x48, 0x91, 0x18, 0x29, + 0x71, 0xd3, 0x00, 0x05, 0x83, 0x96, 0x70, 0x20, + 0x19, 0x25, 0x9a, 0x22, 0x6d, 0x21, 0x30, 0x71, + 0x9b, 0x16, 0x2e, 0xe4, 0x06, 0x2c, 0xdc, 0x40, + 0x82, 0x04, 0xc6, 0x2c, 0x49, 0xc0, 0x64, 0x04, + 0x49, 0x6e, 0x13, 0x82, 0x69, 0x51, 0x80, 0x04, + 0x88, 0x08, 0x64, 0x88, 0x08, 0x10, 0x0c, 0x82, + 0x45, 0x5a, 0x32, 0x46, 0x91, 0x30, 0x2c, 0x81, + 0x84, 0x84, 0x1a, 0xb2, 0x01, 0x00, 0x33, 0x05, + 0x4b, 0x42, 0x12, 0x9a, 0x02, 0x90, 0x62, 0x40, + 0x8e, 0x44, 0x38, 0x89, 0x90, 0xc8, 0x45, 0x92, + 0x28, 0x61, 0x8b, 0x88, 0x68, 0x0b, 0x43, 0x31, + 0x20, 0x43, 0x02, 0xa0, 0x86, 0x8c, 0xcb, 0x84, + 0x0c, 0x84, 0x18, 0x42, 0x24, 0xb3, 0x6d, 0x92, + 0x08, 0x01, 0x02, 0xc5, 0x60, 0x24, 0x36, 0x26, + 0x09, 0x13, 0x20, 0x5b, 0xc6, 0x64, 0x4c, 0xa8, + 0x0d, 0xda, 0x18, 0x09, 0x01, 0x40, 0x91, 0x13, + 0x04, 0x0d, 0x08, 0x99, 0x00, 0x82, 0x94, 0x84, + 0x91, 0x42, 0x92, 0xa2, 0x08, 0x70, 0x10, 0xa8, + 0x8c, 0xa2, 0x44, 0x42, 0x91, 0x02, 0x26, 0xa2, + 0x46, 0x02, 0x24, 0x02, 0x8d, 0x5c, 0x44, 0x2d, + 0x5b, 0x02, 0x90, 0xa2, 0x02, 0x0e, 0x24, 0x07, + 0x80, 0x43, 0x18, 0x6a, 0x5b, 0x40, 0x65, 0x63, + 0xc6, 0x25, 0x9b, 0x06, 0x04, 0x89, 0xc6, 0x28, + 0x82, 0xa6, 0x09, 0x41, 0x42, 0x45, 0x21, 0xb5, + 0x81, 0x22, 0x90, 0x2c, 0xd9, 0x10, 0x2a, 0x92, + 0x12, 0x8e, 0x08, 0x39, 0x6d, 0x58, 0xa2, 0x0d, + 0x22, 0x30, 0x04, 0x82, 0x38, 0x24, 0x4c, 0x02, + 0x28, 0x89, 0x34, 0x89, 0x50, 0xc6, 0x50, 0xc0, + 0x46, 0x90, 0xd8, 0xb0, 0x21, 0x23, 0xa5, 0x88, + 0x60, 0x18, 0x0e, 0x98, 0x12, 0x6e, 0x11, 0x37, + 0x69, 0x11, 0x90, 0x6c, 0xc3, 0x98, 0x8c, 0x42, + 0x24, 0x26, 0x83, 0xa2, 0x49, 0xe1, 0x88, 0x2d, + 0x89, 0x34, 0x08, 0x43, 0x26, 0x6a, 0x88, 0xb8, + 0x45, 0x53, 0x14, 0x04, 0x21, 0x49, 0x09, 0x5c, + 0x90, 0x60, 0x0a, 0x91, 0x8d, 0x4b, 0x14, 0x11, + 0x41, 0x18, 0x86, 0xc1, 0x16, 0x2d, 0x21, 0x84, + 0x68, 0x0c, 0x24, 0x2e, 0x01, 0x90, 0x25, 0xd2, + 0x82, 0x60, 0x10, 0x12, 0x4c, 0x90, 0x88, 0x70, + 0x12, 0x47, 0x82, 0x0a, 0x81, 0x29, 0x80, 0x14, + 0x61, 0xd0, 0x94, 0x29, 0x0a, 0x33, 0x84, 0x00, + 0x23, 0x22, 0x19, 0xb6, 0x90, 0xd8, 0xa6, 0x11, + 0x24, 0xb5, 0x28, 0x03, 0x33, 0x2c, 0x99, 0xb8, + 0x20, 0x93, 0x94, 0x60, 0x14, 0x15, 0x42, 0x1b, + 0x33, 0x4a, 0x0c, 0x11, 0x60, 0x44, 0x08, 0x0c, + 0x90, 0x1e, 0xbe, 0x99, 0x12, 0x31, 0x63, 0xc3, + 0xde, 0x98, 0x3a, 0x0e, 0xac, 0xba, 0x33, 0x79, + 0x50, 0xdf, 0x00, 0x3c, 0xab, 0xca, 0xd0, 0xb9, + 0x4c, 0x51, 0xd9, 0x1f, 0x70, 0x68, 0x0e, 0xe6, + 0x43, 0xf9, 0x18, 0xe2, 0x0b, 0x79, 0xb6, 0x6e, + 0xa3, 0x29, 0xe3, 0x2b, 0x96, 0xbd, 0xb1, 0xf4, + 0x20, 0x64, 0x98, 0x25, 0xc2, 0x01, 0x1b, 0x1e, + 0xc0, 0xf8, 0x9b, 0xa8, 0x91, 0xfc, 0x75, 0x08, + 0x8b, 0x9c, 0x9b, 0x3b, 0x54, 0x0c, 0x40, 0x7d, + 0x86, 0xa0, 0x90, 0x5e, 0x19, 0x55, 0xf0, 0xb5, + 0x22, 0x93, 0xbb, 0x1a, 0x6a, 0x83, 0xda, 0x0a, + 0xe8, 0x3b, 0x8f, 0xa8, 0x96, 0x09, 0x8a, 0xa4, + 0xcd, 0x12, 0xa0, 0xe8, 0x3f, 0x36, 0xdd, 0xc4, + 0x40, 0xdf, 0xea, 0xbf, 0x56, 0x41, 0x38, 0x9f, + 0x4d, 0xca, 0x4b, 0xe1, 0x5e, 0x1e, 0x6b, 0x3e, + 0x91, 0x7b, 0xa2, 0x48, 0x38, 0x0f, 0xc9, 0xfd, + 0xb7, 0x0b, 0x22, 0x29, 0x74, 0x42, 0x82, 0x84, + 0x33, 0x11, 0x76, 0x42, 0x29, 0x73, 0xf8, 0x55, + 0x9f, 0x81, 0xee, 0x95, 0x80, 0xbe, 0x2c, 0xd9, + 0x69, 0xad, 0x8a, 0x45, 0x8a, 0xa4, 0xbb, 0xcb, + 0x82, 0x75, 0x4d, 0x70, 0xc5, 0x1d, 0x46, 0x57, + 0x1d, 0x76, 0xd1, 0xc1, 0xfc, 0xe7, 0xab, 0x71, + 0x3d, 0x3f, 0xfe, 0x6d, 0x9f, 0x97, 0x7d, 0x4d, + 0x68, 0xc8, 0x6d, 0x04, 0xe5, 0xcd, 0x5f, 0xca, + 0x16, 0xa3, 0x18, 0xa9, 0xda, 0x41, 0xd6, 0x21, + 0x40, 0xce, 0x86, 0x6c, 0xee, 0x71, 0xe8, 0x14, + 0xb3, 0x6d, 0x2c, 0x78, 0x38, 0x85, 0xcc, 0xe6, + 0xce, 0xc6, 0x25, 0x30, 0x41, 0x78, 0xa7, 0x6a, + 0x94, 0x71, 0x0e, 0xfb, 0xb3, 0x90, 0xcc, 0xb6, + 0x3a, 0x95, 0xcd, 0xac, 0xab, 0x93, 0xfe, 0x2c, + 0xcf, 0x00, 0x9c, 0x41, 0xfc, 0x6b, 0x67, 0xa9, + 0xf7, 0x40, 0xf9, 0xfa, 0x1e, 0x23, 0x23, 0x11, + 0xa3, 0x99, 0x00, 0xbd, 0xec, 0x4a, 0x71, 0x24, + 0x64, 0x77, 0x82, 0x1c, 0x48, 0x1a, 0xfd, 0x79, + 0xa9, 0x25, 0x02, 0x91, 0xa0, 0x81, 0x19, 0x98, + 0x63, 0x6c, 0x1f, 0x0e, 0x02, 0xc3, 0xa6, 0x7c, + 0xe3, 0x5d, 0xae, 0xfc, 0xf0, 0x58, 0x8f, 0x2a, + 0xd8, 0x18, 0xdc, 0xf8, 0x43, 0xeb, 0x07, 0x6f, + 0x08, 0xf7, 0x10, 0xf1, 0x09, 0x27, 0x51, 0x38, + 0xfa, 0x3b, 0xaf, 0xd2, 0x98, 0x8c, 0xb6, 0xa4, + 0x08, 0xfe, 0x1f, 0xf4, 0xc9, 0xf5, 0x98, 0x67, + 0x1a, 0xf3, 0x1a, 0xb3, 0x08, 0x7f, 0x3a, 0x25, + 0xd5, 0x95, 0xc8, 0x48, 0x30, 0xfb, 0x2e, 0x5c, + 0x3e, 0x7b, 0x82, 0x8d, 0xe0, 0x2c, 0xd8, 0x45, + 0x7e, 0xd0, 0x13, 0x8e, 0xb8, 0x80, 0x63, 0x00, + 0xa0, 0x54, 0x6c, 0x7e, 0x08, 0xde, 0x37, 0xbc, + 0x30, 0xa1, 0x96, 0x41, 0x18, 0x99, 0xfc, 0xa5, + 0xac, 0x0c, 0x1f, 0x0d, 0xcd, 0x43, 0xde, 0x47, + 0xa8, 0x6e, 0x0d, 0x6e, 0x01, 0xe1, 0xc1, 0x71, + 0xb7, 0x6b, 0x35, 0x01, 0x27, 0xc4, 0x34, 0xde, + 0xfb, 0x2e, 0xa1, 0xf7, 0xdb, 0x53, 0xc6, 0x63, + 0xec, 0x5e, 0x70, 0x7c, 0x6e, 0x60, 0x4b, 0x6a, + 0x5b, 0x90, 0x2d, 0x33, 0x23, 0x61, 0xe1, 0x91, + 0x42, 0xdb, 0x04, 0x3f, 0x5b, 0x75, 0x85, 0xe4, + 0xc8, 0x60, 0x7e, 0xfd, 0x11, 0x40, 0x48, 0xcd, + 0xb4, 0x82, 0x29, 0x14, 0x7f, 0x36, 0x78, 0xa5, + 0x28, 0xe8, 0xff, 0x31, 0xd9, 0x43, 0xca, 0x4a, + 0xd6, 0x43, 0xd3, 0x6b, 0xcc, 0x70, 0x75, 0x4f, + 0xf2, 0x68, 0x45, 0x18, 0xfe, 0x8c, 0x0f, 0x3e, + 0x75, 0x29, 0x0e, 0x52, 0xed, 0x88, 0x04, 0xeb, + 0x3a, 0x7f, 0x64, 0x64, 0xfa, 0x60, 0x84, 0x79, + 0x43, 0x56, 0xe6, 0xc7, 0xa5, 0x0f, 0x0d, 0x71, + 0xc8, 0xe1, 0x6d, 0x39, 0x2d, 0xab, 0xd6, 0x8e, + 0xd0, 0x57, 0x9c, 0xfc, 0x75, 0x5a, 0x77, 0x48, + 0x4f, 0xbc, 0xf9, 0xb9, 0xb2, 0xd8, 0xc9, 0xd1, + 0xbf, 0xf3, 0xb9, 0x51, 0x96, 0xcd, 0xae, 0x15, + 0x72, 0x61, 0xbf, 0x39, 0xc3, 0x7b, 0xaf, 0x78, + 0x00, 0xd8, 0x6a, 0x5f, 0x97, 0x7f, 0x07, 0x2f, + 0xf9, 0x0f, 0x8b, 0xeb, 0x88, 0x77, 0x4b, 0x14, + 0x63, 0xf2, 0x32, 0x2b, 0xd0, 0x19, 0x95, 0xc9, + 0x90, 0xbd, 0xee, 0xa9, 0x03, 0x38, 0x2b, 0x0f, + 0x3d, 0x1b, 0x8e, 0xe8, 0x7d, 0x26, 0x1f, 0x03, + 0x1c, 0xf6, 0x70, 0x67, 0x4c, 0xf2, 0x08, 0xd3, + 0xa5, 0xc3, 0x93, 0xce, 0x6c, 0xad, 0x53, 0x7f, + 0x7b, 0x29, 0x2e, 0x98, 0xd1, 0xa0, 0xa6, 0x99, + 0x34, 0x7e, 0xe2, 0x9e, 0x55, 0xf3, 0xce, 0xe7, + 0x35, 0x7b, 0xf2, 0xe6, 0x1c, 0x58, 0x0f, 0x87, + 0xcc, 0x7f, 0xda, 0xa4, 0x8a, 0xc8, 0x19, 0x3d, + 0xce, 0x3c, 0xfb, 0x02, 0x7d, 0x57, 0xc6, 0x84, + 0x17, 0x21, 0x54, 0xba, 0xb4, 0xc7, 0x78, 0x84, + 0xb8, 0xd6, 0x0c, 0x43, 0xef, 0x73, 0x6c, 0x86, + 0x53, 0x73, 0x03, 0xca, 0xe3, 0x96, 0xc2, 0x71, + 0x81, 0x29, 0x5e, 0xec, 0x18, 0xe1, 0x73, 0x99, + 0xaa, 0x36, 0x6b, 0xe1, 0x54, 0x59, 0xbe, 0x3a, + 0xe1, 0x5d, 0x11, 0x53, 0x07, 0x64, 0x09, 0x21, + 0x63, 0x7b, 0xc5, 0x5d, 0x30, 0x54, 0x5d, 0xb6, + 0xad, 0x98, 0x4e, 0xdc, 0x83, 0x89, 0xf5, 0xd5, + 0x82, 0x44, 0x18, 0x05, 0xd7, 0x4b, 0x18, 0x91, + 0xfb, 0x18, 0xee, 0x0e, 0x9f, 0x4e, 0x69, 0xdc, + 0x55, 0x8d, 0xaf, 0x6d, 0x3c, 0xdf, 0x5e, 0x78, + 0xf4, 0x09, 0x4b, 0x52, 0xcd, 0x42, 0xc2, 0x62, + 0xca, 0x1b, 0x3d, 0x40, 0xcb, 0x16, 0x10, 0xef, + 0x9f, 0xc0, 0x43, 0xcb, 0xcf, 0xd8, 0x85, 0xe1, + 0x4f, 0x16, 0xf7, 0xed, 0xaa, 0x3a, 0xb8, 0x9a, + 0x62, 0x6f, 0x57, 0xf3, 0x43, 0x3d, 0x74, 0x8f, + 0x23, 0xab, 0x60, 0x36, 0x89, 0xe5, 0xd9, 0x75, + 0x99, 0x86, 0x6b, 0xa1, 0x78, 0x57, 0xc6, 0xd1, + 0x1a, 0xc8, 0x33, 0x38, 0xe5, 0xd2, 0x2e, 0x36, + 0x2a, 0x5d, 0x83, 0x86, 0x6f, 0x2d, 0x52, 0xd8, + 0x9a, 0x50, 0xc9, 0x6b, 0xc6, 0x4d, 0x4c, 0x60, + 0x25, 0xc2, 0xb1, 0x97, 0xd1, 0xa2, 0x14, 0x8d, + 0xbc, 0x18, 0x8c, 0xc4, 0x69, 0xb4, 0x2b, 0x0c, + 0x4c, 0xe8, 0x00, 0xdc, 0xd4, 0x01, 0xfc, 0xeb, + 0x0a, 0xf3, 0x39, 0x4a, 0x29, 0x25, 0x50, 0x3f, + 0x13, 0x36, 0x0f, 0xf1, 0xcf, 0xc9, 0xf8, 0x14, + 0xe3, 0xf3, 0x0e, 0x55, 0xfd, 0x34, 0x01, 0x59, + 0xff, 0x3c, 0x75, 0xc3, 0xa4, 0x28, 0xe3, 0xd5, + 0xb6, 0xc5, 0xf3, 0xe1, 0x6b, 0xe4, 0x3d, 0x4b, + 0xd8, 0xcc, 0xcc, 0x04, 0x24, 0xed, 0xf4, 0x80, + 0x09, 0x1b, 0x55, 0x5a, 0xe5, 0xe9, 0x2c, 0xc0, + 0x0b, 0xc1, 0x73, 0x0b, 0xd4, 0xa7, 0xc8, 0x2b, + 0x9c, 0xdf, 0xb1, 0xd8, 0x3a, 0x3d, 0x9f, 0xf1, + 0x81, 0x57, 0x54, 0x16, 0x2a, 0x5b, 0x61, 0x48, + 0x0c, 0x7f, 0xe7, 0xef, 0x67, 0x18, 0x20, 0xd5, + 0xa2, 0xb1, 0x16, 0x84, 0x29, 0x5d, 0x9d, 0xc4, + 0xab, 0x4d, 0x8d, 0x5e, 0x8a, 0x7f, 0xc6, 0x96, + 0x81, 0xad, 0x66, 0x01, 0x43, 0x89, 0xba, 0x5e, + 0x53, 0xed, 0xad, 0x20, 0x4a, 0x8d, 0x15, 0x15, + 0x78, 0x2f, 0x69, 0x23, 0x77, 0x90, 0xdf, 0x16, + 0x95, 0x75, 0x0b, 0xad, 0x27, 0xf3, 0x17, 0x13, + 0x5b, 0x93, 0xeb, 0xcb, 0x00, 0x64, 0xcb, 0x6a, + 0x88, 0x88, 0xab, 0x07, 0x75, 0x02, 0xb0, 0x91, + 0xf0, 0xa0, 0x2a, 0x16, 0x7f, 0xf2, 0xf0, 0xcf, + 0xfc, 0xb1, 0x72, 0x08, 0x89, 0x3e, 0xa2, 0xed, + 0xe9, 0x89, 0x50, 0x69, 0x73, 0x7e, 0x13, 0x30, + 0xc8, 0x98, 0x31, 0x4e, 0xd0, 0xd4, 0x16, 0x1a, + 0x13, 0x48, 0x46, 0x16, 0xa9, 0xb6, 0xe5, 0x6e, + 0xe0, 0xa5, 0x89, 0x7f, 0xdc, 0xa8, 0x5c, 0x60, + 0x98, 0xb7, 0x13, 0x54, 0xa6, 0xbc, 0x8f, 0x73, + 0xb9, 0xcc, 0x4f, 0xab, 0xfe, 0xc7, 0xf2, 0x3b, + 0xad, 0x16, 0xff, 0x72, 0xfe, 0x06, 0xdd, 0xba, + 0xd2, 0x8a, 0xd7, 0xfe, 0x98, 0xa3, 0xb8, 0x5a, + 0x29, 0x38, 0x37, 0x60, 0x3f, 0x67, 0x14, 0x64, + 0xfb, 0xc5, 0xe8, 0x9b, 0x72, 0xa4, 0x42, 0x4d, + 0xb4, 0x84, 0xf4, 0x06, 0x35, 0x99, 0x02, 0x31, + 0xd7, 0x1e, 0xa6, 0x55, 0xe4, 0x40, 0xe5, 0x6b, + 0x3a, 0xcb, 0x94, 0x08, 0xc7, 0x22, 0x8e, 0x35, + 0x76, 0xb9, 0x25, 0x2a, 0xd3, 0x30, 0x47, 0xfa, + 0x55, 0xb1, 0x1f, 0xa2, 0x94, 0xd4, 0x64, 0x4e, + 0xd4, 0x8d, 0x4a, 0x41, 0x24, 0xbf, 0x33, 0x0c, + 0x34, 0x5f, 0x12, 0xd9, 0xd3, 0x86, 0xef, 0x65, + 0xb1, 0xcb, 0x69, 0x17, 0x6e, 0x2f, 0xcd, 0xf3, + 0x4e, 0x99, 0x48, 0xe8, 0xc9, 0x78, 0xf7, 0xaf, + 0x7d, 0xc9, 0x28, 0x6b, 0xcc, 0xda, 0x4c, 0x3e, + 0x5b, 0xeb, 0x31, 0xa9, 0xb2, 0xd7, 0x11, 0x44, + 0x8d, 0x6d, 0x8b, 0x27, 0x89, 0xeb, 0x8d, 0xe9, + 0x28, 0xcd, 0x4a, 0x72, 0x1a, 0x1a, 0x6e, 0x79, + 0x2c, 0x4f, 0x3e, 0x42, 0x3c, 0x33, 0xa3, 0x4a, + 0xbf, 0x1e, 0xd7, 0x64, 0x74, 0x72, 0x59, 0xc6, + 0x25, 0x20, 0x5f, 0xaf, 0x23, 0x12, 0xcd, 0x14, + 0x07, 0xd8, 0x2b, 0x5f, 0x67, 0x4e, 0xb0, 0x98, + 0x12, 0x3b, 0x39, 0xdf, 0x0b, 0x5f, 0xbe, 0x90, + 0x4b, 0x9f, 0xb1, 0xba, 0xab, 0x83, 0x47, 0xcd, + 0x60, 0x86, 0xe5, 0x0f, 0xee, 0xa5, 0xee, 0x78, + 0x7f, 0xa3, 0x53, 0x4f, 0x08, 0x96, 0xb0, 0x0f, + 0x71, 0x0b, 0x6e, 0xa2, 0x29, 0x46, 0x4d, 0xd8, + 0x29, 0x21, 0xec, 0x14, 0xc2, 0xcc, 0xcc, 0x23, + 0xcd, 0xd7, 0x9a, 0x14, 0xd8, 0x53, 0xaa, 0xc6, + 0x4e, 0x23, 0x8b, 0xf0, 0xa5, 0x8a, 0xf5, 0xd3, + 0x84, 0x00, 0x5c, 0x0e, 0xf7, 0xa9, 0x8e, 0x18, + 0x5b, 0x36, 0x91, 0x77, 0x98, 0xc7, 0x92, 0x7f, + 0xe7, 0x9a, 0xe6, 0x6b, 0xa3, 0x09, 0xe9, 0xe8, + 0xe3, 0x3e, 0xb9, 0xc4, 0xb8, 0xa7, 0xb6, 0xc7, + 0x38, 0xce, 0x8b, 0x5a, 0x54, 0xf3, 0xb0, 0x8b, + 0x73, 0xae, 0x3f, 0xb7, 0xf4, 0x2f, 0x01, 0x05, + 0x04, 0x31, 0xa3, 0xb8, 0x4f, 0xf2, 0xb0, 0xa6, + 0x75, 0x6f, 0xf4, 0x19, 0xde, 0x10, 0x2c, 0xd5, + 0xea, 0x14, 0xed, 0xec, 0xe3, 0xab, 0x51, 0x50, + 0x79, 0x12, 0x15, 0x3d, 0xcd, 0x3a, 0xc0, 0xcb, + 0xd8, 0xc0, 0x9f, 0xda, 0x3e, 0x4f, 0x17, 0x89, + 0xe7, 0x05, 0xf0, 0x27, 0x6d, 0xc3, 0x07, 0x6a, + 0x25, 0xa8, 0x87, 0x26, 0x09, 0x30, 0x23, 0x1a, + 0x6e, 0x28, 0xd9, 0x52, 0xad, 0x15, 0x20, 0x8d, + 0x8a, 0x7b, 0x0c, 0xed, 0x10, 0x10, 0xd5, 0x55, + 0x2d, 0x93, 0xef, 0x8f, 0xdf, 0xa9, 0x60, 0xc3, + 0xbd, 0x7c, 0x00, 0x8f, 0xbe, 0x44, 0xcb, 0x3c, + 0xde, 0x6d, 0x68, 0xda, 0xb1, 0xd4, 0x5a, 0x55, + 0x50, 0xdb, 0x37, 0xce, 0x57, 0x42, 0xbb, 0x81, + 0x4a, 0x16, 0xd3, 0x85, 0x4a, 0x67, 0x60, 0x6e, + 0xd3, 0xdc, 0x43, 0xab, 0x64, 0x11, 0x34, 0xa8, + 0x72, 0x21, 0xde, 0x16, 0x52, 0x4c, 0x22, 0x97, + 0x59, 0x55, 0x8f, 0x77, 0xd1, 0xd3, 0x05, 0x76, + 0x9d, 0x6d, 0x5c, 0xa1, 0x0e, 0x20, 0xa0, 0xca, + 0x36, 0x28, 0x90, 0x06, 0xb4, 0x59, 0xac, 0x3f, + 0x80, 0xa1, 0xa8, 0xcb, 0x78, 0x7a, 0x2f, 0x2f, + 0x26, 0x82, 0x43, 0xdc, 0x98, 0x44, 0xaa, 0x1d, + 0x61, 0xaa, 0x74, 0x39, 0x92, 0x90, 0x46, 0x05, + 0x8f, 0x3a, 0x47, 0x4b, 0xed, 0x34, 0xee, 0x34, + 0x7b, 0xb3, 0x45, 0x51, 0x74, 0x15, 0x29, 0x25, + 0x21, 0x27, 0x2c, 0xf0, 0x10, 0xb1, 0xb4, 0x99, + 0x09, 0xfe, 0x43, 0x4f, 0xab, 0xf1, 0x55, 0x8d, + 0x3d, 0x60, 0xd6, 0x26, 0xc8, 0xf9, 0x03, 0x33, + 0x29, 0xe4, 0xfa, 0xf8, 0x85, 0x0b, 0xf8, 0x83, + 0x58, 0x02, 0x81, 0x20, 0x75, 0x70, 0xd6, 0xfd, + 0xe5, 0x11, 0x88, 0xe3, 0xa6, 0xb3, 0xa8, 0xe8, + 0xc4, 0x7e, 0xf5, 0x22, 0x48, 0x6f, 0x72, 0x43, + 0xc3, 0x73, 0x6c, 0x1e, 0xa3, 0x04, 0xc5, 0xdf, + 0xbd, 0xa9, 0x4e, 0xd0, 0x6e, 0x39, 0x0e, 0xec, + 0xe2, 0xfb, 0xdc, 0x35, 0xa6, 0x4c, 0x16, 0x85, + 0x75, 0x5b, 0xf4, 0x4b, 0xca, 0xf3, 0xc0, 0xfb, + 0xd3, 0x1c, 0xb8, 0xaa, 0x14, 0x94, 0x4d, 0x96, + 0x36, 0x16, 0xd2, 0xf7, 0x1f, 0x7c, 0x62, 0x4b, + 0xe4, 0xd5, 0x97, 0xdc, 0x63, 0x38, 0x93, 0x7a, + 0x27, 0x03, 0x41, 0x76, 0xa8, 0x46, 0x99, 0x40, + 0x27, 0x46, 0x32, 0x41, 0x7c, 0x0a, 0x13, 0x23, + 0x81, 0xdf, 0x26, 0xe8, 0xd6, 0xfa, 0x18, 0xc6, + 0xf4, 0x62, 0x5f, 0x37, 0xf4, 0x2c, 0x91, 0x0c, + 0xd2, 0x7a, 0x6f, 0x64, 0x52, 0x67, 0xbd, 0x0b, + 0x2e, 0xf4, 0x05, 0x24, 0xbe, 0x97, 0x01, 0x07, + 0x9b, 0x37, 0x55, 0xdc, 0x41, 0xb7, 0xf0, 0x57, + 0xeb, 0xf9, 0x63, 0x8b, 0x6f, 0x88, 0x76, 0x9e, + 0x54, 0x21, 0x68, 0xfd, 0x1e, 0x71, 0xc2, 0xf2, + 0xc5, 0xf7, 0xe0, 0xca, 0x5d, 0xdd, 0x03, 0xed, + 0x07, 0x2f, 0x49, 0x15, 0xf6, 0x0b, 0xf5, 0xe3, + 0xc9, 0x31, 0x5a, 0xcb, 0x58, 0x78, 0x86, 0x2e, + 0x10, 0xe5, 0x10, 0xca, 0x0e, 0x3c, 0x9e, 0x15, + 0x8b, 0x2c, 0xae, 0xcd, 0xd7, 0xf7, 0xb4, 0x04, + 0xee, 0x2f, 0x17, 0xdb, 0x9c, 0xb0, 0xda, 0xdd, + 0xa5, 0xec, 0x90, 0xdc, 0xc7, 0xfc, 0x5c, 0x9a, + 0xfc, 0xec, 0xc6, 0x70, 0x4d, 0x1a, 0x1f, 0xbd, + 0xbc, 0xb0, 0x14, 0x49, 0xf1, 0xcb, 0x28, 0x11, + 0x44, 0x5c, 0x0f, 0xa0, 0x94, 0x99, 0xcb, 0x70, + 0xf7, 0xbd, 0x28, 0xfb, 0xee, 0x93, 0x7c, 0xfe, + 0xb3, 0xd9, 0x29, 0xe9, 0x8f, 0xea, 0x42, 0x9d, + 0x7f, 0xe3, 0xe0, 0x62, 0xa8, 0x0c, 0xd4, 0xbb, + 0xbe, 0x92, 0x8c, 0x09, 0x43, 0xed, 0xec, 0xa6, + 0xbe, 0xa2, 0x61, 0x1a, 0xa9, 0x54, 0xa0, 0x4d, + 0x29, 0x95, 0x6a, 0xd7, 0x7c, 0x61, 0x71, 0x18, + 0x11, 0x09, 0x6b, 0xf0, 0xf1, 0xfd, 0xa2, 0x4e, + 0xb7, 0xc9, 0xa9, 0x50, 0x8b, 0xed, 0x4a, 0xcb, + 0xb3, 0x41, 0x9d, 0x3b, 0xe2, 0xce, 0x47, 0xd7, + 0xec, 0xa3, 0xe4, 0x34, 0x67, 0xa0, 0x0f, 0x3f, + 0xa6, 0xbf, 0xcd, 0x99, 0x55, 0xa1, 0xb5, 0x60, + 0x0e, 0xe9, 0xca, 0xcf, 0xc2, 0x47, 0xf9, 0x72, + 0x0d, 0x2b, 0xba, 0xbf, 0xcc, 0x96, 0xe5, 0x83, + 0x9c, 0xcf, 0x1f, 0xd3, 0x61, 0x8c, 0x76, 0x2d, + 0xb2, 0x51, 0xf3, 0x29, 0x1e, 0xc1, 0x00, 0x9a, + 0x2f, 0x84, 0x11, 0x48, 0x0a, 0xe6, 0x31, 0x19, + 0x01, 0x71, 0x06, 0x9c, 0x56, 0x9e, 0x4d, 0x90, + 0x75, 0x24, 0x50, 0xd1, 0x38, 0xce, 0x7b, 0x3e, + 0x37, 0x32, 0xc0, 0xec, 0x28, 0x72, 0xdb, 0x42, + 0x9b, 0x6c, 0x58, 0xfd, 0x85, 0x41, 0xd9, 0xea, + 0x6e, 0x33, 0xbe, 0x29, 0xa9, 0x24, 0xc4, 0x37, + 0x88, 0x7b, 0x92, 0xad, 0x1b, 0x8e, 0x8b, 0x15, + 0xe8, 0xbc, 0xba, 0x8c, 0xe5, 0xad, 0x02, 0x08, + 0x8d, 0x2c, 0xd5, 0x50, 0xdf, 0xa7, 0xd8, 0xe4, + 0x92, 0x05, 0xa4, 0xe3, 0x09, 0x79, 0x73, 0xb7, + 0x62, 0xef, 0xd8, 0xf0, 0x72, 0x52, 0x2d, 0xf3, + 0x07, 0xbc, 0x2b, 0xaa, 0xd2, 0xb2, 0x8c, 0x96, + 0x8b, 0x88, 0x5f, 0xf0, 0x9f, 0x85, 0x0a, 0x9a, + 0x60, 0x00, 0x86, 0x83, 0x53, 0xb4, 0x00, 0x15, + 0xaa, 0x46, 0xc5, 0x65, 0x05, 0x80, 0xbb, 0x8b, + 0x7f, 0xe5, 0xa9, 0x9d, 0xf2, 0xac, 0xac, 0x6f, + 0xcb, 0x51, 0x9a, 0x1b, 0xf6, 0xd9, 0x52, 0x8a, + 0x09, 0xfd, 0x2d, 0xeb, 0xac, 0x02, 0x8a, 0xe7, + 0x21, 0x0d, 0x91, 0xb0, 0x76, 0x25, 0x34, 0xec, + 0x7a, 0xb9, 0x78, 0xc4, 0xcd, 0x68, 0x30, 0x6c, + 0xe1, 0x67, 0x10, 0xb4, 0xd9, 0x70, 0x00, 0x2b, + 0x8d, 0xa7, 0x72, 0x5b, 0x7d, 0x5b, 0x3b, 0x7d, + 0x7f, 0x54, 0xc5, 0xfc, 0x5e, 0xc8, 0x00, 0xb1, + 0x30, 0x72, 0xaf, 0xaf, 0x9b, 0x42, 0xce, 0x9e, + 0x44, 0x3d, 0x1e, 0xf1, 0x44, 0x1f, 0x79, 0xa3, + 0x73, 0x1c, 0xbd, 0x0b, 0x80, 0xf6, 0x88, 0xd0, + 0xb0, 0x21, 0x5c, 0x8d, 0xf8, 0x63, 0xb5, 0x93, + 0x99, 0x38, 0x92, 0x62, 0xf1, 0xad, 0xdd, 0xea, + 0x17, 0x43, 0xdc, 0xb4, 0xf8, 0x70, 0x0e, 0x53, + 0x57, 0x27, 0xd7, 0x80, 0xc4, 0x56, 0xed, 0xfd, + 0xe3, 0xeb, 0x15, 0xe8, 0x80, 0x20, 0x8c, 0xd5, + 0xaf, 0x44, 0x87, 0x68, 0x28, 0x72, 0xd2, 0x7a, + 0xf9, 0x37, 0xff, 0xed, 0x9c, 0x82, 0x4d, 0xa5, + 0xc9, 0x6b, 0x1c, 0x86, 0x2c, 0xf8, 0x21, 0x1f, + 0x23, 0x42, 0x00, 0x73, 0x0f, 0xf5, 0x83, 0x55, + 0x94, 0x3c, 0xdb, 0xce, 0x82, 0xa9, 0xfe, 0xc9, + 0x7b, 0xf3, 0x83, 0x39, 0x7b, 0x92, 0xd3, 0xab, + 0x55, 0x05, 0x27, 0x28, 0x5e, 0x33, 0x81, 0x6f, + 0xa4, 0xd8, 0xca, 0x93, 0x4c, 0x92, 0x13, 0x08, + 0x64, 0xf7, 0xb3, 0xc5, 0x0e, 0x54, 0x97, 0xe9, + 0x77, 0x96, 0xab, 0xb7, 0xaa, 0xa0, 0x7d, 0x2d, + 0x10, 0xbb, 0xf5, 0x78, 0x3d, 0xbb, 0x44, 0x68, + 0x88, 0x8f, 0x94, 0x48, 0xe3, 0x70, 0x40, 0x27, + 0x56, 0xab, 0x3e, 0x9b, 0x18, 0x16, 0x1d, 0x8c, + 0x07, 0xef, 0x20, 0x55, 0x29, 0x89, 0x83, 0x74, + 0x85, 0x4d, 0x65, 0xb2, 0xed, 0xc6, 0x2d, 0x76, + 0x73, 0xc7, 0x93, 0x40, 0xb3, 0x9b, 0x8c, 0x72, + 0xdd, 0xde, 0x0a, 0x8c, 0x28, 0x11, 0xdb, 0xb5, + 0x77, 0xd1, 0xc5, 0xb0, 0xdd, 0x0f, 0xe0, 0x71, + 0x6a, 0xd1, 0x64, 0x3c, 0x0f, 0x3e, 0x32, 0x99, + 0x78, 0x5f, 0xa3, 0x5b, 0x40, 0xe8, 0x58, 0xe8, + 0x73, 0x24, 0x7a, 0xc2, 0x2f, 0xdf, 0xbd, 0xce, + 0x33, 0xda, 0xef, 0x2f, 0x20, 0x44, 0xa7, 0x2d, + 0x12, 0xac, 0xc0, 0x50, 0xba, 0x3f, 0x21, 0x6f, + 0x62, 0x52, 0x76, 0x00, 0x74, 0xb4, 0x74, 0x43, + 0x25, 0x49, 0x41, 0xd8, 0x87, 0x6d, 0x9f, 0x4a, + 0xe1, 0x20, 0xf5, 0x4d, 0xf3, 0xb6, 0x8b, 0x18, + 0x8b, 0x74, 0x21, 0x6e, 0x38, 0x72, 0x3f, 0x82, + 0xb2, 0x85, 0x1b, 0x9c, 0xb2, 0x10, 0x04, 0x1b, + 0x3f, 0xbc, 0xf2, 0x7f, 0x44, 0xb8, 0x74, 0xcc, + 0x0f, 0x36, 0x37, 0xbb, 0x43, 0x21, 0x8a, 0xf8, + 0x3f, 0x29, 0x90, 0x8b, 0x2a, 0xb7, 0x9a, 0x29, + 0xf2, 0xb6, 0x7a, 0x61, 0x88, 0x3c, 0xc1, 0xda, + 0xd7, 0x53, 0x4f, 0xc0, 0x8a, 0xce, 0x6f, 0x84, + 0xcb, 0x56, 0xee, 0xd1, 0x90, 0xc3, 0xb6, 0xe3, + 0x48, 0x6f, 0x56, 0x0b, 0x68, 0x0c, 0x22, 0x26, + 0x5a, 0xf8, 0x5d, 0x9c, 0xc4, 0x30, 0x3d, 0xe1, + 0x30, 0xa5, 0x99, 0x85, 0xad, 0x75, 0xe6, 0xef, + 0xdd, 0x85, 0x42, 0x16, 0xa0, 0xd8, 0xca, 0x2f, + 0x36, 0x2d, 0xc4, 0x3d, 0x4c, 0x25, 0x0f, 0x5b, + 0x2d, 0xd7, 0xb1, 0x21, 0x59, 0x9c, 0xa9, 0x25, + 0x2f, 0x4a, 0xa3, 0x60, 0xb9, 0x37, 0x79, 0x2d, + 0xa7, 0x9d, 0xb9, 0x0e, 0x79, 0xdd, 0x51, 0xce, + 0x0b, 0xa2, 0x2f, 0x3c, 0x7c, 0x7c, 0x6d, 0x3f, + 0x71, 0xd4, 0x99, 0x65, 0x1f, 0x09, 0xca, 0x4e, + 0xf6, 0x9e, 0x9b, 0x0d, 0x6f, 0x4c, 0xc5, 0x36, + 0xff, 0x76, 0x03, 0x25, 0xfe, 0xd9, 0x9a, 0x20, + 0x77, 0x94, 0x60, 0x01, 0x34, 0x8c, 0xf0, 0x0a, + 0x75, 0xb1, 0xb5, 0x1c, 0x1b, 0x11, 0xa5, 0x50, + 0x60, 0x66, 0x17, 0x24, 0x84, 0x67, 0x8c, 0x05, + 0x85, 0xea, 0xce, 0xc0, 0xec, 0x32, 0x6c, 0x0c, + 0x71, 0xe1, 0xe0, 0xc6, 0x9f, 0xb4, 0x5c, 0x6c, + 0xa2, 0xfe, 0x23, 0xa1, 0x42, 0xb8, 0x47, 0xbb, + 0x85, 0x7a, 0x04, 0x7f, 0x6d, 0x53, 0x61, 0x13, + 0x90, 0xca, 0xa8, 0x0c, 0x4e, 0xaf, 0x07, 0x6d, + 0x74, 0xfe, 0xf1, 0x05, 0xda, 0xeb, 0x30, 0x61, + 0xee, 0x6e, 0xad, 0x5e, 0x67, 0xc2, 0xe6, 0x1e, + 0x2a, 0xfb, 0xd7, 0x31, 0x11, 0x83, 0x6b, 0x27, + 0x22, 0xc2, 0x09, 0xef, 0x6c, 0xda, 0x3b, 0x06, + 0x6c, 0xed, 0x23, 0x63, 0xf9, 0xc4, 0x1d, 0x66, + 0xb5, 0xfc, 0xfd, 0x4d, 0xe5, 0x44, 0x46, 0x58, + 0x17, 0x6e, 0x43, 0x2f, 0x91, 0x90, 0x32, 0x4c, + 0xc7, 0xef, 0xe2, 0xc3, 0xf1, 0x53, 0x59, 0x45, + 0xd6, 0xe0, 0xe1, 0x27, 0x1d, 0x2e, 0xab, 0x60, + 0xa6, 0x6e, 0xb6, 0x7a, 0xc9, 0xd2, 0x89, 0x67, + 0xd5, 0x1c, 0x1f, 0x60, 0x82, 0xc0, 0x18, 0xdb, + 0x9c, 0xd7, 0xc7, 0x69, 0x14, 0xe3, 0x82, 0xdd, + 0xf8, 0x7d, 0xa2, 0x59, 0x7d, 0xd7, 0xcb, 0x8a, + 0xe2, 0x8b, 0x1f, 0x7a, 0x67, 0xf0, 0x2d, 0x39, + 0x43, 0xd5, 0xfd, 0xf0, 0x35, 0x33, 0x7f, 0xc7, + 0x87, 0xe4, 0x74, 0x46, 0xde, 0x57, 0xe0, 0xc2, + 0xa5, 0xec, 0x3d, 0x79, 0x67, 0x49, 0x2f, 0xc0, + 0x02, 0x8c, 0xf3, 0x3c, 0x36, 0xc4, 0xad, 0x35, + 0x11, 0x7e, 0x17, 0x34, 0x0b, 0x7b, 0x75, 0xe0, + 0xfb, 0xa4, 0xaf, 0xeb, 0x21, 0xc7, 0x66, 0x1e, + 0xaa, 0x67, 0xd1, 0x10, 0xc8, 0x69, 0x51, 0x44, + 0x50, 0x93, 0x5a, 0x88, 0xe6, 0xea, 0x1d, 0x6b, + 0xd1, 0x77, 0x9e, 0x04, 0xbd, 0x9d, 0x77, 0x3e, + 0x1f, 0x15, 0xac, 0x39, 0x00, 0x0d, 0xe8, 0x81, + 0xb6, 0x09, 0xeb, 0x46, 0x60, 0xe4, 0x5e, 0x90, + 0x84, 0x45, 0x66, 0x74, 0xcf, 0x8b, 0x66, 0x1c, + 0x57, 0x77, 0xaa, 0x23, 0x4e, 0xde, 0xa8, 0xe7, + 0xa0, 0x13, 0xad, 0x1d, 0xeb, 0xa2, 0x55, 0xd5, + 0x75, 0x0f, 0x84, 0xaa, 0x44, 0x78, 0x3e, 0x37, + 0xc8, 0x11, 0x64, 0x80, 0x95, 0x0e, 0x28, 0x22, + 0x73, 0x81, 0x79, 0xea, 0xb4, 0x07, 0xbe, 0x37, + 0x53, 0x57, 0xc6, 0xc9, 0x7b, 0x41, 0x4b, 0xbb, + 0x6b, 0xd3, 0x66, 0xb4, 0xcb, 0x1a, 0x5a, 0xf7, + 0xca, 0x10, 0x54, 0x72, 0xb9, 0xf2, 0xcc, 0x36, + 0x7a, 0x38, 0x6f, 0x63, 0xcf, 0x51, 0x19, 0x49, + 0x6f, 0x47, 0xa8, 0x5a, 0x64, 0x21, 0x5a, 0x92, + 0x75, 0xa2, 0x5a, 0xa4, 0xd3, 0xa1, 0x4b, 0xe1, + 0x11, 0x2e, 0x09, 0xce, 0x3e, 0x47, 0xe6, 0xde, + 0xcd, 0x2d, 0xbc, 0x30, 0x72, 0x7d, 0x90, 0x3b, + 0xc8, 0xa4, 0x51, 0xad, 0x7d, 0x9b, 0xd6, 0x4a, + 0xdb, 0x79, 0xf1, 0xcd, 0x28, 0xa6, 0x95, 0x09, + 0x4b, 0x09, 0xdb, 0x3c, 0x22, 0xef, 0xea, 0xa6, + 0xe3, 0xe7, 0xbb, 0x04, 0x67, 0xcc, 0x05, 0x76, + 0x4b, 0xfe, 0x37, 0x1d, 0x34, 0xb7, 0xfd, 0xe1, + 0x07, 0x51, 0xc9, 0xc4, 0x1b, 0x52, 0xec, 0x50, + 0x9f, 0x12, 0xa5, 0xa1, 0x56, 0xcc, 0xfe, 0x3b, + 0xf8, 0xc0, 0x70, 0x9c, 0x8d, 0x82, 0x45, 0x22, + 0xf1, 0x3a, 0xf9, 0x22, 0x87, 0x00, 0x9b, 0x54, + 0x03, 0xfa, 0xb8, 0x86, 0x71, 0x01, 0x42, 0x03, + 0xe2, 0xc4, 0x31, 0xbe, 0xcd, 0xab, 0xa3, 0x42, + 0xd5, 0xb7, 0xaf, 0xfd, 0xfa, 0xe3, 0x5a, 0xd0, + 0x3a, 0x68, 0x77, 0x55, 0xca, 0x4b, 0xb5, 0xfb, + 0xd4, 0xe2, 0x31, 0x2b, 0xb3, 0x98, 0x37, 0x5f, + 0xda, 0xe1, 0x7d, 0xb4, 0xd8, 0xb9, 0xbe, 0xe9, + 0x14, 0xdf, 0x97, 0x3a, 0x4f, 0x58, 0x63, 0xb5, + 0x20, 0xdf, 0x2c, 0xd1, 0x53, 0x80, 0x0a, 0x2a, + 0x7d, 0x3c, 0xfd, 0x56, 0x95, 0x09, 0x0e, 0x75, + 0x7f, 0x66, 0x14, 0x97, 0xa9, 0xfe, 0x04, 0xf3, + 0xda, 0x9f, 0x32, 0xc5, 0xd5, 0xff, 0xb7, 0x59, + 0x92, 0x96, 0xb0, 0xde, 0xbe, 0xc1, 0x4d, 0x4e, + 0x98, 0x4d, 0xfb, 0x5c, 0xbb, 0xc5, 0xe9, 0x12, + 0xb8, 0x99, 0xbd, 0xca, 0x5a, 0x14, 0x90, 0x8e, + 0x5a, 0xdb, 0xe4, 0xbb, 0xb8, 0x40, 0xa2, 0xc5, + 0x73, 0x23, 0x3c, 0xd2, 0x9a, 0x94, 0xa2, 0x48, + 0x1b, 0x98, 0x19, 0xaf, 0xcd, 0x99, 0x2e, 0x8c, + 0xd9, 0x6c, 0x9a, 0x89, 0x8d, 0xbf, 0xd4, 0xf8, + 0x0b, 0x51, 0x39, 0xd8, 0x09, 0x0f, 0x57, 0x91, + 0x14, 0x5d, 0x8a, 0x99, 0xec, 0xc6, 0x71, 0x2a, + 0x77, 0x6e, 0x02, 0x6e, 0x32, 0xdf, 0xbf, 0xc8, + 0x2f, 0xe4, 0xf7, 0x29, 0xca, 0xbc, 0x58, 0x25, + 0x0f, 0xfd, 0x2f, 0xc8, 0xd6, 0x15, 0x01, 0x64, + 0x97, 0xab, 0xfe, 0x22, 0xb1, 0x75, 0x31, 0xdc, + 0x0f, 0xd5, 0x05, 0x18, 0x20, 0x3e, 0x5a, 0xeb, + 0x10, 0x85, 0x4e, 0xf7, 0x25, 0xe2, 0xff, 0x45, + 0x2d, 0x7a, 0xdd, 0xd7, 0x74, 0xc0, 0x78, 0x72, + 0x39, 0xa5, 0x67, 0x2b, 0x4d, 0x8a, 0x8a, 0xbb, + 0xe8, 0xf5, 0x02, 0xab, 0xbb, 0x78, 0x38, 0xd1, + 0xd6, 0x0f, 0x66, 0xfe, 0x4e, 0x17, 0x60, 0xd1, + 0x55, 0x00, 0xec, 0xb0, 0xfd, 0x58, 0xb1, 0x92, + 0xf3, 0xd0, 0xa1, 0xd6, 0xf1, 0x66, 0x19, 0xaa, + 0xfd, 0xfe, 0xd9, 0x70, 0x62, 0x1f, 0x96, 0x60, + 0x1c, 0xe8, 0x68, 0x2f, 0xf0, 0x50, 0x64, 0xf2, + 0x60, 0x11, 0xbb, 0x43, 0xc6, 0x66, 0x1a, 0x14, + 0x08, 0x05, 0x69, 0x2d, 0x04, 0x3e, 0x6d, 0xfe, + 0x7e, 0x09, 0x1a, 0xad, 0xfe, 0x95, 0xb5, 0xfb, + 0x68, 0x13, 0x92, 0xd8, 0xb0, 0xd4, 0x34, 0xfd, + 0x9c, 0xd0, 0xca, 0x10, 0x2d, 0xd3, 0x3a, 0xaf, + 0x5d, 0x9d, 0x13, 0x3b, 0xc1, 0x74, 0x2d, 0xb0, + 0x0a, 0xf5, 0xe3, 0x5e, 0x0e, 0x7b, 0x32, 0x8c, + 0x75, 0xfc, 0xcf, 0x71, 0xf4, 0x04, 0x5a, 0x21, + 0xec, 0x8a, 0xce, 0x29, 0xd2, 0x96, 0xdf, 0x42, + 0x79, 0x8f, 0x28, 0xa3, 0xe0, 0xb5, 0x0e, 0xe3, + 0xe1, 0xac, 0x6a, 0xfa, 0xbf, 0x67, 0x10, 0xb0, + 0xbf, 0xc1, 0xde, 0xf5, 0x3a, 0x20, 0x8e, 0x70 + }; + static const byte mu_87[] = { + 0x82, 0xf1, 0x07, 0xb0, 0x41, 0x11, 0x5a, 0x60, + 0xfc, 0x9b, 0x36, 0x93, 0x50, 0x8a, 0x6b, 0x9a, + 0xd8, 0xd4, 0x7e, 0x45, 0x1b, 0x29, 0xe7, 0x52, + 0x63, 0xe4, 0x61, 0x11, 0xa3, 0x4c, 0xd0, 0xb2, + 0x7e, 0xe8, 0xef, 0x02, 0xc9, 0x5b, 0xa8, 0x5d, + 0x9e, 0x9b, 0x3e, 0xc0, 0x92, 0x2d, 0x52, 0x4f, + 0xa5, 0x43, 0x16, 0xf8, 0x9f, 0x0f, 0xfd, 0x71, + 0xf3, 0xd0, 0x0c, 0xea, 0x6f, 0xf8, 0xfc, 0x3b + }; + static const byte sig_87_mu[] = { + 0x71, 0x6e, 0x47, 0xd1, 0x09, 0xe2, 0x40, 0xe5, + 0x9c, 0x7b, 0x50, 0x6f, 0x9f, 0xa4, 0x5c, 0x08, + 0x71, 0x86, 0x9e, 0xbf, 0x6c, 0x5d, 0xc8, 0x14, + 0x2d, 0x1e, 0xe1, 0x62, 0x04, 0x11, 0x9e, 0x7c, + 0x9f, 0x28, 0x64, 0x15, 0x79, 0xb5, 0xbf, 0x3d, + 0x6d, 0x79, 0x6a, 0x0a, 0xe7, 0xae, 0x4b, 0x51, + 0x67, 0xb1, 0xda, 0xd8, 0xd2, 0xa9, 0x14, 0x76, + 0x08, 0x85, 0x9c, 0x47, 0xaa, 0xc1, 0xa7, 0x52, + 0x84, 0x33, 0xd5, 0xb0, 0x4d, 0xe3, 0x83, 0x7c, + 0xa6, 0x85, 0xc1, 0x49, 0xcf, 0x1e, 0x1d, 0x17, + 0x19, 0x1a, 0x22, 0x3d, 0x94, 0xdc, 0xa6, 0xa1, + 0x91, 0x77, 0xe9, 0x2b, 0xef, 0x54, 0x07, 0x1d, + 0x99, 0x6a, 0x3d, 0xfc, 0x11, 0x3b, 0x07, 0x20, + 0xbf, 0x64, 0x31, 0xdf, 0x4f, 0x4a, 0xe9, 0xe3, + 0x9a, 0xb1, 0xd8, 0xce, 0x27, 0xbe, 0xa7, 0xd3, + 0x72, 0xb4, 0x4e, 0x62, 0x30, 0xb0, 0x7c, 0xab, + 0x00, 0x20, 0x32, 0xff, 0xb6, 0x1e, 0x5e, 0xf9, + 0xad, 0xbc, 0xaa, 0x47, 0x9c, 0xf2, 0x41, 0xb6, + 0xa7, 0x68, 0xf7, 0x1c, 0x0f, 0x3d, 0x83, 0xa4, + 0x72, 0xa7, 0xf1, 0x69, 0xd2, 0xd8, 0x99, 0xff, + 0x54, 0x04, 0xed, 0x71, 0x0f, 0x03, 0xf2, 0xbe, + 0xa6, 0xf8, 0x2f, 0xb5, 0x54, 0x80, 0x1e, 0xb6, + 0x09, 0x9d, 0x5a, 0x5d, 0x2f, 0x1e, 0xdb, 0xfd, + 0x0a, 0x73, 0x1b, 0xf6, 0x0b, 0x7a, 0x0b, 0xa5, + 0x4f, 0x46, 0x8c, 0x96, 0x9b, 0x50, 0x39, 0x22, + 0x6c, 0x21, 0xab, 0x72, 0xcc, 0x7a, 0xd1, 0x87, + 0xf1, 0x61, 0x2f, 0x92, 0x19, 0x16, 0xb9, 0x99, + 0xd2, 0xf6, 0xce, 0x11, 0x0f, 0x4a, 0x5e, 0xbb, + 0xd5, 0x7a, 0xc2, 0x73, 0xeb, 0xbf, 0x65, 0x6b, + 0x5f, 0x8b, 0xc1, 0xa2, 0xb2, 0x05, 0xd2, 0xc3, + 0x1d, 0x3f, 0x8f, 0x43, 0x9e, 0x06, 0xa2, 0x18, + 0x39, 0x54, 0xa7, 0x52, 0x86, 0x1f, 0x48, 0x78, + 0xf4, 0x55, 0x15, 0x19, 0xff, 0x32, 0xeb, 0x27, + 0x2f, 0x39, 0xb8, 0xc7, 0x9d, 0x00, 0xe3, 0xfb, + 0x3e, 0xd0, 0x64, 0xba, 0x10, 0x0b, 0xac, 0xd9, + 0x18, 0x2f, 0x42, 0x8c, 0x30, 0xbe, 0xf6, 0xa3, + 0xea, 0xc0, 0xff, 0xf5, 0x5b, 0xaa, 0x35, 0x73, + 0x91, 0x3f, 0x51, 0x28, 0x58, 0x11, 0x33, 0x27, + 0xfd, 0x08, 0x2f, 0x1c, 0xa9, 0x8a, 0x37, 0xae, + 0xf9, 0x70, 0x89, 0xad, 0x15, 0x31, 0x5f, 0x43, + 0xeb, 0x29, 0x46, 0x9b, 0xc9, 0x9f, 0x58, 0x3e, + 0x22, 0xfb, 0x2c, 0x60, 0x17, 0x59, 0x2c, 0xc8, + 0xcf, 0xf7, 0xe9, 0xd9, 0x17, 0xc7, 0x40, 0x7c, + 0xcf, 0x56, 0x9d, 0x2b, 0xd5, 0xc3, 0xd4, 0x7f, + 0xb1, 0xeb, 0xee, 0x2b, 0xcb, 0x5c, 0x59, 0xaa, + 0x87, 0xd3, 0xa8, 0x5a, 0xac, 0x12, 0xc7, 0xfd, + 0x10, 0x47, 0x76, 0x9e, 0x98, 0x29, 0x81, 0xef, + 0xc1, 0x3c, 0x07, 0x60, 0xd7, 0xd6, 0xb0, 0x78, + 0xb3, 0xc6, 0x09, 0x03, 0x20, 0xe8, 0xab, 0x1d, + 0x83, 0x1d, 0x25, 0xd0, 0x25, 0x1d, 0x1c, 0x5d, + 0x12, 0xcb, 0xd5, 0x96, 0xde, 0xf6, 0xdb, 0xeb, + 0xb1, 0x7a, 0x8c, 0x08, 0xab, 0x93, 0x1a, 0x7d, + 0xad, 0xa1, 0x68, 0xf9, 0xe9, 0x96, 0xaa, 0x15, + 0x60, 0x3c, 0x7e, 0x15, 0x83, 0xab, 0x70, 0x8d, + 0x45, 0x4e, 0xab, 0x64, 0xae, 0x4e, 0x83, 0x8d, + 0x19, 0xe2, 0xf5, 0xfa, 0x96, 0x3a, 0x05, 0x34, + 0x2d, 0x19, 0x2a, 0x3d, 0x88, 0x82, 0x7b, 0xba, + 0x9d, 0x67, 0x5d, 0xfa, 0xdc, 0x14, 0x96, 0x2c, + 0x0a, 0x87, 0x96, 0xf5, 0x29, 0x7f, 0x32, 0x22, + 0xf7, 0x23, 0x3a, 0x89, 0x7b, 0x3c, 0x6f, 0xf9, + 0x01, 0x91, 0x35, 0xd5, 0xee, 0x2e, 0x97, 0xdb, + 0xbe, 0x93, 0x47, 0xac, 0x58, 0x72, 0xd3, 0xe9, + 0xae, 0x72, 0x9f, 0xca, 0xf5, 0x8d, 0xf0, 0x64, + 0xa3, 0xea, 0xa6, 0xd6, 0xa2, 0x7f, 0xab, 0xf1, + 0x8f, 0x01, 0x67, 0xea, 0xac, 0xab, 0x27, 0x6d, + 0x29, 0xc9, 0x05, 0xdd, 0x17, 0x3e, 0x0b, 0x28, + 0xa8, 0x19, 0x89, 0xb9, 0x0f, 0x7e, 0x17, 0x8c, + 0x86, 0xd0, 0x7a, 0xd8, 0xfc, 0xb8, 0x3a, 0xea, + 0xf9, 0x47, 0xd2, 0x2f, 0xa3, 0xb8, 0xde, 0x46, + 0x21, 0x14, 0x44, 0x1a, 0x8f, 0x69, 0x7b, 0x45, + 0xee, 0x9f, 0xd9, 0xf2, 0xc4, 0xae, 0xf5, 0xdf, + 0x5d, 0x93, 0x30, 0x63, 0x8a, 0xfa, 0x37, 0xb0, + 0x95, 0x9c, 0xaa, 0x87, 0x58, 0x5b, 0x19, 0x7b, + 0xfb, 0x2b, 0x66, 0x5c, 0x6f, 0xa9, 0xfb, 0x22, + 0x24, 0x1b, 0x16, 0xc5, 0x9b, 0x6d, 0xc7, 0x54, + 0x26, 0x77, 0xf0, 0xb2, 0xa2, 0xf1, 0x11, 0xee, + 0x8b, 0xd4, 0x2b, 0xd7, 0x3a, 0x59, 0x6c, 0xf7, + 0x7c, 0x68, 0x5b, 0x27, 0xf3, 0x57, 0x14, 0xe8, + 0x73, 0x51, 0xca, 0xc8, 0x1c, 0xc4, 0x2e, 0x21, + 0xe0, 0x27, 0xa0, 0x42, 0xb1, 0x37, 0x57, 0x5b, + 0x6d, 0xb2, 0xd4, 0xfa, 0x34, 0x49, 0x6d, 0x75, + 0x8d, 0xdc, 0xb2, 0x83, 0x67, 0x8f, 0xc6, 0x37, + 0xf5, 0xb0, 0x30, 0xce, 0x37, 0x2d, 0xe7, 0x7e, + 0xa6, 0x3e, 0xa0, 0xa9, 0xaf, 0xec, 0x8e, 0x20, + 0xe8, 0x6e, 0x1d, 0x82, 0x9a, 0x80, 0x7a, 0xfe, + 0x83, 0x56, 0x2c, 0xba, 0xba, 0xcb, 0x4b, 0x17, + 0x7e, 0x9a, 0x1e, 0xd2, 0x9a, 0xeb, 0x87, 0xe6, + 0x26, 0x7a, 0x24, 0xa5, 0x2b, 0x62, 0x85, 0x38, + 0x1e, 0x28, 0x1a, 0x05, 0x17, 0x78, 0xa1, 0xf2, + 0x96, 0x83, 0xb4, 0x38, 0xd8, 0x81, 0x0a, 0x2e, + 0xf8, 0x20, 0xcc, 0xa9, 0xd8, 0x94, 0xa0, 0xee, + 0xad, 0x79, 0x4a, 0x24, 0xde, 0xdf, 0x43, 0x77, + 0x83, 0x23, 0xef, 0x7d, 0x21, 0x75, 0x15, 0xce, + 0xe2, 0xe1, 0xe3, 0x63, 0x8e, 0xcd, 0xc1, 0x45, + 0x87, 0x27, 0x80, 0x3b, 0x75, 0xf2, 0x00, 0x13, + 0x6e, 0xfa, 0xbf, 0x6f, 0xec, 0x9c, 0xa6, 0x68, + 0x6a, 0xc6, 0x1d, 0x3c, 0xf2, 0x41, 0xa5, 0xc5, + 0x69, 0xc1, 0x64, 0xa6, 0x1f, 0x5c, 0x8b, 0xc1, + 0x4c, 0x2e, 0xd1, 0x1f, 0xe7, 0x4d, 0x36, 0x6c, + 0xad, 0xc2, 0xc4, 0x39, 0x25, 0x11, 0xb4, 0x89, + 0x0c, 0xf3, 0xd1, 0xc3, 0xc8, 0x20, 0xdf, 0xb1, + 0x55, 0xd3, 0x91, 0xc3, 0x7f, 0x7e, 0x2c, 0x0e, + 0xbb, 0x9b, 0x46, 0x9d, 0x45, 0xe7, 0x1a, 0x27, + 0x2b, 0xfe, 0xd7, 0x1d, 0xba, 0xef, 0xeb, 0x0b, + 0x1b, 0xc7, 0xee, 0xa4, 0x05, 0x44, 0x68, 0xaf, + 0xa7, 0xbc, 0x67, 0x56, 0x4b, 0x17, 0x4d, 0x39, + 0x7d, 0x1e, 0x6c, 0xab, 0x0f, 0x9d, 0xad, 0x22, + 0x8b, 0x80, 0xff, 0x28, 0xe9, 0x03, 0xdb, 0x67, + 0xff, 0xb0, 0x68, 0xfc, 0xc1, 0x19, 0xbf, 0x6c, + 0xb3, 0xa9, 0xb3, 0x08, 0xed, 0x7f, 0x89, 0xba, + 0xa8, 0xe6, 0xe1, 0xcb, 0x38, 0x71, 0x65, 0xd6, + 0xc9, 0x67, 0xa8, 0x39, 0x57, 0xda, 0xfb, 0x23, + 0x12, 0x19, 0x18, 0x30, 0xe6, 0x22, 0x69, 0xfd, + 0xd2, 0x38, 0xe7, 0x2d, 0xc1, 0x96, 0xe8, 0xf3, + 0xc2, 0xc3, 0xbd, 0x47, 0x6d, 0xee, 0xc4, 0xd6, + 0x38, 0xd7, 0x35, 0x34, 0x47, 0xec, 0xd5, 0x7b, + 0xd4, 0x33, 0x21, 0xcd, 0xd3, 0x78, 0x89, 0xb0, + 0x18, 0x54, 0xba, 0x49, 0xb8, 0x86, 0x21, 0x00, + 0x38, 0x4f, 0x86, 0x5e, 0x78, 0x63, 0xf8, 0x81, + 0x48, 0x3e, 0xf3, 0x8b, 0x94, 0x4f, 0x9f, 0xf6, + 0x25, 0xf3, 0xdc, 0xdc, 0x86, 0xed, 0x24, 0x66, + 0x21, 0x74, 0x96, 0x04, 0x87, 0xd5, 0x32, 0x06, + 0x2f, 0x04, 0x74, 0x43, 0xbf, 0x62, 0x8d, 0x5a, + 0x69, 0x6d, 0x91, 0xb6, 0x21, 0xbe, 0x75, 0x73, + 0x17, 0xa8, 0xcc, 0x26, 0x75, 0xc5, 0xc7, 0x5e, + 0x84, 0x0c, 0x8c, 0x50, 0x1e, 0x23, 0x55, 0x2e, + 0x19, 0x9d, 0xd1, 0x76, 0x4a, 0x1a, 0x18, 0x1d, + 0x2c, 0x4f, 0x51, 0xac, 0xf4, 0x16, 0xb6, 0x12, + 0x01, 0x7d, 0xb2, 0x5a, 0xc0, 0xa6, 0x9d, 0x76, + 0x9f, 0x68, 0xf8, 0xc2, 0xe8, 0xc6, 0xc7, 0xd7, + 0x1d, 0x59, 0xa6, 0x06, 0xea, 0x00, 0x9c, 0x9d, + 0xb1, 0xeb, 0xd8, 0xa0, 0x60, 0x1c, 0xbf, 0x13, + 0xd0, 0x01, 0xbb, 0x5d, 0x9f, 0xf1, 0xa3, 0x3b, + 0x9c, 0x18, 0x0b, 0x0b, 0x2e, 0x73, 0x37, 0xac, + 0x03, 0xc2, 0x10, 0xc0, 0xf8, 0x5a, 0x86, 0x31, + 0x17, 0xe6, 0x6b, 0xc8, 0x17, 0xa3, 0x5d, 0xd9, + 0x6e, 0x5a, 0xa4, 0x0f, 0x92, 0x38, 0xf8, 0x0e, + 0x42, 0x8b, 0x1a, 0x85, 0x7f, 0x30, 0x2d, 0x61, + 0x48, 0x5f, 0x52, 0x00, 0xfb, 0x61, 0xd2, 0xa1, + 0xdc, 0xd6, 0x88, 0xb2, 0xff, 0x94, 0x01, 0x67, + 0x1a, 0xac, 0x2c, 0xf9, 0x17, 0xb6, 0x58, 0xbc, + 0x70, 0xf5, 0x9f, 0xee, 0x7c, 0x80, 0xa0, 0x21, + 0x47, 0x5f, 0x8f, 0x4a, 0x33, 0x7b, 0xb7, 0xbe, + 0xee, 0xfa, 0x62, 0xf7, 0xa2, 0x51, 0x1f, 0xe5, + 0x29, 0x66, 0x1c, 0xa0, 0x49, 0x6e, 0x1c, 0xa4, + 0x5a, 0xec, 0x2d, 0xc8, 0x2d, 0x59, 0x6c, 0x21, + 0xa3, 0x39, 0x38, 0x63, 0x44, 0xb3, 0x65, 0x80, + 0x56, 0x83, 0x33, 0xc9, 0xb6, 0xd7, 0xe7, 0x01, + 0x48, 0x07, 0x0c, 0x0d, 0x7a, 0xa7, 0x0b, 0xa7, + 0x22, 0x7e, 0x39, 0x0c, 0x66, 0x12, 0x4a, 0xbf, + 0xaf, 0xac, 0x3e, 0xf2, 0x6b, 0x2b, 0x97, 0x29, + 0x20, 0xd1, 0x0b, 0x57, 0x03, 0x04, 0xc5, 0x80, + 0xeb, 0x64, 0x7c, 0x0b, 0x0e, 0xc6, 0xa2, 0xe1, + 0x4e, 0x08, 0x15, 0x5f, 0xeb, 0x90, 0x51, 0xd7, + 0x77, 0xe8, 0xf9, 0x15, 0x0d, 0x42, 0x48, 0xc0, + 0xc4, 0x78, 0xcd, 0x4d, 0x46, 0xf4, 0x8a, 0x4a, + 0x4c, 0x61, 0xec, 0xd0, 0x4f, 0x5f, 0x8c, 0x6b, + 0x83, 0xed, 0xad, 0x56, 0xd8, 0xe9, 0x50, 0xda, + 0x05, 0x03, 0x3a, 0x29, 0xa5, 0xbc, 0x1f, 0x08, + 0x27, 0xed, 0xad, 0x87, 0x71, 0x90, 0x93, 0xe8, + 0xba, 0x29, 0xbc, 0x2e, 0xeb, 0xba, 0xe5, 0xb7, + 0x50, 0x38, 0xfa, 0x06, 0x52, 0xbf, 0x55, 0x46, + 0x89, 0x5a, 0x39, 0x6b, 0xb2, 0x1f, 0xea, 0xfa, + 0xea, 0xf1, 0x8a, 0x20, 0x14, 0x86, 0xc0, 0xae, + 0x60, 0x40, 0x17, 0xde, 0x2d, 0xeb, 0x87, 0x80, + 0x5d, 0x17, 0xe5, 0xdb, 0x4f, 0xf1, 0x3d, 0x7c, + 0xf8, 0xd0, 0xf7, 0x49, 0x6f, 0xaf, 0x0b, 0x64, + 0x12, 0x51, 0x7f, 0x85, 0xcb, 0xa0, 0x6a, 0x95, + 0xf9, 0x91, 0xf4, 0xf8, 0xa5, 0xae, 0xea, 0x99, + 0xd8, 0x67, 0x33, 0x67, 0x26, 0xab, 0xd4, 0x72, + 0x38, 0x6b, 0x98, 0xe7, 0xfd, 0xb3, 0x0e, 0xc4, + 0x8f, 0x6a, 0x7a, 0x9b, 0xf9, 0x53, 0xbf, 0x15, + 0x70, 0xfa, 0x9e, 0x8a, 0x25, 0x6f, 0xf7, 0x71, + 0xda, 0x1e, 0xe6, 0x54, 0x2c, 0x10, 0x5d, 0xfe, + 0x35, 0xd2, 0xe6, 0x62, 0x1d, 0x0b, 0x72, 0x03, + 0x6d, 0x2e, 0x43, 0x40, 0x88, 0xd9, 0x2a, 0xa3, + 0x01, 0x38, 0x91, 0x5b, 0x90, 0x9d, 0xab, 0x7f, + 0x9b, 0x27, 0xd2, 0x79, 0xfa, 0xfb, 0xe5, 0xb9, + 0xd2, 0x8b, 0x84, 0x01, 0x9b, 0xe8, 0x2a, 0x55, + 0x28, 0x24, 0x26, 0x92, 0x9a, 0x44, 0xf8, 0x07, + 0x55, 0x0d, 0xe6, 0x98, 0xd4, 0x01, 0x11, 0xd6, + 0x3c, 0xe3, 0x07, 0x0e, 0xfd, 0x6c, 0xae, 0xea, + 0xfc, 0x16, 0x26, 0x81, 0xa3, 0xe6, 0xa1, 0x83, + 0x88, 0xb3, 0xd5, 0x8a, 0xa9, 0xd6, 0x06, 0x1b, + 0xf1, 0x62, 0x21, 0x67, 0x46, 0x9f, 0x00, 0x6a, + 0x61, 0x2b, 0x76, 0x41, 0xf8, 0x41, 0x90, 0x06, + 0x62, 0x68, 0xe8, 0xae, 0x1e, 0xd2, 0x16, 0x29, + 0xf9, 0xed, 0xb5, 0xee, 0x6b, 0x2f, 0x72, 0xeb, + 0xd7, 0x7d, 0x1c, 0xe6, 0x4a, 0xe2, 0x85, 0x50, + 0x9d, 0xb0, 0xba, 0x72, 0x85, 0x3b, 0xcb, 0x88, + 0x2f, 0x27, 0xb5, 0xab, 0x98, 0xb4, 0x7b, 0x27, + 0x2d, 0x77, 0x8b, 0xdd, 0x66, 0x8b, 0x75, 0xf7, + 0xd1, 0xde, 0x64, 0x52, 0x8e, 0x66, 0x38, 0x21, + 0xe5, 0x64, 0x31, 0x62, 0x22, 0xa8, 0x79, 0x98, + 0x51, 0x63, 0xbe, 0xa8, 0xec, 0x86, 0x92, 0x33, + 0x94, 0xee, 0x66, 0x99, 0xf5, 0x53, 0xd5, 0x83, + 0x42, 0xbb, 0x83, 0x8e, 0x93, 0x9b, 0x67, 0x9a, + 0xf4, 0x91, 0xa8, 0xdb, 0x95, 0x12, 0xfe, 0xa2, + 0x44, 0xe6, 0xc0, 0x01, 0x21, 0x0b, 0x83, 0xe0, + 0xe7, 0xfb, 0x3a, 0xcf, 0x51, 0x9b, 0x19, 0xa0, + 0x48, 0x4d, 0x34, 0xb2, 0x83, 0x68, 0xac, 0x75, + 0xd7, 0x80, 0x7e, 0x66, 0x14, 0x04, 0x8a, 0xe3, + 0xa1, 0x8b, 0x3d, 0x7f, 0x6f, 0x58, 0xeb, 0xb7, + 0xc2, 0xc7, 0xe4, 0x6a, 0x74, 0x09, 0xf9, 0x4d, + 0x8f, 0xc4, 0xeb, 0xa1, 0xec, 0x6d, 0x29, 0x7c, + 0xe0, 0xac, 0x1a, 0x0e, 0x7e, 0xbd, 0x86, 0x0b, + 0xf7, 0x41, 0x95, 0x71, 0x47, 0x73, 0x52, 0x80, + 0x70, 0x8b, 0x94, 0xc1, 0x1f, 0xea, 0xde, 0x29, + 0xc0, 0x6e, 0x91, 0x2b, 0x28, 0x7b, 0xa9, 0x47, + 0x4d, 0x6d, 0x35, 0x53, 0x81, 0x8b, 0xf2, 0x32, + 0x01, 0x9a, 0x49, 0xaa, 0x5f, 0x02, 0x94, 0xfc, + 0xe2, 0x84, 0x1a, 0x6f, 0xbf, 0x08, 0x8e, 0xad, + 0x94, 0x9e, 0xd8, 0x89, 0x13, 0xd0, 0x6c, 0xbf, + 0x4f, 0x1f, 0xe0, 0x3d, 0x1b, 0x60, 0x65, 0xc1, + 0x56, 0xae, 0x13, 0xd3, 0xd3, 0xca, 0x4a, 0x2c, + 0x76, 0x06, 0xbd, 0xbb, 0x73, 0x57, 0x9a, 0x8b, + 0x66, 0xdd, 0x5e, 0xf4, 0x8d, 0x73, 0x8a, 0x58, + 0x81, 0x67, 0xe5, 0x3c, 0x56, 0x34, 0xd2, 0xc9, + 0x70, 0x25, 0x90, 0x4a, 0x0c, 0x7d, 0xc2, 0x3f, + 0x70, 0x04, 0xe3, 0x2d, 0x4b, 0xd7, 0x84, 0x10, + 0x4d, 0x7b, 0x2d, 0x84, 0x64, 0xb7, 0x62, 0x30, + 0x2b, 0x99, 0x1b, 0xd6, 0x9b, 0x06, 0x60, 0x0f, + 0x00, 0xcb, 0x22, 0x53, 0x8d, 0xda, 0xbc, 0xa5, + 0x64, 0x08, 0xf6, 0x89, 0x1e, 0x5f, 0x74, 0x17, + 0x18, 0x01, 0xa0, 0x0f, 0xe4, 0xae, 0xc3, 0x2d, + 0x8a, 0x8e, 0x85, 0x98, 0x8c, 0x33, 0x1a, 0x9d, + 0x46, 0x53, 0xe3, 0xdc, 0xc5, 0x13, 0xbd, 0xe7, + 0xf2, 0x10, 0xa2, 0x05, 0x86, 0x37, 0x9b, 0x61, + 0xa4, 0xe9, 0x95, 0x87, 0xf7, 0xc1, 0x16, 0xec, + 0x29, 0xde, 0x61, 0xb4, 0x60, 0x38, 0x9f, 0xbc, + 0xcf, 0x97, 0x83, 0x9e, 0xf3, 0x8a, 0xed, 0x91, + 0x33, 0xd1, 0xb5, 0x04, 0xfe, 0x49, 0xa0, 0x27, + 0xa8, 0xae, 0x3b, 0x8a, 0x27, 0x03, 0xc1, 0xd5, + 0x2f, 0x91, 0xab, 0x20, 0x55, 0x33, 0xe5, 0x85, + 0x13, 0xae, 0x1a, 0xaf, 0x09, 0xd4, 0x8e, 0xbd, + 0x09, 0xd8, 0x1b, 0x76, 0x18, 0x86, 0xb1, 0x09, + 0x17, 0x95, 0x50, 0xba, 0xc4, 0xbe, 0xa1, 0xe1, + 0x24, 0x6f, 0x8a, 0x7e, 0xb2, 0xe1, 0x2d, 0x2d, + 0x12, 0x6d, 0x8b, 0xcf, 0x64, 0x82, 0x4c, 0x07, + 0x42, 0x2e, 0xf7, 0x20, 0x77, 0x8e, 0x22, 0x00, + 0x72, 0xcf, 0xdf, 0x3c, 0xd3, 0x09, 0xd8, 0x70, + 0xb2, 0xe6, 0x2e, 0xcc, 0xc1, 0x71, 0xd4, 0xd4, + 0x9d, 0x45, 0x35, 0x37, 0x46, 0xd8, 0x2c, 0x99, + 0x3a, 0x3f, 0x90, 0x66, 0x30, 0x14, 0x01, 0x99, + 0x67, 0xda, 0xd1, 0xee, 0x4b, 0x9a, 0xcb, 0x26, + 0x34, 0xab, 0x9b, 0xaf, 0xc6, 0x0c, 0x4d, 0xf3, + 0xa2, 0x79, 0x50, 0x78, 0xd8, 0x66, 0x5c, 0xbb, + 0xcd, 0xe8, 0xb3, 0x09, 0xf9, 0x77, 0x61, 0x39, + 0x51, 0x6c, 0x3f, 0x26, 0x7b, 0xbb, 0x15, 0x8d, + 0x65, 0xe1, 0x6c, 0x52, 0x01, 0x6f, 0x20, 0x0e, + 0x7a, 0xd1, 0x84, 0x9b, 0x44, 0x83, 0x9d, 0x6d, + 0x35, 0x9a, 0x3e, 0x20, 0x48, 0x6c, 0xa0, 0xb2, + 0x70, 0x87, 0x09, 0xc3, 0xda, 0x4c, 0xbf, 0x6a, + 0x37, 0x47, 0x74, 0xa3, 0x43, 0x06, 0x3d, 0x9c, + 0x5c, 0xa8, 0xf9, 0x7d, 0x86, 0x8b, 0xb6, 0x08, + 0x30, 0xbb, 0xe7, 0x4d, 0x40, 0xf4, 0xe4, 0x43, + 0x83, 0x11, 0x11, 0xba, 0xa3, 0xb2, 0xb1, 0x86, + 0x1c, 0x89, 0x8b, 0x86, 0x84, 0x22, 0xbf, 0xb0, + 0x67, 0x4a, 0x28, 0xdd, 0xb6, 0x86, 0x31, 0x2d, + 0xd1, 0xa3, 0x87, 0x68, 0x08, 0x28, 0x18, 0xbf, + 0xdc, 0x09, 0xac, 0xac, 0xf8, 0x60, 0xc9, 0x68, + 0xe9, 0x98, 0xea, 0x7b, 0x55, 0xdf, 0x3c, 0x69, + 0x5b, 0x44, 0xf1, 0x75, 0xf1, 0x68, 0xf2, 0xe8, + 0x6d, 0x7d, 0xbb, 0x18, 0x8e, 0xd3, 0xbe, 0xc9, + 0x34, 0xfd, 0x9d, 0x6e, 0xdf, 0xe4, 0x03, 0x1a, + 0x7c, 0x52, 0x57, 0x9c, 0x11, 0xdc, 0xbd, 0x9f, + 0x41, 0xce, 0x2d, 0x33, 0x12, 0x92, 0x23, 0xff, + 0x83, 0xf2, 0x93, 0xcd, 0x14, 0xf1, 0x55, 0xbb, + 0x8d, 0x10, 0xa8, 0xc9, 0x60, 0x8f, 0xc9, 0xfb, + 0x70, 0xe1, 0xa8, 0x00, 0x68, 0x18, 0x87, 0x21, + 0x12, 0x52, 0xaa, 0xab, 0x6e, 0x56, 0xfa, 0x6c, + 0x96, 0x87, 0x04, 0xeb, 0x80, 0x94, 0xa6, 0xbe, + 0x3d, 0x90, 0x84, 0xd2, 0x73, 0x40, 0x80, 0x06, + 0x80, 0xc1, 0x40, 0xb9, 0x71, 0x25, 0xea, 0xe4, + 0x7b, 0xe5, 0x68, 0xf9, 0x20, 0x78, 0xa7, 0x07, + 0x01, 0x61, 0x9f, 0x50, 0xf9, 0x65, 0xc8, 0x1b, + 0x57, 0x53, 0xe8, 0xea, 0x18, 0xaa, 0x7a, 0x33, + 0x49, 0xb1, 0x34, 0x02, 0x7e, 0xdf, 0xa6, 0xf3, + 0x1b, 0xb3, 0x3f, 0xe9, 0xd7, 0xf3, 0x57, 0xc1, + 0x85, 0xdb, 0x37, 0xb6, 0x96, 0x29, 0xee, 0x20, + 0x05, 0xcb, 0x3a, 0xc4, 0x2c, 0x12, 0x8b, 0xdc, + 0xb2, 0x4f, 0x4e, 0x55, 0xc1, 0xe6, 0xa5, 0xb9, + 0x83, 0x0c, 0x03, 0xb1, 0x59, 0xb9, 0x5c, 0x85, + 0x78, 0xeb, 0xdb, 0xb0, 0x21, 0xac, 0x71, 0x85, + 0x05, 0x9c, 0x7a, 0xd9, 0x5f, 0xde, 0x96, 0xf1, + 0xb5, 0x30, 0x12, 0xfc, 0x8d, 0xce, 0x36, 0x0e, + 0x01, 0x17, 0x10, 0x4b, 0xdf, 0xb5, 0x01, 0x4d, + 0x30, 0x85, 0xb4, 0x9a, 0x50, 0x14, 0x40, 0x24, + 0x88, 0x87, 0x98, 0x21, 0x6f, 0xf2, 0xac, 0x68, + 0xeb, 0x60, 0xb4, 0xf3, 0x55, 0x78, 0xf2, 0x11, + 0x99, 0x34, 0xac, 0x79, 0xf5, 0xe6, 0xbd, 0xbb, + 0x04, 0x17, 0xdd, 0x76, 0x35, 0xf7, 0x36, 0x2f, + 0xb1, 0x49, 0xfb, 0x3a, 0x5e, 0x75, 0x21, 0xf7, + 0x06, 0x43, 0x20, 0x48, 0xfb, 0xd2, 0xd9, 0xbd, + 0xd1, 0x3b, 0x65, 0x8e, 0xd3, 0xac, 0x6c, 0xcf, + 0xef, 0xb1, 0x39, 0xc9, 0xb7, 0x91, 0x8d, 0xa8, + 0x5a, 0x78, 0xd6, 0x7d, 0x11, 0xcb, 0x3c, 0x62, + 0x54, 0xd9, 0x09, 0x1d, 0x8d, 0x87, 0x0c, 0x83, + 0x74, 0x9c, 0xf9, 0x9e, 0x6d, 0x59, 0xc9, 0xa6, + 0x83, 0x6e, 0x6d, 0xf1, 0xdc, 0xfa, 0xb0, 0x3e, + 0xcb, 0xab, 0x7b, 0xf1, 0xc1, 0xc0, 0x33, 0xef, + 0xe1, 0x17, 0xc2, 0x2a, 0x65, 0xe1, 0x17, 0xe9, + 0x1a, 0x1b, 0x84, 0x33, 0x64, 0x97, 0xa0, 0xcf, + 0x94, 0x72, 0x05, 0x61, 0x31, 0x61, 0x14, 0x88, + 0xe1, 0x9b, 0x81, 0xc6, 0xe2, 0x77, 0x51, 0x69, + 0x3f, 0xf3, 0xc6, 0x9e, 0x64, 0x36, 0x03, 0x1b, + 0x96, 0x69, 0x29, 0x0d, 0x8f, 0xc1, 0x79, 0xa4, + 0x1f, 0xac, 0x10, 0x52, 0x98, 0x8b, 0x29, 0x13, + 0x69, 0x50, 0x61, 0x68, 0xb4, 0xd6, 0xb4, 0x04, + 0x0b, 0xe0, 0x9f, 0x98, 0xb7, 0x22, 0xf8, 0x8c, + 0x3e, 0x29, 0x07, 0x1b, 0x0e, 0x52, 0x99, 0x3b, + 0xbb, 0x7b, 0x3f, 0xe4, 0xc5, 0xea, 0x36, 0x5a, + 0x0d, 0xfe, 0xc9, 0xfb, 0x4b, 0xe5, 0x79, 0xf8, + 0x86, 0x02, 0x24, 0x3b, 0xf4, 0x50, 0xfc, 0xb2, + 0x96, 0x98, 0xb5, 0xb2, 0x68, 0xba, 0x58, 0xfc, + 0x93, 0xd6, 0x2a, 0x27, 0x1f, 0x73, 0x47, 0xfd, + 0x27, 0x8f, 0x6a, 0x97, 0x10, 0x7b, 0xc2, 0xde, + 0x2c, 0x8d, 0x95, 0xd0, 0xef, 0xaf, 0xd9, 0x44, + 0xe5, 0xb4, 0x3a, 0x83, 0x4d, 0x9f, 0xa5, 0x6c, + 0x69, 0xd6, 0xa0, 0x88, 0x79, 0x31, 0xdd, 0x31, + 0x34, 0x07, 0x15, 0xe7, 0x73, 0x96, 0xd9, 0xb8, + 0x21, 0xd5, 0xcc, 0xa7, 0x8e, 0xf4, 0x6e, 0x47, + 0x9f, 0x82, 0x58, 0x9e, 0x5b, 0xe7, 0xa6, 0x60, + 0xcf, 0x05, 0x6e, 0x47, 0xab, 0x37, 0xcb, 0x99, + 0x5a, 0x2f, 0x49, 0x9d, 0x17, 0xa3, 0xa0, 0xcd, + 0x86, 0xc2, 0xb5, 0x9d, 0x7d, 0xc4, 0xbf, 0x59, + 0x57, 0x97, 0x48, 0x29, 0xdb, 0x52, 0xbb, 0x18, + 0xff, 0x85, 0xb6, 0xb6, 0x54, 0xbf, 0xfe, 0xaa, + 0x20, 0xc4, 0x61, 0xe2, 0xf0, 0x00, 0x7b, 0x25, + 0x17, 0xf6, 0x9b, 0x78, 0xfe, 0xff, 0x10, 0xb8, + 0x33, 0x0c, 0x3d, 0x1e, 0x7e, 0xc5, 0x6a, 0xa9, + 0x24, 0x6d, 0x07, 0x6f, 0x81, 0x6f, 0x5d, 0x90, + 0x5a, 0x16, 0xf9, 0x2b, 0xdc, 0x93, 0x48, 0xb1, + 0x30, 0xd8, 0x7f, 0x22, 0xb8, 0xbf, 0xde, 0xda, + 0xea, 0x69, 0xcc, 0xab, 0x40, 0xe9, 0xae, 0xa5, + 0x2e, 0xe1, 0x9f, 0x4d, 0x7e, 0x57, 0x58, 0xda, + 0x60, 0x48, 0x24, 0x42, 0x37, 0xdd, 0x88, 0xee, + 0x32, 0xa9, 0x5a, 0xf7, 0x2c, 0xfb, 0xcc, 0xf2, + 0xf6, 0x66, 0x26, 0xda, 0xe7, 0x4c, 0xa0, 0x72, + 0x18, 0x90, 0xf1, 0x19, 0x9d, 0x65, 0x62, 0xc9, + 0x8f, 0x11, 0xe7, 0x51, 0x56, 0xe1, 0xdc, 0x0f, + 0xb1, 0x46, 0xcb, 0xbd, 0x0a, 0x32, 0x62, 0x18, + 0x0e, 0x42, 0x75, 0x5a, 0xbb, 0xf2, 0x0f, 0x7f, + 0x2d, 0xb3, 0x14, 0x11, 0x6d, 0xc4, 0xa7, 0x2b, + 0x40, 0x94, 0x73, 0xfb, 0x5a, 0x89, 0x87, 0xe4, + 0x28, 0xab, 0xe9, 0x09, 0x56, 0xc6, 0x81, 0x12, + 0x1a, 0x31, 0xab, 0x6c, 0xf9, 0xf6, 0x72, 0x63, + 0xbb, 0x10, 0x63, 0xa2, 0x53, 0x75, 0xaa, 0xcf, + 0x34, 0xb4, 0x1b, 0x41, 0x69, 0x41, 0x59, 0x5b, + 0x1b, 0xaf, 0xf6, 0xca, 0xce, 0xdc, 0x45, 0x50, + 0xd1, 0x8e, 0xb1, 0xbe, 0x85, 0xc4, 0xc6, 0x38, + 0xa2, 0xfc, 0x54, 0x86, 0x72, 0xa5, 0xf3, 0x0e, + 0x82, 0x79, 0x74, 0xbc, 0x0e, 0x4c, 0x93, 0xf8, + 0xa4, 0x1e, 0xc1, 0x96, 0xe0, 0x08, 0x71, 0x03, + 0x49, 0x66, 0x36, 0x4f, 0x4c, 0x58, 0x37, 0xdf, + 0xf7, 0x0b, 0xa5, 0xb3, 0x91, 0x34, 0x83, 0xe2, + 0x5d, 0xc8, 0x15, 0xe9, 0xcc, 0x34, 0x3a, 0xc8, + 0x67, 0xbc, 0x50, 0xe5, 0xf9, 0xe5, 0xcd, 0x66, + 0x07, 0x69, 0x98, 0x45, 0xdd, 0xfb, 0xfd, 0xc0, + 0x5e, 0xd5, 0x14, 0xbc, 0xbe, 0xb0, 0x0e, 0x33, + 0xc5, 0x42, 0x45, 0x5d, 0x7b, 0x86, 0x5e, 0xb9, + 0xb2, 0x15, 0x82, 0x89, 0x20, 0x7f, 0x8d, 0x54, + 0x57, 0x1a, 0x37, 0x6c, 0x78, 0xca, 0xf2, 0x26, + 0x8c, 0x4e, 0x34, 0x01, 0xe1, 0x0c, 0x65, 0x94, + 0x1f, 0xde, 0x9b, 0x10, 0x5a, 0x09, 0xde, 0x93, + 0xa7, 0x57, 0xa7, 0x0c, 0xc6, 0x19, 0x33, 0x5a, + 0xb3, 0x23, 0x36, 0x72, 0x98, 0x72, 0xcf, 0x73, + 0x48, 0x7c, 0xca, 0xcd, 0xd1, 0x6e, 0xe8, 0x3d, + 0x4c, 0x25, 0xd2, 0x06, 0x0a, 0x2c, 0xcc, 0x2e, + 0xed, 0x9f, 0x87, 0xf3, 0xbc, 0x5f, 0x7f, 0xce, + 0x0f, 0xf5, 0x78, 0x98, 0x95, 0xa3, 0xc2, 0xe9, + 0x37, 0xa1, 0x6e, 0x4a, 0x84, 0xe4, 0x5e, 0x18, + 0x79, 0xf8, 0x9a, 0xa0, 0xa8, 0x77, 0xb5, 0xa8, + 0xa4, 0x6a, 0xb1, 0xbc, 0x19, 0xad, 0x29, 0x46, + 0xb0, 0xd1, 0x4a, 0x3c, 0xd8, 0x77, 0x8a, 0xe9, + 0x2d, 0x51, 0xc1, 0x02, 0x93, 0x84, 0x97, 0xd9, + 0xbd, 0xf7, 0xff, 0x40, 0x3a, 0xb8, 0x06, 0xa9, + 0xe4, 0x23, 0xa4, 0x8e, 0x48, 0x12, 0x4a, 0xdb, + 0x57, 0xc8, 0x21, 0xa9, 0x38, 0x40, 0x9c, 0xd0, + 0x86, 0x76, 0x2c, 0xb4, 0x5e, 0x91, 0xbe, 0x3e, + 0x82, 0x84, 0x3a, 0xa5, 0xda, 0x94, 0xb5, 0xed, + 0x0c, 0xd5, 0x93, 0xc7, 0x9c, 0xac, 0xfc, 0xac, + 0xf1, 0x81, 0xc5, 0xfa, 0x7d, 0x51, 0x78, 0x6f, + 0xab, 0x44, 0xac, 0x6e, 0x1b, 0x2d, 0x9e, 0x03, + 0xd4, 0x4a, 0xd3, 0x5e, 0xf3, 0x72, 0x0d, 0xd5, + 0x1e, 0x85, 0xad, 0x74, 0x20, 0xfe, 0x35, 0x58, + 0xf2, 0xdb, 0x1d, 0xde, 0xd8, 0xb9, 0x44, 0x84, + 0x40, 0x87, 0x42, 0xee, 0x70, 0xcb, 0x74, 0x4c, + 0x2b, 0xde, 0x69, 0x91, 0x8d, 0x4f, 0xcb, 0x2e, + 0xfb, 0xa8, 0xf1, 0xeb, 0x2e, 0xbd, 0x8f, 0xdc, + 0xf8, 0x4d, 0xd7, 0x93, 0xc8, 0x61, 0x06, 0xa4, + 0xb4, 0x32, 0x44, 0x4a, 0x42, 0x53, 0x69, 0xfa, + 0xb9, 0x48, 0x40, 0xf6, 0xb7, 0x72, 0xe5, 0x48, + 0x6d, 0x09, 0x61, 0xc4, 0xba, 0x40, 0x27, 0x61, + 0x7c, 0x3a, 0x70, 0xfd, 0x6d, 0x38, 0xff, 0x58, + 0x3e, 0xcd, 0x44, 0x8e, 0xe9, 0xc4, 0xb8, 0xcf, + 0x31, 0xd3, 0x36, 0xfc, 0x39, 0x18, 0x81, 0x8a, + 0x2b, 0x25, 0x8c, 0x76, 0x1e, 0xd1, 0x24, 0xea, + 0xb7, 0x83, 0xf4, 0xc3, 0x86, 0x16, 0x33, 0xd7, + 0x6d, 0x7b, 0x58, 0x1c, 0x6a, 0x29, 0x49, 0x07, + 0xab, 0x8f, 0xbc, 0xa3, 0x1a, 0xbc, 0xf4, 0xca, + 0xf2, 0x43, 0x15, 0x2c, 0xaa, 0x6f, 0x57, 0xc5, + 0xcf, 0x0c, 0x91, 0x53, 0xbf, 0xeb, 0xa8, 0x44, + 0x01, 0x82, 0xbb, 0xc8, 0x7f, 0x4e, 0xd6, 0xd3, + 0x79, 0x79, 0x4d, 0x84, 0xa1, 0x3a, 0x26, 0x68, + 0x0c, 0x2a, 0xa2, 0xee, 0x92, 0xaf, 0x2d, 0x8a, + 0x07, 0x54, 0x37, 0x6e, 0x95, 0xd5, 0x68, 0x78, + 0x04, 0x43, 0x53, 0x1c, 0x59, 0xcc, 0xe1, 0xec, + 0x43, 0xd7, 0x6c, 0x3b, 0xcb, 0x3b, 0x28, 0x8c, + 0x86, 0x0f, 0x71, 0x29, 0xd1, 0xcb, 0x09, 0x3f, + 0x6c, 0x76, 0x1b, 0x45, 0x5a, 0xdb, 0x75, 0xe1, + 0x3a, 0x4f, 0x32, 0x80, 0x09, 0xa2, 0xc3, 0xba, + 0xfc, 0x6b, 0x11, 0x47, 0x12, 0x68, 0x60, 0x79, + 0xa1, 0x28, 0x6e, 0x6e, 0xca, 0x22, 0xb8, 0xce, + 0x31, 0x23, 0xf1, 0xab, 0xe4, 0x78, 0xa2, 0x4d, + 0xb8, 0x4a, 0x18, 0xfd, 0xdc, 0x2d, 0xa1, 0x70, + 0xb1, 0xbc, 0xd2, 0x72, 0x08, 0x4b, 0x97, 0x8b, + 0x31, 0x59, 0x34, 0x01, 0x26, 0xac, 0x8a, 0x90, + 0x99, 0xaf, 0x75, 0xe3, 0x82, 0x21, 0x47, 0x76, + 0xc0, 0xae, 0x42, 0xc4, 0xe2, 0x13, 0xdf, 0xdb, + 0x8f, 0x79, 0x52, 0xd8, 0x1b, 0xf8, 0x30, 0x74, + 0x97, 0xde, 0xed, 0xa0, 0xe4, 0xaf, 0xb3, 0x01, + 0xaa, 0x89, 0x43, 0xcb, 0xaf, 0x37, 0x13, 0x44, + 0xb8, 0x33, 0x5a, 0xab, 0x53, 0xff, 0xef, 0x62, + 0xaf, 0x4c, 0x86, 0xcb, 0x6a, 0xa9, 0x02, 0x5d, + 0x54, 0xa1, 0xaf, 0xb2, 0x97, 0xb9, 0x20, 0x13, + 0xe7, 0xae, 0x27, 0x8f, 0x53, 0x97, 0x3b, 0xf8, + 0x29, 0xb2, 0x03, 0x13, 0x86, 0x37, 0xe3, 0xb9, + 0xe8, 0x28, 0xce, 0x84, 0xec, 0xbd, 0xd5, 0x54, + 0xf7, 0x5c, 0x2d, 0x16, 0xe6, 0x29, 0x03, 0xd0, + 0x5e, 0x4b, 0x04, 0xa6, 0xb9, 0xda, 0x17, 0x7e, + 0xfa, 0x0b, 0x36, 0xb9, 0xef, 0xa9, 0xcb, 0xf4, + 0x3f, 0xc6, 0x14, 0x75, 0xeb, 0x4b, 0x56, 0x26, + 0x92, 0xac, 0x0a, 0x23, 0x60, 0xde, 0x5b, 0xf9, + 0x99, 0x90, 0xa5, 0x94, 0x28, 0x1d, 0x4e, 0xc8, + 0xf4, 0x55, 0xaf, 0x8e, 0x08, 0xb8, 0xf0, 0xcc, + 0x4b, 0xe9, 0xb0, 0xf2, 0xb8, 0xf4, 0x23, 0x5c, + 0x94, 0xa5, 0x50, 0x34, 0xb7, 0xec, 0xdd, 0x45, + 0x45, 0x1b, 0x24, 0x21, 0xf1, 0x3c, 0xe0, 0x89, + 0x20, 0xc3, 0xda, 0x1b, 0x5b, 0x63, 0xbd, 0x67, + 0x70, 0xf1, 0x97, 0x6c, 0x82, 0x52, 0x67, 0xa8, + 0xc4, 0x6b, 0x16, 0xcc, 0x89, 0x07, 0x3b, 0x10, + 0x3c, 0x6e, 0x27, 0xc8, 0xf9, 0xce, 0xfa, 0x2e, + 0xac, 0x31, 0x90, 0xf7, 0xe0, 0x3e, 0x2b, 0x5e, + 0x8f, 0x1e, 0x7b, 0xc3, 0xfb, 0xdd, 0xb9, 0xe8, + 0xee, 0x1a, 0x0b, 0x1c, 0xa8, 0xd0, 0x3b, 0x27, + 0x8b, 0x43, 0x22, 0x7c, 0xe9, 0x9d, 0x56, 0xa4, + 0xe8, 0x19, 0xd3, 0xd0, 0xfc, 0x70, 0xed, 0x3d, + 0x39, 0x16, 0x4e, 0x54, 0x2b, 0xf7, 0x0f, 0x6f, + 0x94, 0xbe, 0x2d, 0x43, 0x6a, 0xe6, 0xad, 0xc7, + 0x38, 0x50, 0xd5, 0x48, 0x55, 0xda, 0x2b, 0xba, + 0x99, 0x6c, 0x6f, 0xc8, 0x39, 0xf4, 0xed, 0x29, + 0x53, 0xed, 0x6c, 0x2a, 0x84, 0xad, 0x6a, 0x96, + 0x77, 0x5f, 0x14, 0xd3, 0xda, 0xe2, 0xf1, 0x14, + 0x5d, 0xaa, 0x3e, 0x95, 0xdb, 0x8a, 0x2a, 0xb2, + 0x32, 0xcf, 0x62, 0x25, 0xe6, 0xc8, 0x56, 0x09, + 0x87, 0x35, 0x31, 0xe6, 0x55, 0xe3, 0xf8, 0x40, + 0x82, 0x1a, 0x1f, 0x86, 0x68, 0x60, 0x40, 0x29, + 0x3a, 0xac, 0x76, 0x6d, 0xf4, 0x7a, 0x0f, 0xcc, + 0x1f, 0x69, 0x7e, 0xb0, 0xc6, 0xaa, 0x44, 0xff, + 0x6b, 0x5e, 0xf1, 0xa4, 0xba, 0x81, 0xb7, 0xd8, + 0xf6, 0x38, 0x24, 0x9b, 0x47, 0x7f, 0x69, 0xf6, + 0x8c, 0xac, 0x98, 0x4c, 0xf5, 0xf0, 0x55, 0x76, + 0x7f, 0x8c, 0xd8, 0x43, 0x1b, 0x69, 0x28, 0x4a, + 0xdc, 0x95, 0x29, 0x44, 0x0e, 0xc8, 0x2a, 0x4b, + 0xe5, 0x2e, 0xb4, 0xb5, 0x4f, 0xbc, 0x34, 0x05, + 0xf0, 0x82, 0x1a, 0x54, 0xec, 0x89, 0xe9, 0xc7, + 0xae, 0x60, 0x82, 0xd5, 0x54, 0x49, 0x26, 0xde, + 0x2a, 0x87, 0x04, 0xed, 0xbe, 0x2b, 0x31, 0x95, + 0x07, 0x8e, 0xcd, 0xd1, 0x62, 0xa0, 0xa0, 0x89, + 0xdc, 0x09, 0x3c, 0xcb, 0xb0, 0x0a, 0xec, 0x70, + 0x64, 0xfe, 0xbf, 0xf8, 0xc7, 0x10, 0x6e, 0x61, + 0x8b, 0xd7, 0x2a, 0xa0, 0x57, 0xb1, 0x01, 0x76, + 0x18, 0x3a, 0xe9, 0x05, 0xb4, 0x50, 0x84, 0x36, + 0x68, 0xbe, 0x38, 0x9d, 0x03, 0xe6, 0x13, 0xad, + 0xbd, 0xfc, 0xc2, 0xb1, 0x12, 0x4a, 0x00, 0xf0, + 0x02, 0xda, 0x0c, 0xe8, 0x9c, 0x0f, 0x44, 0x31, + 0xc3, 0xf2, 0xd6, 0x23, 0x0b, 0xce, 0xef, 0xab, + 0xc9, 0x5a, 0x58, 0x4a, 0x59, 0x7c, 0x6c, 0x8b, + 0x98, 0x21, 0xdf, 0xb8, 0x5f, 0xc8, 0x1e, 0x9c, + 0xaa, 0x52, 0x42, 0x64, 0xb4, 0xe0, 0x83, 0x78, + 0xea, 0xed, 0xb4, 0x92, 0xde, 0x5b, 0x99, 0x33, + 0x61, 0xdc, 0x04, 0x71, 0x30, 0x2e, 0x2c, 0xf8, + 0xf7, 0xb6, 0x5b, 0x9b, 0xad, 0xee, 0x1b, 0x67, + 0x40, 0x16, 0x57, 0x77, 0xfa, 0x17, 0xe5, 0x6d, + 0xd8, 0x94, 0xc2, 0x25, 0x4c, 0xf9, 0x42, 0x2e, + 0x3d, 0xbf, 0xcd, 0x81, 0x4c, 0x79, 0x92, 0x46, + 0x62, 0xde, 0xc8, 0x3b, 0x91, 0xee, 0x59, 0x16, + 0x4d, 0x74, 0xfc, 0x63, 0xea, 0x6c, 0x6f, 0x66, + 0xee, 0x61, 0x0e, 0x0a, 0x3e, 0x6c, 0x20, 0xe3, + 0x23, 0xfd, 0xa0, 0x88, 0xb9, 0xea, 0x55, 0x83, + 0x99, 0x41, 0xaa, 0x8d, 0xe2, 0x74, 0xa8, 0x61, + 0xd9, 0xb3, 0xc7, 0x6c, 0xe9, 0x28, 0x12, 0x6d, + 0xe0, 0x73, 0xa0, 0x4b, 0x5a, 0x77, 0x55, 0x51, + 0xd8, 0x02, 0x83, 0x81, 0xd1, 0x67, 0x10, 0x55, + 0x32, 0xc6, 0xea, 0x3e, 0x14, 0xce, 0xc4, 0x4c, + 0x95, 0x63, 0x61, 0x8f, 0x06, 0x20, 0xaa, 0x2d, + 0x74, 0x93, 0xf3, 0x47, 0x2d, 0x0b, 0x3c, 0xd5, + 0xf8, 0xce, 0x1f, 0x7b, 0x10, 0x2e, 0x5a, 0xf2, + 0x3d, 0x54, 0xaa, 0xfd, 0x56, 0x3f, 0xc9, 0x11, + 0x48, 0xd3, 0x31, 0x11, 0x28, 0x6c, 0x63, 0x5a, + 0x4f, 0xee, 0xdd, 0x73, 0x06, 0x1e, 0xea, 0x54, + 0x01, 0x4b, 0x9f, 0x82, 0x46, 0x83, 0x71, 0xad, + 0x26, 0x19, 0xc9, 0xf5, 0x7d, 0x57, 0x07, 0x74, + 0xb4, 0x08, 0x2e, 0x4c, 0xfd, 0x72, 0x30, 0xf1, + 0x72, 0x74, 0xf5, 0x98, 0xa9, 0xbb, 0x92, 0xa5, + 0x02, 0x81, 0x48, 0xd2, 0xc4, 0x1c, 0x47, 0x51, + 0x2f, 0xf8, 0xf1, 0x0f, 0xbb, 0xab, 0x48, 0x02, + 0xcb, 0xbc, 0xf3, 0xb8, 0x85, 0xd0, 0xab, 0xcf, + 0x97, 0x48, 0x95, 0x48, 0x08, 0x35, 0xda, 0x1e, + 0x66, 0x34, 0xd4, 0x83, 0x02, 0xbe, 0xfb, 0xdd, + 0xe1, 0xe6, 0x39, 0xbd, 0xed, 0xe2, 0x73, 0x75, + 0x05, 0xda, 0x24, 0xa5, 0x0d, 0x2c, 0x7e, 0x21, + 0x4d, 0x84, 0x64, 0xa2, 0x8f, 0x23, 0x6f, 0x73, + 0xeb, 0xba, 0x8f, 0x84, 0x65, 0x15, 0x13, 0xaa, + 0xed, 0x7e, 0x10, 0xe8, 0x41, 0xd3, 0xa8, 0x96, + 0x59, 0x46, 0x54, 0xa8, 0xef, 0x37, 0xfb, 0xf8, + 0xfd, 0x46, 0x04, 0xc6, 0x91, 0x55, 0x0b, 0xcb, + 0x88, 0x71, 0x5b, 0x41, 0x09, 0x3d, 0xa1, 0xa1, + 0x03, 0x01, 0x80, 0xd4, 0xde, 0xbb, 0x91, 0xf1, + 0x7e, 0xab, 0x26, 0xbb, 0x44, 0xa6, 0xa5, 0xa9, + 0xf5, 0xe0, 0x57, 0x2c, 0xd1, 0x88, 0x19, 0x74, + 0xa4, 0x46, 0xbf, 0x9c, 0xc1, 0x94, 0xc9, 0xfe, + 0xe5, 0x27, 0x2c, 0x77, 0x61, 0x04, 0x51, 0x83, + 0x08, 0xa3, 0xc7, 0x84, 0xcf, 0xb7, 0xe4, 0x02, + 0x72, 0x44, 0xad, 0x63, 0x90, 0xbf, 0x88, 0x90, + 0x1d, 0x2b, 0xb9, 0x56, 0x48, 0xcc, 0xc6, 0xa4, + 0x8d, 0xa8, 0x9d, 0xcd, 0x35, 0x26, 0xfc, 0x3a, + 0xa5, 0x96, 0x57, 0x2a, 0x63, 0x9c, 0xb9, 0x97, + 0x75, 0xa5, 0x94, 0xd9, 0xdd, 0x43, 0x61, 0x82, + 0x31, 0x2f, 0xea, 0x71, 0x4a, 0xdb, 0xad, 0x9b, + 0x93, 0xb5, 0x28, 0x77, 0x01, 0xad, 0x83, 0x89, + 0x34, 0x09, 0xa2, 0xce, 0x60, 0xc3, 0xdb, 0xbe, + 0x27, 0x53, 0xc7, 0xf5, 0x69, 0xdb, 0x30, 0x3b, + 0x2c, 0x62, 0xda, 0x3c, 0x1e, 0xae, 0x18, 0x1b, + 0x3b, 0xdc, 0xc2, 0x5f, 0xa4, 0x61, 0xa3, 0x4a, + 0x96, 0x6c, 0x22, 0x3c, 0x59, 0xcd, 0xcb, 0xb4, + 0x44, 0x12, 0x95, 0x41, 0x74, 0x78, 0x9d, 0xea, + 0x08, 0x52, 0x48, 0xa4, 0x58, 0xa2, 0x10, 0x9c, + 0xd6, 0x2e, 0x34, 0x07, 0x48, 0xf8, 0x71, 0x73, + 0x09, 0x51, 0xfa, 0x58, 0x1c, 0xdc, 0xf6, 0xda, + 0xc1, 0x1b, 0xf3, 0xd8, 0x1a, 0x8f, 0xf2, 0xbe, + 0xf1, 0xe4, 0x1a, 0xe1, 0x1e, 0xfa, 0x6e, 0x01, + 0x40, 0x24, 0x1d, 0xbd, 0x2c, 0xb3, 0x9d, 0x41, + 0xdc, 0x36, 0x7d, 0x91, 0xd0, 0xa3, 0xec, 0xd1, + 0xd5, 0x57, 0xb7, 0x48, 0x40, 0xec, 0x4b, 0xb1, + 0xe8, 0xbc, 0xf8, 0x82, 0x25, 0x50, 0x1e, 0xf6, + 0x05, 0xc7, 0x6d, 0x4b, 0xaa, 0xd6, 0x1c, 0x62, + 0x1c, 0x67, 0x46, 0x25, 0xdd, 0xf1, 0xdc, 0xfa, + 0xb7, 0x1d, 0x7c, 0x7c, 0x32, 0x10, 0xc8, 0x50, + 0xdb, 0xb8, 0xe4, 0xdc, 0xc7, 0x5b, 0xbc, 0x25, + 0x98, 0x90, 0x4d, 0xa9, 0xc3, 0xc3, 0x9c, 0x9e, + 0xb0, 0xd4, 0x6a, 0x34, 0xa4, 0xc1, 0xed, 0x72, + 0xa4, 0x19, 0xdc, 0x25, 0xda, 0x8d, 0x68, 0x5b, + 0x34, 0xf9, 0x0b, 0xc7, 0xa6, 0xa3, 0x8f, 0xee, + 0x60, 0x3d, 0x82, 0xd6, 0x77, 0x2c, 0x03, 0x5b, + 0x43, 0xcd, 0xd7, 0x7c, 0x72, 0x67, 0x49, 0x8b, + 0x32, 0x3b, 0x01, 0x75, 0x48, 0xb8, 0x26, 0x4e, + 0xca, 0x0e, 0xb0, 0x5c, 0xbd, 0x1f, 0xb4, 0xe7, + 0x8d, 0x86, 0xd4, 0x23, 0x46, 0x76, 0x2e, 0x72, + 0x64, 0x5e, 0x23, 0x78, 0xe3, 0xdd, 0x70, 0xcc, + 0xbf, 0x78, 0x4c, 0x6d, 0x80, 0xbf, 0xde, 0x10, + 0xad, 0x4b, 0x5f, 0xe7, 0x98, 0x20, 0x04, 0xe7, + 0xcb, 0x80, 0x3c, 0x1c, 0x48, 0x45, 0xac, 0x80, + 0x7e, 0xaf, 0x8f, 0x6f, 0x26, 0x25, 0x5b, 0x44, + 0x1e, 0x5e, 0x5a, 0xa3, 0x60, 0xf8, 0xd1, 0x4c, + 0x86, 0x29, 0xa9, 0x98, 0xd0, 0x03, 0x82, 0x02, + 0x02, 0x7b, 0x6f, 0x6a, 0x80, 0xb1, 0x13, 0x00, + 0x2f, 0x25, 0x4f, 0x5c, 0x63, 0x8a, 0x90, 0xf4, + 0x65, 0x8e, 0x90, 0x96, 0xc3, 0xe8, 0x0f, 0x21, + 0x28, 0x44, 0x51, 0x56, 0x5d, 0x5f, 0x08, 0x27, + 0x43, 0x4f, 0xa9, 0xad, 0xd9, 0xe2, 0x69, 0x99, + 0xa5, 0xbc, 0x2a, 0x3a, 0x4a, 0x54, 0x8d, 0x90, + 0xc9, 0xdf, 0x1b, 0x23, 0x46, 0x51, 0x87, 0x89, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x08, 0x0e, 0x16, 0x1e, + 0x22, 0x2a, 0x30 + }; + + + ExpectNotNull(key = (dilithium_key*)XMALLOC(sizeof(*key), NULL, + DYNAMIC_TYPE_TMP_BUFFER)); + ExpectNotNull(sig = (byte*)XMALLOC(DILITHIUM_MAX_SIG_SIZE, NULL, + DYNAMIC_TYPE_TMP_BUFFER)); + PRIVATE_KEY_UNLOCK(); + +#ifndef WOLFSSL_NO_ML_DSA_44 + /* ML-DSA-44: sign with externalMu, deterministic seed (zeros). */ + ExpectIntEQ(wc_dilithium_init_ex(key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_dilithium_set_level(key, WC_ML_DSA_44), 0); + ExpectIntEQ(wc_dilithium_import_private(sk_44_mu, + (word32)sizeof(sk_44_mu), key), 0); + sigLen = DILITHIUM_MAX_SIG_SIZE; + ExpectIntEQ(wc_dilithium_sign_mu_with_seed(mu_44, + (word32)sizeof(mu_44), sig, &sigLen, key, zeroSeed), 0); + ExpectIntEQ(sigLen, (word32)sizeof(sig_44_mu)); + ExpectIntEQ(XMEMCMP(sig, sig_44_mu, sizeof(sig_44_mu)), 0); + wc_dilithium_free(key); +#endif /* !WOLFSSL_NO_ML_DSA_44 */ +#ifndef WOLFSSL_NO_ML_DSA_65 + /* ML-DSA-65: sign with externalMu, deterministic seed (zeros). */ + ExpectIntEQ(wc_dilithium_init_ex(key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_dilithium_set_level(key, WC_ML_DSA_65), 0); + ExpectIntEQ(wc_dilithium_import_private(sk_65_mu, + (word32)sizeof(sk_65_mu), key), 0); + sigLen = DILITHIUM_MAX_SIG_SIZE; + ExpectIntEQ(wc_dilithium_sign_mu_with_seed(mu_65, + (word32)sizeof(mu_65), sig, &sigLen, key, zeroSeed), 0); + ExpectIntEQ(sigLen, (word32)sizeof(sig_65_mu)); + ExpectIntEQ(XMEMCMP(sig, sig_65_mu, sizeof(sig_65_mu)), 0); + wc_dilithium_free(key); +#endif /* !WOLFSSL_NO_ML_DSA_65 */ +#ifndef WOLFSSL_NO_ML_DSA_87 + /* ML-DSA-87: sign with externalMu, deterministic seed (zeros). */ + ExpectIntEQ(wc_dilithium_init_ex(key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_dilithium_set_level(key, WC_ML_DSA_87), 0); + ExpectIntEQ(wc_dilithium_import_private(sk_87_mu, + (word32)sizeof(sk_87_mu), key), 0); + sigLen = DILITHIUM_MAX_SIG_SIZE; + ExpectIntEQ(wc_dilithium_sign_mu_with_seed(mu_87, + (word32)sizeof(mu_87), sig, &sigLen, key, zeroSeed), 0); + ExpectIntEQ(sigLen, (word32)sizeof(sig_87_mu)); + ExpectIntEQ(XMEMCMP(sig, sig_87_mu, sizeof(sig_87_mu)), 0); + wc_dilithium_free(key); +#endif /* !WOLFSSL_NO_ML_DSA_87 */ + PRIVATE_KEY_LOCK(); + XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return EXPECT_RESULT(); +} + +/* Known-answer tests for the ML-DSA externalMu verify API + * (wc_dilithium_verify_mu). Reuses the vectors above and adds two + * negative cases per parameter set: a bit flip in mu and in sig. + * + * Userspace-only (see note on test_wc_dilithium_sign_mu_kats above); + * kernel-module chunking does not apply. */ +int test_wc_dilithium_verify_mu_kats(void) +{ + EXPECT_DECLS; +#if defined(HAVE_DILITHIUM) && defined(WOLFSSL_WC_DILITHIUM) && \ + !defined(WOLFSSL_DILITHIUM_NO_VERIFY) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + dilithium_key* key = NULL; + byte* sigBuf = NULL; + byte muBuf[DILITHIUM_MU_SZ]; + int res; + + /* ML-DSA-44 externalMu: deterministic, tcId 91 + * Source: kh-fork-fips/wolfACVP/v7.0.0-known/ + * ML-DSA-sigGen-request.json. Deterministic mode + * uses rnd = 0^32 per FIPS 204 Section 3.7. */ + static const byte pk_44_mu[] = { + 0x81, 0xf5, 0x5d, 0xba, 0xcc, 0x51, 0xeb, 0xde, + 0x5c, 0x5a, 0x25, 0x8c, 0x14, 0xf5, 0x54, 0xfb, + 0x3a, 0x93, 0xe1, 0x6c, 0x78, 0x3a, 0x7e, 0x8c, + 0x60, 0x8e, 0x6e, 0xbd, 0xd2, 0x35, 0x2f, 0x20, + 0x60, 0x63, 0x13, 0x99, 0xdf, 0xe2, 0xd9, 0x7c, + 0xec, 0xfb, 0x23, 0xdb, 0x18, 0x3e, 0x67, 0x29, + 0xa6, 0x1b, 0x6d, 0x07, 0xcc, 0x85, 0xd8, 0x29, + 0x7c, 0x04, 0xa0, 0x5c, 0xab, 0x45, 0xf2, 0xdb, + 0xc8, 0x7f, 0x4a, 0xd5, 0x9a, 0x2b, 0x4e, 0x86, + 0x29, 0x95, 0x4f, 0x11, 0xa9, 0xf4, 0x34, 0xed, + 0x0a, 0xe8, 0x51, 0x45, 0x2c, 0xce, 0xff, 0x15, + 0x8c, 0x7e, 0x1c, 0xd7, 0xba, 0x3a, 0xdd, 0xaf, + 0x7d, 0xf7, 0xeb, 0x10, 0x42, 0x38, 0x87, 0xf9, + 0xe2, 0xc7, 0xab, 0xd7, 0x3e, 0xd2, 0xf7, 0x86, + 0xba, 0x6a, 0x50, 0x93, 0x80, 0xc2, 0xce, 0x48, + 0x2e, 0xbc, 0xdd, 0x63, 0x0c, 0x02, 0xdb, 0x0b, + 0x7a, 0x24, 0xb3, 0xc4, 0xbf, 0xf1, 0x57, 0x6d, + 0xc1, 0x62, 0x99, 0x3a, 0x5f, 0x13, 0x6b, 0x2f, + 0x4f, 0xdd, 0x1b, 0x82, 0x41, 0xb6, 0x12, 0x59, + 0x8b, 0x54, 0x9c, 0x78, 0x84, 0xeb, 0xb7, 0x36, + 0x5f, 0x9f, 0x96, 0xbc, 0xb1, 0x99, 0x3c, 0xca, + 0xe2, 0x83, 0x7a, 0xa9, 0xe2, 0x43, 0x37, 0x8e, + 0x86, 0x7b, 0x2a, 0xca, 0x30, 0x7b, 0x19, 0x33, + 0xfc, 0x12, 0x17, 0x22, 0xd3, 0x35, 0xd9, 0xb1, + 0x50, 0x56, 0x25, 0x41, 0x11, 0xdf, 0xfc, 0xc6, + 0x77, 0x17, 0xd3, 0x77, 0xaa, 0x36, 0x70, 0xfc, + 0xf8, 0xdc, 0xc5, 0xcc, 0xc7, 0x23, 0x7c, 0x74, + 0xef, 0x3c, 0x40, 0x9a, 0xd5, 0x36, 0x5b, 0x4e, + 0xfa, 0x25, 0x26, 0xb7, 0x9f, 0x50, 0x5c, 0x24, + 0x6e, 0x14, 0x4c, 0x98, 0x2f, 0x7a, 0x67, 0x62, + 0x39, 0xd8, 0xf9, 0xd9, 0xb4, 0x6c, 0x90, 0x31, + 0x99, 0x1e, 0xac, 0x56, 0xd9, 0x83, 0x71, 0x18, + 0x55, 0x8f, 0x38, 0x5b, 0x4e, 0x4c, 0xe9, 0x4d, + 0xce, 0x82, 0xee, 0x67, 0x1a, 0x7d, 0xb6, 0x3b, + 0x62, 0xad, 0x1b, 0xb9, 0x10, 0x9e, 0xcf, 0xcd, + 0x66, 0xf3, 0xcf, 0xda, 0xd1, 0x59, 0xbd, 0x1a, + 0x8b, 0x9d, 0x5a, 0x88, 0xcd, 0x26, 0x3b, 0xa8, + 0xd1, 0xf5, 0x26, 0xd9, 0xfb, 0x34, 0x10, 0x79, + 0xc7, 0x08, 0xdc, 0xfa, 0xd0, 0x48, 0x3a, 0x06, + 0x1f, 0xa5, 0x7e, 0xc0, 0xce, 0xf4, 0x4e, 0xb2, + 0x9f, 0xed, 0xe3, 0xbe, 0x4b, 0x3f, 0x42, 0x67, + 0xb0, 0xe3, 0x17, 0x09, 0xda, 0x38, 0xec, 0x4d, + 0xd6, 0x62, 0x52, 0xe6, 0xc9, 0x1e, 0x1e, 0x6e, + 0x25, 0x4f, 0x07, 0x4e, 0x95, 0x01, 0xfb, 0xf2, + 0x5b, 0xba, 0x2c, 0xec, 0x03, 0xad, 0x9b, 0x74, + 0x44, 0xd8, 0xd0, 0x4a, 0x8c, 0xa4, 0x1b, 0x19, + 0xcb, 0xf8, 0x21, 0x3d, 0x3a, 0xb0, 0x75, 0x62, + 0x20, 0x21, 0x37, 0xf4, 0x96, 0x05, 0x54, 0x18, + 0x16, 0x7e, 0xa7, 0xef, 0xd9, 0x04, 0x8f, 0xd9, + 0x3e, 0x18, 0xf4, 0x0a, 0x22, 0xea, 0x31, 0x26, + 0xf7, 0x79, 0x8b, 0x42, 0xf7, 0x76, 0x37, 0xe8, + 0x04, 0xa1, 0x7f, 0x54, 0x0e, 0xf3, 0xf4, 0x13, + 0x19, 0x5e, 0x48, 0xf0, 0x50, 0xc6, 0xb7, 0x14, + 0xa2, 0x64, 0xa8, 0xcf, 0x75, 0xa7, 0xf9, 0x5d, + 0x0c, 0x73, 0xd9, 0x57, 0x34, 0x0a, 0x6c, 0x28, + 0x06, 0x58, 0x8c, 0x8a, 0xfd, 0x63, 0x86, 0x50, + 0x44, 0xba, 0xff, 0xf0, 0xc0, 0x1d, 0xf4, 0x32, + 0x80, 0xea, 0x98, 0x03, 0xb7, 0x14, 0x7e, 0xca, + 0xc6, 0x97, 0x6b, 0xeb, 0xc9, 0xc9, 0xeb, 0x3a, + 0xfa, 0x3d, 0x73, 0xf8, 0x7e, 0xb8, 0x4e, 0x42, + 0x72, 0x47, 0x76, 0xbc, 0x58, 0xd8, 0x0e, 0xc7, + 0x6f, 0x9f, 0xc1, 0x12, 0xa5, 0x02, 0x5a, 0x18, + 0xe4, 0x5c, 0x79, 0xe7, 0xf5, 0x74, 0x17, 0x72, + 0x01, 0xfb, 0x82, 0xa2, 0xd3, 0x27, 0x67, 0xb7, + 0xb9, 0xc8, 0xfb, 0x8a, 0x6b, 0xf3, 0x89, 0xac, + 0x82, 0x53, 0x23, 0xbc, 0x1a, 0x11, 0xa8, 0xfb, + 0xc8, 0xd2, 0x82, 0xec, 0x68, 0x68, 0x68, 0x4e, + 0x9c, 0x97, 0x6b, 0xb3, 0x2d, 0x87, 0xe9, 0xdb, + 0xb7, 0x86, 0xbc, 0x2f, 0x71, 0xfa, 0xc0, 0x30, + 0x58, 0x34, 0x04, 0xfc, 0x37, 0x66, 0x5c, 0x71, + 0x5f, 0xea, 0xbd, 0x5e, 0x74, 0xa5, 0xbc, 0x3e, + 0x95, 0xab, 0x12, 0x3f, 0x16, 0x3b, 0x92, 0xea, + 0xdb, 0x4c, 0x2c, 0x04, 0x6e, 0xcd, 0xa5, 0x8b, + 0x29, 0x86, 0xa8, 0x64, 0xa2, 0x34, 0xf6, 0x9c, + 0xfb, 0x6a, 0x4f, 0x06, 0x80, 0x9a, 0x54, 0xac, + 0x65, 0xc7, 0xd3, 0x0b, 0xb3, 0xc3, 0x62, 0x55, + 0x9e, 0x11, 0x8b, 0x45, 0x46, 0xc1, 0x70, 0xfc, + 0x41, 0xa1, 0x36, 0x9c, 0x42, 0x63, 0xdf, 0x5c, + 0x6a, 0xeb, 0xdc, 0x42, 0x36, 0xd8, 0x5a, 0x97, + 0x67, 0xb3, 0x32, 0xbe, 0x1f, 0x7e, 0x15, 0x45, + 0xad, 0x35, 0x01, 0xa1, 0x39, 0x6b, 0x86, 0xdd, + 0xac, 0x1b, 0xf2, 0xda, 0x2f, 0x2a, 0x7a, 0x5a, + 0xb8, 0x48, 0x15, 0xe6, 0x68, 0x73, 0xc0, 0xf1, + 0x55, 0xdb, 0x9a, 0x91, 0xc1, 0xf2, 0x45, 0xcd, + 0x82, 0xc2, 0x24, 0x20, 0xae, 0x6c, 0x0a, 0x66, + 0x2d, 0x83, 0x68, 0x53, 0x7f, 0xe9, 0x19, 0x69, + 0x6c, 0x50, 0xfa, 0x90, 0xfd, 0xa3, 0x0a, 0xa3, + 0x0e, 0xea, 0x21, 0x29, 0x69, 0x3b, 0xd1, 0xcc, + 0x31, 0x2a, 0x4a, 0x68, 0x80, 0xbc, 0xef, 0x57, + 0xfa, 0x1e, 0xb1, 0x5f, 0x12, 0xb2, 0x13, 0x67, + 0x6d, 0x5a, 0x0f, 0x60, 0x44, 0x7a, 0xbb, 0x65, + 0x99, 0x6a, 0x4a, 0x56, 0x80, 0x38, 0x6b, 0x9f, + 0xe8, 0x14, 0x23, 0xd3, 0x9a, 0x07, 0xcf, 0x36, + 0x48, 0x69, 0xe8, 0x3c, 0xbf, 0x8d, 0x6e, 0xba, + 0x2b, 0x0c, 0x8d, 0x6e, 0x6a, 0x2a, 0x0f, 0xab, + 0x07, 0xb5, 0x61, 0xb2, 0x5c, 0x2e, 0x08, 0xe9, + 0x13, 0x61, 0xe7, 0x20, 0x64, 0xd6, 0x05, 0x87, + 0x25, 0x2b, 0x00, 0xcb, 0xdb, 0xd8, 0x51, 0x3d, + 0x26, 0x7f, 0x33, 0x91, 0x6f, 0xe5, 0xf8, 0xa5, + 0xcd, 0x2c, 0x55, 0xfe, 0x97, 0xe5, 0x4b, 0x55, + 0x10, 0xae, 0xa7, 0xf2, 0x1b, 0x8b, 0x08, 0xc0, + 0xb4, 0x25, 0xdc, 0x3b, 0xf5, 0x61, 0x08, 0x7d, + 0x1e, 0x04, 0x10, 0xf4, 0x24, 0x94, 0x00, 0xe8, + 0x87, 0xac, 0x54, 0xa5, 0xa3, 0xb6, 0x22, 0xdf, + 0x37, 0x49, 0xd5, 0xd8, 0x6c, 0x33, 0x0a, 0x7d, + 0xda, 0x54, 0x12, 0x9a, 0x23, 0x8f, 0xcf, 0x69, + 0xc2, 0x1f, 0xaa, 0x8c, 0xeb, 0xff, 0x81, 0x28, + 0x3d, 0x5e, 0x58, 0x5b, 0xe2, 0xd3, 0xba, 0xa9, + 0xc3, 0x9a, 0xe1, 0x47, 0x0a, 0xcd, 0xe7, 0x07, + 0xfb, 0x70, 0x71, 0xf1, 0x3b, 0xe2, 0x87, 0xe6, + 0x3a, 0x42, 0x9c, 0x90, 0x01, 0x11, 0xe6, 0x39, + 0xb5, 0x23, 0x1e, 0xf1, 0xd6, 0xce, 0x2e, 0x24, + 0x1d, 0x7b, 0x60, 0x5b, 0xa7, 0x29, 0x95, 0x86, + 0x33, 0xd1, 0x53, 0xaf, 0x90, 0x68, 0xd2, 0x7a, + 0x4c, 0x67, 0x14, 0x30, 0x2e, 0xe6, 0xba, 0xe0, + 0x03, 0x14, 0x3d, 0x7a, 0xe9, 0x51, 0x03, 0xbc, + 0xea, 0x9d, 0x87, 0xba, 0xee, 0xf9, 0xec, 0xb5, + 0x54, 0x69, 0x3a, 0x32, 0x95, 0xba, 0x0d, 0xc5, + 0xbd, 0x31, 0x87, 0xee, 0x36, 0xf1, 0xbd, 0x36, + 0x8c, 0x86, 0x96, 0x08, 0x44, 0x81, 0x86, 0x1b, + 0xd3, 0x20, 0xdc, 0xa5, 0x87, 0x04, 0x43, 0xf1, + 0x57, 0x56, 0xd2, 0x34, 0xe6, 0xcf, 0xd2, 0x88, + 0xe3, 0x64, 0x5b, 0x15, 0x20, 0xf8, 0xad, 0x8b, + 0x3f, 0x1e, 0xa4, 0x49, 0x5e, 0xc4, 0x4d, 0x5b, + 0xf5, 0xfd, 0xbd, 0x2f, 0xdf, 0x4e, 0x37, 0xa9, + 0x70, 0xd3, 0xbc, 0x10, 0x5c, 0xb8, 0xc2, 0x1e, + 0xf1, 0xb8, 0xb3, 0xe1, 0x9a, 0xa6, 0xad, 0xf7, + 0x51, 0xe5, 0xcc, 0x4d, 0xea, 0x14, 0xd8, 0xab, + 0x88, 0x0f, 0x28, 0xca, 0x8f, 0xaa, 0xc0, 0x60, + 0xa1, 0x6c, 0x84, 0xdf, 0xa4, 0xd9, 0xb5, 0x76, + 0xc0, 0x99, 0x37, 0x3e, 0xd2, 0x78, 0x14, 0x38, + 0xf7, 0x44, 0x0d, 0xd7, 0xb7, 0x6a, 0x16, 0x30, + 0x46, 0x95, 0x72, 0xe9, 0x8c, 0xbb, 0x45, 0xb5, + 0xc0, 0xce, 0x00, 0x12, 0xf1, 0x1b, 0x0a, 0x09, + 0x99, 0xd4, 0xea, 0xdd, 0x6e, 0xd9, 0x10, 0x66, + 0x5e, 0x88, 0x09, 0x92, 0x42, 0x02, 0x28, 0x7f, + 0x40, 0x0f, 0x54, 0x00, 0x2a, 0x37, 0x0e, 0x21, + 0xbf, 0xd5, 0x55, 0xd5, 0x49, 0x5d, 0xaa, 0xf2, + 0x3b, 0x0f, 0x44, 0xff, 0x3e, 0x94, 0x1b, 0x0d, + 0x2b, 0x1f, 0x1a, 0xf3, 0xc1, 0x3b, 0xc2, 0xe1, + 0x08, 0x7d, 0x40, 0x93, 0xf9, 0x37, 0xe8, 0x87, + 0x06, 0x0c, 0xf3, 0xf0, 0xaf, 0xf7, 0x03, 0xf9, + 0xd7, 0x4c, 0x01, 0x3a, 0xcc, 0xb3, 0x63, 0xfa, + 0xce, 0x48, 0xd6, 0x8e, 0x00, 0x42, 0x47, 0x2a, + 0xc9, 0xc3, 0xb2, 0xa4, 0xc7, 0x63, 0x46, 0xa6, + 0xe0, 0xd3, 0xc2, 0xd6, 0x2f, 0x8d, 0x52, 0x85, + 0xca, 0x92, 0xb2, 0xfe, 0x4d, 0x25, 0x62, 0x5e, + 0x70, 0xde, 0x12, 0x8e, 0xca, 0xdd, 0x32, 0x48, + 0x26, 0x84, 0x04, 0xf8, 0x6a, 0x4e, 0xd9, 0x4a, + 0x18, 0xc4, 0x64, 0x3e, 0x97, 0x52, 0x17, 0x5b, + 0xf8, 0x4f, 0x64, 0x3e, 0x3b, 0x98, 0x62, 0xf9, + 0x31, 0x6b, 0xa9, 0x49, 0x51, 0x06, 0xf9, 0x95, + 0xe8, 0xf4, 0xa0, 0x26, 0xf0, 0x0e, 0xb7, 0x23, + 0x0f, 0x0f, 0x4a, 0xe2, 0x34, 0x71, 0xe6, 0x14, + 0x63, 0x17, 0x48, 0xdb, 0x41, 0xea, 0x18, 0x3d, + 0x2f, 0x44, 0xe8, 0x95, 0xc0, 0xb4, 0xce, 0x70, + 0xab, 0xcd, 0x53, 0xda, 0x9d, 0x1b, 0x61, 0x47, + 0xb7, 0xa2, 0x69, 0x18, 0xdf, 0x25, 0x82, 0xef, + 0x2d, 0xae, 0x3d, 0x59, 0xe7, 0x3f, 0x16, 0x44, + 0x95, 0xe4, 0x68, 0x51, 0xd5, 0xd5, 0xfb, 0xfc, + 0x48, 0x09, 0x68, 0xe6, 0x4f, 0x05, 0x46, 0x2d, + 0x89, 0xde, 0x35, 0x33, 0x29, 0x26, 0x69, 0xaa, + 0xeb, 0x68, 0xad, 0x66, 0xd9, 0xb1, 0x75, 0xc6, + 0x4d, 0xfc, 0x62, 0xce, 0x20, 0x3f, 0xb4, 0xa3 + }; + static const byte mu_44[] = { + 0xe7, 0x8a, 0xe8, 0x1f, 0xbf, 0xc8, 0xef, 0x71, + 0x9a, 0xf1, 0xae, 0xca, 0xc8, 0xea, 0x9a, 0x9b, + 0x19, 0x42, 0x4d, 0x15, 0xf1, 0x41, 0x8e, 0xaf, + 0xd7, 0xa7, 0x6f, 0x6a, 0xed, 0x00, 0x78, 0x25, + 0x2a, 0x1f, 0xdb, 0x9e, 0x0c, 0x6f, 0x00, 0x52, + 0x33, 0x59, 0xf6, 0x8a, 0x30, 0xe9, 0xc1, 0x58, + 0xf1, 0x67, 0x4f, 0x1d, 0x34, 0x59, 0xb8, 0xc3, + 0x29, 0xf4, 0x8f, 0xbf, 0x1a, 0x22, 0xca, 0x91 + }; + static const byte sig_44_mu[] = { + 0xa3, 0xf1, 0xe8, 0xd7, 0xf3, 0x38, 0x9e, 0x08, + 0x0e, 0xe3, 0x00, 0xa9, 0xf7, 0x71, 0x03, 0x70, + 0x3e, 0x28, 0xc7, 0x3c, 0xd4, 0xec, 0x3d, 0x62, + 0xba, 0xf5, 0x9c, 0x1b, 0x86, 0xd9, 0x0c, 0xe0, + 0xde, 0x85, 0xe0, 0x85, 0xc1, 0x7c, 0x1a, 0xe8, + 0x42, 0x7c, 0xb5, 0x37, 0x2b, 0x88, 0x69, 0x0c, + 0xe7, 0xee, 0x5a, 0xec, 0xed, 0xce, 0xc0, 0x1a, + 0x35, 0x88, 0xee, 0x15, 0xa6, 0x10, 0x83, 0x4d, + 0x61, 0xc1, 0x1a, 0x7d, 0xe8, 0xcb, 0xa3, 0x54, + 0x7a, 0x3c, 0x43, 0xba, 0x26, 0xef, 0x54, 0x62, + 0x33, 0x2d, 0x4a, 0x2f, 0x43, 0x07, 0x6c, 0x1e, + 0x2a, 0x6f, 0x76, 0x9e, 0x6b, 0x74, 0x24, 0x17, + 0x06, 0xa8, 0x1f, 0x5d, 0x8a, 0x59, 0x30, 0x9f, + 0x97, 0xbd, 0x8c, 0x55, 0x0c, 0xa6, 0xc2, 0xbf, + 0x34, 0x0a, 0x36, 0x6f, 0xe5, 0x52, 0x55, 0x25, + 0xb3, 0x15, 0x9e, 0x4c, 0xba, 0x16, 0x72, 0x50, + 0xf1, 0x0a, 0x45, 0xb1, 0x65, 0xb5, 0x06, 0x14, + 0x1a, 0x24, 0x10, 0xeb, 0xe1, 0x5b, 0xa3, 0x3b, + 0x01, 0xdc, 0xd0, 0x18, 0xf7, 0xcd, 0x02, 0x15, + 0xd5, 0x82, 0x76, 0x52, 0x1d, 0x60, 0x16, 0x08, + 0xbf, 0x44, 0x51, 0x0a, 0xb2, 0xd4, 0x68, 0x99, + 0xc6, 0x9c, 0x97, 0xf5, 0x37, 0x1c, 0xd1, 0x27, + 0xcf, 0xe8, 0x33, 0x2f, 0x81, 0x14, 0xd5, 0xa6, + 0x9a, 0x9c, 0x61, 0xc0, 0x91, 0x6a, 0x5a, 0x63, + 0x39, 0x11, 0x9d, 0x35, 0x33, 0x98, 0xf6, 0x2c, + 0x78, 0xba, 0x4c, 0x6b, 0x7f, 0x3c, 0x71, 0x64, + 0x5b, 0x29, 0xf7, 0xdc, 0x3d, 0x25, 0x45, 0xed, + 0x30, 0xc1, 0xb5, 0x3e, 0x18, 0x51, 0xa7, 0x06, + 0x6d, 0x24, 0xc2, 0x43, 0x55, 0x91, 0xab, 0x4c, + 0xdd, 0xbd, 0x54, 0xb0, 0x48, 0x0e, 0x87, 0x75, + 0xdb, 0x31, 0x3c, 0x70, 0x61, 0x92, 0xd8, 0xed, + 0xbe, 0x18, 0xe7, 0xd3, 0xc4, 0xbe, 0xd5, 0x5e, + 0x46, 0xf5, 0xf4, 0x14, 0xc5, 0xba, 0xb6, 0x4f, + 0x23, 0x97, 0x13, 0x6e, 0x6a, 0x86, 0x76, 0x6a, + 0x20, 0x3f, 0x46, 0x38, 0xa9, 0x5d, 0x33, 0xf7, + 0x14, 0x6f, 0xc5, 0x3f, 0x4f, 0x5b, 0xe4, 0xf2, + 0x78, 0x34, 0x23, 0x88, 0xdf, 0xb9, 0xf1, 0xd9, + 0x3e, 0x1f, 0x30, 0x94, 0xfb, 0x99, 0x32, 0xb9, + 0x76, 0xda, 0x97, 0x52, 0xbd, 0x73, 0xd8, 0x33, + 0x44, 0x3f, 0xfc, 0x9b, 0x75, 0xe0, 0x04, 0xa3, + 0x37, 0x0c, 0xd4, 0x48, 0x9f, 0x72, 0xc0, 0xd5, + 0xba, 0xe6, 0x5f, 0x93, 0x0d, 0x07, 0x82, 0xbb, + 0x6c, 0x06, 0xeb, 0x9f, 0x6a, 0xe4, 0x9f, 0x29, + 0x25, 0xac, 0x22, 0xc3, 0x50, 0x53, 0x3e, 0xa8, + 0x32, 0x5e, 0x55, 0xde, 0x86, 0x42, 0x63, 0x7e, + 0xc4, 0x40, 0x12, 0x42, 0xb5, 0x5a, 0xc4, 0x2f, + 0xe4, 0xa3, 0xe7, 0x13, 0xbf, 0x1f, 0x3b, 0x9c, + 0x3a, 0xab, 0xa9, 0xa8, 0x34, 0x52, 0x1f, 0xee, + 0xb2, 0x75, 0xe7, 0x25, 0xac, 0x8c, 0x4f, 0x34, + 0x8e, 0xb6, 0x29, 0x43, 0xf4, 0x37, 0x04, 0xe5, + 0x58, 0xde, 0xf0, 0xd2, 0x72, 0x1e, 0xb4, 0xc2, + 0x17, 0xe7, 0x97, 0xa9, 0x9d, 0x26, 0xfa, 0x68, + 0x21, 0x3c, 0x8c, 0xea, 0xa2, 0x9e, 0x3a, 0x18, + 0x6e, 0x79, 0x2b, 0x83, 0x24, 0x2c, 0xf2, 0x46, + 0x07, 0x19, 0x39, 0x45, 0x47, 0x50, 0x96, 0x5a, + 0xa2, 0x57, 0x62, 0x24, 0x72, 0xbb, 0x95, 0x65, + 0xbb, 0x22, 0x33, 0x83, 0x51, 0x10, 0x99, 0x6c, + 0x21, 0xa4, 0x82, 0x41, 0xc9, 0x2d, 0xa3, 0xa2, + 0xd9, 0xee, 0xc1, 0x03, 0x27, 0x92, 0x33, 0x4e, + 0x2d, 0x6f, 0x54, 0x86, 0x76, 0x7d, 0xd8, 0xc4, + 0x45, 0xdf, 0xe1, 0xa7, 0xb0, 0xeb, 0xa8, 0x56, + 0x5f, 0x89, 0x99, 0xa2, 0x78, 0xb4, 0x96, 0xe4, + 0x56, 0xd2, 0xea, 0x56, 0x2e, 0xf8, 0x93, 0x04, + 0x9c, 0x5f, 0xf2, 0x70, 0x6e, 0x8e, 0x5f, 0x17, + 0xd4, 0x91, 0x75, 0x63, 0x39, 0xdc, 0x67, 0xd7, + 0x7f, 0x30, 0x4d, 0x2d, 0x4b, 0x87, 0xea, 0xf9, + 0x78, 0xff, 0x0a, 0xb3, 0xab, 0x9d, 0xad, 0xb3, + 0x52, 0x9b, 0xea, 0x8c, 0x7f, 0xa9, 0xe6, 0x63, + 0x8c, 0xe5, 0x70, 0x34, 0x9f, 0xf2, 0x0d, 0x90, + 0x72, 0x32, 0x89, 0x64, 0x2c, 0x65, 0x14, 0xb1, + 0x44, 0xf7, 0x46, 0x36, 0xd2, 0xd8, 0xd7, 0x84, + 0x4a, 0xab, 0x08, 0xc4, 0x9b, 0xb7, 0x6b, 0x14, + 0xbe, 0x37, 0x59, 0xec, 0x6f, 0x0f, 0x16, 0x99, + 0x75, 0x6e, 0x00, 0xbe, 0x8a, 0x7f, 0x31, 0xe3, + 0xec, 0x59, 0x71, 0x32, 0xa4, 0x0b, 0xde, 0x96, + 0x9a, 0x36, 0xe2, 0x8f, 0x60, 0x16, 0x2c, 0x23, + 0x47, 0x37, 0x91, 0x3e, 0x30, 0x2d, 0x36, 0x97, + 0x96, 0x40, 0xa8, 0x37, 0x98, 0x64, 0x9f, 0xfc, + 0x86, 0x82, 0x6d, 0x6a, 0x8c, 0x2e, 0xf5, 0x35, + 0x12, 0x91, 0xcb, 0x5e, 0x52, 0x31, 0x11, 0x3d, + 0x67, 0x23, 0x9f, 0x4f, 0x53, 0x0c, 0xf9, 0xd0, + 0xbb, 0x8a, 0x3b, 0xb3, 0xf4, 0x00, 0x12, 0x7b, + 0x73, 0x1b, 0x96, 0x0c, 0x56, 0x90, 0x80, 0x3c, + 0x6c, 0x44, 0x23, 0xc3, 0xd4, 0xac, 0x53, 0x22, + 0x10, 0x70, 0xf0, 0x44, 0xe9, 0xbb, 0x1a, 0xa3, + 0xf2, 0x1b, 0x0e, 0x39, 0x43, 0xea, 0x2c, 0x05, + 0xf7, 0x41, 0x5d, 0x48, 0x7d, 0xb1, 0x4b, 0xfc, + 0xcf, 0x76, 0x86, 0x57, 0xcd, 0x42, 0xdf, 0xd1, + 0xcc, 0x89, 0xf1, 0x23, 0x8e, 0xe8, 0xe4, 0x91, + 0xf6, 0x94, 0xc6, 0x9e, 0x51, 0x6a, 0x4a, 0x66, + 0x84, 0xcd, 0xfc, 0xa1, 0xb7, 0x3b, 0x5c, 0xf9, + 0xb2, 0x4c, 0x00, 0x49, 0x8d, 0xc2, 0x79, 0xc2, + 0xf9, 0xe0, 0xcc, 0x1b, 0xd7, 0xd8, 0xa8, 0x98, + 0xa9, 0xc7, 0x13, 0x14, 0x9d, 0x8a, 0x9c, 0xc1, + 0xd9, 0x95, 0x52, 0x51, 0x55, 0xfc, 0x3a, 0x1d, + 0x71, 0x8f, 0x23, 0x6a, 0x4a, 0xc2, 0x8b, 0x1e, + 0xac, 0x4b, 0x2f, 0xaa, 0x22, 0xd3, 0xfe, 0xce, + 0x30, 0x36, 0x4b, 0xa0, 0xe6, 0x3b, 0x38, 0x53, + 0xec, 0xd8, 0x76, 0x41, 0xc8, 0x24, 0xa4, 0xe6, + 0x59, 0x7a, 0xd1, 0x6d, 0x34, 0xb4, 0x6a, 0x40, + 0xdd, 0xa5, 0xd5, 0x86, 0x45, 0xcc, 0x72, 0xcd, + 0x82, 0xb5, 0x9a, 0x38, 0x69, 0x1b, 0xf4, 0x53, + 0xb0, 0xdb, 0x90, 0x3e, 0xc7, 0x0b, 0x66, 0x93, + 0x93, 0x52, 0xd3, 0x80, 0x93, 0x9f, 0xde, 0x39, + 0xdb, 0x7b, 0xae, 0xbb, 0x8e, 0xfd, 0xd9, 0xfc, + 0x54, 0xf6, 0x41, 0xc5, 0x38, 0x09, 0x16, 0xbd, + 0x1b, 0x21, 0xed, 0xbe, 0x33, 0xc4, 0xb1, 0xbd, + 0x77, 0x88, 0x05, 0x06, 0x09, 0x4c, 0x41, 0xda, + 0xb7, 0x17, 0x70, 0xf0, 0x3e, 0x44, 0x2f, 0xa3, + 0x0c, 0x55, 0x65, 0xc4, 0xc0, 0x0d, 0x34, 0x82, + 0xb1, 0x54, 0xb4, 0xff, 0x39, 0xe2, 0x68, 0x67, + 0x72, 0x7b, 0xd8, 0x60, 0x4e, 0x61, 0x48, 0xdc, + 0x65, 0x02, 0xf7, 0x28, 0x82, 0xf2, 0xb8, 0xf5, + 0x87, 0x5e, 0x91, 0x7c, 0xea, 0xd4, 0xef, 0xaf, + 0xee, 0x24, 0x8d, 0xab, 0xfb, 0x8d, 0xab, 0x59, + 0xaa, 0x85, 0xfa, 0x52, 0x6a, 0x96, 0xcf, 0x08, + 0x60, 0x47, 0x2d, 0xe3, 0xdf, 0xad, 0x6f, 0x75, + 0xbd, 0x15, 0x99, 0xb0, 0x9c, 0x75, 0xf3, 0x91, + 0x36, 0x1a, 0xcf, 0x84, 0x78, 0xf5, 0x33, 0x3a, + 0x78, 0x51, 0x40, 0x87, 0x47, 0x88, 0x56, 0xc0, + 0x8c, 0x1f, 0xc2, 0x94, 0x52, 0xe6, 0x18, 0xd9, + 0xe6, 0x0a, 0x9b, 0xd4, 0xa5, 0x3a, 0xea, 0x35, + 0x49, 0xae, 0xfe, 0xcb, 0xc1, 0x7c, 0x99, 0x9c, + 0x29, 0x38, 0x83, 0x3b, 0xbe, 0xc9, 0x4d, 0x33, + 0x16, 0xca, 0x9a, 0x72, 0xfa, 0x07, 0x9f, 0x72, + 0xba, 0x11, 0x13, 0x06, 0x38, 0xf3, 0xc3, 0x0c, + 0xd7, 0x79, 0xee, 0x3b, 0xcf, 0x9a, 0xe8, 0xbb, + 0x26, 0x03, 0x22, 0x75, 0xf9, 0x78, 0xb0, 0x4a, + 0x65, 0xa8, 0x9f, 0x95, 0xd6, 0xd9, 0xb3, 0x7b, + 0xe0, 0x59, 0xd1, 0x71, 0x25, 0xce, 0x60, 0xc1, + 0x50, 0x3e, 0x2e, 0xd5, 0xab, 0xf7, 0xd3, 0x27, + 0xd3, 0xc7, 0x9b, 0xc4, 0xd3, 0x57, 0x82, 0x10, + 0xa4, 0xef, 0x20, 0x20, 0xf5, 0x8b, 0xa0, 0x0c, + 0x08, 0xec, 0xf0, 0x39, 0x02, 0xe4, 0xe6, 0xd9, + 0x52, 0x7e, 0x76, 0x73, 0x48, 0x5d, 0x15, 0x86, + 0xc4, 0x28, 0xee, 0x6e, 0x5c, 0x47, 0xd4, 0x52, + 0xfd, 0xd0, 0xba, 0x3c, 0xec, 0x59, 0x93, 0x01, + 0x04, 0xa9, 0x1f, 0xf5, 0x73, 0xeb, 0x18, 0xf7, + 0x48, 0x57, 0x20, 0xcd, 0xa5, 0x67, 0xcc, 0x9f, + 0x9c, 0x18, 0xb7, 0xcf, 0xf2, 0x55, 0xf2, 0x08, + 0x8d, 0x40, 0x3f, 0xaa, 0xb5, 0x83, 0xf2, 0x85, + 0x33, 0x8a, 0x0f, 0xd2, 0x25, 0x10, 0x30, 0xda, + 0x5a, 0xd3, 0x39, 0xb1, 0xc0, 0x9c, 0x01, 0xef, + 0x8e, 0x81, 0x4b, 0x0d, 0x00, 0x21, 0x06, 0xd0, + 0xcf, 0x1b, 0x9a, 0xea, 0x49, 0xaa, 0xaa, 0xa8, + 0x08, 0x7b, 0x01, 0x3c, 0x96, 0x65, 0xe9, 0x0b, + 0x74, 0x44, 0x36, 0x25, 0x26, 0x08, 0xc7, 0xac, + 0x16, 0x15, 0x38, 0xbb, 0xfe, 0xac, 0x0c, 0x86, + 0x6a, 0xce, 0x71, 0x2c, 0xea, 0xfa, 0xbd, 0xda, + 0x5c, 0xd2, 0x51, 0x71, 0xfe, 0xe2, 0x13, 0xae, + 0x33, 0x8d, 0xfa, 0xfa, 0x80, 0x1c, 0x7b, 0xe8, + 0xb2, 0x79, 0xa7, 0x4a, 0xbc, 0x68, 0x72, 0xdb, + 0x5a, 0x45, 0x33, 0x73, 0x24, 0xb1, 0xa4, 0xe0, + 0x24, 0x29, 0x1c, 0xb3, 0x6a, 0x16, 0xa0, 0xf6, + 0x04, 0x50, 0x25, 0xdc, 0x21, 0x20, 0xec, 0xf0, + 0x3d, 0x46, 0x0c, 0x55, 0x53, 0x7d, 0xff, 0xde, + 0x1f, 0x4d, 0xcb, 0x42, 0xd6, 0xee, 0x14, 0x66, + 0xb5, 0xf2, 0x2f, 0x3e, 0x47, 0xd5, 0x46, 0x45, + 0xa5, 0xc8, 0xba, 0x5b, 0x7e, 0xbd, 0x7a, 0xc6, + 0x64, 0x2e, 0xdb, 0x3f, 0x01, 0x1e, 0x89, 0xe3, + 0x48, 0xdd, 0x44, 0xa2, 0x7b, 0xeb, 0x1a, 0x57, + 0x10, 0xd4, 0x02, 0x08, 0x50, 0x2d, 0xdf, 0xfd, + 0x4b, 0x00, 0xba, 0xed, 0x1c, 0xdc, 0x10, 0x5a, + 0xa3, 0x75, 0xce, 0xae, 0xff, 0xa8, 0xb3, 0x75, + 0x5a, 0xbc, 0x13, 0x2e, 0xeb, 0x20, 0x13, 0xfc, + 0xe4, 0x4d, 0xa8, 0x01, 0xa1, 0x6d, 0xef, 0x73, + 0xf2, 0x8c, 0x7b, 0xd9, 0x37, 0xb1, 0xe3, 0x28, + 0x71, 0x70, 0xeb, 0xfe, 0x4a, 0x4f, 0xaf, 0x6a, + 0xe1, 0x3a, 0xdf, 0x05, 0x27, 0x4d, 0x7a, 0x90, + 0xb1, 0x00, 0x16, 0x8b, 0x5d, 0x59, 0x38, 0x94, + 0xfc, 0x88, 0x1f, 0x00, 0xdc, 0x01, 0xf5, 0x02, + 0x3b, 0x1d, 0x8e, 0x34, 0xa6, 0xe9, 0x86, 0x72, + 0x7b, 0x97, 0x01, 0x6e, 0x75, 0xf0, 0xdd, 0xb0, + 0x2a, 0xed, 0x68, 0x22, 0xc7, 0x0d, 0xdf, 0x52, + 0x1b, 0x81, 0xf9, 0x8f, 0x74, 0x18, 0x36, 0xec, + 0x7d, 0xe7, 0x68, 0x7e, 0x8c, 0xc3, 0x58, 0xdc, + 0xc9, 0x04, 0xa0, 0x55, 0x87, 0xc7, 0xaa, 0xad, + 0x2e, 0x63, 0xc9, 0x94, 0x2b, 0x19, 0x30, 0x4c, + 0x35, 0xa2, 0x63, 0xc5, 0x8e, 0x80, 0xe9, 0x92, + 0xbe, 0xce, 0x2a, 0x12, 0x97, 0x84, 0xc9, 0x31, + 0x08, 0x97, 0x3b, 0xec, 0xd3, 0x1d, 0x92, 0x79, + 0x14, 0x4b, 0x25, 0x2c, 0x60, 0x30, 0xe6, 0x16, + 0x60, 0x7e, 0xfb, 0x1b, 0x97, 0x83, 0xd5, 0xbf, + 0xcf, 0x88, 0x1a, 0xf3, 0x15, 0xdc, 0x51, 0x71, + 0xed, 0xf8, 0xe0, 0xed, 0xc4, 0x45, 0xb4, 0x96, + 0xf9, 0xd0, 0x25, 0xa7, 0xf8, 0xd9, 0xe4, 0x41, + 0xd4, 0xb9, 0x04, 0x70, 0x02, 0x60, 0xeb, 0x17, + 0xa8, 0x10, 0x4e, 0xe8, 0xdb, 0x6c, 0x20, 0x7f, + 0x41, 0x63, 0x01, 0x6d, 0xa8, 0x40, 0x82, 0x30, + 0x67, 0x4c, 0x87, 0x54, 0x6f, 0x19, 0x95, 0x4a, + 0xa6, 0x46, 0x43, 0x8e, 0xb3, 0xfd, 0x86, 0xf0, + 0xc5, 0x3e, 0x67, 0x8c, 0xb6, 0x6f, 0x8a, 0x15, + 0x01, 0x35, 0xf0, 0x7b, 0x67, 0x65, 0x0d, 0x69, + 0x65, 0xb8, 0x3f, 0x30, 0xcb, 0x10, 0xb3, 0x02, + 0x08, 0x8e, 0xef, 0x9c, 0x50, 0x90, 0x4f, 0x85, + 0x23, 0xb5, 0xfa, 0x75, 0xc2, 0x70, 0x9b, 0x33, + 0xf9, 0xeb, 0x69, 0x33, 0xfb, 0xbe, 0x67, 0x87, + 0x5e, 0x9f, 0x79, 0x54, 0x8b, 0xb4, 0x27, 0xf1, + 0xd7, 0x77, 0xdd, 0x32, 0x9a, 0xea, 0x7b, 0x97, + 0x7e, 0x10, 0xb1, 0x49, 0xf2, 0x45, 0xef, 0x47, + 0xa6, 0x3f, 0x34, 0xdf, 0x0e, 0x6c, 0xed, 0x5d, + 0x1f, 0x80, 0x71, 0x00, 0x3e, 0x9c, 0x6f, 0x37, + 0x60, 0x2d, 0xd7, 0xb1, 0x63, 0xb1, 0xf8, 0x0f, + 0xc6, 0xdf, 0x99, 0xff, 0x5c, 0x1a, 0x37, 0x0e, + 0x48, 0xba, 0x33, 0xa8, 0x2a, 0xad, 0x04, 0xae, + 0x14, 0xb8, 0x9d, 0x9b, 0x7d, 0xe6, 0x1a, 0xd5, + 0x8a, 0x55, 0xfb, 0x21, 0x27, 0xc8, 0xd5, 0xc7, + 0x41, 0xb1, 0x73, 0xa1, 0xe6, 0x3f, 0x08, 0x68, + 0x35, 0xf5, 0xb2, 0x85, 0xa8, 0x3a, 0xed, 0xe5, + 0x0e, 0x3a, 0x3d, 0x2c, 0x87, 0x5d, 0x6e, 0xc7, + 0x66, 0x4e, 0xcf, 0x00, 0x04, 0x15, 0xd9, 0x78, + 0x65, 0x77, 0x08, 0x79, 0xb3, 0x6b, 0x47, 0xea, + 0x45, 0x67, 0xe5, 0x95, 0x42, 0xde, 0x07, 0xd6, + 0x6e, 0x41, 0x01, 0x18, 0x37, 0xf9, 0xb5, 0x55, + 0x3c, 0xb0, 0x6c, 0xdd, 0xfe, 0x33, 0x5b, 0x53, + 0x03, 0x88, 0x42, 0xae, 0xfd, 0xbe, 0x02, 0xf3, + 0xd5, 0x32, 0x95, 0x4c, 0x5c, 0x4b, 0xb8, 0x9b, + 0x54, 0x93, 0x3f, 0x50, 0x99, 0xfc, 0x31, 0x5a, + 0xbc, 0x13, 0x9c, 0x73, 0x65, 0x33, 0x01, 0xe0, + 0x04, 0xb7, 0x91, 0xf5, 0x2a, 0x0b, 0xd4, 0xb2, + 0xbf, 0xf6, 0x55, 0x2c, 0xa5, 0xd9, 0x7e, 0x13, + 0x88, 0x80, 0x78, 0xfb, 0xde, 0xb9, 0x92, 0x3e, + 0x0d, 0x58, 0xdf, 0x5e, 0xaf, 0x29, 0xf1, 0x60, + 0x3b, 0xb9, 0xcf, 0x48, 0x7d, 0x87, 0x62, 0x4e, + 0x49, 0x46, 0x26, 0x38, 0x33, 0x63, 0xc0, 0x31, + 0x58, 0x03, 0xf1, 0xa0, 0xd8, 0x1c, 0xf2, 0xc2, + 0x1f, 0x1e, 0x91, 0x34, 0x55, 0xeb, 0xbb, 0x13, + 0xea, 0x7e, 0x66, 0xaf, 0x12, 0x43, 0x4c, 0x0f, + 0x79, 0x57, 0x22, 0xd0, 0x84, 0x80, 0x23, 0xf5, + 0x32, 0x3a, 0x53, 0x69, 0x91, 0x89, 0x8c, 0x84, + 0x9a, 0x8d, 0xc3, 0xd8, 0xf6, 0x87, 0x89, 0x9c, + 0x5c, 0x1d, 0xd8, 0x63, 0x26, 0xfa, 0x37, 0xbc, + 0x9e, 0x36, 0x75, 0x59, 0x81, 0xcc, 0xbb, 0xa3, + 0xa1, 0x2d, 0x9d, 0x59, 0xe7, 0x1c, 0x8c, 0xff, + 0x61, 0x44, 0x65, 0x92, 0x9f, 0xae, 0x1e, 0x55, + 0xff, 0xb8, 0x1f, 0xf9, 0xb3, 0xd4, 0x8e, 0x03, + 0x23, 0xe9, 0x49, 0x1d, 0x74, 0x71, 0x71, 0x98, + 0x59, 0xee, 0xf8, 0x7e, 0xf3, 0x6e, 0x0c, 0x9c, + 0x87, 0xd4, 0xa1, 0x2e, 0xee, 0xac, 0x24, 0x11, + 0xac, 0xe1, 0xc4, 0x5b, 0x0f, 0x40, 0x83, 0xb8, + 0xfd, 0x0b, 0x36, 0xff, 0xf5, 0xfc, 0x38, 0x55, + 0x71, 0x51, 0xfd, 0x15, 0x86, 0x6f, 0x2d, 0xe1, + 0xf5, 0xff, 0xcb, 0xdd, 0x27, 0x0b, 0x9d, 0x74, + 0x50, 0x5c, 0x4f, 0x7a, 0x4d, 0x32, 0x0d, 0x58, + 0x9f, 0x48, 0xc3, 0x60, 0xfe, 0x86, 0xf0, 0x4f, + 0xfd, 0x98, 0xfd, 0x4f, 0xd2, 0xd0, 0xe5, 0xcb, + 0x57, 0xab, 0xab, 0x54, 0xc8, 0xb5, 0x2e, 0x45, + 0x84, 0xa5, 0xa7, 0x69, 0x4d, 0xfe, 0xa2, 0x94, + 0x0e, 0xdf, 0xe6, 0x3a, 0xa9, 0x89, 0xe5, 0xaf, + 0x11, 0x8e, 0x72, 0xe0, 0xbb, 0x04, 0xdd, 0xe9, + 0x39, 0x38, 0x81, 0xd9, 0x72, 0xc7, 0x38, 0x66, + 0x3e, 0xe2, 0x90, 0xb9, 0x69, 0x2a, 0xe1, 0x4b, + 0x93, 0x45, 0x77, 0x72, 0x8c, 0x98, 0x12, 0x18, + 0xeb, 0x07, 0x77, 0xe8, 0x8b, 0x12, 0x4a, 0xbd, + 0xe3, 0x0c, 0x0b, 0x3b, 0xe9, 0x3a, 0x24, 0xe4, + 0x7a, 0x82, 0x94, 0x88, 0x6d, 0xbf, 0x37, 0x3a, + 0x62, 0xf8, 0x1e, 0x13, 0xa7, 0x08, 0xfd, 0x26, + 0xbd, 0x0b, 0xb3, 0xef, 0x04, 0x2a, 0x56, 0x8f, + 0xa1, 0x1c, 0xbc, 0xa5, 0x7a, 0x14, 0x0e, 0xf3, + 0xe8, 0x7e, 0x44, 0x54, 0x90, 0x54, 0x9c, 0xf8, + 0xe3, 0x39, 0xcd, 0xa1, 0x45, 0x2d, 0x6c, 0xfb, + 0x2a, 0x5d, 0x13, 0x91, 0xb2, 0x25, 0xf8, 0xe7, + 0x1c, 0x4e, 0x63, 0xb0, 0x1b, 0xdf, 0xdd, 0xcb, + 0x63, 0x1c, 0x30, 0xa8, 0x50, 0x35, 0xdd, 0x48, + 0x63, 0xad, 0xd8, 0x89, 0xbd, 0xf3, 0xf3, 0x1d, + 0x03, 0x5f, 0x8b, 0xe1, 0xdf, 0xa5, 0x0b, 0x04, + 0x80, 0x70, 0x4d, 0xac, 0x2f, 0x88, 0xd3, 0x7e, + 0x45, 0x7a, 0x4e, 0x19, 0xbd, 0xa9, 0xaa, 0x21, + 0x91, 0xc4, 0x7d, 0x8e, 0x1a, 0xcf, 0x20, 0x4d, + 0x30, 0x0c, 0x07, 0x82, 0xd1, 0x0b, 0x01, 0x3a, + 0x6f, 0x91, 0x37, 0x3e, 0xe6, 0x43, 0xf5, 0xe3, + 0x1e, 0xce, 0x75, 0x3f, 0x1d, 0x3c, 0x65, 0xdb, + 0x39, 0x89, 0xa7, 0x4b, 0x30, 0x4e, 0x37, 0xd5, + 0xcc, 0xf5, 0x5a, 0xb1, 0x45, 0x86, 0x44, 0x6c, + 0xea, 0x2f, 0xdb, 0xfe, 0xe9, 0x2e, 0x12, 0x4c, + 0x47, 0x15, 0x08, 0x58, 0x59, 0x9f, 0x6a, 0x05, + 0x24, 0xa8, 0x46, 0x71, 0xd6, 0x65, 0xd5, 0x79, + 0x1b, 0x6c, 0x3b, 0xf3, 0x59, 0x6b, 0x6d, 0x6a, + 0xa9, 0x75, 0xe7, 0x6b, 0x53, 0xbd, 0x63, 0x81, + 0x45, 0x7f, 0x59, 0xc3, 0xfb, 0x98, 0xc5, 0x2f, + 0xe2, 0x17, 0x0f, 0x0a, 0xad, 0xfe, 0xf4, 0x30, + 0x6e, 0x10, 0xf4, 0x25, 0x90, 0x4f, 0x50, 0xb3, + 0xca, 0xc9, 0x1a, 0x47, 0xf2, 0x75, 0xa2, 0x86, + 0xff, 0xd9, 0xfc, 0xae, 0x77, 0xaa, 0xa6, 0x03, + 0xd2, 0x07, 0x21, 0x65, 0x4e, 0x2e, 0x0b, 0x00, + 0x48, 0x8b, 0x27, 0xd0, 0x28, 0x96, 0xa4, 0x00, + 0x04, 0xcf, 0x63, 0x38, 0xc9, 0x55, 0xd6, 0x0d, + 0x49, 0x03, 0xfb, 0x68, 0xde, 0x43, 0x24, 0x5f, + 0x4e, 0x40, 0xfa, 0x1e, 0xf2, 0x19, 0x72, 0xa4, + 0x00, 0x32, 0xdb, 0x1c, 0xbc, 0xc3, 0x66, 0x62, + 0x7e, 0x39, 0x1f, 0x6d, 0x17, 0xeb, 0x32, 0x6e, + 0x4d, 0x20, 0x71, 0xd8, 0x90, 0x41, 0x5c, 0xc3, + 0x04, 0x14, 0x1c, 0x37, 0x40, 0x49, 0x54, 0x57, + 0x67, 0x6d, 0x71, 0x77, 0x85, 0x87, 0xc4, 0xd9, + 0xe4, 0xee, 0x12, 0x1e, 0x22, 0x42, 0x66, 0x6d, + 0x72, 0x7a, 0xa4, 0xc6, 0xcf, 0xed, 0xef, 0x02, + 0x08, 0x0f, 0x14, 0x67, 0xbb, 0xc2, 0xca, 0xeb, + 0x00, 0x01, 0x24, 0x37, 0x3f, 0x4f, 0x5f, 0x70, + 0x73, 0x76, 0xb9, 0xbb, 0xcc, 0xde, 0xe2, 0xeb, + 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x12, 0x1f, 0x28, 0x39 + }; + + /* ML-DSA-65 externalMu: deterministic, tcId 121 + * Source: kh-fork-fips/wolfACVP/v7.0.0-known/ + * ML-DSA-sigGen-request.json. Deterministic mode + * uses rnd = 0^32 per FIPS 204 Section 3.7. */ + static const byte pk_65_mu[] = { + 0xba, 0xba, 0x6c, 0x1f, 0x57, 0xed, 0x64, 0x1c, + 0x3b, 0x7e, 0xba, 0x49, 0xe3, 0x81, 0x5b, 0xf9, + 0x78, 0x1d, 0x6e, 0x49, 0x46, 0x2e, 0x2e, 0x22, + 0x50, 0xad, 0x46, 0x7c, 0x1c, 0x82, 0x8d, 0xce, + 0xf0, 0xd3, 0x06, 0xc3, 0x20, 0x44, 0x4e, 0xcb, + 0x62, 0x81, 0x54, 0xb0, 0x47, 0xf3, 0xdc, 0x3d, + 0x64, 0xe1, 0xf3, 0x49, 0x3e, 0x9d, 0x06, 0xee, + 0x1f, 0x67, 0x47, 0x74, 0x51, 0xb5, 0xcb, 0x6b, + 0xb7, 0x63, 0x0e, 0x7e, 0x8b, 0x34, 0x4b, 0x24, + 0x08, 0xb3, 0x85, 0x33, 0x3c, 0x03, 0x05, 0x99, + 0xe6, 0x33, 0xe2, 0x3e, 0x1c, 0xb2, 0xae, 0xe9, + 0xf5, 0x75, 0x08, 0x97, 0x18, 0x0c, 0x21, 0xbf, + 0x73, 0x9e, 0xbc, 0x5f, 0xdd, 0x9a, 0xb9, 0x3a, + 0xb1, 0x8c, 0xf8, 0xdf, 0x4c, 0xb7, 0x1d, 0x14, + 0x3b, 0x68, 0x80, 0x2b, 0xf9, 0xb2, 0x86, 0xa4, + 0xe5, 0x24, 0x92, 0x7b, 0x1e, 0x8f, 0x57, 0x50, + 0x60, 0x29, 0xe1, 0xc5, 0xea, 0x1d, 0x56, 0x79, + 0x2c, 0x87, 0x8c, 0x88, 0x59, 0x4d, 0x47, 0xdc, + 0x19, 0x53, 0x28, 0x24, 0x38, 0x91, 0xa2, 0x67, + 0xfb, 0x93, 0x9f, 0x1b, 0xf0, 0xd5, 0xad, 0x7f, + 0xd3, 0xdf, 0x83, 0xd9, 0xeb, 0xc7, 0x5b, 0x28, + 0x55, 0x20, 0xab, 0x5a, 0x46, 0xb3, 0xb7, 0x1c, + 0x12, 0x2a, 0x56, 0xd8, 0x1f, 0xfc, 0x84, 0x0e, + 0x9d, 0x43, 0x35, 0x51, 0x81, 0x45, 0x3d, 0xd3, + 0x41, 0x1c, 0xbe, 0x50, 0x38, 0xd1, 0x3d, 0x16, + 0x84, 0xb5, 0x00, 0xb1, 0xfd, 0xf8, 0x9b, 0xb2, + 0x23, 0xe4, 0x25, 0x0d, 0xd1, 0xee, 0x40, 0xc3, + 0x45, 0x61, 0x96, 0x50, 0x54, 0x5c, 0x99, 0xbe, + 0x1d, 0xcb, 0x2a, 0xec, 0xe7, 0x69, 0x0f, 0x94, + 0xae, 0x3d, 0x04, 0xc3, 0xde, 0xaa, 0xdf, 0x67, + 0x5e, 0xcc, 0x47, 0xb8, 0x74, 0x2a, 0xda, 0xd7, + 0x16, 0xdd, 0x8e, 0xb5, 0x8e, 0xaf, 0xc7, 0xc3, + 0x49, 0x77, 0xd3, 0xe5, 0x36, 0x22, 0x98, 0x6b, + 0x74, 0xd5, 0xd7, 0xbb, 0x1c, 0xf0, 0xaa, 0x79, + 0xfd, 0x9c, 0x13, 0x5f, 0x0f, 0xd8, 0xa7, 0xca, + 0x9b, 0xb3, 0x4c, 0xa2, 0x2d, 0x32, 0x16, 0x3d, + 0x8a, 0x1b, 0x0e, 0x79, 0xc8, 0x4e, 0x86, 0x59, + 0xa9, 0x1e, 0x3f, 0x68, 0x32, 0x54, 0xe9, 0x3c, + 0xa9, 0x8c, 0x40, 0xea, 0x47, 0xec, 0x87, 0xf0, + 0xb6, 0x7a, 0x13, 0x0c, 0x78, 0x09, 0x98, 0x50, + 0x67, 0x8c, 0x06, 0xde, 0x2b, 0xcf, 0x4a, 0xaa, + 0xa1, 0x0b, 0x05, 0x28, 0x3e, 0xea, 0xde, 0x3d, + 0x97, 0x58, 0x04, 0xf7, 0x29, 0x01, 0x04, 0x70, + 0xb7, 0x1e, 0x03, 0x28, 0x55, 0x99, 0xbb, 0x91, + 0xfe, 0xad, 0x80, 0x50, 0xf4, 0x30, 0x52, 0x76, + 0xc3, 0x90, 0x4e, 0x77, 0xcf, 0xb0, 0xb4, 0xc9, + 0x71, 0xe7, 0x1e, 0x49, 0x09, 0x5e, 0x8f, 0x60, + 0x6e, 0x9b, 0x55, 0x9c, 0x98, 0xf7, 0x48, 0x85, + 0xfe, 0xea, 0x3b, 0x09, 0x04, 0xec, 0x1b, 0x01, + 0x72, 0x39, 0x2e, 0xfa, 0xa1, 0x23, 0xb4, 0xe1, + 0xde, 0xb8, 0xde, 0xcc, 0xf9, 0x38, 0xf3, 0x9c, + 0x6b, 0x17, 0xfa, 0x85, 0x05, 0xeb, 0xc4, 0x68, + 0x17, 0x4f, 0xbb, 0xfa, 0x7b, 0x02, 0x63, 0x2c, + 0x07, 0x51, 0x84, 0x3f, 0xcd, 0x1e, 0x48, 0x48, + 0x09, 0x06, 0x39, 0xc5, 0x47, 0x25, 0x94, 0x2d, + 0xa0, 0xcc, 0x37, 0xdc, 0xfb, 0xc6, 0x97, 0xaf, + 0x86, 0x73, 0xbf, 0x10, 0x94, 0x9f, 0x70, 0x1f, + 0xab, 0x62, 0x96, 0x70, 0x93, 0xe6, 0xa7, 0x19, + 0x32, 0xba, 0x07, 0x0f, 0xda, 0xe1, 0x48, 0x39, + 0x20, 0x3d, 0xa0, 0x77, 0x43, 0x85, 0x8a, 0xa1, + 0x85, 0xba, 0xae, 0x50, 0xf6, 0x93, 0x84, 0x6f, + 0xfb, 0x8d, 0x72, 0x64, 0x05, 0x63, 0x0a, 0x03, + 0xc2, 0x42, 0xd0, 0x2d, 0xe5, 0xb6, 0xed, 0xac, + 0x67, 0x7e, 0x35, 0xca, 0x59, 0xf1, 0x3a, 0x5c, + 0xfa, 0x41, 0x85, 0xfe, 0x05, 0x82, 0xee, 0xdc, + 0x0d, 0xf9, 0xd0, 0x69, 0x65, 0x51, 0xf5, 0x18, + 0x1c, 0x6e, 0xc0, 0x00, 0x5e, 0xe8, 0xdf, 0x77, + 0xd4, 0x7e, 0xe6, 0x36, 0x37, 0x76, 0x87, 0x38, + 0xd2, 0x83, 0xf7, 0xc9, 0x99, 0xd2, 0xb7, 0xbf, + 0xd3, 0xeb, 0x31, 0xdd, 0x7a, 0x61, 0x31, 0x6c, + 0xef, 0x3f, 0x1f, 0x21, 0xb9, 0xb3, 0xc7, 0xe4, + 0xd6, 0x54, 0xb9, 0x23, 0x56, 0x44, 0x36, 0x7a, + 0x7f, 0x74, 0x50, 0x90, 0x38, 0x71, 0x45, 0xd8, + 0x38, 0x6e, 0xd6, 0xd0, 0xc2, 0xb1, 0x48, 0x86, + 0x56, 0xf2, 0xdb, 0xf7, 0x5e, 0xcc, 0xda, 0x4b, + 0x7e, 0xda, 0x64, 0x3b, 0xa0, 0xee, 0x7e, 0x51, + 0x8d, 0x21, 0x4b, 0x19, 0x6f, 0xdd, 0xe9, 0x01, + 0x67, 0x75, 0x75, 0x4e, 0x94, 0xf5, 0x5e, 0xa5, + 0xc2, 0xe2, 0x65, 0x7d, 0xcd, 0x60, 0x14, 0x5d, + 0x8f, 0x86, 0xb9, 0xb9, 0x27, 0x34, 0x80, 0x56, + 0x9e, 0xef, 0x22, 0xc1, 0xd4, 0x86, 0x03, 0x50, + 0xb7, 0xc1, 0xaa, 0x36, 0x8a, 0x10, 0xdc, 0x7a, + 0x8f, 0x40, 0x92, 0xbb, 0xd5, 0x47, 0xdf, 0x8d, + 0x50, 0xe9, 0x71, 0xf8, 0xf4, 0x0e, 0x3e, 0x83, + 0x65, 0x78, 0x92, 0xdc, 0x16, 0x89, 0x7c, 0xcf, + 0xbf, 0x19, 0xaf, 0x63, 0xb9, 0x4c, 0x65, 0x04, + 0xed, 0xd4, 0xf4, 0x62, 0xbe, 0x8d, 0x69, 0xe4, + 0xf4, 0x22, 0x41, 0x55, 0xa9, 0xab, 0x81, 0xdd, + 0xf2, 0x37, 0x0f, 0xf5, 0x48, 0x4e, 0x52, 0x44, + 0x31, 0xee, 0xf2, 0x82, 0x07, 0xd9, 0xe2, 0x90, + 0x49, 0x16, 0x69, 0x26, 0xb5, 0xdc, 0x8d, 0x72, + 0x3d, 0x8e, 0xd9, 0xa1, 0x48, 0x6b, 0xa9, 0xca, + 0x2c, 0x3a, 0xa5, 0x67, 0x65, 0xc7, 0x82, 0x04, + 0x7b, 0xf1, 0x03, 0xa2, 0x7b, 0x51, 0xfb, 0xab, + 0x66, 0x7e, 0xe2, 0x5e, 0x09, 0x20, 0x83, 0xd1, + 0x14, 0x58, 0xe9, 0xb9, 0xac, 0x31, 0x86, 0x47, + 0xa3, 0x99, 0x4d, 0xc2, 0x86, 0x29, 0xf7, 0xf1, + 0x27, 0x43, 0x6c, 0xca, 0xc9, 0x27, 0xfb, 0x03, + 0xc5, 0xde, 0xaa, 0xb7, 0xe0, 0xd4, 0x52, 0x05, + 0x1d, 0xcb, 0x82, 0x06, 0xc1, 0xc5, 0xbb, 0xc6, + 0x0a, 0x3f, 0xde, 0xda, 0x6b, 0x6f, 0x26, 0x0c, + 0xe6, 0xe4, 0xf2, 0xe2, 0xd5, 0x62, 0x74, 0x5a, + 0x3f, 0x4f, 0xbb, 0x2a, 0x22, 0x0f, 0x70, 0xf2, + 0x8e, 0xde, 0x2c, 0xed, 0xbb, 0x84, 0x38, 0x12, + 0x7a, 0xaa, 0x4a, 0x08, 0x73, 0x5d, 0xcf, 0x4f, + 0x01, 0x8e, 0x7a, 0x36, 0x15, 0x27, 0xdc, 0x2e, + 0x4c, 0xe9, 0x6f, 0x01, 0xa0, 0x0d, 0xbb, 0xd2, + 0xfa, 0xd0, 0x35, 0x6b, 0x20, 0x2c, 0x3a, 0x7f, + 0xe9, 0x09, 0xbb, 0x65, 0x80, 0x80, 0xb5, 0xb6, + 0x83, 0xe2, 0x0f, 0x1f, 0xaa, 0x72, 0xd9, 0xaf, + 0x62, 0xbd, 0x83, 0x44, 0xba, 0x21, 0xbc, 0xfb, + 0xbe, 0x55, 0xbc, 0x3e, 0x80, 0xc5, 0x20, 0x4a, + 0xf7, 0x39, 0x57, 0x96, 0x1a, 0xf7, 0x5b, 0x20, + 0x8c, 0xb3, 0x73, 0xd5, 0x12, 0x85, 0x9d, 0x06, + 0xea, 0xf2, 0x99, 0x15, 0x82, 0xc8, 0x2a, 0x76, + 0xb6, 0x5a, 0x0b, 0xdf, 0x11, 0xbc, 0xf8, 0x40, + 0xa6, 0xa1, 0x27, 0xbf, 0x3a, 0x2c, 0xe2, 0xd3, + 0x83, 0x22, 0xc9, 0xef, 0x0f, 0xfb, 0x54, 0xa7, + 0x6c, 0xc7, 0x25, 0xa3, 0x37, 0xc3, 0x2f, 0xe6, + 0x76, 0x06, 0x4f, 0x95, 0xe6, 0xf1, 0xe4, 0x4f, + 0xb6, 0x66, 0x47, 0x13, 0xe3, 0x32, 0xf7, 0x74, + 0x93, 0x1a, 0x8a, 0xbe, 0x82, 0x58, 0xd0, 0xda, + 0x57, 0x60, 0x9d, 0x8c, 0x20, 0xa5, 0x29, 0x76, + 0xbf, 0xf5, 0xe2, 0x7a, 0xa4, 0x2d, 0xee, 0x94, + 0xa4, 0xfc, 0xa7, 0x37, 0x5e, 0x23, 0xd5, 0xd3, + 0x63, 0x6d, 0x61, 0x1e, 0xb9, 0xc1, 0xe9, 0x5e, + 0x1a, 0xaf, 0xc4, 0x0b, 0xbb, 0xfd, 0x95, 0x3b, + 0x25, 0x62, 0x89, 0x1d, 0x3f, 0xb0, 0xa8, 0xf9, + 0x78, 0xe3, 0x3b, 0xe6, 0x48, 0xbb, 0xcb, 0x97, + 0x97, 0x7e, 0x5a, 0xb8, 0x79, 0x2a, 0x34, 0xa2, + 0x91, 0x9b, 0x2a, 0x5f, 0x75, 0x61, 0xc1, 0xd0, + 0xae, 0xdb, 0x77, 0xb2, 0x2b, 0xba, 0x06, 0x38, + 0xbb, 0xcf, 0x87, 0xd1, 0x69, 0x80, 0xb3, 0x43, + 0xe6, 0x5f, 0x07, 0xd8, 0x96, 0x00, 0x25, 0x8f, + 0x76, 0xa9, 0x8f, 0x46, 0x24, 0x9f, 0x1e, 0xfa, + 0x2f, 0x2c, 0x42, 0xc1, 0x5f, 0x49, 0x7e, 0x62, + 0xd8, 0x37, 0x38, 0x9c, 0x9e, 0x75, 0x5f, 0x75, + 0x2b, 0x4e, 0x27, 0xb1, 0x49, 0x91, 0xe9, 0xe1, + 0x13, 0x87, 0xa9, 0x46, 0x71, 0x48, 0x0b, 0x8a, + 0x98, 0xf6, 0x07, 0x6b, 0xa4, 0x77, 0x85, 0xf5, + 0x1b, 0x5b, 0x37, 0x3a, 0xec, 0xb4, 0xbb, 0xf7, + 0xc8, 0x5d, 0x47, 0x96, 0x8e, 0x1e, 0x93, 0x1c, + 0x8a, 0x64, 0x12, 0x7a, 0xba, 0x2e, 0x88, 0x77, + 0x8a, 0xc6, 0xa3, 0xbd, 0x9c, 0x29, 0x69, 0x6b, + 0x58, 0x8f, 0x3f, 0xdc, 0xa2, 0x61, 0x7c, 0x5f, + 0x88, 0xaf, 0xbd, 0x10, 0x10, 0x6e, 0x38, 0x68, + 0x45, 0xab, 0xff, 0x03, 0x72, 0xfc, 0xbb, 0x26, + 0xfd, 0x23, 0x2e, 0xeb, 0xef, 0xe6, 0x47, 0x4e, + 0xdc, 0xda, 0xaf, 0x26, 0xa7, 0x66, 0x50, 0x27, + 0xc3, 0x01, 0xb1, 0x53, 0xf0, 0xef, 0x05, 0x92, + 0x9b, 0xf4, 0x6d, 0x75, 0x00, 0x1b, 0xbd, 0x2c, + 0x51, 0xf9, 0x66, 0x12, 0xe9, 0xc7, 0xf8, 0x91, + 0x6a, 0xf9, 0xfc, 0xca, 0xf4, 0xa5, 0xff, 0xb7, + 0x21, 0xa2, 0xfb, 0x67, 0x81, 0x5b, 0x07, 0x22, + 0xaf, 0x6e, 0xad, 0xd2, 0xa4, 0xf8, 0x14, 0xa5, + 0xfa, 0x1c, 0x8a, 0xe9, 0x32, 0xb7, 0x46, 0x93, + 0x5c, 0x34, 0x14, 0xa4, 0xc6, 0x78, 0x03, 0xbd, + 0x2b, 0x22, 0xc8, 0x37, 0xc0, 0x09, 0x63, 0xc4, + 0xd4, 0xed, 0x38, 0xa2, 0x8c, 0xc9, 0xc0, 0x3f, + 0xf9, 0xeb, 0xbf, 0xa7, 0x94, 0x4f, 0x2f, 0x56, + 0xcf, 0x5a, 0xdc, 0xa5, 0xa2, 0x6f, 0x87, 0x48, + 0x4f, 0x62, 0x04, 0xc0, 0x14, 0xa7, 0xed, 0x0d, + 0xd6, 0x4a, 0x92, 0x38, 0xf2, 0x05, 0xa8, 0x87, + 0xa5, 0xe2, 0xbe, 0x43, 0x59, 0x7d, 0xb9, 0xd6, + 0xab, 0xcd, 0x11, 0x7c, 0xee, 0xa9, 0xcb, 0x49, + 0x70, 0x21, 0xb4, 0x23, 0xe5, 0xdb, 0xe3, 0xcb, + 0x86, 0xf5, 0x70, 0x1c, 0xbc, 0x46, 0xd3, 0x9b, + 0x9b, 0x43, 0x1e, 0x0b, 0xac, 0xd6, 0x6a, 0xe7, + 0xe9, 0xa2, 0x1c, 0x12, 0x04, 0x4c, 0x95, 0x9e, + 0x3d, 0x63, 0xa8, 0x27, 0xc1, 0x6e, 0x9c, 0xd8, + 0xe0, 0x57, 0x65, 0xcf, 0x87, 0x95, 0xbf, 0xbe, + 0x7f, 0x40, 0xef, 0xde, 0x42, 0x7e, 0x5a, 0x5f, + 0x46, 0x84, 0x94, 0xe5, 0xa7, 0x96, 0xa7, 0x1f, + 0xdd, 0xbb, 0x45, 0x44, 0xe7, 0xb3, 0x1a, 0xc4, + 0xee, 0x27, 0xe5, 0x88, 0x17, 0x34, 0x72, 0x63, + 0xb9, 0x94, 0xfa, 0xc8, 0x57, 0x80, 0x19, 0x3a, + 0x82, 0x6a, 0xd3, 0x6c, 0x4d, 0x19, 0x1a, 0xc0, + 0x60, 0x15, 0x46, 0xf2, 0x55, 0x9f, 0xcb, 0x76, + 0xd7, 0x40, 0xef, 0x26, 0x9d, 0xe4, 0xda, 0xda, + 0x32, 0x33, 0xa6, 0x5b, 0xc8, 0x36, 0x18, 0x1e, + 0x23, 0xf9, 0x7f, 0x8e, 0xd6, 0x25, 0xfe, 0x31, + 0x9c, 0x98, 0xc4, 0x0e, 0xb7, 0x89, 0x46, 0xd7, + 0x22, 0xf4, 0x66, 0x67, 0xd2, 0xc7, 0xee, 0xb8, + 0xbf, 0xe6, 0xfe, 0x94, 0x6d, 0x14, 0xcb, 0x11, + 0xe7, 0xf0, 0x6a, 0xd2, 0x21, 0x09, 0x3f, 0xe9, + 0x18, 0xac, 0x80, 0xbb, 0x9f, 0x1e, 0x59, 0xc6, + 0x0c, 0x41, 0x06, 0xa2, 0x47, 0x9c, 0xe0, 0x32, + 0xf5, 0xc9, 0xe4, 0x83, 0xc8, 0x5d, 0x24, 0xb5, + 0xde, 0x5a, 0x98, 0xff, 0x06, 0x11, 0x91, 0xbf, + 0xb6, 0x02, 0x5a, 0x1a, 0xfe, 0x9d, 0xe1, 0x5e, + 0x98, 0x62, 0xb9, 0xdd, 0x46, 0xf1, 0x6e, 0xc9, + 0xbe, 0xd8, 0x5b, 0x45, 0x53, 0xef, 0x1c, 0xd3, + 0xc9, 0x77, 0x60, 0x36, 0xa4, 0x58, 0x24, 0x1b, + 0x71, 0x7f, 0x48, 0x73, 0xd0, 0x8b, 0x0f, 0x81, + 0x3f, 0x23, 0x33, 0xb7, 0x92, 0x4a, 0x7e, 0x39, + 0xdb, 0xc9, 0x5d, 0x99, 0x96, 0xc6, 0xa7, 0x17, + 0x51, 0x6b, 0xa7, 0x9b, 0x59, 0x7c, 0x9e, 0x7b, + 0xf5, 0x7a, 0x66, 0xb9, 0x62, 0x49, 0x5e, 0xaf, + 0x40, 0x9c, 0x75, 0xc5, 0x09, 0x33, 0x95, 0x32, + 0x2f, 0x24, 0xd8, 0x77, 0x70, 0x94, 0xdc, 0x33, + 0x1b, 0x21, 0x52, 0x45, 0xa6, 0xa7, 0xb1, 0x87, + 0xc3, 0x12, 0xea, 0x6b, 0x27, 0xb3, 0xea, 0xbf, + 0x24, 0x3b, 0x85, 0xe2, 0x34, 0x5d, 0x76, 0xbf, + 0xee, 0xf9, 0x87, 0x31, 0xdd, 0x59, 0x52, 0xbd, + 0xcd, 0x0d, 0x82, 0xe3, 0x94, 0x36, 0xcb, 0x25, + 0x5f, 0x2a, 0x6f, 0x6b, 0xbd, 0x97, 0xf2, 0x55, + 0x0c, 0x3b, 0x8d, 0xfd, 0x60, 0x6d, 0x1e, 0x93, + 0xb7, 0x23, 0x18, 0xa0, 0x17, 0x27, 0xc7, 0xec, + 0x2b, 0x75, 0x6d, 0x80, 0x1d, 0x80, 0x26, 0x0d, + 0xfa, 0x4e, 0xa1, 0xff, 0xbd, 0xc0, 0x72, 0x82, + 0x78, 0xd5, 0xd1, 0x62, 0x89, 0x3b, 0xe2, 0xf3, + 0x50, 0x2f, 0xf8, 0xf6, 0x82, 0x37, 0xc1, 0x83, + 0xb3, 0xff, 0xc1, 0xb9, 0x55, 0x18, 0xa9, 0xef, + 0xfb, 0x53, 0x9f, 0x49, 0x5c, 0xeb, 0x2d, 0x31, + 0x5b, 0x20, 0x05, 0x28, 0xf1, 0x04, 0x33, 0x16, + 0xb4, 0xe8, 0x3c, 0x15, 0x10, 0x1a, 0x15, 0x5d, + 0x57, 0x01, 0x59, 0xd6, 0x3e, 0xb4, 0x20, 0xb6, + 0x0c, 0xd2, 0x95, 0x4a, 0xcd, 0xe6, 0xf2, 0x78, + 0xc7, 0x79, 0xe9, 0x2f, 0xe3, 0x7b, 0x34, 0xf0, + 0xb9, 0xcc, 0x4c, 0xe2, 0x3f, 0x67, 0x64, 0xf8, + 0xbe, 0x4c, 0xa8, 0xe2, 0x2f, 0xb0, 0x37, 0xbe, + 0x25, 0xb8, 0x0e, 0xaf, 0x2f, 0x77, 0xfc, 0xd8, + 0x8a, 0x70, 0x2a, 0xe4, 0xfa, 0xb4, 0xe5, 0x9d, + 0x9d, 0xb4, 0x32, 0x24, 0x35, 0xf8, 0x9a, 0x4a, + 0xa1, 0x28, 0xb2, 0xea, 0xa1, 0xdd, 0xe6, 0xbf, + 0x73, 0x1c, 0x38, 0xcc, 0x7e, 0x1b, 0x82, 0xb9, + 0xb8, 0x16, 0x48, 0xb1, 0x9c, 0x12, 0x4b, 0xea, + 0x8d, 0x46, 0x5d, 0xf4, 0xa8, 0xc5, 0x87, 0x3c, + 0x45, 0x5b, 0xe6, 0xe2, 0x5d, 0xc7, 0xe9, 0xef, + 0xf2, 0x37, 0x3b, 0x10, 0xdf, 0x89, 0xc9, 0x1e, + 0x2b, 0xb0, 0x17, 0x97, 0xaa, 0x9d, 0xda, 0x3a, + 0x7b, 0xf1, 0xcb, 0xca, 0xe0, 0x52, 0xeb, 0x89, + 0xab, 0x38, 0xf2, 0xc2, 0x8d, 0x83, 0x2d, 0x3b, + 0x00, 0xaa, 0x7d, 0xbb, 0x1c, 0x23, 0x85, 0x73, + 0x27, 0x4e, 0x6e, 0xd3, 0xfd, 0x11, 0x6b, 0xee, + 0x06, 0xa2, 0xb0, 0xd5, 0x40, 0x02, 0x65, 0x9d, + 0x74, 0xba, 0x7f, 0x48, 0x40, 0x40, 0xe3, 0xd1, + 0x4b, 0x42, 0x00, 0xb3, 0x97, 0xe4, 0xbe, 0x05, + 0xd2, 0xbd, 0x72, 0x28, 0x44, 0xc2, 0x44, 0xc4, + 0x44, 0xae, 0xa9, 0xa5, 0x79, 0xa8, 0x1d, 0x53, + 0xa3, 0xb7, 0xe5, 0xff, 0x8a, 0x05, 0x0e, 0x38, + 0x6c, 0x92, 0x6d, 0xc6, 0x65, 0x6d, 0xb0, 0xc8, + 0x19, 0x3f, 0xf8, 0x61, 0x54, 0x71, 0x97, 0x9c, + 0x3f, 0xd8, 0x34, 0xa5, 0x02, 0xbc, 0xcf, 0x34 + }; + static const byte mu_65[] = { + 0x32, 0x6f, 0xd5, 0xf3, 0x76, 0x2b, 0xd8, 0xc1, + 0x31, 0x4b, 0x83, 0x07, 0x22, 0x5b, 0x2e, 0x6a, + 0x23, 0x08, 0x86, 0x63, 0x8d, 0x8a, 0xb4, 0xe7, + 0x8e, 0x5c, 0xff, 0xfa, 0x1c, 0xdc, 0xb9, 0x61, + 0x6f, 0x01, 0x0b, 0xb8, 0x66, 0x2d, 0x7d, 0xec, + 0x82, 0xb8, 0x00, 0xa8, 0x48, 0x77, 0x12, 0x21, + 0xea, 0x67, 0x30, 0x45, 0x21, 0x39, 0x7d, 0x3d, + 0x27, 0x3c, 0x21, 0xf4, 0x18, 0x5b, 0x79, 0x31 + }; + static const byte sig_65_mu[] = { + 0xc8, 0x39, 0x74, 0x5f, 0xbc, 0xef, 0x91, 0x4b, + 0x5e, 0x3e, 0x06, 0x86, 0xe3, 0x69, 0x57, 0xe1, + 0xf1, 0xc5, 0x6e, 0x06, 0x87, 0xf8, 0x24, 0x1c, + 0xb5, 0x38, 0x8d, 0xe3, 0x53, 0xfb, 0xe0, 0xd6, + 0x31, 0x61, 0x85, 0xa5, 0xe5, 0x86, 0x46, 0xdf, + 0xe3, 0x0e, 0xab, 0xfe, 0x06, 0x01, 0x4d, 0xa3, + 0x74, 0x1f, 0x52, 0xb9, 0x55, 0xd1, 0xf5, 0xce, + 0xac, 0x51, 0x2c, 0x3b, 0xb3, 0x64, 0xdd, 0xd3, + 0x85, 0x80, 0xd8, 0xd3, 0x64, 0x3f, 0x6f, 0xa7, + 0x3d, 0x2b, 0xc5, 0xfe, 0x29, 0x18, 0x0e, 0x8e, + 0x15, 0x5b, 0xab, 0x14, 0xcd, 0xb3, 0x3f, 0x85, + 0x4c, 0xcc, 0x0d, 0x49, 0xee, 0x1a, 0x01, 0x15, + 0xd4, 0xfe, 0xdb, 0xc8, 0x94, 0xe3, 0x84, 0x53, + 0x67, 0x26, 0x6b, 0x61, 0x2b, 0x66, 0x77, 0x9a, + 0x7d, 0xa5, 0x04, 0xf4, 0x7f, 0x4e, 0x34, 0x17, + 0x26, 0x4f, 0x31, 0x2e, 0x47, 0x38, 0x92, 0xd8, + 0xd6, 0x12, 0x69, 0xed, 0x28, 0x86, 0x25, 0xeb, + 0x29, 0x21, 0x66, 0x42, 0x53, 0x56, 0xe8, 0x5b, + 0x2d, 0x80, 0x4b, 0xf6, 0x9a, 0x41, 0x45, 0x51, + 0x71, 0xef, 0x46, 0x39, 0x6f, 0xa6, 0x95, 0x30, + 0xa4, 0xf0, 0x8f, 0xea, 0x32, 0x86, 0x05, 0x3a, + 0x9f, 0xc0, 0x0f, 0x91, 0x62, 0xd3, 0xc2, 0xe1, + 0x10, 0x1a, 0x60, 0x88, 0x6e, 0x7d, 0x7a, 0x74, + 0x51, 0x75, 0x3f, 0x8b, 0x3d, 0x1e, 0x3b, 0xcc, + 0x64, 0x90, 0xa0, 0x52, 0xe4, 0xc5, 0x3b, 0xaf, + 0x35, 0x01, 0xeb, 0xe5, 0xdb, 0xa7, 0xbf, 0x9d, + 0x2f, 0xc4, 0x37, 0x75, 0xfb, 0xbd, 0x16, 0x0e, + 0xda, 0x2f, 0x01, 0x63, 0x8b, 0x59, 0xb9, 0x9b, + 0x4f, 0x0c, 0x8b, 0x51, 0xfb, 0xf5, 0x5d, 0x6a, + 0x9d, 0xc8, 0xce, 0xaf, 0xca, 0x3f, 0x03, 0x95, + 0x1d, 0xd1, 0x26, 0xa3, 0x7c, 0x8b, 0xad, 0x92, + 0xf2, 0xe5, 0x88, 0x09, 0xeb, 0xbe, 0xff, 0x3b, + 0x4e, 0x34, 0xf8, 0x98, 0x7f, 0xf9, 0x0c, 0x7e, + 0x2c, 0x40, 0x7b, 0xc8, 0xd1, 0x21, 0x0c, 0xf6, + 0xeb, 0xba, 0x24, 0x25, 0xe2, 0x7d, 0x45, 0x92, + 0x33, 0x2b, 0xab, 0xb8, 0xd6, 0x7d, 0x91, 0x5a, + 0x36, 0xd3, 0x81, 0x4c, 0x73, 0x9c, 0x99, 0x82, + 0xcc, 0xa0, 0x1e, 0xf9, 0xd1, 0x07, 0x39, 0x31, + 0x9b, 0x3a, 0xdc, 0xb3, 0xc9, 0x3d, 0x3a, 0xb3, + 0xa1, 0x0d, 0xcd, 0x20, 0x38, 0x22, 0xa9, 0x05, + 0x74, 0xd0, 0x72, 0x32, 0x12, 0x07, 0x06, 0x7b, + 0xd3, 0xcd, 0x02, 0x1e, 0x72, 0x54, 0x6d, 0x7f, + 0xe6, 0xd2, 0x3c, 0x86, 0xed, 0x88, 0x31, 0x3c, + 0x7d, 0x21, 0x42, 0x3e, 0xbc, 0x97, 0xfd, 0x0e, + 0x75, 0xde, 0x0a, 0x3a, 0x1b, 0x32, 0x19, 0x7b, + 0x9b, 0x28, 0x0f, 0xe4, 0xf1, 0xcc, 0x77, 0xfa, + 0x81, 0x70, 0xd0, 0x6a, 0x41, 0xd3, 0xe3, 0x8b, + 0x70, 0x40, 0x30, 0x3f, 0xed, 0x5a, 0x7c, 0x7c, + 0xd4, 0x84, 0xa3, 0x36, 0x14, 0x58, 0xaa, 0xd7, + 0x9e, 0x9f, 0x64, 0x4f, 0x7b, 0x7f, 0xfd, 0x4d, + 0x6c, 0xb9, 0x1e, 0xae, 0xd0, 0x8b, 0x60, 0x61, + 0xc1, 0xe0, 0xcb, 0x14, 0xda, 0x11, 0x0d, 0xa4, + 0x4e, 0x10, 0xac, 0x59, 0x77, 0xda, 0xce, 0x8b, + 0x99, 0xcc, 0x6d, 0xf0, 0x2c, 0xd3, 0x66, 0x9a, + 0xca, 0x5a, 0x5e, 0xd6, 0x41, 0x70, 0xdf, 0x8d, + 0x17, 0x2d, 0x8e, 0xb0, 0xc5, 0x29, 0x15, 0x23, + 0x90, 0x9b, 0x21, 0xaa, 0xc3, 0xe2, 0xc1, 0x72, + 0x59, 0x20, 0xa0, 0x22, 0x49, 0x46, 0xe1, 0x68, + 0xcd, 0x58, 0x43, 0xef, 0x32, 0x20, 0xa2, 0xdd, + 0xb7, 0x4b, 0xeb, 0xfd, 0x9d, 0x87, 0x20, 0xd8, + 0x9d, 0x47, 0xf6, 0x06, 0xbb, 0x2f, 0x33, 0xee, + 0xfd, 0x01, 0x2c, 0x21, 0x41, 0x2b, 0x73, 0x7f, + 0x3b, 0x48, 0x62, 0x42, 0x76, 0xf0, 0xb3, 0x30, + 0xb2, 0x50, 0xa1, 0x00, 0xe1, 0xd6, 0x62, 0xc5, + 0xb0, 0xbb, 0x93, 0x2d, 0xda, 0xd2, 0x41, 0x14, + 0x3c, 0xbb, 0x6d, 0xee, 0xac, 0x99, 0x05, 0x0b, + 0xc0, 0x89, 0x0b, 0x6f, 0x5b, 0x04, 0x21, 0x3b, + 0x3f, 0x51, 0x25, 0xc0, 0x30, 0xc9, 0x07, 0xd6, + 0x4d, 0xec, 0x06, 0xb5, 0x14, 0x03, 0x19, 0x6e, + 0x32, 0x4f, 0xd7, 0x59, 0x32, 0x7b, 0xdb, 0x45, + 0x80, 0x6c, 0xba, 0x23, 0xba, 0x25, 0xc8, 0xf7, + 0x59, 0xf7, 0x51, 0xb3, 0x9f, 0xbe, 0xa2, 0xf9, + 0x44, 0x55, 0x3b, 0x09, 0x83, 0xab, 0x13, 0x55, + 0x6d, 0xb9, 0xeb, 0x44, 0x72, 0x9d, 0xb1, 0xed, + 0x2f, 0xfd, 0x28, 0x3b, 0xbc, 0xe6, 0xd6, 0x41, + 0xe5, 0x64, 0x1f, 0x9b, 0x8b, 0x58, 0xfd, 0x1c, + 0xe4, 0x48, 0xff, 0xa2, 0xbb, 0xa0, 0xff, 0xe7, + 0x29, 0x8b, 0xe3, 0x86, 0x10, 0xf4, 0xb1, 0xaf, + 0x06, 0xc1, 0x4b, 0x57, 0xbc, 0xc6, 0xd1, 0x83, + 0x59, 0x8e, 0x5a, 0x68, 0xa6, 0x0e, 0xce, 0xbe, + 0x65, 0x38, 0x18, 0x35, 0x20, 0x10, 0x90, 0x47, + 0x07, 0xe7, 0xb1, 0x5f, 0xb0, 0xb4, 0xe9, 0x7f, + 0x9e, 0x82, 0x49, 0x6e, 0x0c, 0xed, 0xb0, 0xc8, + 0x29, 0xea, 0xef, 0x90, 0x99, 0x61, 0xc2, 0xec, + 0xf7, 0x03, 0x8a, 0x23, 0x6b, 0x18, 0xe8, 0x60, + 0x28, 0x8a, 0x00, 0xbc, 0x3d, 0xca, 0x6e, 0x31, + 0x3f, 0x01, 0xd2, 0x26, 0xc9, 0x98, 0xf0, 0x5a, + 0x24, 0x74, 0x2b, 0x37, 0x78, 0x40, 0x06, 0x96, + 0xb2, 0xf6, 0x55, 0x96, 0xd1, 0x68, 0x7a, 0x1b, + 0x7a, 0x34, 0xbd, 0x98, 0x09, 0x9d, 0x9a, 0x39, + 0xc6, 0x25, 0x2d, 0x07, 0x92, 0xda, 0xd6, 0x5e, + 0xd9, 0x5b, 0x8d, 0x4c, 0xe0, 0x42, 0x72, 0x10, + 0x39, 0x29, 0xc6, 0x91, 0x74, 0x2c, 0x95, 0xd8, + 0x65, 0x3e, 0x7c, 0x40, 0x66, 0xcc, 0x19, 0x68, + 0x24, 0xb3, 0xa8, 0x9f, 0xf0, 0xd0, 0x65, 0xdd, + 0x02, 0x3d, 0xc4, 0xd4, 0x8c, 0xb6, 0xdf, 0xae, + 0xf9, 0xf4, 0x05, 0x76, 0x48, 0xba, 0x33, 0x7d, + 0xbd, 0x90, 0x40, 0x56, 0x95, 0x99, 0x2b, 0x13, + 0xfa, 0x79, 0x2b, 0x95, 0xd1, 0x31, 0x3c, 0x26, + 0x2c, 0xe7, 0x82, 0x87, 0xc4, 0x7e, 0x7c, 0x26, + 0x34, 0x78, 0x05, 0x5c, 0xbd, 0x0b, 0xd0, 0xa3, + 0x3d, 0x72, 0x50, 0x06, 0x49, 0x1f, 0x89, 0xc1, + 0xcf, 0xae, 0x21, 0x84, 0xb0, 0x63, 0x59, 0xca, + 0x4c, 0xe2, 0xcb, 0xb5, 0x6e, 0x5a, 0x74, 0x63, + 0x45, 0x18, 0xdb, 0x67, 0x78, 0x71, 0x13, 0x0b, + 0x4b, 0x85, 0xa0, 0x02, 0x68, 0x87, 0x6d, 0x12, + 0x2b, 0x5c, 0x3c, 0x14, 0x4b, 0x8b, 0xd0, 0x66, + 0xc2, 0x1b, 0x25, 0xf2, 0xcd, 0x19, 0xa2, 0x53, + 0x0b, 0xe3, 0x8c, 0x74, 0xdc, 0xe6, 0x33, 0x6f, + 0x1c, 0xfd, 0x29, 0x6e, 0x0b, 0x42, 0x27, 0x9d, + 0x8a, 0xce, 0x49, 0xaa, 0x02, 0x6d, 0xcf, 0x74, + 0x2b, 0xdb, 0x3a, 0x18, 0x2a, 0xf9, 0x22, 0xe3, + 0xd2, 0xdd, 0x2d, 0xa1, 0xce, 0x96, 0x82, 0xbe, + 0xfe, 0x98, 0xf5, 0x56, 0xe2, 0x7e, 0x3f, 0xeb, + 0x5a, 0x9c, 0x72, 0x7f, 0x02, 0x93, 0x3c, 0x2f, + 0x40, 0x91, 0x50, 0x5f, 0x49, 0xcc, 0x62, 0x58, + 0xdf, 0x7a, 0x81, 0x8a, 0xc9, 0xec, 0x08, 0x81, + 0x06, 0x6f, 0xbf, 0x69, 0x3a, 0x85, 0x53, 0x17, + 0x02, 0xc7, 0xee, 0xb5, 0x68, 0xe4, 0x6f, 0x5f, + 0xa1, 0xe9, 0x6c, 0x86, 0x85, 0x1f, 0x9e, 0x7b, + 0xd5, 0x15, 0xfc, 0x5c, 0x03, 0xde, 0x43, 0x64, + 0x7f, 0x36, 0x64, 0xd3, 0x2b, 0x6b, 0x6b, 0x65, + 0x52, 0x67, 0x4b, 0xd2, 0xca, 0x4d, 0x9d, 0x8b, + 0x6c, 0xe3, 0x0a, 0x71, 0x32, 0xcd, 0xb7, 0x6f, + 0xbc, 0x99, 0xa0, 0xe6, 0x3e, 0x9d, 0xa3, 0x21, + 0x03, 0x45, 0xd3, 0x0f, 0xf1, 0x04, 0x76, 0x5c, + 0xde, 0x37, 0xd0, 0x49, 0x51, 0xa7, 0xf9, 0x89, + 0x37, 0x71, 0x0e, 0x4a, 0x8e, 0x0c, 0x3c, 0x4c, + 0x3a, 0x7f, 0x55, 0xdc, 0x62, 0x47, 0x4f, 0x4e, + 0xd1, 0x72, 0xd0, 0xe1, 0x14, 0xf7, 0x24, 0xe7, + 0xfb, 0x82, 0x71, 0xa6, 0xe7, 0x40, 0xed, 0xd7, + 0x6f, 0x50, 0x6e, 0xc7, 0xc9, 0xcc, 0x14, 0xf8, + 0x1d, 0x5c, 0x49, 0xbd, 0xa7, 0x6a, 0xf3, 0xca, + 0xbe, 0xfb, 0x31, 0x8d, 0x9d, 0x64, 0x60, 0xee, + 0xd9, 0xfb, 0x0e, 0x1c, 0xd8, 0x63, 0x79, 0x03, + 0x3e, 0x93, 0xe4, 0x47, 0xa2, 0xfc, 0xc5, 0xe9, + 0xfd, 0x2f, 0xa5, 0x03, 0x55, 0xb6, 0x75, 0xed, + 0xa5, 0xc9, 0x27, 0x38, 0x04, 0xed, 0x86, 0x3f, + 0xd9, 0xcc, 0x28, 0xbc, 0xd1, 0x49, 0xe0, 0xbf, + 0x68, 0xde, 0xac, 0xff, 0xe1, 0x4d, 0xfc, 0x6b, + 0xfa, 0x63, 0x65, 0x23, 0xeb, 0xdb, 0x3a, 0x3f, + 0x11, 0xd0, 0x63, 0xa5, 0x73, 0x42, 0xbf, 0x40, + 0xf3, 0xab, 0x27, 0x18, 0x1b, 0x0b, 0x87, 0x77, + 0x13, 0x75, 0x08, 0xce, 0x63, 0x4b, 0xc6, 0x58, + 0x1a, 0x43, 0xb5, 0xd0, 0x4c, 0x29, 0x8c, 0xec, + 0x2d, 0x82, 0xc2, 0xe4, 0xaa, 0xc1, 0x3e, 0x4e, + 0x08, 0x21, 0x41, 0x20, 0xc5, 0x9f, 0x69, 0x98, + 0x1d, 0x33, 0x23, 0x4e, 0xb7, 0x6d, 0xe4, 0x2a, + 0x95, 0xb8, 0x6c, 0x39, 0xf3, 0x18, 0x01, 0x63, + 0xaa, 0x83, 0x27, 0x53, 0xd5, 0x3c, 0x37, 0xb0, + 0xda, 0x72, 0x01, 0x03, 0x85, 0x74, 0x09, 0x59, + 0x94, 0x0b, 0x10, 0x95, 0xe4, 0xad, 0x48, 0x37, + 0xcb, 0xef, 0x54, 0xe7, 0xf9, 0x8a, 0x42, 0xf8, + 0x5a, 0x56, 0xfc, 0x64, 0x92, 0xd9, 0xff, 0x75, + 0x2b, 0xee, 0x2f, 0x5d, 0x67, 0xb3, 0x98, 0x9f, + 0x20, 0x1e, 0xfe, 0x8c, 0xf2, 0x60, 0x2e, 0xcb, + 0xcd, 0x19, 0xfb, 0x31, 0x5f, 0xcf, 0xcf, 0x96, + 0x3c, 0x98, 0xe8, 0x9c, 0x3b, 0x1b, 0xf0, 0xdd, + 0x52, 0xb2, 0x9c, 0x4f, 0x83, 0x68, 0xb1, 0x42, + 0x82, 0xa4, 0x57, 0x52, 0x47, 0x0e, 0x59, 0x8c, + 0x4f, 0x76, 0x49, 0xf4, 0xc0, 0x02, 0x96, 0x10, + 0x36, 0xa0, 0x0d, 0x3d, 0x89, 0xc9, 0x1f, 0x85, + 0x96, 0x53, 0x1d, 0x89, 0xf8, 0x7a, 0xb3, 0xe4, + 0x20, 0x12, 0x65, 0x06, 0x3a, 0x89, 0xff, 0x8f, + 0x32, 0x4c, 0x81, 0x44, 0x00, 0x0a, 0xbe, 0x26, + 0x51, 0x27, 0x4b, 0x9b, 0x0d, 0x4e, 0x7c, 0xa5, + 0x71, 0xfb, 0x91, 0x08, 0x32, 0xa4, 0x82, 0xcb, + 0x9c, 0xb2, 0x0d, 0x5e, 0x22, 0xda, 0x6c, 0xd6, + 0x5f, 0xa8, 0x5b, 0xfa, 0xdc, 0x27, 0x8f, 0xa0, + 0xac, 0x58, 0xd1, 0xeb, 0xd9, 0xab, 0x2f, 0x2d, + 0xbf, 0xb7, 0x27, 0x6e, 0xfe, 0xd0, 0x54, 0x34, + 0xfe, 0x2a, 0x2f, 0x99, 0xda, 0xd2, 0xf0, 0x82, + 0x8d, 0x13, 0x72, 0x87, 0x1a, 0xa6, 0x7f, 0x9b, + 0x2b, 0x6d, 0xff, 0x8e, 0x5b, 0x23, 0xc3, 0x0a, + 0x5a, 0x5e, 0x35, 0xfa, 0xbb, 0xe0, 0xc6, 0xdc, + 0xff, 0x9f, 0x75, 0xb0, 0x27, 0xe8, 0xdd, 0x7d, + 0x1e, 0xcb, 0x61, 0x1b, 0x30, 0xe2, 0x50, 0x6a, + 0xa6, 0x0f, 0xca, 0x64, 0x74, 0x03, 0xdc, 0xe5, + 0x36, 0xdf, 0xed, 0x31, 0xa0, 0x89, 0x30, 0xb9, + 0x57, 0x3f, 0x7a, 0x2e, 0x3a, 0x3f, 0xee, 0x01, + 0x61, 0x32, 0x8a, 0xd4, 0x22, 0x01, 0x43, 0x49, + 0x60, 0x7a, 0xe2, 0x0f, 0x1c, 0x9f, 0x99, 0x88, + 0xe5, 0x84, 0x2a, 0x56, 0x56, 0x6f, 0xf7, 0x39, + 0xa7, 0xae, 0xef, 0x04, 0x4b, 0x3d, 0x9a, 0xab, + 0x2a, 0xd7, 0xd6, 0xe5, 0xc8, 0xd6, 0xe9, 0x8a, + 0x42, 0x06, 0x21, 0xb8, 0x50, 0x17, 0xf4, 0x44, + 0x09, 0x54, 0x99, 0xdd, 0x90, 0x0a, 0x50, 0x4f, + 0x5e, 0x87, 0x2e, 0xda, 0xb7, 0x18, 0xfa, 0xd4, + 0x98, 0x8e, 0x26, 0x51, 0x82, 0xfc, 0xf3, 0x88, + 0x77, 0xa0, 0xbd, 0x80, 0xc4, 0xa3, 0x07, 0x70, + 0x80, 0x91, 0xd8, 0x20, 0xf0, 0x6b, 0x01, 0xb9, + 0x89, 0xc1, 0x51, 0xcd, 0x20, 0x47, 0xd4, 0xad, + 0xd7, 0x96, 0x64, 0xe7, 0xb1, 0xbf, 0xff, 0x54, + 0xca, 0x2f, 0x04, 0x47, 0xce, 0xf8, 0x7b, 0x74, + 0x25, 0x0b, 0x15, 0xde, 0x75, 0x00, 0x61, 0xff, + 0xe4, 0x7b, 0x22, 0xf6, 0x4f, 0x45, 0x79, 0xe6, + 0xd5, 0x9e, 0xba, 0x2a, 0x6f, 0xc5, 0x21, 0x85, + 0xe8, 0x35, 0x73, 0x72, 0x1d, 0x8a, 0xcc, 0xb2, + 0x14, 0xeb, 0x7e, 0xcc, 0x4b, 0x43, 0x46, 0xb5, + 0x53, 0x51, 0x14, 0xf5, 0xb5, 0xd9, 0x76, 0x96, + 0x99, 0x8f, 0xbd, 0x6a, 0xdf, 0x36, 0x07, 0xb2, + 0xb2, 0x7b, 0xae, 0x5a, 0xf9, 0x78, 0xa7, 0x27, + 0x9a, 0x6f, 0xd5, 0xa7, 0xc4, 0x97, 0x82, 0xf2, + 0xbb, 0x4c, 0x9c, 0xe1, 0x11, 0x2c, 0x45, 0x9d, + 0x8b, 0x7f, 0x86, 0x12, 0x74, 0xc1, 0xe6, 0xe9, + 0x34, 0xba, 0x19, 0x59, 0x07, 0x18, 0xc2, 0xb3, + 0x45, 0x19, 0xe8, 0x9b, 0x97, 0xcd, 0x8a, 0xdf, + 0xb4, 0x4b, 0x8d, 0x30, 0x7b, 0xed, 0x81, 0x3f, + 0x73, 0x54, 0xc3, 0x17, 0x5c, 0xef, 0xcd, 0xf6, + 0xb6, 0xf0, 0x6b, 0xee, 0x67, 0x5e, 0x2f, 0xb8, + 0x76, 0x92, 0x20, 0x95, 0x1d, 0x50, 0x4e, 0x27, + 0x4b, 0x7f, 0xa7, 0xa6, 0x10, 0xd5, 0x28, 0x2e, + 0xd0, 0x69, 0xf7, 0x07, 0x35, 0x48, 0x7c, 0xdb, + 0xb8, 0x81, 0x91, 0x37, 0x69, 0x20, 0xd0, 0x50, + 0x1d, 0xe7, 0xa5, 0x07, 0x55, 0xd6, 0xf0, 0x8b, + 0x61, 0x0f, 0xf7, 0x19, 0xff, 0x78, 0x16, 0x70, + 0xbe, 0xae, 0xe6, 0x01, 0x56, 0x2a, 0x36, 0x47, + 0x9f, 0xd5, 0xcd, 0x96, 0x44, 0x78, 0xf6, 0x03, + 0xd4, 0x16, 0x6c, 0xc0, 0xbd, 0x30, 0xa6, 0x7a, + 0xf2, 0x35, 0x83, 0x2a, 0x74, 0x49, 0x15, 0x91, + 0xaf, 0x6c, 0x8d, 0x3a, 0xd4, 0x03, 0x68, 0xe5, + 0x0e, 0xcd, 0xfd, 0x81, 0x98, 0xb9, 0x94, 0x7f, + 0xea, 0x5f, 0xa2, 0x3d, 0x11, 0x15, 0x58, 0x97, + 0xc7, 0xa6, 0xdd, 0x90, 0x66, 0xbb, 0x3e, 0xca, + 0x33, 0x8b, 0xbf, 0x0b, 0x4c, 0x82, 0x58, 0x41, + 0xe1, 0xa3, 0x71, 0xfe, 0x92, 0x97, 0x81, 0x09, + 0xe9, 0xd1, 0x06, 0xb6, 0xea, 0x2a, 0xae, 0x31, + 0xd1, 0xe2, 0xba, 0x24, 0xaa, 0x47, 0x18, 0x63, + 0x5a, 0xcb, 0xc0, 0x86, 0xd2, 0xb3, 0x6d, 0x20, + 0x32, 0x1f, 0x84, 0xaf, 0xa2, 0x16, 0x67, 0xa4, + 0xe6, 0xf9, 0xac, 0x9a, 0x7f, 0xdc, 0x17, 0x88, + 0x12, 0xc5, 0xa0, 0x24, 0x0a, 0xca, 0x23, 0x95, + 0x03, 0xe9, 0x6e, 0x84, 0xb8, 0x12, 0x9f, 0x4e, + 0xd5, 0x60, 0x07, 0x3b, 0xcd, 0xa2, 0x28, 0x38, + 0x7f, 0x27, 0x87, 0xce, 0x01, 0x1f, 0x78, 0x66, + 0x62, 0x40, 0x97, 0x10, 0x19, 0x47, 0x5b, 0xbd, + 0x69, 0x63, 0x2b, 0x96, 0xd8, 0xa4, 0x25, 0xb1, + 0x16, 0xf8, 0xcb, 0xde, 0xee, 0xfd, 0xbf, 0x7b, + 0x0d, 0x16, 0x85, 0xb7, 0xa5, 0xe5, 0xe5, 0x4b, + 0x62, 0xc1, 0x60, 0x0f, 0x67, 0xdc, 0x42, 0x73, + 0x1d, 0x3f, 0xfb, 0x31, 0x42, 0xf5, 0x1a, 0xfb, + 0x47, 0x6b, 0x13, 0x48, 0xc8, 0x60, 0x9e, 0xf6, + 0x89, 0x7b, 0xcf, 0x34, 0x22, 0x35, 0x81, 0x7c, + 0x90, 0x0d, 0xb4, 0x47, 0x53, 0x40, 0x1d, 0x77, + 0x6f, 0xc6, 0xdf, 0x5b, 0xa3, 0xfd, 0xd8, 0x37, + 0x3e, 0xa2, 0xe4, 0x1a, 0x5c, 0x09, 0xee, 0x4b, + 0x99, 0x6b, 0x95, 0x5f, 0x4f, 0x3b, 0x4f, 0x8d, + 0xf7, 0x83, 0x2a, 0x0a, 0x15, 0x8f, 0xa8, 0xd0, + 0xf9, 0x11, 0x65, 0x24, 0xd5, 0xa8, 0x97, 0x55, + 0xd0, 0x63, 0x7c, 0x27, 0x26, 0xa5, 0x74, 0x12, + 0xa6, 0xe6, 0x00, 0xca, 0xb3, 0x00, 0xb9, 0xbe, + 0x2d, 0x58, 0xf9, 0x37, 0x6a, 0x04, 0x5c, 0x82, + 0xb5, 0x90, 0x86, 0xfc, 0x5d, 0xee, 0x24, 0xf8, + 0xd9, 0x75, 0x87, 0xf7, 0x39, 0xca, 0x0b, 0x26, + 0xf2, 0xae, 0x31, 0x57, 0x2d, 0x29, 0x53, 0x88, + 0xce, 0xdc, 0x4c, 0x3e, 0x6e, 0x23, 0x12, 0x89, + 0x0f, 0x8b, 0xcf, 0xd8, 0xd2, 0xf5, 0x1d, 0x50, + 0xd3, 0x0b, 0x50, 0x1d, 0xc1, 0xa5, 0xa1, 0x5a, + 0x78, 0x78, 0x86, 0xbb, 0xb9, 0xf1, 0xc6, 0x1c, + 0xec, 0xea, 0xa4, 0x5a, 0xf7, 0xd8, 0x9d, 0x87, + 0x35, 0x51, 0x78, 0xe7, 0x8c, 0x1c, 0x15, 0x29, + 0x54, 0xc1, 0x8f, 0x44, 0xb7, 0x5c, 0x9e, 0xe6, + 0xfd, 0xfe, 0x17, 0xc9, 0x43, 0x5a, 0xec, 0xa3, + 0x8a, 0xbd, 0xe9, 0xf5, 0xf7, 0x3d, 0xac, 0x5d, + 0x17, 0xe3, 0x2d, 0xa9, 0xb5, 0xdf, 0xc3, 0xa5, + 0x34, 0x2e, 0x49, 0xe1, 0x50, 0x90, 0xd7, 0x35, + 0x7a, 0xc6, 0x73, 0xd4, 0x4c, 0xa9, 0x4c, 0xec, + 0x16, 0x06, 0x0a, 0x39, 0xcb, 0x54, 0x97, 0x91, + 0x80, 0x5d, 0x96, 0x45, 0x29, 0x45, 0x30, 0x86, + 0xbb, 0x53, 0x2e, 0x30, 0xe1, 0x5e, 0xcb, 0x1a, + 0x03, 0x84, 0xd4, 0xd9, 0x6d, 0x14, 0xc5, 0x34, + 0x5a, 0xf7, 0xca, 0x33, 0xfe, 0x55, 0x4d, 0x9e, + 0xf0, 0x03, 0xb7, 0x47, 0xc6, 0x4f, 0x1e, 0xa0, + 0x53, 0x19, 0x8e, 0x4b, 0x8a, 0x11, 0x60, 0x50, + 0x70, 0xc5, 0xee, 0x09, 0xe1, 0xc1, 0x37, 0xf9, + 0x1b, 0xbf, 0xfc, 0x21, 0x0a, 0x4c, 0xa8, 0x6e, + 0x19, 0xba, 0x9e, 0x10, 0x09, 0x81, 0x6d, 0x00, + 0xcb, 0x24, 0x7c, 0xa4, 0xd3, 0x14, 0xb5, 0xf8, + 0x9c, 0x78, 0x2c, 0x97, 0x44, 0xd5, 0x82, 0xf1, + 0x25, 0x73, 0xa0, 0x12, 0x7a, 0x65, 0xc9, 0x08, + 0xdc, 0xda, 0x1a, 0x88, 0x5a, 0xc5, 0x5b, 0x5d, + 0x3a, 0xaf, 0x5d, 0xea, 0xe6, 0xe4, 0xfe, 0x05, + 0x06, 0x15, 0xad, 0x17, 0xfd, 0xec, 0x06, 0x0f, + 0xdb, 0xbb, 0x0e, 0x37, 0xf9, 0xc7, 0x69, 0xd0, + 0x27, 0x03, 0x65, 0xb9, 0x96, 0xe7, 0x0b, 0x04, + 0x5e, 0xdf, 0x93, 0x93, 0xa6, 0x10, 0x1e, 0x1a, + 0x90, 0x33, 0x48, 0x39, 0x0b, 0xe8, 0xd9, 0x22, + 0xbf, 0x9d, 0xf8, 0x7d, 0x1e, 0xd0, 0x79, 0xca, + 0xed, 0xa8, 0x9c, 0xc6, 0xf5, 0xa6, 0xcf, 0xa5, + 0x34, 0x76, 0x76, 0x8b, 0x9c, 0x3a, 0xa7, 0x04, + 0xc7, 0xfe, 0xb7, 0x24, 0x7c, 0x74, 0x53, 0x08, + 0xf2, 0x48, 0x6a, 0x52, 0x47, 0x8c, 0xc6, 0x86, + 0xc1, 0xae, 0x2c, 0xa0, 0xcd, 0xba, 0x4d, 0x0d, + 0x28, 0x38, 0x35, 0x83, 0xd7, 0xe1, 0x85, 0x98, + 0x2e, 0xad, 0xc3, 0x98, 0xe5, 0xb2, 0x11, 0x7b, + 0x8c, 0x87, 0xeb, 0x58, 0x1f, 0xa0, 0x95, 0x1e, + 0x62, 0x8c, 0x3b, 0xd8, 0xca, 0x23, 0x70, 0x11, + 0x9f, 0xc2, 0xa7, 0x8c, 0x7d, 0xe6, 0xe3, 0x6d, + 0x8e, 0x90, 0x8a, 0xf7, 0xab, 0x81, 0xd0, 0x09, + 0xaa, 0x49, 0x4d, 0xb7, 0xbd, 0xde, 0x29, 0x64, + 0x8e, 0x65, 0x76, 0xdb, 0x04, 0x14, 0x60, 0x99, + 0x41, 0xd8, 0x03, 0xf5, 0x43, 0x1a, 0x66, 0x55, + 0x65, 0x6b, 0x27, 0x6c, 0xe4, 0x33, 0xd5, 0x20, + 0xd2, 0xc9, 0x5d, 0x89, 0xdf, 0x44, 0xfa, 0xa6, + 0x72, 0x9e, 0x26, 0xbc, 0x78, 0x09, 0xc4, 0x22, + 0x4d, 0x9d, 0x1d, 0x48, 0xfd, 0xa2, 0xec, 0x60, + 0xef, 0xdf, 0x85, 0x5b, 0x3d, 0x04, 0x1e, 0x5d, + 0x01, 0x64, 0x76, 0x7e, 0x25, 0xda, 0x44, 0xff, + 0xf4, 0xd2, 0x8b, 0x3e, 0x7c, 0x0e, 0x87, 0x1a, + 0x04, 0xe3, 0xa1, 0xbc, 0xd3, 0x7f, 0xc2, 0x67, + 0x50, 0x29, 0x57, 0xc7, 0x57, 0xff, 0x7e, 0x94, + 0x21, 0xde, 0x66, 0xa0, 0x16, 0x55, 0xe6, 0xf9, + 0x36, 0xd9, 0xae, 0xb2, 0xc5, 0xd5, 0xf5, 0xb8, + 0x8b, 0x75, 0xbf, 0xef, 0xe6, 0xda, 0xfa, 0x40, + 0x8d, 0x21, 0xd8, 0x66, 0x6d, 0x07, 0x83, 0xf9, + 0x13, 0xa1, 0xb0, 0xb3, 0x48, 0x55, 0x35, 0x20, + 0x19, 0xb7, 0xec, 0x2a, 0x8f, 0x0c, 0xcc, 0xc7, + 0xd6, 0xfa, 0xd0, 0x5c, 0xfe, 0xaa, 0xc8, 0xa5, + 0xd2, 0xd1, 0x05, 0xa6, 0x91, 0x97, 0xc5, 0xd1, + 0x84, 0x70, 0x41, 0xd7, 0x4b, 0x55, 0x23, 0xf0, + 0x92, 0x30, 0x97, 0x2d, 0xa5, 0x72, 0x18, 0x46, + 0xf8, 0x15, 0x3e, 0xe7, 0xd7, 0x19, 0x8f, 0x17, + 0x06, 0xa2, 0x97, 0xe8, 0x39, 0xe0, 0x4d, 0x72, + 0x3a, 0x68, 0x73, 0xa4, 0x0b, 0x88, 0x86, 0x34, + 0x1d, 0xb6, 0x84, 0x99, 0x97, 0xd5, 0xb2, 0x3b, + 0x16, 0x32, 0x60, 0x3c, 0x7d, 0x61, 0x0b, 0x77, + 0xea, 0xe5, 0xa4, 0x11, 0x8b, 0xf3, 0xf4, 0x0d, + 0xc2, 0x70, 0xe9, 0x31, 0x30, 0xc2, 0x35, 0x57, + 0xfb, 0x6a, 0xae, 0x0a, 0xeb, 0x85, 0x3f, 0xb9, + 0x2c, 0x58, 0x42, 0x4d, 0x64, 0x36, 0x8a, 0x59, + 0x09, 0x60, 0xb9, 0x07, 0xfb, 0xb1, 0x76, 0xf8, + 0x1c, 0xd3, 0xf7, 0x48, 0x4c, 0xaf, 0x53, 0xe2, + 0x1a, 0x41, 0x5a, 0xbc, 0xe0, 0x7c, 0x51, 0x11, + 0x5d, 0x01, 0xc1, 0x19, 0xc8, 0xb8, 0xf8, 0xe8, + 0x79, 0x87, 0x32, 0x76, 0x6d, 0xb0, 0xa9, 0x10, + 0x7d, 0x83, 0xb6, 0xde, 0xea, 0x6d, 0x87, 0x50, + 0xa8, 0xe0, 0xd7, 0x99, 0x98, 0x46, 0x4d, 0x8e, + 0xb6, 0x43, 0x12, 0x06, 0xe0, 0xf1, 0x0a, 0x9c, + 0x6b, 0xe9, 0x17, 0x28, 0xe2, 0xa7, 0x53, 0x49, + 0xef, 0x3c, 0x68, 0x90, 0x33, 0x34, 0xb5, 0x1f, + 0x2b, 0x65, 0xea, 0x77, 0xa9, 0x61, 0xdf, 0x01, + 0xb8, 0x0c, 0xd4, 0x24, 0x46, 0xf8, 0xdd, 0x9f, + 0xe6, 0x96, 0x08, 0x90, 0x05, 0x12, 0x59, 0x07, + 0x60, 0x74, 0x2a, 0xfe, 0x1b, 0xac, 0x46, 0x86, + 0xa8, 0x83, 0x40, 0xb5, 0xa1, 0xc1, 0x28, 0xad, + 0x44, 0xba, 0x0a, 0xa7, 0x00, 0x0d, 0xed, 0x98, + 0x01, 0x1b, 0x51, 0x93, 0xa8, 0x35, 0xf4, 0x50, + 0x45, 0xfe, 0xfe, 0xad, 0x1f, 0x94, 0x73, 0xbc, + 0xca, 0x00, 0x2e, 0x6c, 0xc9, 0x59, 0x45, 0x9b, + 0x13, 0x9a, 0x4c, 0x61, 0xa5, 0xae, 0x47, 0x7c, + 0xdc, 0x05, 0xde, 0xbe, 0xf8, 0xe1, 0x3a, 0x08, + 0x75, 0x1c, 0x70, 0x9e, 0xf6, 0xec, 0x9d, 0x4c, + 0x19, 0xcb, 0x1c, 0x0a, 0x69, 0xbd, 0x14, 0x09, + 0xa3, 0x81, 0x08, 0x34, 0x54, 0x5b, 0x29, 0x13, + 0xa7, 0xc5, 0x20, 0x71, 0x31, 0xc4, 0x41, 0x40, + 0xe3, 0xff, 0x72, 0x88, 0x9d, 0x05, 0x2c, 0x4d, + 0xcb, 0xc9, 0x4b, 0xeb, 0xd6, 0xe4, 0xe0, 0x61, + 0x92, 0x3f, 0xb0, 0xe7, 0x04, 0x04, 0xa1, 0x06, + 0x83, 0xd9, 0x94, 0x8f, 0x28, 0x8d, 0xb1, 0xcc, + 0x89, 0x42, 0xd9, 0x23, 0x5b, 0x5c, 0xf1, 0x2c, + 0x9d, 0x40, 0xf0, 0xa7, 0xad, 0x99, 0x5f, 0x19, + 0xc7, 0x29, 0x6d, 0x2c, 0x23, 0x45, 0x7e, 0x46, + 0x26, 0x97, 0xb0, 0x11, 0xd7, 0x3f, 0xd2, 0xb2, + 0x02, 0x4f, 0x41, 0xc4, 0x7d, 0xbd, 0x6f, 0x51, + 0xe7, 0xdd, 0x0b, 0x41, 0x56, 0x51, 0xf0, 0x17, + 0xe3, 0x89, 0x4d, 0xed, 0xc7, 0xd4, 0x82, 0x46, + 0xbb, 0x53, 0xcf, 0x1f, 0xbf, 0x10, 0x47, 0x75, + 0x0b, 0x4f, 0xc6, 0xb8, 0xc6, 0xb4, 0x30, 0x6b, + 0x20, 0x28, 0x31, 0xa9, 0x60, 0xaf, 0x61, 0xe2, + 0xa1, 0x0d, 0x3b, 0x46, 0xda, 0xef, 0xcf, 0x41, + 0x9f, 0xe8, 0xac, 0xf3, 0x09, 0xf9, 0x39, 0xe5, + 0xaf, 0x81, 0x3c, 0x51, 0x70, 0x8b, 0x8b, 0xad, + 0x90, 0x5b, 0x29, 0x97, 0x84, 0xa6, 0x4f, 0x7a, + 0xd7, 0x9d, 0x5e, 0x23, 0xb1, 0x27, 0x06, 0x3f, + 0x6e, 0xb4, 0x7b, 0x35, 0xfc, 0xea, 0x3a, 0x6b, + 0x87, 0x54, 0x53, 0xa3, 0xd6, 0xa3, 0x9a, 0x9c, + 0x1b, 0x78, 0x07, 0x82, 0xb8, 0x50, 0x8d, 0x69, + 0x3a, 0x95, 0xe8, 0x50, 0x56, 0x1a, 0xaf, 0x06, + 0xc3, 0xe0, 0xd7, 0x1f, 0xdf, 0x61, 0xc7, 0x25, + 0xa2, 0x30, 0x3a, 0x08, 0xd6, 0xc0, 0x7d, 0x17, + 0xbb, 0x00, 0x4f, 0xf0, 0xc8, 0x96, 0x38, 0x32, + 0xa8, 0xe0, 0x87, 0x85, 0x37, 0x65, 0x3c, 0x7a, + 0xfa, 0xf4, 0xf5, 0x16, 0x17, 0xf4, 0xf1, 0x53, + 0xb4, 0x76, 0x64, 0x97, 0x53, 0xee, 0x26, 0xcc, + 0x32, 0x5c, 0x05, 0x1a, 0x33, 0x02, 0x1b, 0x66, + 0x2a, 0xd9, 0x8f, 0x54, 0xfc, 0xf1, 0xb8, 0x75, + 0x71, 0xb6, 0xce, 0xc4, 0x17, 0x5e, 0xef, 0xab, + 0xb9, 0x5f, 0xb0, 0x56, 0xc8, 0xed, 0x75, 0x2e, + 0xfc, 0x07, 0x80, 0x71, 0xa4, 0x1f, 0xa7, 0x83, + 0x6f, 0x41, 0x1e, 0x89, 0x9c, 0x91, 0x8c, 0x88, + 0xe5, 0x21, 0x0d, 0x72, 0xbe, 0x0e, 0xc3, 0xa9, + 0x5a, 0x02, 0x5d, 0xc3, 0x1f, 0x78, 0xfa, 0xef, + 0x2d, 0xd1, 0x19, 0x60, 0xe4, 0x2b, 0x3c, 0x1a, + 0x37, 0x6c, 0x8e, 0xfe, 0x5f, 0xa6, 0x6b, 0x40, + 0x79, 0x16, 0xa8, 0x60, 0x6f, 0x4f, 0x98, 0x42, + 0xd4, 0x73, 0x2b, 0xc1, 0xd1, 0x47, 0x1d, 0x79, + 0x5f, 0xb1, 0xae, 0xf3, 0xea, 0x67, 0x29, 0xc5, + 0x78, 0xb2, 0xd7, 0xa7, 0x32, 0xde, 0x40, 0x14, + 0x85, 0xd5, 0xbb, 0x2a, 0x39, 0x44, 0x4c, 0xd2, + 0x4c, 0xc1, 0xc5, 0x05, 0xc5, 0xc7, 0x26, 0xee, + 0x67, 0x5c, 0x37, 0x53, 0xc4, 0x99, 0x42, 0x60, + 0xf0, 0x7a, 0x1f, 0x21, 0x63, 0x4b, 0xf3, 0xa4, + 0x70, 0x2f, 0xd5, 0x00, 0x25, 0x65, 0x90, 0x34, + 0xa5, 0x19, 0x62, 0xdc, 0x64, 0x98, 0x46, 0x81, + 0x99, 0xa5, 0xe5, 0x28, 0x4c, 0x74, 0xe6, 0x49, + 0x21, 0x68, 0x07, 0x38, 0xa7, 0xee, 0xc5, 0x2f, + 0x01, 0x11, 0x2a, 0x6c, 0x86, 0x8c, 0x9a, 0x31, + 0x49, 0x6a, 0xd1, 0xd4, 0x01, 0x52, 0x72, 0xbb, + 0x07, 0x12, 0x54, 0x6f, 0xa5, 0xad, 0xbe, 0xf2, + 0x12, 0x7d, 0x83, 0xe5, 0x13, 0xa4, 0xdd, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0x0c, 0x10, 0x18, 0x1c, 0x1f + }; + + /* ML-DSA-87 externalMu: deterministic, tcId 151 + * Source: kh-fork-fips/wolfACVP/v7.0.0-known/ + * ML-DSA-sigGen-request.json. Deterministic mode + * uses rnd = 0^32 per FIPS 204 Section 3.7. */ + static const byte pk_87_mu[] = { + 0x89, 0x39, 0x24, 0xc8, 0xaa, 0x0a, 0xb4, 0xef, + 0x46, 0xc6, 0x5f, 0x73, 0xf9, 0xea, 0x76, 0x52, + 0xa9, 0xd5, 0x3d, 0xe7, 0x96, 0x40, 0x37, 0xd7, + 0x35, 0xd5, 0xf3, 0x13, 0xe3, 0x23, 0xbf, 0x27, + 0x33, 0x46, 0xff, 0xf4, 0xd5, 0x91, 0x39, 0x58, + 0xb9, 0x6b, 0x06, 0x3f, 0x4e, 0x9c, 0xd0, 0x3c, + 0x2d, 0xcd, 0xb1, 0x0a, 0x85, 0xf1, 0x2d, 0x30, + 0xa1, 0x14, 0xcd, 0x08, 0xa2, 0xf0, 0xc7, 0x09, + 0x36, 0x35, 0x93, 0x93, 0xb6, 0x8c, 0xf2, 0xa0, + 0xe0, 0x62, 0xf3, 0xb1, 0xeb, 0x6f, 0x4c, 0x5a, + 0x51, 0x1f, 0x28, 0xaa, 0xc2, 0xe4, 0xf4, 0xf1, + 0x33, 0x1a, 0x28, 0x22, 0xd4, 0x64, 0x71, 0xac, + 0x77, 0x71, 0xd7, 0x0a, 0x87, 0x62, 0xf9, 0xa8, + 0x1b, 0xa1, 0x6e, 0x23, 0x84, 0xf3, 0x61, 0x43, + 0x55, 0xb5, 0x4d, 0xae, 0x7c, 0xee, 0x17, 0xd7, + 0xc9, 0x8c, 0x7c, 0xea, 0x91, 0x9f, 0x9e, 0x23, + 0x0c, 0xb2, 0xf2, 0xa0, 0x08, 0x1c, 0x47, 0x55, + 0xeb, 0xec, 0xc4, 0x01, 0x68, 0xe2, 0xe0, 0x7f, + 0x7a, 0xce, 0x84, 0x0f, 0xf8, 0x97, 0x0a, 0x15, + 0xf0, 0x77, 0xe6, 0x2f, 0x95, 0xc1, 0xf4, 0xb1, + 0x27, 0xa4, 0xb3, 0xe7, 0xe3, 0x05, 0xaf, 0xcd, + 0xf6, 0xed, 0x6e, 0x4a, 0x6c, 0x26, 0x37, 0x43, + 0xd7, 0x98, 0x8b, 0x7f, 0x91, 0x6a, 0xd7, 0x7f, + 0x8e, 0x0d, 0x8f, 0x76, 0x1a, 0x2e, 0x1b, 0x99, + 0x02, 0x62, 0x9d, 0x9e, 0xa2, 0x0f, 0x7f, 0x8b, + 0x50, 0x39, 0xd3, 0x4b, 0xb6, 0x53, 0x89, 0x98, + 0x15, 0x59, 0x54, 0x18, 0x15, 0x0f, 0x21, 0x4f, + 0x10, 0x4d, 0x8b, 0x1e, 0xb9, 0xf2, 0xc4, 0x90, + 0x22, 0x7e, 0xe5, 0x41, 0xaf, 0x1b, 0xc5, 0x12, + 0x0a, 0xe5, 0x00, 0xab, 0xd8, 0x58, 0xf4, 0x85, + 0x12, 0x17, 0x4a, 0xb6, 0x38, 0x47, 0x50, 0x55, + 0x7f, 0x67, 0xbd, 0x25, 0xfa, 0x50, 0x1a, 0x42, + 0x4e, 0x64, 0x40, 0x04, 0x5c, 0x3c, 0xbf, 0x5e, + 0x1c, 0xd3, 0xf4, 0x71, 0x84, 0x9c, 0x5b, 0x64, + 0x42, 0xb3, 0x96, 0x1a, 0xd0, 0xd7, 0xb3, 0x83, + 0xbf, 0x62, 0xec, 0xce, 0xb0, 0xf1, 0x2d, 0xdd, + 0x02, 0xab, 0x8b, 0xd6, 0x72, 0x37, 0x8e, 0xe9, + 0x15, 0xd6, 0x1e, 0x5e, 0x62, 0x61, 0x96, 0x87, + 0x43, 0xac, 0x12, 0x7c, 0x44, 0x8e, 0xc6, 0x1d, + 0x4a, 0xed, 0x7a, 0x6b, 0x33, 0x0e, 0x81, 0x1d, + 0x10, 0x72, 0xa4, 0xb7, 0x8b, 0xa7, 0x70, 0xad, + 0x8c, 0x86, 0xfe, 0x64, 0xec, 0xe1, 0x6b, 0x71, + 0xe3, 0x23, 0x4c, 0x8f, 0xfe, 0x9d, 0x1c, 0x0a, + 0xe8, 0x90, 0xce, 0x5f, 0x28, 0x1b, 0x81, 0x97, + 0xc3, 0xe2, 0x02, 0x72, 0x38, 0x5d, 0x3d, 0xd0, + 0x91, 0x76, 0x21, 0x14, 0xe4, 0x23, 0xd5, 0x12, + 0x16, 0x5f, 0x64, 0xe5, 0x17, 0xe0, 0xb1, 0x86, + 0xe5, 0xff, 0x87, 0xb6, 0x67, 0x60, 0x53, 0xed, + 0x31, 0xd6, 0xfd, 0xdd, 0x39, 0x59, 0x54, 0xa3, + 0x6d, 0xda, 0x43, 0xab, 0x09, 0x08, 0x83, 0xe9, + 0x06, 0xf5, 0x96, 0x83, 0x04, 0x02, 0x09, 0xe6, + 0xf2, 0xd8, 0xa9, 0x7d, 0x85, 0xa8, 0xd8, 0x9c, + 0x0e, 0x55, 0x0c, 0xeb, 0xe6, 0x48, 0xde, 0x9d, + 0x8a, 0xf8, 0x53, 0x7c, 0x00, 0xb7, 0x5e, 0x70, + 0xfc, 0x8f, 0x97, 0x66, 0x05, 0xb4, 0xdb, 0xeb, + 0x9c, 0xdc, 0xda, 0x4c, 0x95, 0xae, 0xd8, 0xcc, + 0xc3, 0xbb, 0x9f, 0x94, 0x17, 0xa7, 0x24, 0x67, + 0xf6, 0xa7, 0xf2, 0xa2, 0x5a, 0x2d, 0x44, 0x80, + 0xef, 0xd7, 0x73, 0xf2, 0x47, 0xc9, 0x69, 0xec, + 0x99, 0xc7, 0x17, 0xde, 0xf0, 0xc4, 0x94, 0xb7, + 0x0b, 0xfb, 0xf8, 0xfc, 0xbd, 0x63, 0x56, 0x72, + 0x26, 0x23, 0x51, 0x4a, 0x5c, 0xa3, 0x4e, 0xfa, + 0x16, 0x8d, 0xaf, 0xcf, 0x93, 0xc5, 0x8c, 0x76, + 0xb8, 0x45, 0xb8, 0xca, 0xea, 0xd9, 0xf9, 0x7f, + 0xbb, 0xa7, 0x15, 0xfa, 0xab, 0xce, 0x89, 0xbb, + 0x71, 0xc3, 0x08, 0xf6, 0x18, 0x53, 0xfa, 0xfb, + 0x77, 0x8c, 0x3e, 0x06, 0x96, 0xf3, 0x92, 0x0c, + 0x1e, 0x45, 0xe1, 0x4d, 0x45, 0x04, 0xa9, 0xa7, + 0x1d, 0x10, 0x4d, 0xec, 0xc1, 0x75, 0xae, 0xb9, + 0x4a, 0x5e, 0x96, 0x1f, 0x39, 0x65, 0xa3, 0x26, + 0xe2, 0x33, 0x7c, 0x44, 0x10, 0xb8, 0x55, 0xec, + 0xa4, 0x64, 0x94, 0x6b, 0xae, 0xf2, 0x56, 0xd3, + 0x84, 0xe5, 0xcd, 0x09, 0x95, 0x84, 0x48, 0xa5, + 0x72, 0x67, 0x60, 0xcb, 0x16, 0x97, 0x14, 0xef, + 0xc0, 0xcb, 0x7d, 0x99, 0x71, 0x69, 0x31, 0x52, + 0xd5, 0xc4, 0x02, 0xb4, 0x46, 0x03, 0x3d, 0x5f, + 0x56, 0xb9, 0x6f, 0xb6, 0xad, 0x22, 0xce, 0xce, + 0x6f, 0x93, 0xe0, 0x66, 0x51, 0x7d, 0xb4, 0x1d, + 0x0a, 0xd3, 0xc2, 0xa8, 0x78, 0xeb, 0xd6, 0x6d, + 0xdc, 0x8c, 0x34, 0x2c, 0x1f, 0x3b, 0x5a, 0xb6, + 0x8b, 0x5a, 0x25, 0xac, 0x44, 0x50, 0x4f, 0x0c, + 0x19, 0x4a, 0x36, 0xfe, 0xba, 0x45, 0x75, 0x13, + 0x1b, 0x26, 0x4c, 0x07, 0xc0, 0xa5, 0x81, 0x0f, + 0x47, 0x0a, 0xac, 0xf0, 0x7c, 0x92, 0x0a, 0xf7, + 0x46, 0xf1, 0x7b, 0xd4, 0xf0, 0xa6, 0x6c, 0x70, + 0x27, 0x4f, 0xb9, 0x11, 0xd8, 0x56, 0x27, 0x66, + 0x3c, 0x1d, 0x21, 0x28, 0x86, 0x2a, 0x0f, 0x70, + 0x1f, 0xee, 0x00, 0x46, 0x7b, 0x17, 0x84, 0x56, + 0x74, 0xca, 0x71, 0x58, 0xfe, 0x92, 0x0d, 0xe4, + 0x26, 0x9e, 0xe0, 0xb4, 0x03, 0xa3, 0xd5, 0x36, + 0x23, 0xa9, 0xd6, 0x1a, 0x35, 0x9f, 0x12, 0x48, + 0x37, 0xbb, 0xa5, 0x63, 0xfc, 0xd9, 0x62, 0x10, + 0x12, 0x9a, 0xe6, 0x75, 0x03, 0x83, 0x45, 0x99, + 0x42, 0x21, 0xf8, 0xe4, 0x4e, 0xde, 0xdd, 0x36, + 0xb3, 0xdf, 0xda, 0x53, 0xc4, 0x1b, 0x85, 0x4c, + 0x6e, 0x52, 0x75, 0xe7, 0x7f, 0xec, 0x77, 0x1b, + 0xa9, 0x47, 0xd2, 0x52, 0x42, 0xb8, 0x74, 0x9f, + 0x68, 0xf0, 0x74, 0x5a, 0x75, 0x05, 0xa7, 0xe0, + 0xd0, 0xde, 0x98, 0x4e, 0x78, 0x06, 0x3b, 0x8b, + 0x0f, 0x9d, 0x55, 0xe2, 0x56, 0xe5, 0x2c, 0x62, + 0x6e, 0x04, 0x5a, 0x0f, 0x07, 0x13, 0x24, 0xbe, + 0xbe, 0x67, 0x70, 0x05, 0x80, 0x72, 0x0f, 0x1e, + 0x11, 0x92, 0x23, 0x11, 0xaf, 0x09, 0xb1, 0x84, + 0xe8, 0x75, 0xab, 0x23, 0x3f, 0xef, 0x40, 0x9e, + 0x9c, 0x44, 0xc2, 0xa5, 0x29, 0xae, 0x3a, 0x03, + 0x45, 0xd9, 0xce, 0x8b, 0x84, 0x5e, 0xac, 0x3b, + 0x44, 0x15, 0xaa, 0xa2, 0x55, 0x3a, 0x69, 0xd6, + 0x65, 0x95, 0xed, 0xee, 0x9e, 0xa0, 0x3a, 0x4c, + 0xa4, 0x56, 0xb8, 0xed, 0xae, 0x13, 0xec, 0x23, + 0x4c, 0x54, 0x92, 0x66, 0xba, 0x8a, 0x69, 0x83, + 0x6c, 0x7f, 0x10, 0x0a, 0x48, 0x91, 0x91, 0x6b, + 0x69, 0x79, 0x14, 0x4c, 0x43, 0xa2, 0xe2, 0x7f, + 0x25, 0x61, 0xa2, 0xe4, 0xf5, 0x89, 0x32, 0xde, + 0xad, 0xbb, 0x06, 0x10, 0x57, 0x64, 0x83, 0x60, + 0x8a, 0x4c, 0xa7, 0x79, 0xc1, 0xcb, 0x89, 0x5f, + 0x9a, 0x0f, 0xba, 0x73, 0x84, 0xdd, 0x3d, 0xe5, + 0x59, 0x7e, 0x19, 0x85, 0xf7, 0xa5, 0xfe, 0x0c, + 0xd9, 0xa2, 0x47, 0x3b, 0x37, 0x48, 0xaf, 0xef, + 0x21, 0x29, 0x48, 0xb5, 0xd9, 0x4b, 0x9f, 0x95, + 0xa9, 0x8d, 0x18, 0xa3, 0xa4, 0x2b, 0x1d, 0xa8, + 0x5e, 0xb4, 0x2c, 0x74, 0x86, 0x32, 0x0d, 0x41, + 0xc5, 0xe6, 0x78, 0x1d, 0xe6, 0x0a, 0xae, 0x00, + 0xa0, 0x6d, 0x1a, 0x5d, 0x9f, 0x66, 0x56, 0x62, + 0xb8, 0xdf, 0x5b, 0x69, 0x1c, 0xb3, 0x00, 0x7b, + 0xaa, 0x85, 0xb8, 0x6d, 0x1c, 0x9d, 0x63, 0x26, + 0x4f, 0x14, 0x7e, 0xb3, 0xfb, 0xb8, 0xcd, 0x72, + 0xe3, 0x83, 0x7b, 0x8e, 0x38, 0x4e, 0xba, 0x51, + 0x99, 0xd1, 0x04, 0xdf, 0xec, 0x8a, 0xa0, 0xf3, + 0x60, 0xe6, 0xcd, 0x19, 0xeb, 0xdd, 0xd4, 0xa2, + 0x6d, 0x3d, 0x34, 0x22, 0xd8, 0x95, 0xe0, 0xdc, + 0xeb, 0x3a, 0x6c, 0xca, 0xdd, 0xa6, 0xd4, 0xf1, + 0xfa, 0x10, 0xa4, 0xe8, 0x12, 0x67, 0xd2, 0xb2, + 0x2a, 0x2d, 0xa5, 0x61, 0x54, 0x4e, 0x0b, 0x83, + 0xcb, 0x2c, 0xc1, 0x5e, 0x6c, 0xd5, 0x0c, 0x4d, + 0x40, 0xa9, 0x30, 0x46, 0x80, 0x15, 0x48, 0x80, + 0x9c, 0xcd, 0x04, 0xc6, 0x05, 0x5e, 0xca, 0xcd, + 0xe5, 0x88, 0x1e, 0x48, 0x65, 0xa8, 0xab, 0x8d, + 0xc5, 0x34, 0x57, 0x24, 0x32, 0x3d, 0x4f, 0xfa, + 0x20, 0xaa, 0x97, 0x8a, 0xad, 0x38, 0x33, 0xaa, + 0x8c, 0x34, 0x1e, 0x4a, 0x34, 0xee, 0xb6, 0xba, + 0x18, 0x8b, 0xe8, 0x4e, 0x58, 0x4b, 0xf4, 0xd2, + 0xf3, 0x84, 0x44, 0x8f, 0xe2, 0x25, 0xe9, 0x31, + 0xeb, 0xbb, 0x6f, 0xf5, 0x6c, 0x89, 0x0b, 0x18, + 0x3e, 0x5e, 0x6c, 0x9f, 0xcc, 0x05, 0x5c, 0xa5, + 0xda, 0x11, 0x7a, 0x11, 0xef, 0x00, 0x4a, 0xbd, + 0xd8, 0xa4, 0x3a, 0xc3, 0xaf, 0x7c, 0x15, 0xe9, + 0x01, 0xea, 0x79, 0x18, 0x5e, 0xd0, 0x99, 0xd2, + 0x6c, 0xaa, 0xaa, 0x22, 0x56, 0xca, 0x67, 0x83, + 0xa9, 0xe9, 0xbd, 0x91, 0x8b, 0x1f, 0xd7, 0x5f, + 0x59, 0x74, 0xc5, 0xff, 0xae, 0xec, 0x0e, 0x94, + 0xf3, 0x4f, 0x02, 0xb0, 0xfe, 0x33, 0xe8, 0xa4, + 0x96, 0xb3, 0x36, 0x93, 0xd4, 0xc1, 0xb9, 0x63, + 0xb5, 0x1b, 0xb7, 0x4a, 0x90, 0xc1, 0x6e, 0x51, + 0x7e, 0x01, 0xe0, 0x63, 0x45, 0x2e, 0x51, 0xc7, + 0xf3, 0x0a, 0xe8, 0x42, 0x8e, 0x73, 0x7f, 0x02, + 0xc8, 0xaa, 0x54, 0x1e, 0x24, 0xbc, 0x4c, 0x29, + 0xee, 0xde, 0x29, 0x76, 0xe9, 0xc2, 0xac, 0x6e, + 0x25, 0xd3, 0x28, 0x67, 0x13, 0x98, 0x18, 0x10, + 0xec, 0xb9, 0xd2, 0x3f, 0x1c, 0x3a, 0x40, 0x0e, + 0x7e, 0xc1, 0x29, 0x34, 0x6c, 0x76, 0x84, 0x9e, + 0x6d, 0x0c, 0xcf, 0x8e, 0x61, 0x1b, 0xc5, 0xcf, + 0x7a, 0xad, 0x54, 0x6b, 0xfc, 0x5b, 0x00, 0xad, + 0x51, 0x68, 0x80, 0xb4, 0x23, 0x71, 0x28, 0x87, + 0x85, 0x40, 0xb0, 0xe1, 0x9e, 0x23, 0x0c, 0x1a, + 0xc7, 0x4d, 0x3b, 0x6b, 0xec, 0x21, 0xa1, 0xd9, + 0x92, 0x00, 0x35, 0x5f, 0x4a, 0x87, 0x74, 0xfb, + 0xe0, 0xf5, 0xb6, 0x22, 0x86, 0xd0, 0x6f, 0xa5, + 0x05, 0x45, 0xe9, 0xae, 0xc5, 0x24, 0xd5, 0x32, + 0xd3, 0x38, 0xc9, 0x26, 0x05, 0xa1, 0x71, 0x38, + 0x5c, 0x4a, 0xc7, 0x6f, 0xd8, 0xf9, 0xc8, 0xf4, + 0x2b, 0xfc, 0x24, 0x9d, 0xaa, 0x04, 0x64, 0xef, + 0x5d, 0xfb, 0x7f, 0xd8, 0x38, 0xf3, 0xed, 0x6e, + 0x71, 0x0b, 0x4b, 0x5f, 0x57, 0xaf, 0xad, 0xf9, + 0x92, 0x51, 0x3b, 0xc3, 0x3c, 0x9b, 0xeb, 0xd5, + 0xd6, 0xbe, 0x85, 0x2a, 0xf9, 0xc2, 0xaf, 0x27, + 0x6c, 0x52, 0x27, 0x5e, 0xe6, 0x39, 0x61, 0x82, + 0xe2, 0x6c, 0xf2, 0xd8, 0x05, 0xee, 0x2f, 0x19, + 0xe1, 0x5a, 0xbd, 0x88, 0x43, 0xc7, 0x1b, 0xd7, + 0x4b, 0xfe, 0xe2, 0xbf, 0x55, 0x1b, 0x9e, 0x07, + 0x3c, 0xfb, 0xb7, 0xf4, 0xbd, 0xe4, 0x9f, 0xf3, + 0x9a, 0xb9, 0x13, 0x88, 0x82, 0xb8, 0x21, 0x4b, + 0xda, 0x91, 0xe3, 0x65, 0xf0, 0x18, 0x27, 0x2e, + 0xd1, 0x65, 0x8b, 0x30, 0xa1, 0x3d, 0xa2, 0x9e, + 0x19, 0x71, 0x41, 0x16, 0xfd, 0x2e, 0xce, 0x55, + 0xf4, 0x33, 0x62, 0x93, 0x08, 0x13, 0x02, 0x87, + 0x62, 0x95, 0xd8, 0x26, 0x01, 0x78, 0xd9, 0x26, + 0xae, 0x65, 0xe2, 0x59, 0xd0, 0x31, 0x13, 0x2f, + 0x9d, 0xa9, 0x45, 0x20, 0x82, 0x74, 0x7d, 0x5f, + 0x7c, 0x1f, 0xd0, 0xf8, 0xe8, 0x31, 0x94, 0xa8, + 0xcc, 0x55, 0x4d, 0xf1, 0x27, 0x92, 0x52, 0xa9, + 0x94, 0x04, 0x46, 0x36, 0xbd, 0xf8, 0xe1, 0x4d, + 0xc7, 0x4a, 0x1d, 0x2d, 0xcf, 0x68, 0x5d, 0x6b, + 0x41, 0x17, 0x4a, 0xba, 0xac, 0x65, 0x11, 0x65, + 0xa9, 0xde, 0xdd, 0x38, 0x99, 0x4e, 0xad, 0xaf, + 0x57, 0xf1, 0x0d, 0x0e, 0xfa, 0xc4, 0x92, 0x9a, + 0x37, 0x44, 0x43, 0xdd, 0x1f, 0x60, 0xd6, 0x1c, + 0x9f, 0x0f, 0x43, 0x66, 0x2d, 0x9a, 0x1e, 0x5c, + 0xc2, 0x02, 0x9f, 0x0a, 0x0a, 0x51, 0x40, 0x16, + 0x10, 0xc6, 0x19, 0x76, 0x60, 0xcc, 0x24, 0xfc, + 0xda, 0xa0, 0xb4, 0xbf, 0x32, 0xa5, 0x71, 0xb3, + 0xf7, 0x70, 0x7e, 0x5f, 0x9f, 0x28, 0xcf, 0xf4, + 0x9a, 0x87, 0x9e, 0x63, 0xd6, 0xe8, 0xa7, 0x27, + 0x2e, 0x03, 0x47, 0x32, 0x56, 0x54, 0x3d, 0x89, + 0x78, 0x7f, 0x38, 0x18, 0x2e, 0x3e, 0x1b, 0x96, + 0x85, 0xae, 0xe0, 0xe1, 0x4d, 0xf5, 0x57, 0x7f, + 0x67, 0xa0, 0x36, 0xd5, 0x19, 0x66, 0xa8, 0xbd, + 0x41, 0x49, 0x8f, 0x44, 0x95, 0xb6, 0xfc, 0x71, + 0x6a, 0x2b, 0x66, 0x91, 0x16, 0x8e, 0x80, 0x12, + 0xd9, 0x17, 0x68, 0xa6, 0xd6, 0xfc, 0x8f, 0x5d, + 0xc8, 0x51, 0x5e, 0xf4, 0xaa, 0xa8, 0xe4, 0xfc, + 0x97, 0xfb, 0x8e, 0xb0, 0xf1, 0xb6, 0xbb, 0x74, + 0x97, 0x6e, 0xae, 0x9e, 0xc7, 0x4b, 0x10, 0xb4, + 0xc8, 0xb6, 0xd6, 0x17, 0xb7, 0x3e, 0x41, 0x4e, + 0xf6, 0x10, 0xae, 0x45, 0x26, 0x44, 0x62, 0xa9, + 0xbb, 0x77, 0x50, 0xc5, 0x86, 0xd3, 0xa8, 0xd3, + 0x3b, 0x7f, 0xf6, 0x74, 0xfe, 0xa4, 0xdf, 0xc5, + 0x71, 0xca, 0xf9, 0x57, 0xb4, 0x08, 0x82, 0x30, + 0x3d, 0xb3, 0x1d, 0x53, 0xef, 0x9f, 0xcd, 0x0f, + 0x56, 0x56, 0xa8, 0xe0, 0x2d, 0xe4, 0x2e, 0xf5, + 0x28, 0x10, 0xfd, 0xac, 0xeb, 0x9c, 0x88, 0x7f, + 0x9d, 0x5d, 0xff, 0xa0, 0x8a, 0x4f, 0x49, 0x6a, + 0x7f, 0x26, 0x6d, 0x79, 0x3b, 0xae, 0x21, 0x34, + 0x99, 0xb4, 0x36, 0xd1, 0xcd, 0xb9, 0x3e, 0x4b, + 0x89, 0xd9, 0x32, 0x39, 0x61, 0xe5, 0x22, 0x1e, + 0x27, 0x47, 0xf1, 0x0d, 0x17, 0x25, 0xf3, 0x38, + 0x8b, 0x8d, 0xf9, 0x5f, 0x62, 0x7f, 0xd9, 0xd0, + 0x86, 0xbe, 0x7f, 0xf1, 0x71, 0xd3, 0x3e, 0x6b, + 0x4c, 0x1f, 0xdc, 0x07, 0xef, 0xd8, 0x80, 0x21, + 0x18, 0x0e, 0xb6, 0x95, 0xde, 0x72, 0xb2, 0xf2, + 0xa0, 0xe2, 0x5b, 0x8c, 0xd5, 0x8b, 0x91, 0x17, + 0xa5, 0x32, 0xca, 0xc2, 0x66, 0x73, 0x11, 0x0e, + 0x30, 0x7a, 0x23, 0x4b, 0xd2, 0xc7, 0xae, 0xcb, + 0xf7, 0xb0, 0x72, 0x34, 0xae, 0x41, 0x36, 0xb6, + 0x0e, 0x3a, 0x23, 0xf0, 0x06, 0xb9, 0x79, 0x3a, + 0x93, 0xa2, 0x8c, 0x00, 0x75, 0x22, 0x15, 0x00, + 0x63, 0x27, 0x33, 0xcf, 0xd3, 0xba, 0x22, 0xd4, + 0xeb, 0x42, 0x20, 0xb6, 0x7a, 0xe9, 0x74, 0x56, + 0x1a, 0xe9, 0x56, 0x18, 0x4f, 0xa4, 0x0f, 0xbe, + 0x3c, 0x1f, 0x8c, 0x00, 0x19, 0x28, 0xd3, 0xf3, + 0xba, 0x13, 0x9e, 0xaa, 0xbe, 0x98, 0xad, 0x49, + 0xa7, 0x5d, 0xc8, 0x2c, 0x5d, 0xa3, 0x58, 0x11, + 0x25, 0xd3, 0x97, 0x51, 0xa0, 0x89, 0xb8, 0xf1, + 0xb0, 0x65, 0x15, 0xf6, 0x4c, 0x70, 0xae, 0xb4, + 0xf2, 0x21, 0xa4, 0xfc, 0xf8, 0x53, 0xca, 0x57, + 0x89, 0x32, 0x13, 0xd6, 0xdf, 0x9b, 0x3c, 0xe6, + 0x03, 0x56, 0xd0, 0x63, 0x99, 0x22, 0x0f, 0xf3, + 0x61, 0xed, 0x7d, 0x73, 0x83, 0xdb, 0x5c, 0x3f, + 0x78, 0xf8, 0x56, 0xcf, 0x1b, 0x2f, 0xa8, 0x3c, + 0x40, 0x63, 0x04, 0xa6, 0x4f, 0xa2, 0x5b, 0xbd, + 0x2c, 0xe1, 0xf4, 0xe9, 0xd7, 0x88, 0xae, 0x8b, + 0x2f, 0x91, 0x06, 0x32, 0x06, 0x16, 0x06, 0x4e, + 0x0b, 0x44, 0x8b, 0x2a, 0x84, 0x0a, 0x61, 0x3d, + 0x4d, 0xe2, 0x6c, 0x5f, 0x62, 0x7f, 0x36, 0x59, + 0x6f, 0x99, 0xc6, 0x06, 0xf5, 0x38, 0x33, 0xa4, + 0x82, 0x4b, 0x76, 0xd7, 0x65, 0x74, 0x57, 0x4a, + 0x14, 0xda, 0xc2, 0x78, 0xe8, 0xeb, 0x74, 0x0f, + 0x3f, 0x6e, 0x1a, 0xc0, 0xbe, 0xd1, 0x4b, 0x1f, + 0x9c, 0x97, 0xcb, 0x0d, 0x79, 0xd0, 0x7e, 0x53, + 0xbd, 0xa1, 0x23, 0xd1, 0x02, 0xf9, 0xd2, 0xed, + 0x16, 0xee, 0x60, 0xb8, 0x2e, 0x24, 0x0f, 0x36, + 0x93, 0x42, 0x2b, 0x85, 0x06, 0xeb, 0xab, 0x8c, + 0x63, 0xc1, 0x13, 0xe5, 0xe5, 0x2b, 0x08, 0x8a, + 0x61, 0x71, 0x37, 0x96, 0xcc, 0x18, 0xa5, 0x54, + 0xe3, 0x83, 0xed, 0xc0, 0x69, 0x2b, 0xba, 0xf3, + 0x8c, 0xb6, 0x8f, 0x69, 0x5a, 0x70, 0xf7, 0x21, + 0xa5, 0x28, 0x9a, 0x64, 0xc9, 0x61, 0x2b, 0x43, + 0xb6, 0x9c, 0xf9, 0xaf, 0xdb, 0x79, 0x0f, 0x3c, + 0x25, 0x1b, 0xae, 0x32, 0x6b, 0xbe, 0x97, 0xa5, + 0x25, 0x9e, 0x28, 0xe6, 0x27, 0xeb, 0x21, 0xf7, + 0xc1, 0xb0, 0xce, 0x37, 0xf0, 0xde, 0xce, 0x7b, + 0xc0, 0x0a, 0x86, 0xd3, 0x9d, 0xa5, 0x19, 0xb7, + 0xe6, 0xe9, 0x49, 0xe8, 0xbf, 0x56, 0x73, 0x03, + 0x49, 0xd6, 0xea, 0xcc, 0x65, 0x17, 0xb5, 0xed, + 0x5c, 0xc1, 0x79, 0xb8, 0xa3, 0x67, 0xc8, 0x4e, + 0x33, 0xf2, 0x58, 0xe2, 0x4d, 0x11, 0x5d, 0xe3, + 0x4c, 0x51, 0x02, 0xed, 0xce, 0x55, 0x1c, 0x62, + 0x44, 0x1b, 0x15, 0xee, 0x34, 0x5f, 0x7a, 0x57, + 0x5e, 0x6c, 0x1d, 0x17, 0xf3, 0xf9, 0x59, 0xb6, + 0x68, 0x32, 0x53, 0x99, 0x44, 0xc8, 0x10, 0xc7, + 0x4c, 0x68, 0x33, 0x5b, 0x8a, 0xf2, 0xae, 0xa9, + 0x09, 0xa3, 0xb0, 0x39, 0x39, 0x64, 0xec, 0x16, + 0x42, 0x27, 0x2e, 0xcd, 0x71, 0xbf, 0xb4, 0x0a, + 0x58, 0x6d, 0xa7, 0x7d, 0x63, 0x35, 0xec, 0x0f, + 0xb0, 0x1d, 0x47, 0xd7, 0x2b, 0x87, 0x95, 0xaa, + 0xcc, 0xfe, 0x61, 0x67, 0x06, 0x6b, 0x8d, 0x69, + 0x63, 0xc1, 0xd4, 0x33, 0x86, 0x0d, 0x1c, 0x32, + 0x1d, 0x51, 0xff, 0x87, 0x4d, 0xa0, 0x43, 0xe9, + 0x36, 0x6c, 0x92, 0x4c, 0x37, 0xce, 0xd0, 0x6d, + 0xfe, 0x42, 0x9d, 0x42, 0x21, 0xb2, 0xe2, 0x7f, + 0xf9, 0xc1, 0xa3, 0x21, 0xd6, 0x16, 0xb9, 0x97, + 0x01, 0xa0, 0x48, 0xd3, 0xaa, 0xd4, 0x8f, 0x42, + 0x8b, 0xb1, 0x51, 0x8c, 0x1e, 0xfe, 0x7b, 0x38, + 0x1b, 0x8b, 0xb9, 0x9b, 0xde, 0x5b, 0x14, 0x23, + 0x47, 0x37, 0x5e, 0x91, 0xeb, 0xb5, 0x58, 0x34, + 0xd9, 0x56, 0x29, 0x0f, 0xb8, 0xef, 0xca, 0x29, + 0x70, 0x6d, 0xd1, 0x1c, 0x00, 0x7b, 0x57, 0xa0, + 0x88, 0x67, 0x82, 0x3d, 0x35, 0x48, 0x72, 0xd7, + 0xaa, 0x6b, 0x72, 0xbd, 0x80, 0xd6, 0xd8, 0x5e, + 0xe0, 0x02, 0x1f, 0x46, 0x8c, 0x61, 0xd4, 0xde, + 0xb8, 0xdf, 0x7a, 0xa3, 0x4d, 0x7f, 0x6c, 0xf1, + 0xf2, 0x59, 0xf6, 0x15, 0xc5, 0x58, 0xeb, 0xfb, + 0xe4, 0x96, 0x86, 0x3d, 0xed, 0x00, 0x3b, 0x35, + 0x5e, 0x38, 0xef, 0x1f, 0xcb, 0xf7, 0x6e, 0xda, + 0xd6, 0xd2, 0x78, 0xf9, 0xef, 0xe9, 0x3e, 0x74, + 0x12, 0x96, 0xb4, 0x33, 0x01, 0x33, 0xbf, 0x46, + 0xd0, 0x7a, 0xb8, 0xe9, 0x51, 0x01, 0xcd, 0x65, + 0x5c, 0xbb, 0xc6, 0x9d, 0x10, 0x8e, 0xe8, 0xeb, + 0x30, 0x87, 0x94, 0xe6, 0xef, 0x55, 0x76, 0xac, + 0x30, 0x9e, 0x3d, 0xc6, 0x7e, 0x7e, 0xf6, 0x46, + 0x59, 0x39, 0xb0, 0x0f, 0xf0, 0xed, 0xc3, 0xfc, + 0xc7, 0x39, 0x8f, 0x6d, 0xb2, 0x42, 0xcb, 0xf6, + 0xf6, 0xe9, 0x6c, 0xa6, 0x48, 0x15, 0x8b, 0x7a, + 0xab, 0x60, 0x4c, 0x73, 0xec, 0x52, 0x37, 0x19, + 0xcc, 0x20, 0xc0, 0xf7, 0xf2, 0xed, 0x4f, 0xac, + 0x29, 0xe4, 0xbb, 0x67, 0xb7, 0x03, 0x8c, 0x56, + 0xb3, 0x32, 0x4d, 0x75, 0x0e, 0x0e, 0x0f, 0xf1, + 0xfa, 0xea, 0x9c, 0x64, 0xa2, 0x44, 0xc2, 0x30, + 0xef, 0x93, 0x5c, 0x8f, 0x7a, 0xfa, 0x5a, 0x54, + 0xb3, 0x23, 0x1f, 0x76, 0x18, 0x3f, 0x0b, 0xa3, + 0x50, 0x4a, 0xb5, 0x95, 0x48, 0xea, 0x9a, 0x4f, + 0x77, 0x6e, 0x42, 0x28, 0x9d, 0x35, 0x6c, 0x9d, + 0x80, 0x3f, 0xa8, 0x73, 0x6e, 0xfa, 0x7f, 0x0c, + 0xb5, 0xc8, 0xaf, 0x43, 0x72, 0x5f, 0xa7, 0xf6, + 0x9b, 0x0b, 0xd5, 0xf8, 0xcd, 0xd8, 0xcb, 0x3e + }; + static const byte mu_87[] = { + 0x82, 0xf1, 0x07, 0xb0, 0x41, 0x11, 0x5a, 0x60, + 0xfc, 0x9b, 0x36, 0x93, 0x50, 0x8a, 0x6b, 0x9a, + 0xd8, 0xd4, 0x7e, 0x45, 0x1b, 0x29, 0xe7, 0x52, + 0x63, 0xe4, 0x61, 0x11, 0xa3, 0x4c, 0xd0, 0xb2, + 0x7e, 0xe8, 0xef, 0x02, 0xc9, 0x5b, 0xa8, 0x5d, + 0x9e, 0x9b, 0x3e, 0xc0, 0x92, 0x2d, 0x52, 0x4f, + 0xa5, 0x43, 0x16, 0xf8, 0x9f, 0x0f, 0xfd, 0x71, + 0xf3, 0xd0, 0x0c, 0xea, 0x6f, 0xf8, 0xfc, 0x3b + }; + static const byte sig_87_mu[] = { + 0x71, 0x6e, 0x47, 0xd1, 0x09, 0xe2, 0x40, 0xe5, + 0x9c, 0x7b, 0x50, 0x6f, 0x9f, 0xa4, 0x5c, 0x08, + 0x71, 0x86, 0x9e, 0xbf, 0x6c, 0x5d, 0xc8, 0x14, + 0x2d, 0x1e, 0xe1, 0x62, 0x04, 0x11, 0x9e, 0x7c, + 0x9f, 0x28, 0x64, 0x15, 0x79, 0xb5, 0xbf, 0x3d, + 0x6d, 0x79, 0x6a, 0x0a, 0xe7, 0xae, 0x4b, 0x51, + 0x67, 0xb1, 0xda, 0xd8, 0xd2, 0xa9, 0x14, 0x76, + 0x08, 0x85, 0x9c, 0x47, 0xaa, 0xc1, 0xa7, 0x52, + 0x84, 0x33, 0xd5, 0xb0, 0x4d, 0xe3, 0x83, 0x7c, + 0xa6, 0x85, 0xc1, 0x49, 0xcf, 0x1e, 0x1d, 0x17, + 0x19, 0x1a, 0x22, 0x3d, 0x94, 0xdc, 0xa6, 0xa1, + 0x91, 0x77, 0xe9, 0x2b, 0xef, 0x54, 0x07, 0x1d, + 0x99, 0x6a, 0x3d, 0xfc, 0x11, 0x3b, 0x07, 0x20, + 0xbf, 0x64, 0x31, 0xdf, 0x4f, 0x4a, 0xe9, 0xe3, + 0x9a, 0xb1, 0xd8, 0xce, 0x27, 0xbe, 0xa7, 0xd3, + 0x72, 0xb4, 0x4e, 0x62, 0x30, 0xb0, 0x7c, 0xab, + 0x00, 0x20, 0x32, 0xff, 0xb6, 0x1e, 0x5e, 0xf9, + 0xad, 0xbc, 0xaa, 0x47, 0x9c, 0xf2, 0x41, 0xb6, + 0xa7, 0x68, 0xf7, 0x1c, 0x0f, 0x3d, 0x83, 0xa4, + 0x72, 0xa7, 0xf1, 0x69, 0xd2, 0xd8, 0x99, 0xff, + 0x54, 0x04, 0xed, 0x71, 0x0f, 0x03, 0xf2, 0xbe, + 0xa6, 0xf8, 0x2f, 0xb5, 0x54, 0x80, 0x1e, 0xb6, + 0x09, 0x9d, 0x5a, 0x5d, 0x2f, 0x1e, 0xdb, 0xfd, + 0x0a, 0x73, 0x1b, 0xf6, 0x0b, 0x7a, 0x0b, 0xa5, + 0x4f, 0x46, 0x8c, 0x96, 0x9b, 0x50, 0x39, 0x22, + 0x6c, 0x21, 0xab, 0x72, 0xcc, 0x7a, 0xd1, 0x87, + 0xf1, 0x61, 0x2f, 0x92, 0x19, 0x16, 0xb9, 0x99, + 0xd2, 0xf6, 0xce, 0x11, 0x0f, 0x4a, 0x5e, 0xbb, + 0xd5, 0x7a, 0xc2, 0x73, 0xeb, 0xbf, 0x65, 0x6b, + 0x5f, 0x8b, 0xc1, 0xa2, 0xb2, 0x05, 0xd2, 0xc3, + 0x1d, 0x3f, 0x8f, 0x43, 0x9e, 0x06, 0xa2, 0x18, + 0x39, 0x54, 0xa7, 0x52, 0x86, 0x1f, 0x48, 0x78, + 0xf4, 0x55, 0x15, 0x19, 0xff, 0x32, 0xeb, 0x27, + 0x2f, 0x39, 0xb8, 0xc7, 0x9d, 0x00, 0xe3, 0xfb, + 0x3e, 0xd0, 0x64, 0xba, 0x10, 0x0b, 0xac, 0xd9, + 0x18, 0x2f, 0x42, 0x8c, 0x30, 0xbe, 0xf6, 0xa3, + 0xea, 0xc0, 0xff, 0xf5, 0x5b, 0xaa, 0x35, 0x73, + 0x91, 0x3f, 0x51, 0x28, 0x58, 0x11, 0x33, 0x27, + 0xfd, 0x08, 0x2f, 0x1c, 0xa9, 0x8a, 0x37, 0xae, + 0xf9, 0x70, 0x89, 0xad, 0x15, 0x31, 0x5f, 0x43, + 0xeb, 0x29, 0x46, 0x9b, 0xc9, 0x9f, 0x58, 0x3e, + 0x22, 0xfb, 0x2c, 0x60, 0x17, 0x59, 0x2c, 0xc8, + 0xcf, 0xf7, 0xe9, 0xd9, 0x17, 0xc7, 0x40, 0x7c, + 0xcf, 0x56, 0x9d, 0x2b, 0xd5, 0xc3, 0xd4, 0x7f, + 0xb1, 0xeb, 0xee, 0x2b, 0xcb, 0x5c, 0x59, 0xaa, + 0x87, 0xd3, 0xa8, 0x5a, 0xac, 0x12, 0xc7, 0xfd, + 0x10, 0x47, 0x76, 0x9e, 0x98, 0x29, 0x81, 0xef, + 0xc1, 0x3c, 0x07, 0x60, 0xd7, 0xd6, 0xb0, 0x78, + 0xb3, 0xc6, 0x09, 0x03, 0x20, 0xe8, 0xab, 0x1d, + 0x83, 0x1d, 0x25, 0xd0, 0x25, 0x1d, 0x1c, 0x5d, + 0x12, 0xcb, 0xd5, 0x96, 0xde, 0xf6, 0xdb, 0xeb, + 0xb1, 0x7a, 0x8c, 0x08, 0xab, 0x93, 0x1a, 0x7d, + 0xad, 0xa1, 0x68, 0xf9, 0xe9, 0x96, 0xaa, 0x15, + 0x60, 0x3c, 0x7e, 0x15, 0x83, 0xab, 0x70, 0x8d, + 0x45, 0x4e, 0xab, 0x64, 0xae, 0x4e, 0x83, 0x8d, + 0x19, 0xe2, 0xf5, 0xfa, 0x96, 0x3a, 0x05, 0x34, + 0x2d, 0x19, 0x2a, 0x3d, 0x88, 0x82, 0x7b, 0xba, + 0x9d, 0x67, 0x5d, 0xfa, 0xdc, 0x14, 0x96, 0x2c, + 0x0a, 0x87, 0x96, 0xf5, 0x29, 0x7f, 0x32, 0x22, + 0xf7, 0x23, 0x3a, 0x89, 0x7b, 0x3c, 0x6f, 0xf9, + 0x01, 0x91, 0x35, 0xd5, 0xee, 0x2e, 0x97, 0xdb, + 0xbe, 0x93, 0x47, 0xac, 0x58, 0x72, 0xd3, 0xe9, + 0xae, 0x72, 0x9f, 0xca, 0xf5, 0x8d, 0xf0, 0x64, + 0xa3, 0xea, 0xa6, 0xd6, 0xa2, 0x7f, 0xab, 0xf1, + 0x8f, 0x01, 0x67, 0xea, 0xac, 0xab, 0x27, 0x6d, + 0x29, 0xc9, 0x05, 0xdd, 0x17, 0x3e, 0x0b, 0x28, + 0xa8, 0x19, 0x89, 0xb9, 0x0f, 0x7e, 0x17, 0x8c, + 0x86, 0xd0, 0x7a, 0xd8, 0xfc, 0xb8, 0x3a, 0xea, + 0xf9, 0x47, 0xd2, 0x2f, 0xa3, 0xb8, 0xde, 0x46, + 0x21, 0x14, 0x44, 0x1a, 0x8f, 0x69, 0x7b, 0x45, + 0xee, 0x9f, 0xd9, 0xf2, 0xc4, 0xae, 0xf5, 0xdf, + 0x5d, 0x93, 0x30, 0x63, 0x8a, 0xfa, 0x37, 0xb0, + 0x95, 0x9c, 0xaa, 0x87, 0x58, 0x5b, 0x19, 0x7b, + 0xfb, 0x2b, 0x66, 0x5c, 0x6f, 0xa9, 0xfb, 0x22, + 0x24, 0x1b, 0x16, 0xc5, 0x9b, 0x6d, 0xc7, 0x54, + 0x26, 0x77, 0xf0, 0xb2, 0xa2, 0xf1, 0x11, 0xee, + 0x8b, 0xd4, 0x2b, 0xd7, 0x3a, 0x59, 0x6c, 0xf7, + 0x7c, 0x68, 0x5b, 0x27, 0xf3, 0x57, 0x14, 0xe8, + 0x73, 0x51, 0xca, 0xc8, 0x1c, 0xc4, 0x2e, 0x21, + 0xe0, 0x27, 0xa0, 0x42, 0xb1, 0x37, 0x57, 0x5b, + 0x6d, 0xb2, 0xd4, 0xfa, 0x34, 0x49, 0x6d, 0x75, + 0x8d, 0xdc, 0xb2, 0x83, 0x67, 0x8f, 0xc6, 0x37, + 0xf5, 0xb0, 0x30, 0xce, 0x37, 0x2d, 0xe7, 0x7e, + 0xa6, 0x3e, 0xa0, 0xa9, 0xaf, 0xec, 0x8e, 0x20, + 0xe8, 0x6e, 0x1d, 0x82, 0x9a, 0x80, 0x7a, 0xfe, + 0x83, 0x56, 0x2c, 0xba, 0xba, 0xcb, 0x4b, 0x17, + 0x7e, 0x9a, 0x1e, 0xd2, 0x9a, 0xeb, 0x87, 0xe6, + 0x26, 0x7a, 0x24, 0xa5, 0x2b, 0x62, 0x85, 0x38, + 0x1e, 0x28, 0x1a, 0x05, 0x17, 0x78, 0xa1, 0xf2, + 0x96, 0x83, 0xb4, 0x38, 0xd8, 0x81, 0x0a, 0x2e, + 0xf8, 0x20, 0xcc, 0xa9, 0xd8, 0x94, 0xa0, 0xee, + 0xad, 0x79, 0x4a, 0x24, 0xde, 0xdf, 0x43, 0x77, + 0x83, 0x23, 0xef, 0x7d, 0x21, 0x75, 0x15, 0xce, + 0xe2, 0xe1, 0xe3, 0x63, 0x8e, 0xcd, 0xc1, 0x45, + 0x87, 0x27, 0x80, 0x3b, 0x75, 0xf2, 0x00, 0x13, + 0x6e, 0xfa, 0xbf, 0x6f, 0xec, 0x9c, 0xa6, 0x68, + 0x6a, 0xc6, 0x1d, 0x3c, 0xf2, 0x41, 0xa5, 0xc5, + 0x69, 0xc1, 0x64, 0xa6, 0x1f, 0x5c, 0x8b, 0xc1, + 0x4c, 0x2e, 0xd1, 0x1f, 0xe7, 0x4d, 0x36, 0x6c, + 0xad, 0xc2, 0xc4, 0x39, 0x25, 0x11, 0xb4, 0x89, + 0x0c, 0xf3, 0xd1, 0xc3, 0xc8, 0x20, 0xdf, 0xb1, + 0x55, 0xd3, 0x91, 0xc3, 0x7f, 0x7e, 0x2c, 0x0e, + 0xbb, 0x9b, 0x46, 0x9d, 0x45, 0xe7, 0x1a, 0x27, + 0x2b, 0xfe, 0xd7, 0x1d, 0xba, 0xef, 0xeb, 0x0b, + 0x1b, 0xc7, 0xee, 0xa4, 0x05, 0x44, 0x68, 0xaf, + 0xa7, 0xbc, 0x67, 0x56, 0x4b, 0x17, 0x4d, 0x39, + 0x7d, 0x1e, 0x6c, 0xab, 0x0f, 0x9d, 0xad, 0x22, + 0x8b, 0x80, 0xff, 0x28, 0xe9, 0x03, 0xdb, 0x67, + 0xff, 0xb0, 0x68, 0xfc, 0xc1, 0x19, 0xbf, 0x6c, + 0xb3, 0xa9, 0xb3, 0x08, 0xed, 0x7f, 0x89, 0xba, + 0xa8, 0xe6, 0xe1, 0xcb, 0x38, 0x71, 0x65, 0xd6, + 0xc9, 0x67, 0xa8, 0x39, 0x57, 0xda, 0xfb, 0x23, + 0x12, 0x19, 0x18, 0x30, 0xe6, 0x22, 0x69, 0xfd, + 0xd2, 0x38, 0xe7, 0x2d, 0xc1, 0x96, 0xe8, 0xf3, + 0xc2, 0xc3, 0xbd, 0x47, 0x6d, 0xee, 0xc4, 0xd6, + 0x38, 0xd7, 0x35, 0x34, 0x47, 0xec, 0xd5, 0x7b, + 0xd4, 0x33, 0x21, 0xcd, 0xd3, 0x78, 0x89, 0xb0, + 0x18, 0x54, 0xba, 0x49, 0xb8, 0x86, 0x21, 0x00, + 0x38, 0x4f, 0x86, 0x5e, 0x78, 0x63, 0xf8, 0x81, + 0x48, 0x3e, 0xf3, 0x8b, 0x94, 0x4f, 0x9f, 0xf6, + 0x25, 0xf3, 0xdc, 0xdc, 0x86, 0xed, 0x24, 0x66, + 0x21, 0x74, 0x96, 0x04, 0x87, 0xd5, 0x32, 0x06, + 0x2f, 0x04, 0x74, 0x43, 0xbf, 0x62, 0x8d, 0x5a, + 0x69, 0x6d, 0x91, 0xb6, 0x21, 0xbe, 0x75, 0x73, + 0x17, 0xa8, 0xcc, 0x26, 0x75, 0xc5, 0xc7, 0x5e, + 0x84, 0x0c, 0x8c, 0x50, 0x1e, 0x23, 0x55, 0x2e, + 0x19, 0x9d, 0xd1, 0x76, 0x4a, 0x1a, 0x18, 0x1d, + 0x2c, 0x4f, 0x51, 0xac, 0xf4, 0x16, 0xb6, 0x12, + 0x01, 0x7d, 0xb2, 0x5a, 0xc0, 0xa6, 0x9d, 0x76, + 0x9f, 0x68, 0xf8, 0xc2, 0xe8, 0xc6, 0xc7, 0xd7, + 0x1d, 0x59, 0xa6, 0x06, 0xea, 0x00, 0x9c, 0x9d, + 0xb1, 0xeb, 0xd8, 0xa0, 0x60, 0x1c, 0xbf, 0x13, + 0xd0, 0x01, 0xbb, 0x5d, 0x9f, 0xf1, 0xa3, 0x3b, + 0x9c, 0x18, 0x0b, 0x0b, 0x2e, 0x73, 0x37, 0xac, + 0x03, 0xc2, 0x10, 0xc0, 0xf8, 0x5a, 0x86, 0x31, + 0x17, 0xe6, 0x6b, 0xc8, 0x17, 0xa3, 0x5d, 0xd9, + 0x6e, 0x5a, 0xa4, 0x0f, 0x92, 0x38, 0xf8, 0x0e, + 0x42, 0x8b, 0x1a, 0x85, 0x7f, 0x30, 0x2d, 0x61, + 0x48, 0x5f, 0x52, 0x00, 0xfb, 0x61, 0xd2, 0xa1, + 0xdc, 0xd6, 0x88, 0xb2, 0xff, 0x94, 0x01, 0x67, + 0x1a, 0xac, 0x2c, 0xf9, 0x17, 0xb6, 0x58, 0xbc, + 0x70, 0xf5, 0x9f, 0xee, 0x7c, 0x80, 0xa0, 0x21, + 0x47, 0x5f, 0x8f, 0x4a, 0x33, 0x7b, 0xb7, 0xbe, + 0xee, 0xfa, 0x62, 0xf7, 0xa2, 0x51, 0x1f, 0xe5, + 0x29, 0x66, 0x1c, 0xa0, 0x49, 0x6e, 0x1c, 0xa4, + 0x5a, 0xec, 0x2d, 0xc8, 0x2d, 0x59, 0x6c, 0x21, + 0xa3, 0x39, 0x38, 0x63, 0x44, 0xb3, 0x65, 0x80, + 0x56, 0x83, 0x33, 0xc9, 0xb6, 0xd7, 0xe7, 0x01, + 0x48, 0x07, 0x0c, 0x0d, 0x7a, 0xa7, 0x0b, 0xa7, + 0x22, 0x7e, 0x39, 0x0c, 0x66, 0x12, 0x4a, 0xbf, + 0xaf, 0xac, 0x3e, 0xf2, 0x6b, 0x2b, 0x97, 0x29, + 0x20, 0xd1, 0x0b, 0x57, 0x03, 0x04, 0xc5, 0x80, + 0xeb, 0x64, 0x7c, 0x0b, 0x0e, 0xc6, 0xa2, 0xe1, + 0x4e, 0x08, 0x15, 0x5f, 0xeb, 0x90, 0x51, 0xd7, + 0x77, 0xe8, 0xf9, 0x15, 0x0d, 0x42, 0x48, 0xc0, + 0xc4, 0x78, 0xcd, 0x4d, 0x46, 0xf4, 0x8a, 0x4a, + 0x4c, 0x61, 0xec, 0xd0, 0x4f, 0x5f, 0x8c, 0x6b, + 0x83, 0xed, 0xad, 0x56, 0xd8, 0xe9, 0x50, 0xda, + 0x05, 0x03, 0x3a, 0x29, 0xa5, 0xbc, 0x1f, 0x08, + 0x27, 0xed, 0xad, 0x87, 0x71, 0x90, 0x93, 0xe8, + 0xba, 0x29, 0xbc, 0x2e, 0xeb, 0xba, 0xe5, 0xb7, + 0x50, 0x38, 0xfa, 0x06, 0x52, 0xbf, 0x55, 0x46, + 0x89, 0x5a, 0x39, 0x6b, 0xb2, 0x1f, 0xea, 0xfa, + 0xea, 0xf1, 0x8a, 0x20, 0x14, 0x86, 0xc0, 0xae, + 0x60, 0x40, 0x17, 0xde, 0x2d, 0xeb, 0x87, 0x80, + 0x5d, 0x17, 0xe5, 0xdb, 0x4f, 0xf1, 0x3d, 0x7c, + 0xf8, 0xd0, 0xf7, 0x49, 0x6f, 0xaf, 0x0b, 0x64, + 0x12, 0x51, 0x7f, 0x85, 0xcb, 0xa0, 0x6a, 0x95, + 0xf9, 0x91, 0xf4, 0xf8, 0xa5, 0xae, 0xea, 0x99, + 0xd8, 0x67, 0x33, 0x67, 0x26, 0xab, 0xd4, 0x72, + 0x38, 0x6b, 0x98, 0xe7, 0xfd, 0xb3, 0x0e, 0xc4, + 0x8f, 0x6a, 0x7a, 0x9b, 0xf9, 0x53, 0xbf, 0x15, + 0x70, 0xfa, 0x9e, 0x8a, 0x25, 0x6f, 0xf7, 0x71, + 0xda, 0x1e, 0xe6, 0x54, 0x2c, 0x10, 0x5d, 0xfe, + 0x35, 0xd2, 0xe6, 0x62, 0x1d, 0x0b, 0x72, 0x03, + 0x6d, 0x2e, 0x43, 0x40, 0x88, 0xd9, 0x2a, 0xa3, + 0x01, 0x38, 0x91, 0x5b, 0x90, 0x9d, 0xab, 0x7f, + 0x9b, 0x27, 0xd2, 0x79, 0xfa, 0xfb, 0xe5, 0xb9, + 0xd2, 0x8b, 0x84, 0x01, 0x9b, 0xe8, 0x2a, 0x55, + 0x28, 0x24, 0x26, 0x92, 0x9a, 0x44, 0xf8, 0x07, + 0x55, 0x0d, 0xe6, 0x98, 0xd4, 0x01, 0x11, 0xd6, + 0x3c, 0xe3, 0x07, 0x0e, 0xfd, 0x6c, 0xae, 0xea, + 0xfc, 0x16, 0x26, 0x81, 0xa3, 0xe6, 0xa1, 0x83, + 0x88, 0xb3, 0xd5, 0x8a, 0xa9, 0xd6, 0x06, 0x1b, + 0xf1, 0x62, 0x21, 0x67, 0x46, 0x9f, 0x00, 0x6a, + 0x61, 0x2b, 0x76, 0x41, 0xf8, 0x41, 0x90, 0x06, + 0x62, 0x68, 0xe8, 0xae, 0x1e, 0xd2, 0x16, 0x29, + 0xf9, 0xed, 0xb5, 0xee, 0x6b, 0x2f, 0x72, 0xeb, + 0xd7, 0x7d, 0x1c, 0xe6, 0x4a, 0xe2, 0x85, 0x50, + 0x9d, 0xb0, 0xba, 0x72, 0x85, 0x3b, 0xcb, 0x88, + 0x2f, 0x27, 0xb5, 0xab, 0x98, 0xb4, 0x7b, 0x27, + 0x2d, 0x77, 0x8b, 0xdd, 0x66, 0x8b, 0x75, 0xf7, + 0xd1, 0xde, 0x64, 0x52, 0x8e, 0x66, 0x38, 0x21, + 0xe5, 0x64, 0x31, 0x62, 0x22, 0xa8, 0x79, 0x98, + 0x51, 0x63, 0xbe, 0xa8, 0xec, 0x86, 0x92, 0x33, + 0x94, 0xee, 0x66, 0x99, 0xf5, 0x53, 0xd5, 0x83, + 0x42, 0xbb, 0x83, 0x8e, 0x93, 0x9b, 0x67, 0x9a, + 0xf4, 0x91, 0xa8, 0xdb, 0x95, 0x12, 0xfe, 0xa2, + 0x44, 0xe6, 0xc0, 0x01, 0x21, 0x0b, 0x83, 0xe0, + 0xe7, 0xfb, 0x3a, 0xcf, 0x51, 0x9b, 0x19, 0xa0, + 0x48, 0x4d, 0x34, 0xb2, 0x83, 0x68, 0xac, 0x75, + 0xd7, 0x80, 0x7e, 0x66, 0x14, 0x04, 0x8a, 0xe3, + 0xa1, 0x8b, 0x3d, 0x7f, 0x6f, 0x58, 0xeb, 0xb7, + 0xc2, 0xc7, 0xe4, 0x6a, 0x74, 0x09, 0xf9, 0x4d, + 0x8f, 0xc4, 0xeb, 0xa1, 0xec, 0x6d, 0x29, 0x7c, + 0xe0, 0xac, 0x1a, 0x0e, 0x7e, 0xbd, 0x86, 0x0b, + 0xf7, 0x41, 0x95, 0x71, 0x47, 0x73, 0x52, 0x80, + 0x70, 0x8b, 0x94, 0xc1, 0x1f, 0xea, 0xde, 0x29, + 0xc0, 0x6e, 0x91, 0x2b, 0x28, 0x7b, 0xa9, 0x47, + 0x4d, 0x6d, 0x35, 0x53, 0x81, 0x8b, 0xf2, 0x32, + 0x01, 0x9a, 0x49, 0xaa, 0x5f, 0x02, 0x94, 0xfc, + 0xe2, 0x84, 0x1a, 0x6f, 0xbf, 0x08, 0x8e, 0xad, + 0x94, 0x9e, 0xd8, 0x89, 0x13, 0xd0, 0x6c, 0xbf, + 0x4f, 0x1f, 0xe0, 0x3d, 0x1b, 0x60, 0x65, 0xc1, + 0x56, 0xae, 0x13, 0xd3, 0xd3, 0xca, 0x4a, 0x2c, + 0x76, 0x06, 0xbd, 0xbb, 0x73, 0x57, 0x9a, 0x8b, + 0x66, 0xdd, 0x5e, 0xf4, 0x8d, 0x73, 0x8a, 0x58, + 0x81, 0x67, 0xe5, 0x3c, 0x56, 0x34, 0xd2, 0xc9, + 0x70, 0x25, 0x90, 0x4a, 0x0c, 0x7d, 0xc2, 0x3f, + 0x70, 0x04, 0xe3, 0x2d, 0x4b, 0xd7, 0x84, 0x10, + 0x4d, 0x7b, 0x2d, 0x84, 0x64, 0xb7, 0x62, 0x30, + 0x2b, 0x99, 0x1b, 0xd6, 0x9b, 0x06, 0x60, 0x0f, + 0x00, 0xcb, 0x22, 0x53, 0x8d, 0xda, 0xbc, 0xa5, + 0x64, 0x08, 0xf6, 0x89, 0x1e, 0x5f, 0x74, 0x17, + 0x18, 0x01, 0xa0, 0x0f, 0xe4, 0xae, 0xc3, 0x2d, + 0x8a, 0x8e, 0x85, 0x98, 0x8c, 0x33, 0x1a, 0x9d, + 0x46, 0x53, 0xe3, 0xdc, 0xc5, 0x13, 0xbd, 0xe7, + 0xf2, 0x10, 0xa2, 0x05, 0x86, 0x37, 0x9b, 0x61, + 0xa4, 0xe9, 0x95, 0x87, 0xf7, 0xc1, 0x16, 0xec, + 0x29, 0xde, 0x61, 0xb4, 0x60, 0x38, 0x9f, 0xbc, + 0xcf, 0x97, 0x83, 0x9e, 0xf3, 0x8a, 0xed, 0x91, + 0x33, 0xd1, 0xb5, 0x04, 0xfe, 0x49, 0xa0, 0x27, + 0xa8, 0xae, 0x3b, 0x8a, 0x27, 0x03, 0xc1, 0xd5, + 0x2f, 0x91, 0xab, 0x20, 0x55, 0x33, 0xe5, 0x85, + 0x13, 0xae, 0x1a, 0xaf, 0x09, 0xd4, 0x8e, 0xbd, + 0x09, 0xd8, 0x1b, 0x76, 0x18, 0x86, 0xb1, 0x09, + 0x17, 0x95, 0x50, 0xba, 0xc4, 0xbe, 0xa1, 0xe1, + 0x24, 0x6f, 0x8a, 0x7e, 0xb2, 0xe1, 0x2d, 0x2d, + 0x12, 0x6d, 0x8b, 0xcf, 0x64, 0x82, 0x4c, 0x07, + 0x42, 0x2e, 0xf7, 0x20, 0x77, 0x8e, 0x22, 0x00, + 0x72, 0xcf, 0xdf, 0x3c, 0xd3, 0x09, 0xd8, 0x70, + 0xb2, 0xe6, 0x2e, 0xcc, 0xc1, 0x71, 0xd4, 0xd4, + 0x9d, 0x45, 0x35, 0x37, 0x46, 0xd8, 0x2c, 0x99, + 0x3a, 0x3f, 0x90, 0x66, 0x30, 0x14, 0x01, 0x99, + 0x67, 0xda, 0xd1, 0xee, 0x4b, 0x9a, 0xcb, 0x26, + 0x34, 0xab, 0x9b, 0xaf, 0xc6, 0x0c, 0x4d, 0xf3, + 0xa2, 0x79, 0x50, 0x78, 0xd8, 0x66, 0x5c, 0xbb, + 0xcd, 0xe8, 0xb3, 0x09, 0xf9, 0x77, 0x61, 0x39, + 0x51, 0x6c, 0x3f, 0x26, 0x7b, 0xbb, 0x15, 0x8d, + 0x65, 0xe1, 0x6c, 0x52, 0x01, 0x6f, 0x20, 0x0e, + 0x7a, 0xd1, 0x84, 0x9b, 0x44, 0x83, 0x9d, 0x6d, + 0x35, 0x9a, 0x3e, 0x20, 0x48, 0x6c, 0xa0, 0xb2, + 0x70, 0x87, 0x09, 0xc3, 0xda, 0x4c, 0xbf, 0x6a, + 0x37, 0x47, 0x74, 0xa3, 0x43, 0x06, 0x3d, 0x9c, + 0x5c, 0xa8, 0xf9, 0x7d, 0x86, 0x8b, 0xb6, 0x08, + 0x30, 0xbb, 0xe7, 0x4d, 0x40, 0xf4, 0xe4, 0x43, + 0x83, 0x11, 0x11, 0xba, 0xa3, 0xb2, 0xb1, 0x86, + 0x1c, 0x89, 0x8b, 0x86, 0x84, 0x22, 0xbf, 0xb0, + 0x67, 0x4a, 0x28, 0xdd, 0xb6, 0x86, 0x31, 0x2d, + 0xd1, 0xa3, 0x87, 0x68, 0x08, 0x28, 0x18, 0xbf, + 0xdc, 0x09, 0xac, 0xac, 0xf8, 0x60, 0xc9, 0x68, + 0xe9, 0x98, 0xea, 0x7b, 0x55, 0xdf, 0x3c, 0x69, + 0x5b, 0x44, 0xf1, 0x75, 0xf1, 0x68, 0xf2, 0xe8, + 0x6d, 0x7d, 0xbb, 0x18, 0x8e, 0xd3, 0xbe, 0xc9, + 0x34, 0xfd, 0x9d, 0x6e, 0xdf, 0xe4, 0x03, 0x1a, + 0x7c, 0x52, 0x57, 0x9c, 0x11, 0xdc, 0xbd, 0x9f, + 0x41, 0xce, 0x2d, 0x33, 0x12, 0x92, 0x23, 0xff, + 0x83, 0xf2, 0x93, 0xcd, 0x14, 0xf1, 0x55, 0xbb, + 0x8d, 0x10, 0xa8, 0xc9, 0x60, 0x8f, 0xc9, 0xfb, + 0x70, 0xe1, 0xa8, 0x00, 0x68, 0x18, 0x87, 0x21, + 0x12, 0x52, 0xaa, 0xab, 0x6e, 0x56, 0xfa, 0x6c, + 0x96, 0x87, 0x04, 0xeb, 0x80, 0x94, 0xa6, 0xbe, + 0x3d, 0x90, 0x84, 0xd2, 0x73, 0x40, 0x80, 0x06, + 0x80, 0xc1, 0x40, 0xb9, 0x71, 0x25, 0xea, 0xe4, + 0x7b, 0xe5, 0x68, 0xf9, 0x20, 0x78, 0xa7, 0x07, + 0x01, 0x61, 0x9f, 0x50, 0xf9, 0x65, 0xc8, 0x1b, + 0x57, 0x53, 0xe8, 0xea, 0x18, 0xaa, 0x7a, 0x33, + 0x49, 0xb1, 0x34, 0x02, 0x7e, 0xdf, 0xa6, 0xf3, + 0x1b, 0xb3, 0x3f, 0xe9, 0xd7, 0xf3, 0x57, 0xc1, + 0x85, 0xdb, 0x37, 0xb6, 0x96, 0x29, 0xee, 0x20, + 0x05, 0xcb, 0x3a, 0xc4, 0x2c, 0x12, 0x8b, 0xdc, + 0xb2, 0x4f, 0x4e, 0x55, 0xc1, 0xe6, 0xa5, 0xb9, + 0x83, 0x0c, 0x03, 0xb1, 0x59, 0xb9, 0x5c, 0x85, + 0x78, 0xeb, 0xdb, 0xb0, 0x21, 0xac, 0x71, 0x85, + 0x05, 0x9c, 0x7a, 0xd9, 0x5f, 0xde, 0x96, 0xf1, + 0xb5, 0x30, 0x12, 0xfc, 0x8d, 0xce, 0x36, 0x0e, + 0x01, 0x17, 0x10, 0x4b, 0xdf, 0xb5, 0x01, 0x4d, + 0x30, 0x85, 0xb4, 0x9a, 0x50, 0x14, 0x40, 0x24, + 0x88, 0x87, 0x98, 0x21, 0x6f, 0xf2, 0xac, 0x68, + 0xeb, 0x60, 0xb4, 0xf3, 0x55, 0x78, 0xf2, 0x11, + 0x99, 0x34, 0xac, 0x79, 0xf5, 0xe6, 0xbd, 0xbb, + 0x04, 0x17, 0xdd, 0x76, 0x35, 0xf7, 0x36, 0x2f, + 0xb1, 0x49, 0xfb, 0x3a, 0x5e, 0x75, 0x21, 0xf7, + 0x06, 0x43, 0x20, 0x48, 0xfb, 0xd2, 0xd9, 0xbd, + 0xd1, 0x3b, 0x65, 0x8e, 0xd3, 0xac, 0x6c, 0xcf, + 0xef, 0xb1, 0x39, 0xc9, 0xb7, 0x91, 0x8d, 0xa8, + 0x5a, 0x78, 0xd6, 0x7d, 0x11, 0xcb, 0x3c, 0x62, + 0x54, 0xd9, 0x09, 0x1d, 0x8d, 0x87, 0x0c, 0x83, + 0x74, 0x9c, 0xf9, 0x9e, 0x6d, 0x59, 0xc9, 0xa6, + 0x83, 0x6e, 0x6d, 0xf1, 0xdc, 0xfa, 0xb0, 0x3e, + 0xcb, 0xab, 0x7b, 0xf1, 0xc1, 0xc0, 0x33, 0xef, + 0xe1, 0x17, 0xc2, 0x2a, 0x65, 0xe1, 0x17, 0xe9, + 0x1a, 0x1b, 0x84, 0x33, 0x64, 0x97, 0xa0, 0xcf, + 0x94, 0x72, 0x05, 0x61, 0x31, 0x61, 0x14, 0x88, + 0xe1, 0x9b, 0x81, 0xc6, 0xe2, 0x77, 0x51, 0x69, + 0x3f, 0xf3, 0xc6, 0x9e, 0x64, 0x36, 0x03, 0x1b, + 0x96, 0x69, 0x29, 0x0d, 0x8f, 0xc1, 0x79, 0xa4, + 0x1f, 0xac, 0x10, 0x52, 0x98, 0x8b, 0x29, 0x13, + 0x69, 0x50, 0x61, 0x68, 0xb4, 0xd6, 0xb4, 0x04, + 0x0b, 0xe0, 0x9f, 0x98, 0xb7, 0x22, 0xf8, 0x8c, + 0x3e, 0x29, 0x07, 0x1b, 0x0e, 0x52, 0x99, 0x3b, + 0xbb, 0x7b, 0x3f, 0xe4, 0xc5, 0xea, 0x36, 0x5a, + 0x0d, 0xfe, 0xc9, 0xfb, 0x4b, 0xe5, 0x79, 0xf8, + 0x86, 0x02, 0x24, 0x3b, 0xf4, 0x50, 0xfc, 0xb2, + 0x96, 0x98, 0xb5, 0xb2, 0x68, 0xba, 0x58, 0xfc, + 0x93, 0xd6, 0x2a, 0x27, 0x1f, 0x73, 0x47, 0xfd, + 0x27, 0x8f, 0x6a, 0x97, 0x10, 0x7b, 0xc2, 0xde, + 0x2c, 0x8d, 0x95, 0xd0, 0xef, 0xaf, 0xd9, 0x44, + 0xe5, 0xb4, 0x3a, 0x83, 0x4d, 0x9f, 0xa5, 0x6c, + 0x69, 0xd6, 0xa0, 0x88, 0x79, 0x31, 0xdd, 0x31, + 0x34, 0x07, 0x15, 0xe7, 0x73, 0x96, 0xd9, 0xb8, + 0x21, 0xd5, 0xcc, 0xa7, 0x8e, 0xf4, 0x6e, 0x47, + 0x9f, 0x82, 0x58, 0x9e, 0x5b, 0xe7, 0xa6, 0x60, + 0xcf, 0x05, 0x6e, 0x47, 0xab, 0x37, 0xcb, 0x99, + 0x5a, 0x2f, 0x49, 0x9d, 0x17, 0xa3, 0xa0, 0xcd, + 0x86, 0xc2, 0xb5, 0x9d, 0x7d, 0xc4, 0xbf, 0x59, + 0x57, 0x97, 0x48, 0x29, 0xdb, 0x52, 0xbb, 0x18, + 0xff, 0x85, 0xb6, 0xb6, 0x54, 0xbf, 0xfe, 0xaa, + 0x20, 0xc4, 0x61, 0xe2, 0xf0, 0x00, 0x7b, 0x25, + 0x17, 0xf6, 0x9b, 0x78, 0xfe, 0xff, 0x10, 0xb8, + 0x33, 0x0c, 0x3d, 0x1e, 0x7e, 0xc5, 0x6a, 0xa9, + 0x24, 0x6d, 0x07, 0x6f, 0x81, 0x6f, 0x5d, 0x90, + 0x5a, 0x16, 0xf9, 0x2b, 0xdc, 0x93, 0x48, 0xb1, + 0x30, 0xd8, 0x7f, 0x22, 0xb8, 0xbf, 0xde, 0xda, + 0xea, 0x69, 0xcc, 0xab, 0x40, 0xe9, 0xae, 0xa5, + 0x2e, 0xe1, 0x9f, 0x4d, 0x7e, 0x57, 0x58, 0xda, + 0x60, 0x48, 0x24, 0x42, 0x37, 0xdd, 0x88, 0xee, + 0x32, 0xa9, 0x5a, 0xf7, 0x2c, 0xfb, 0xcc, 0xf2, + 0xf6, 0x66, 0x26, 0xda, 0xe7, 0x4c, 0xa0, 0x72, + 0x18, 0x90, 0xf1, 0x19, 0x9d, 0x65, 0x62, 0xc9, + 0x8f, 0x11, 0xe7, 0x51, 0x56, 0xe1, 0xdc, 0x0f, + 0xb1, 0x46, 0xcb, 0xbd, 0x0a, 0x32, 0x62, 0x18, + 0x0e, 0x42, 0x75, 0x5a, 0xbb, 0xf2, 0x0f, 0x7f, + 0x2d, 0xb3, 0x14, 0x11, 0x6d, 0xc4, 0xa7, 0x2b, + 0x40, 0x94, 0x73, 0xfb, 0x5a, 0x89, 0x87, 0xe4, + 0x28, 0xab, 0xe9, 0x09, 0x56, 0xc6, 0x81, 0x12, + 0x1a, 0x31, 0xab, 0x6c, 0xf9, 0xf6, 0x72, 0x63, + 0xbb, 0x10, 0x63, 0xa2, 0x53, 0x75, 0xaa, 0xcf, + 0x34, 0xb4, 0x1b, 0x41, 0x69, 0x41, 0x59, 0x5b, + 0x1b, 0xaf, 0xf6, 0xca, 0xce, 0xdc, 0x45, 0x50, + 0xd1, 0x8e, 0xb1, 0xbe, 0x85, 0xc4, 0xc6, 0x38, + 0xa2, 0xfc, 0x54, 0x86, 0x72, 0xa5, 0xf3, 0x0e, + 0x82, 0x79, 0x74, 0xbc, 0x0e, 0x4c, 0x93, 0xf8, + 0xa4, 0x1e, 0xc1, 0x96, 0xe0, 0x08, 0x71, 0x03, + 0x49, 0x66, 0x36, 0x4f, 0x4c, 0x58, 0x37, 0xdf, + 0xf7, 0x0b, 0xa5, 0xb3, 0x91, 0x34, 0x83, 0xe2, + 0x5d, 0xc8, 0x15, 0xe9, 0xcc, 0x34, 0x3a, 0xc8, + 0x67, 0xbc, 0x50, 0xe5, 0xf9, 0xe5, 0xcd, 0x66, + 0x07, 0x69, 0x98, 0x45, 0xdd, 0xfb, 0xfd, 0xc0, + 0x5e, 0xd5, 0x14, 0xbc, 0xbe, 0xb0, 0x0e, 0x33, + 0xc5, 0x42, 0x45, 0x5d, 0x7b, 0x86, 0x5e, 0xb9, + 0xb2, 0x15, 0x82, 0x89, 0x20, 0x7f, 0x8d, 0x54, + 0x57, 0x1a, 0x37, 0x6c, 0x78, 0xca, 0xf2, 0x26, + 0x8c, 0x4e, 0x34, 0x01, 0xe1, 0x0c, 0x65, 0x94, + 0x1f, 0xde, 0x9b, 0x10, 0x5a, 0x09, 0xde, 0x93, + 0xa7, 0x57, 0xa7, 0x0c, 0xc6, 0x19, 0x33, 0x5a, + 0xb3, 0x23, 0x36, 0x72, 0x98, 0x72, 0xcf, 0x73, + 0x48, 0x7c, 0xca, 0xcd, 0xd1, 0x6e, 0xe8, 0x3d, + 0x4c, 0x25, 0xd2, 0x06, 0x0a, 0x2c, 0xcc, 0x2e, + 0xed, 0x9f, 0x87, 0xf3, 0xbc, 0x5f, 0x7f, 0xce, + 0x0f, 0xf5, 0x78, 0x98, 0x95, 0xa3, 0xc2, 0xe9, + 0x37, 0xa1, 0x6e, 0x4a, 0x84, 0xe4, 0x5e, 0x18, + 0x79, 0xf8, 0x9a, 0xa0, 0xa8, 0x77, 0xb5, 0xa8, + 0xa4, 0x6a, 0xb1, 0xbc, 0x19, 0xad, 0x29, 0x46, + 0xb0, 0xd1, 0x4a, 0x3c, 0xd8, 0x77, 0x8a, 0xe9, + 0x2d, 0x51, 0xc1, 0x02, 0x93, 0x84, 0x97, 0xd9, + 0xbd, 0xf7, 0xff, 0x40, 0x3a, 0xb8, 0x06, 0xa9, + 0xe4, 0x23, 0xa4, 0x8e, 0x48, 0x12, 0x4a, 0xdb, + 0x57, 0xc8, 0x21, 0xa9, 0x38, 0x40, 0x9c, 0xd0, + 0x86, 0x76, 0x2c, 0xb4, 0x5e, 0x91, 0xbe, 0x3e, + 0x82, 0x84, 0x3a, 0xa5, 0xda, 0x94, 0xb5, 0xed, + 0x0c, 0xd5, 0x93, 0xc7, 0x9c, 0xac, 0xfc, 0xac, + 0xf1, 0x81, 0xc5, 0xfa, 0x7d, 0x51, 0x78, 0x6f, + 0xab, 0x44, 0xac, 0x6e, 0x1b, 0x2d, 0x9e, 0x03, + 0xd4, 0x4a, 0xd3, 0x5e, 0xf3, 0x72, 0x0d, 0xd5, + 0x1e, 0x85, 0xad, 0x74, 0x20, 0xfe, 0x35, 0x58, + 0xf2, 0xdb, 0x1d, 0xde, 0xd8, 0xb9, 0x44, 0x84, + 0x40, 0x87, 0x42, 0xee, 0x70, 0xcb, 0x74, 0x4c, + 0x2b, 0xde, 0x69, 0x91, 0x8d, 0x4f, 0xcb, 0x2e, + 0xfb, 0xa8, 0xf1, 0xeb, 0x2e, 0xbd, 0x8f, 0xdc, + 0xf8, 0x4d, 0xd7, 0x93, 0xc8, 0x61, 0x06, 0xa4, + 0xb4, 0x32, 0x44, 0x4a, 0x42, 0x53, 0x69, 0xfa, + 0xb9, 0x48, 0x40, 0xf6, 0xb7, 0x72, 0xe5, 0x48, + 0x6d, 0x09, 0x61, 0xc4, 0xba, 0x40, 0x27, 0x61, + 0x7c, 0x3a, 0x70, 0xfd, 0x6d, 0x38, 0xff, 0x58, + 0x3e, 0xcd, 0x44, 0x8e, 0xe9, 0xc4, 0xb8, 0xcf, + 0x31, 0xd3, 0x36, 0xfc, 0x39, 0x18, 0x81, 0x8a, + 0x2b, 0x25, 0x8c, 0x76, 0x1e, 0xd1, 0x24, 0xea, + 0xb7, 0x83, 0xf4, 0xc3, 0x86, 0x16, 0x33, 0xd7, + 0x6d, 0x7b, 0x58, 0x1c, 0x6a, 0x29, 0x49, 0x07, + 0xab, 0x8f, 0xbc, 0xa3, 0x1a, 0xbc, 0xf4, 0xca, + 0xf2, 0x43, 0x15, 0x2c, 0xaa, 0x6f, 0x57, 0xc5, + 0xcf, 0x0c, 0x91, 0x53, 0xbf, 0xeb, 0xa8, 0x44, + 0x01, 0x82, 0xbb, 0xc8, 0x7f, 0x4e, 0xd6, 0xd3, + 0x79, 0x79, 0x4d, 0x84, 0xa1, 0x3a, 0x26, 0x68, + 0x0c, 0x2a, 0xa2, 0xee, 0x92, 0xaf, 0x2d, 0x8a, + 0x07, 0x54, 0x37, 0x6e, 0x95, 0xd5, 0x68, 0x78, + 0x04, 0x43, 0x53, 0x1c, 0x59, 0xcc, 0xe1, 0xec, + 0x43, 0xd7, 0x6c, 0x3b, 0xcb, 0x3b, 0x28, 0x8c, + 0x86, 0x0f, 0x71, 0x29, 0xd1, 0xcb, 0x09, 0x3f, + 0x6c, 0x76, 0x1b, 0x45, 0x5a, 0xdb, 0x75, 0xe1, + 0x3a, 0x4f, 0x32, 0x80, 0x09, 0xa2, 0xc3, 0xba, + 0xfc, 0x6b, 0x11, 0x47, 0x12, 0x68, 0x60, 0x79, + 0xa1, 0x28, 0x6e, 0x6e, 0xca, 0x22, 0xb8, 0xce, + 0x31, 0x23, 0xf1, 0xab, 0xe4, 0x78, 0xa2, 0x4d, + 0xb8, 0x4a, 0x18, 0xfd, 0xdc, 0x2d, 0xa1, 0x70, + 0xb1, 0xbc, 0xd2, 0x72, 0x08, 0x4b, 0x97, 0x8b, + 0x31, 0x59, 0x34, 0x01, 0x26, 0xac, 0x8a, 0x90, + 0x99, 0xaf, 0x75, 0xe3, 0x82, 0x21, 0x47, 0x76, + 0xc0, 0xae, 0x42, 0xc4, 0xe2, 0x13, 0xdf, 0xdb, + 0x8f, 0x79, 0x52, 0xd8, 0x1b, 0xf8, 0x30, 0x74, + 0x97, 0xde, 0xed, 0xa0, 0xe4, 0xaf, 0xb3, 0x01, + 0xaa, 0x89, 0x43, 0xcb, 0xaf, 0x37, 0x13, 0x44, + 0xb8, 0x33, 0x5a, 0xab, 0x53, 0xff, 0xef, 0x62, + 0xaf, 0x4c, 0x86, 0xcb, 0x6a, 0xa9, 0x02, 0x5d, + 0x54, 0xa1, 0xaf, 0xb2, 0x97, 0xb9, 0x20, 0x13, + 0xe7, 0xae, 0x27, 0x8f, 0x53, 0x97, 0x3b, 0xf8, + 0x29, 0xb2, 0x03, 0x13, 0x86, 0x37, 0xe3, 0xb9, + 0xe8, 0x28, 0xce, 0x84, 0xec, 0xbd, 0xd5, 0x54, + 0xf7, 0x5c, 0x2d, 0x16, 0xe6, 0x29, 0x03, 0xd0, + 0x5e, 0x4b, 0x04, 0xa6, 0xb9, 0xda, 0x17, 0x7e, + 0xfa, 0x0b, 0x36, 0xb9, 0xef, 0xa9, 0xcb, 0xf4, + 0x3f, 0xc6, 0x14, 0x75, 0xeb, 0x4b, 0x56, 0x26, + 0x92, 0xac, 0x0a, 0x23, 0x60, 0xde, 0x5b, 0xf9, + 0x99, 0x90, 0xa5, 0x94, 0x28, 0x1d, 0x4e, 0xc8, + 0xf4, 0x55, 0xaf, 0x8e, 0x08, 0xb8, 0xf0, 0xcc, + 0x4b, 0xe9, 0xb0, 0xf2, 0xb8, 0xf4, 0x23, 0x5c, + 0x94, 0xa5, 0x50, 0x34, 0xb7, 0xec, 0xdd, 0x45, + 0x45, 0x1b, 0x24, 0x21, 0xf1, 0x3c, 0xe0, 0x89, + 0x20, 0xc3, 0xda, 0x1b, 0x5b, 0x63, 0xbd, 0x67, + 0x70, 0xf1, 0x97, 0x6c, 0x82, 0x52, 0x67, 0xa8, + 0xc4, 0x6b, 0x16, 0xcc, 0x89, 0x07, 0x3b, 0x10, + 0x3c, 0x6e, 0x27, 0xc8, 0xf9, 0xce, 0xfa, 0x2e, + 0xac, 0x31, 0x90, 0xf7, 0xe0, 0x3e, 0x2b, 0x5e, + 0x8f, 0x1e, 0x7b, 0xc3, 0xfb, 0xdd, 0xb9, 0xe8, + 0xee, 0x1a, 0x0b, 0x1c, 0xa8, 0xd0, 0x3b, 0x27, + 0x8b, 0x43, 0x22, 0x7c, 0xe9, 0x9d, 0x56, 0xa4, + 0xe8, 0x19, 0xd3, 0xd0, 0xfc, 0x70, 0xed, 0x3d, + 0x39, 0x16, 0x4e, 0x54, 0x2b, 0xf7, 0x0f, 0x6f, + 0x94, 0xbe, 0x2d, 0x43, 0x6a, 0xe6, 0xad, 0xc7, + 0x38, 0x50, 0xd5, 0x48, 0x55, 0xda, 0x2b, 0xba, + 0x99, 0x6c, 0x6f, 0xc8, 0x39, 0xf4, 0xed, 0x29, + 0x53, 0xed, 0x6c, 0x2a, 0x84, 0xad, 0x6a, 0x96, + 0x77, 0x5f, 0x14, 0xd3, 0xda, 0xe2, 0xf1, 0x14, + 0x5d, 0xaa, 0x3e, 0x95, 0xdb, 0x8a, 0x2a, 0xb2, + 0x32, 0xcf, 0x62, 0x25, 0xe6, 0xc8, 0x56, 0x09, + 0x87, 0x35, 0x31, 0xe6, 0x55, 0xe3, 0xf8, 0x40, + 0x82, 0x1a, 0x1f, 0x86, 0x68, 0x60, 0x40, 0x29, + 0x3a, 0xac, 0x76, 0x6d, 0xf4, 0x7a, 0x0f, 0xcc, + 0x1f, 0x69, 0x7e, 0xb0, 0xc6, 0xaa, 0x44, 0xff, + 0x6b, 0x5e, 0xf1, 0xa4, 0xba, 0x81, 0xb7, 0xd8, + 0xf6, 0x38, 0x24, 0x9b, 0x47, 0x7f, 0x69, 0xf6, + 0x8c, 0xac, 0x98, 0x4c, 0xf5, 0xf0, 0x55, 0x76, + 0x7f, 0x8c, 0xd8, 0x43, 0x1b, 0x69, 0x28, 0x4a, + 0xdc, 0x95, 0x29, 0x44, 0x0e, 0xc8, 0x2a, 0x4b, + 0xe5, 0x2e, 0xb4, 0xb5, 0x4f, 0xbc, 0x34, 0x05, + 0xf0, 0x82, 0x1a, 0x54, 0xec, 0x89, 0xe9, 0xc7, + 0xae, 0x60, 0x82, 0xd5, 0x54, 0x49, 0x26, 0xde, + 0x2a, 0x87, 0x04, 0xed, 0xbe, 0x2b, 0x31, 0x95, + 0x07, 0x8e, 0xcd, 0xd1, 0x62, 0xa0, 0xa0, 0x89, + 0xdc, 0x09, 0x3c, 0xcb, 0xb0, 0x0a, 0xec, 0x70, + 0x64, 0xfe, 0xbf, 0xf8, 0xc7, 0x10, 0x6e, 0x61, + 0x8b, 0xd7, 0x2a, 0xa0, 0x57, 0xb1, 0x01, 0x76, + 0x18, 0x3a, 0xe9, 0x05, 0xb4, 0x50, 0x84, 0x36, + 0x68, 0xbe, 0x38, 0x9d, 0x03, 0xe6, 0x13, 0xad, + 0xbd, 0xfc, 0xc2, 0xb1, 0x12, 0x4a, 0x00, 0xf0, + 0x02, 0xda, 0x0c, 0xe8, 0x9c, 0x0f, 0x44, 0x31, + 0xc3, 0xf2, 0xd6, 0x23, 0x0b, 0xce, 0xef, 0xab, + 0xc9, 0x5a, 0x58, 0x4a, 0x59, 0x7c, 0x6c, 0x8b, + 0x98, 0x21, 0xdf, 0xb8, 0x5f, 0xc8, 0x1e, 0x9c, + 0xaa, 0x52, 0x42, 0x64, 0xb4, 0xe0, 0x83, 0x78, + 0xea, 0xed, 0xb4, 0x92, 0xde, 0x5b, 0x99, 0x33, + 0x61, 0xdc, 0x04, 0x71, 0x30, 0x2e, 0x2c, 0xf8, + 0xf7, 0xb6, 0x5b, 0x9b, 0xad, 0xee, 0x1b, 0x67, + 0x40, 0x16, 0x57, 0x77, 0xfa, 0x17, 0xe5, 0x6d, + 0xd8, 0x94, 0xc2, 0x25, 0x4c, 0xf9, 0x42, 0x2e, + 0x3d, 0xbf, 0xcd, 0x81, 0x4c, 0x79, 0x92, 0x46, + 0x62, 0xde, 0xc8, 0x3b, 0x91, 0xee, 0x59, 0x16, + 0x4d, 0x74, 0xfc, 0x63, 0xea, 0x6c, 0x6f, 0x66, + 0xee, 0x61, 0x0e, 0x0a, 0x3e, 0x6c, 0x20, 0xe3, + 0x23, 0xfd, 0xa0, 0x88, 0xb9, 0xea, 0x55, 0x83, + 0x99, 0x41, 0xaa, 0x8d, 0xe2, 0x74, 0xa8, 0x61, + 0xd9, 0xb3, 0xc7, 0x6c, 0xe9, 0x28, 0x12, 0x6d, + 0xe0, 0x73, 0xa0, 0x4b, 0x5a, 0x77, 0x55, 0x51, + 0xd8, 0x02, 0x83, 0x81, 0xd1, 0x67, 0x10, 0x55, + 0x32, 0xc6, 0xea, 0x3e, 0x14, 0xce, 0xc4, 0x4c, + 0x95, 0x63, 0x61, 0x8f, 0x06, 0x20, 0xaa, 0x2d, + 0x74, 0x93, 0xf3, 0x47, 0x2d, 0x0b, 0x3c, 0xd5, + 0xf8, 0xce, 0x1f, 0x7b, 0x10, 0x2e, 0x5a, 0xf2, + 0x3d, 0x54, 0xaa, 0xfd, 0x56, 0x3f, 0xc9, 0x11, + 0x48, 0xd3, 0x31, 0x11, 0x28, 0x6c, 0x63, 0x5a, + 0x4f, 0xee, 0xdd, 0x73, 0x06, 0x1e, 0xea, 0x54, + 0x01, 0x4b, 0x9f, 0x82, 0x46, 0x83, 0x71, 0xad, + 0x26, 0x19, 0xc9, 0xf5, 0x7d, 0x57, 0x07, 0x74, + 0xb4, 0x08, 0x2e, 0x4c, 0xfd, 0x72, 0x30, 0xf1, + 0x72, 0x74, 0xf5, 0x98, 0xa9, 0xbb, 0x92, 0xa5, + 0x02, 0x81, 0x48, 0xd2, 0xc4, 0x1c, 0x47, 0x51, + 0x2f, 0xf8, 0xf1, 0x0f, 0xbb, 0xab, 0x48, 0x02, + 0xcb, 0xbc, 0xf3, 0xb8, 0x85, 0xd0, 0xab, 0xcf, + 0x97, 0x48, 0x95, 0x48, 0x08, 0x35, 0xda, 0x1e, + 0x66, 0x34, 0xd4, 0x83, 0x02, 0xbe, 0xfb, 0xdd, + 0xe1, 0xe6, 0x39, 0xbd, 0xed, 0xe2, 0x73, 0x75, + 0x05, 0xda, 0x24, 0xa5, 0x0d, 0x2c, 0x7e, 0x21, + 0x4d, 0x84, 0x64, 0xa2, 0x8f, 0x23, 0x6f, 0x73, + 0xeb, 0xba, 0x8f, 0x84, 0x65, 0x15, 0x13, 0xaa, + 0xed, 0x7e, 0x10, 0xe8, 0x41, 0xd3, 0xa8, 0x96, + 0x59, 0x46, 0x54, 0xa8, 0xef, 0x37, 0xfb, 0xf8, + 0xfd, 0x46, 0x04, 0xc6, 0x91, 0x55, 0x0b, 0xcb, + 0x88, 0x71, 0x5b, 0x41, 0x09, 0x3d, 0xa1, 0xa1, + 0x03, 0x01, 0x80, 0xd4, 0xde, 0xbb, 0x91, 0xf1, + 0x7e, 0xab, 0x26, 0xbb, 0x44, 0xa6, 0xa5, 0xa9, + 0xf5, 0xe0, 0x57, 0x2c, 0xd1, 0x88, 0x19, 0x74, + 0xa4, 0x46, 0xbf, 0x9c, 0xc1, 0x94, 0xc9, 0xfe, + 0xe5, 0x27, 0x2c, 0x77, 0x61, 0x04, 0x51, 0x83, + 0x08, 0xa3, 0xc7, 0x84, 0xcf, 0xb7, 0xe4, 0x02, + 0x72, 0x44, 0xad, 0x63, 0x90, 0xbf, 0x88, 0x90, + 0x1d, 0x2b, 0xb9, 0x56, 0x48, 0xcc, 0xc6, 0xa4, + 0x8d, 0xa8, 0x9d, 0xcd, 0x35, 0x26, 0xfc, 0x3a, + 0xa5, 0x96, 0x57, 0x2a, 0x63, 0x9c, 0xb9, 0x97, + 0x75, 0xa5, 0x94, 0xd9, 0xdd, 0x43, 0x61, 0x82, + 0x31, 0x2f, 0xea, 0x71, 0x4a, 0xdb, 0xad, 0x9b, + 0x93, 0xb5, 0x28, 0x77, 0x01, 0xad, 0x83, 0x89, + 0x34, 0x09, 0xa2, 0xce, 0x60, 0xc3, 0xdb, 0xbe, + 0x27, 0x53, 0xc7, 0xf5, 0x69, 0xdb, 0x30, 0x3b, + 0x2c, 0x62, 0xda, 0x3c, 0x1e, 0xae, 0x18, 0x1b, + 0x3b, 0xdc, 0xc2, 0x5f, 0xa4, 0x61, 0xa3, 0x4a, + 0x96, 0x6c, 0x22, 0x3c, 0x59, 0xcd, 0xcb, 0xb4, + 0x44, 0x12, 0x95, 0x41, 0x74, 0x78, 0x9d, 0xea, + 0x08, 0x52, 0x48, 0xa4, 0x58, 0xa2, 0x10, 0x9c, + 0xd6, 0x2e, 0x34, 0x07, 0x48, 0xf8, 0x71, 0x73, + 0x09, 0x51, 0xfa, 0x58, 0x1c, 0xdc, 0xf6, 0xda, + 0xc1, 0x1b, 0xf3, 0xd8, 0x1a, 0x8f, 0xf2, 0xbe, + 0xf1, 0xe4, 0x1a, 0xe1, 0x1e, 0xfa, 0x6e, 0x01, + 0x40, 0x24, 0x1d, 0xbd, 0x2c, 0xb3, 0x9d, 0x41, + 0xdc, 0x36, 0x7d, 0x91, 0xd0, 0xa3, 0xec, 0xd1, + 0xd5, 0x57, 0xb7, 0x48, 0x40, 0xec, 0x4b, 0xb1, + 0xe8, 0xbc, 0xf8, 0x82, 0x25, 0x50, 0x1e, 0xf6, + 0x05, 0xc7, 0x6d, 0x4b, 0xaa, 0xd6, 0x1c, 0x62, + 0x1c, 0x67, 0x46, 0x25, 0xdd, 0xf1, 0xdc, 0xfa, + 0xb7, 0x1d, 0x7c, 0x7c, 0x32, 0x10, 0xc8, 0x50, + 0xdb, 0xb8, 0xe4, 0xdc, 0xc7, 0x5b, 0xbc, 0x25, + 0x98, 0x90, 0x4d, 0xa9, 0xc3, 0xc3, 0x9c, 0x9e, + 0xb0, 0xd4, 0x6a, 0x34, 0xa4, 0xc1, 0xed, 0x72, + 0xa4, 0x19, 0xdc, 0x25, 0xda, 0x8d, 0x68, 0x5b, + 0x34, 0xf9, 0x0b, 0xc7, 0xa6, 0xa3, 0x8f, 0xee, + 0x60, 0x3d, 0x82, 0xd6, 0x77, 0x2c, 0x03, 0x5b, + 0x43, 0xcd, 0xd7, 0x7c, 0x72, 0x67, 0x49, 0x8b, + 0x32, 0x3b, 0x01, 0x75, 0x48, 0xb8, 0x26, 0x4e, + 0xca, 0x0e, 0xb0, 0x5c, 0xbd, 0x1f, 0xb4, 0xe7, + 0x8d, 0x86, 0xd4, 0x23, 0x46, 0x76, 0x2e, 0x72, + 0x64, 0x5e, 0x23, 0x78, 0xe3, 0xdd, 0x70, 0xcc, + 0xbf, 0x78, 0x4c, 0x6d, 0x80, 0xbf, 0xde, 0x10, + 0xad, 0x4b, 0x5f, 0xe7, 0x98, 0x20, 0x04, 0xe7, + 0xcb, 0x80, 0x3c, 0x1c, 0x48, 0x45, 0xac, 0x80, + 0x7e, 0xaf, 0x8f, 0x6f, 0x26, 0x25, 0x5b, 0x44, + 0x1e, 0x5e, 0x5a, 0xa3, 0x60, 0xf8, 0xd1, 0x4c, + 0x86, 0x29, 0xa9, 0x98, 0xd0, 0x03, 0x82, 0x02, + 0x02, 0x7b, 0x6f, 0x6a, 0x80, 0xb1, 0x13, 0x00, + 0x2f, 0x25, 0x4f, 0x5c, 0x63, 0x8a, 0x90, 0xf4, + 0x65, 0x8e, 0x90, 0x96, 0xc3, 0xe8, 0x0f, 0x21, + 0x28, 0x44, 0x51, 0x56, 0x5d, 0x5f, 0x08, 0x27, + 0x43, 0x4f, 0xa9, 0xad, 0xd9, 0xe2, 0x69, 0x99, + 0xa5, 0xbc, 0x2a, 0x3a, 0x4a, 0x54, 0x8d, 0x90, + 0xc9, 0xdf, 0x1b, 0x23, 0x46, 0x51, 0x87, 0x89, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x08, 0x0e, 0x16, 0x1e, + 0x22, 0x2a, 0x30 + }; + + + ExpectNotNull(key = (dilithium_key*)XMALLOC(sizeof(*key), NULL, + DYNAMIC_TYPE_TMP_BUFFER)); + +#ifndef WOLFSSL_NO_ML_DSA_44 + /* ML-DSA-44: verify the known-good (mu, sig) pair. */ + ExpectIntEQ(wc_dilithium_init_ex(key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_dilithium_set_level(key, WC_ML_DSA_44), 0); + ExpectIntEQ(wc_dilithium_import_public(pk_44_mu, + (word32)sizeof(pk_44_mu), key), 0); + res = 0; + ExpectIntEQ(wc_dilithium_verify_mu(sig_44_mu, + (word32)sizeof(sig_44_mu), mu_44, + (word32)sizeof(mu_44), &res, key), 0); + ExpectIntEQ(res, 1); + + /* Tamper mu: verification must fail. */ + XMEMCPY(muBuf, mu_44, sizeof(mu_44)); + muBuf[0] ^= 0x01; + res = 1; + (void)wc_dilithium_verify_mu(sig_44_mu, + (word32)sizeof(sig_44_mu), muBuf, + (word32)sizeof(mu_44), &res, key); + ExpectIntEQ(res, 0); + + /* Tamper signature: verification must fail. */ + ExpectNotNull(sigBuf = (byte*)XMALLOC(sizeof(sig_44_mu), + NULL, DYNAMIC_TYPE_TMP_BUFFER)); + if (sigBuf != NULL) { + XMEMCPY(sigBuf, sig_44_mu, sizeof(sig_44_mu)); + sigBuf[0] ^= 0x01; + res = 1; + (void)wc_dilithium_verify_mu(sigBuf, + (word32)sizeof(sig_44_mu), mu_44, + (word32)sizeof(mu_44), &res, key); + ExpectIntEQ(res, 0); + XFREE(sigBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + sigBuf = NULL; + } + wc_dilithium_free(key); +#endif /* !WOLFSSL_NO_ML_DSA_44 */ +#ifndef WOLFSSL_NO_ML_DSA_65 + /* ML-DSA-65: verify the known-good (mu, sig) pair. */ + ExpectIntEQ(wc_dilithium_init_ex(key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_dilithium_set_level(key, WC_ML_DSA_65), 0); + ExpectIntEQ(wc_dilithium_import_public(pk_65_mu, + (word32)sizeof(pk_65_mu), key), 0); + res = 0; + ExpectIntEQ(wc_dilithium_verify_mu(sig_65_mu, + (word32)sizeof(sig_65_mu), mu_65, + (word32)sizeof(mu_65), &res, key), 0); + ExpectIntEQ(res, 1); + + /* Tamper mu: verification must fail. */ + XMEMCPY(muBuf, mu_65, sizeof(mu_65)); + muBuf[0] ^= 0x01; + res = 1; + (void)wc_dilithium_verify_mu(sig_65_mu, + (word32)sizeof(sig_65_mu), muBuf, + (word32)sizeof(mu_65), &res, key); + ExpectIntEQ(res, 0); + + /* Tamper signature: verification must fail. */ + ExpectNotNull(sigBuf = (byte*)XMALLOC(sizeof(sig_65_mu), + NULL, DYNAMIC_TYPE_TMP_BUFFER)); + if (sigBuf != NULL) { + XMEMCPY(sigBuf, sig_65_mu, sizeof(sig_65_mu)); + sigBuf[0] ^= 0x01; + res = 1; + (void)wc_dilithium_verify_mu(sigBuf, + (word32)sizeof(sig_65_mu), mu_65, + (word32)sizeof(mu_65), &res, key); + ExpectIntEQ(res, 0); + XFREE(sigBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + sigBuf = NULL; + } + wc_dilithium_free(key); +#endif /* !WOLFSSL_NO_ML_DSA_65 */ +#ifndef WOLFSSL_NO_ML_DSA_87 + /* ML-DSA-87: verify the known-good (mu, sig) pair. */ + ExpectIntEQ(wc_dilithium_init_ex(key, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_dilithium_set_level(key, WC_ML_DSA_87), 0); + ExpectIntEQ(wc_dilithium_import_public(pk_87_mu, + (word32)sizeof(pk_87_mu), key), 0); + res = 0; + ExpectIntEQ(wc_dilithium_verify_mu(sig_87_mu, + (word32)sizeof(sig_87_mu), mu_87, + (word32)sizeof(mu_87), &res, key), 0); + ExpectIntEQ(res, 1); + + /* Tamper mu: verification must fail. */ + XMEMCPY(muBuf, mu_87, sizeof(mu_87)); + muBuf[0] ^= 0x01; + res = 1; + (void)wc_dilithium_verify_mu(sig_87_mu, + (word32)sizeof(sig_87_mu), muBuf, + (word32)sizeof(mu_87), &res, key); + ExpectIntEQ(res, 0); + + /* Tamper signature: verification must fail. */ + ExpectNotNull(sigBuf = (byte*)XMALLOC(sizeof(sig_87_mu), + NULL, DYNAMIC_TYPE_TMP_BUFFER)); + if (sigBuf != NULL) { + XMEMCPY(sigBuf, sig_87_mu, sizeof(sig_87_mu)); + sigBuf[0] ^= 0x01; + res = 1; + (void)wc_dilithium_verify_mu(sigBuf, + (word32)sizeof(sig_87_mu), mu_87, + (word32)sizeof(mu_87), &res, key); + ExpectIntEQ(res, 0); + XFREE(sigBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + sigBuf = NULL; + } + wc_dilithium_free(key); +#endif /* !WOLFSSL_NO_ML_DSA_87 */ + XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return EXPECT_RESULT(); +} + #if !defined(NO_ASN) && defined(HAVE_PKCS8) && \ defined(HAVE_DILITHIUM) && defined(WOLFSSL_WC_DILITHIUM) && \ !defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) && \ @@ -24609,6 +29717,8 @@ int test_wc_Dilithium_PrivateKeyDecode_OpenSSL_form(void) ExpectNotNull(der = (byte*) XMALLOC(derMaxSz, NULL, DYNAMIC_TYPE_TMP_BUFFER)); + PRIVATE_KEY_UNLOCK(); + for (size_t i = 0; i < sizeof(ossl_form) / sizeof(ossl_form[0]); ++i) { ExpectNotNull(fp = XFOPEN(ossl_form[i].fileName, "rb")); ExpectIntGT(derSz = XFREAD(der, 1, derMaxSz, fp), 0); @@ -24675,6 +29785,8 @@ int test_wc_Dilithium_PrivateKeyDecode_OpenSSL_form(void) wc_dilithium_free(&key); } + PRIVATE_KEY_LOCK(); + XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return EXPECT_RESULT(); diff --git a/tests/api/test_mldsa.h b/tests/api/test_mldsa.h index dc1ff87ab1..73825bf61d 100644 --- a/tests/api/test_mldsa.h +++ b/tests/api/test_mldsa.h @@ -38,6 +38,8 @@ int test_wc_dilithium_sig_kats(void); int test_wc_dilithium_sign_ctx_kats(void); int test_wc_dilithium_verify_ctx_kats(void); int test_wc_dilithium_verify_kats(void); +int test_wc_dilithium_sign_mu_kats(void); +int test_wc_dilithium_verify_mu_kats(void); int test_wc_Dilithium_PrivateKeyDecode_OpenSSL_form(void); int test_mldsa_pkcs8_import_OpenSSL_form(void); int test_mldsa_pkcs8_export_import_wolfSSL_form(void); @@ -59,6 +61,8 @@ int test_mldsa_pkcs12(void); TEST_DECL_GROUP("mldsa", test_wc_dilithium_sign_ctx_kats), \ TEST_DECL_GROUP("mldsa", test_wc_dilithium_verify_ctx_kats), \ TEST_DECL_GROUP("mldsa", test_wc_dilithium_verify_kats), \ + TEST_DECL_GROUP("mldsa", test_wc_dilithium_sign_mu_kats), \ + TEST_DECL_GROUP("mldsa", test_wc_dilithium_verify_mu_kats), \ TEST_DECL_GROUP("mldsa", test_wc_Dilithium_PrivateKeyDecode_OpenSSL_form), \ TEST_DECL_GROUP("mldsa", test_mldsa_pkcs8_import_OpenSSL_form), \ TEST_DECL_GROUP("mldsa", test_mldsa_pkcs8_export_import_wolfSSL_form), \ diff --git a/tests/api/test_mlkem.c b/tests/api/test_mlkem.c index 4ff7660438..0e3cea39ff 100644 --- a/tests/api/test_mlkem.c +++ b/tests/api/test_mlkem.c @@ -1451,6 +1451,8 @@ int test_wc_mlkem_make_key_kats(void) XMEMSET(key, 0, sizeof(MlKemKey)); } + PRIVATE_KEY_UNLOCK(); + #ifndef WOLFSSL_NO_ML_KEM_512 ExpectIntEQ(wc_MlKemKey_Init(key, WC_ML_KEM_512, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_MlKemKey_MakeKeyWithRandom(key, seed_512, sizeof(seed_512)), @@ -1488,6 +1490,8 @@ int test_wc_mlkem_make_key_kats(void) wc_MlKemKey_Free(key); #endif + PRIVATE_KEY_LOCK(); + XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return EXPECT_RESULT(); @@ -3845,6 +3849,8 @@ int test_wc_mlkem_decapsulate_kats(void) XMEMSET(key, 0, sizeof(MlKemKey)); } + PRIVATE_KEY_UNLOCK(); + #ifndef WOLFSSL_NO_ML_KEM_512 ExpectIntEQ(wc_MlKemKey_Init(key, WC_ML_KEM_512, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_MlKemKey_DecodePrivateKey(key, dk_512, sizeof(dk_512)), 0); @@ -3867,6 +3873,8 @@ int test_wc_mlkem_decapsulate_kats(void) wc_MlKemKey_Free(key); #endif + PRIVATE_KEY_LOCK(); + XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return EXPECT_RESULT(); @@ -3937,8 +3945,10 @@ int test_wc_mlkem_decapsulate_pubonly_fails(void) ExpectIntEQ(wc_MlKemKey_DecodePublicKey(pubOnlyKey, pubBuf, pubLen), 0); /* Decapsulating with a public-key-only object must fail. */ + PRIVATE_KEY_UNLOCK(); ExpectIntEQ(wc_MlKemKey_Decapsulate(pubOnlyKey, ssDec, ct, ctLen), WC_NO_ERR_TRACE(BAD_STATE_E)); + PRIVATE_KEY_LOCK(); DoExpectIntEQ(wc_FreeRng(&rng), 0); wc_MlKemKey_Free(pubOnlyKey); @@ -3993,22 +4003,31 @@ int test_wc_mlkem_decap_fo_reject(void) /* Untampered ciphertext recovers the original ss. */ XMEMSET(ssDec, 0, sizeof(ssDec)); + PRIVATE_KEY_UNLOCK(); ExpectIntEQ(wc_MlKemKey_Decapsulate(key, ssDec, ct, ctLen), 0); + PRIVATE_KEY_LOCK(); ExpectIntEQ(XMEMCMP(ssDec, ss, WC_ML_KEM_SS_SZ), 0); /* Tamper at byte 32: implicit rejection must fire. */ XMEMCPY(ctTampered, ct, ctLen); ctTampered[32] ^= 0x01; XMEMSET(ssTampered, 0, sizeof(ssTampered)); + PRIVATE_KEY_UNLOCK(); ExpectIntEQ(wc_MlKemKey_Decapsulate(key, ssTampered, ctTampered, ctLen), 0); + PRIVATE_KEY_LOCK(); ExpectIntNE(XMEMCMP(ssTampered, ss, WC_ML_KEM_SS_SZ), 0); - /* Tamper at byte 0: also must be rejected. */ + /* Tamper at byte 0: decapsulation must still return 0. We do NOT assert + * ssTampered != ss here: byte 0 sits in the lossy-compressed u portion of + * the ciphertext, so a single-bit flip can be absorbed by Decompress and + * yield the original shared secret. The byte-32 case above already covers + * the "rejection produces a different secret" property. */ XMEMCPY(ctTampered, ct, ctLen); ctTampered[0] ^= 0x01; XMEMSET(ssTampered, 0, sizeof(ssTampered)); + PRIVATE_KEY_UNLOCK(); ExpectIntEQ(wc_MlKemKey_Decapsulate(key, ssTampered, ctTampered, ctLen), 0); - ExpectIntNE(XMEMCMP(ssTampered, ss, WC_ML_KEM_SS_SZ), 0); + PRIVATE_KEY_LOCK(); DoExpectIntEQ(wc_FreeRng(&rng), 0); wc_MlKemKey_Free(key); diff --git a/tests/api/test_random.c b/tests/api/test_random.c index fe8aaf0ee1..79f8c27b5e 100644 --- a/tests/api/test_random.c +++ b/tests/api/test_random.c @@ -530,3 +530,146 @@ int test_wc_RNG_HealthTest(void) return EXPECT_RESULT(); } +/* + * Testing wc_RNG_HealthTest_SHA512() + * Test vectors from NIST CAVP drbgtestvectors.zip, Hash_DRBG.rsp, [SHA-512]. + * Source: https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm- + * Validation-Program/documents/drbg/drbgtestvectors.zip + */ +int test_wc_RNG_HealthTest_SHA512(void) +{ + EXPECT_DECLS; +#if defined(HAVE_HASHDRBG) && defined(WOLFSSL_DRBG_SHA512) && \ + !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + + /* No-reseed test: drbgvectors_no_reseed/Hash_DRBG.rsp, [SHA-512], + * COUNT=0 */ + const byte test1Seed[] = + { + /* EntropyInput (32 bytes) */ + 0x6b, 0x50, 0xa7, 0xd8, 0xf8, 0xa5, 0x5d, 0x7a, + 0x3d, 0xf8, 0xbb, 0x40, 0xbc, 0xc3, 0xb7, 0x22, + 0xd8, 0x70, 0x8d, 0xe6, 0x7f, 0xda, 0x01, 0x0b, + 0x03, 0xc4, 0xc8, 0x4d, 0x72, 0x09, 0x6f, 0x8c, + /* Nonce (16 bytes) */ + 0x3e, 0xc6, 0x49, 0xcc, 0x62, 0x56, 0xd9, 0xfa, + 0x31, 0xdb, 0x7a, 0x29, 0x04, 0xaa, 0xf0, 0x25 + }; + const byte test1Output[] = + { + 0x95, 0xb7, 0xf1, 0x7e, 0x98, 0x02, 0xd3, 0x57, + 0x73, 0x92, 0xc6, 0xa9, 0xc0, 0x80, 0x83, 0xb6, + 0x7d, 0xd1, 0x29, 0x22, 0x65, 0xb5, 0xf4, 0x2d, + 0x23, 0x7f, 0x1c, 0x55, 0xbb, 0x9b, 0x10, 0xbf, + 0xcf, 0xd8, 0x2c, 0x77, 0xa3, 0x78, 0xb8, 0x26, + 0x6a, 0x00, 0x99, 0x14, 0x3b, 0x3c, 0x2d, 0x64, + 0x61, 0x1e, 0xee, 0xb6, 0x9a, 0xcd, 0xc0, 0x55, + 0x95, 0x7c, 0x13, 0x9e, 0x8b, 0x19, 0x0c, 0x7a, + 0x06, 0x95, 0x5f, 0x2c, 0x79, 0x7c, 0x27, 0x78, + 0xde, 0x94, 0x03, 0x96, 0xa5, 0x01, 0xf4, 0x0e, + 0x91, 0x39, 0x6a, 0xcf, 0x8d, 0x7e, 0x45, 0xeb, + 0xdb, 0xb5, 0x3b, 0xbf, 0x8c, 0x97, 0x52, 0x30, + 0xd2, 0xf0, 0xff, 0x91, 0x06, 0xc7, 0x61, 0x19, + 0xae, 0x49, 0x8e, 0x7f, 0xbc, 0x03, 0xd9, 0x0f, + 0x8e, 0x4c, 0x51, 0x62, 0x7a, 0xed, 0x5c, 0x8d, + 0x42, 0x63, 0xd5, 0xd2, 0xb9, 0x78, 0x87, 0x3a, + 0x0d, 0xe5, 0x96, 0xee, 0x6d, 0xc7, 0xf7, 0xc2, + 0x9e, 0x37, 0xee, 0xe8, 0xb3, 0x4c, 0x90, 0xdd, + 0x1c, 0xf6, 0xa9, 0xdd, 0xb2, 0x2b, 0x4c, 0xbd, + 0x08, 0x6b, 0x14, 0xb3, 0x5d, 0xe9, 0x3d, 0xa2, + 0xd5, 0xcb, 0x18, 0x06, 0x69, 0x8c, 0xbd, 0x7b, + 0xbb, 0x67, 0xbf, 0xe3, 0xd3, 0x1f, 0xd2, 0xd1, + 0xdb, 0xd2, 0xa1, 0xe0, 0x58, 0xa3, 0xeb, 0x99, + 0xd7, 0xe5, 0x1f, 0x1a, 0x93, 0x8e, 0xed, 0x5e, + 0x1c, 0x1d, 0xe2, 0x3a, 0x6b, 0x43, 0x45, 0xd3, + 0x19, 0x14, 0x09, 0xf9, 0x2f, 0x39, 0xb3, 0x67, + 0x0d, 0x8d, 0xbf, 0xb6, 0x35, 0xd8, 0xe6, 0xa3, + 0x69, 0x32, 0xd8, 0x10, 0x33, 0xd1, 0x44, 0x8d, + 0x63, 0xb4, 0x03, 0xdd, 0xf8, 0x8e, 0x12, 0x1b, + 0x6e, 0x81, 0x9a, 0xc3, 0x81, 0x22, 0x6c, 0x13, + 0x21, 0xe4, 0xb0, 0x86, 0x44, 0xf6, 0x72, 0x7c, + 0x36, 0x8c, 0x5a, 0x9f, 0x7a, 0x4b, 0x3e, 0xe2 + }; + + /* Reseed test: drbgvectors_pr_false/Hash_DRBG.rsp, [SHA-512], COUNT=0 */ + const byte test2SeedA[] = + { + /* EntropyInput (32 bytes) */ + 0x31, 0x44, 0xe1, 0x7a, 0x10, 0xc8, 0x56, 0x12, + 0x97, 0x64, 0xf5, 0x8f, 0xd8, 0xe4, 0x23, 0x10, + 0x20, 0x54, 0x69, 0x96, 0xc0, 0xbf, 0x6c, 0xff, + 0x8e, 0x91, 0xc2, 0x4e, 0xe0, 0x9b, 0xe3, 0x33, + /* Nonce (16 bytes) */ + 0xb1, 0x6f, 0xcb, 0x1c, 0xf0, 0xc0, 0x10, 0xf3, + 0x1f, 0xea, 0xb7, 0x33, 0x58, 0x8b, 0x8e, 0x04 + }; + const byte test2SeedB[] = + { + /* EntropyInputReseed (32 bytes) */ + 0xa0, 0xb3, 0x58, 0x4c, 0x2c, 0x84, 0x12, 0xf6, + 0x18, 0x40, 0x68, 0x34, 0x40, 0x4d, 0x1e, 0xb0, + 0xce, 0x99, 0x9b, 0xa2, 0x89, 0x66, 0x05, 0x4d, + 0x7e, 0x49, 0x7e, 0x0d, 0xb6, 0x08, 0xb9, 0x67 + }; + const byte test2Output[] = + { + 0xef, 0xa3, 0x5d, 0xd0, 0x36, 0x2a, 0xdb, 0x76, + 0x26, 0x45, 0x6b, 0x36, 0xfa, 0xc7, 0x4d, 0x3c, + 0x28, 0xd0, 0x1d, 0x92, 0x64, 0x20, 0x27, 0x5a, + 0x28, 0xbe, 0xa9, 0xc9, 0xdd, 0x75, 0x47, 0xc1, + 0x5e, 0x79, 0x31, 0x85, 0x2a, 0xc1, 0x27, 0x70, + 0x76, 0x56, 0x75, 0x35, 0x23, 0x9c, 0x1f, 0x42, + 0x9c, 0x7f, 0x75, 0xcf, 0x74, 0xc2, 0x26, 0x7d, + 0xeb, 0x6a, 0x3e, 0x59, 0x6c, 0xf3, 0x26, 0x15, + 0x6c, 0x79, 0x69, 0x41, 0x28, 0x3b, 0x8d, 0x58, + 0x3f, 0x17, 0x1c, 0x2f, 0x6e, 0x33, 0x23, 0xf7, + 0x55, 0x5e, 0x1b, 0x18, 0x1f, 0xfd, 0xa3, 0x05, + 0x07, 0x21, 0x0c, 0xb1, 0xf5, 0x89, 0xb2, 0x3c, + 0xd7, 0x18, 0x80, 0xfd, 0x44, 0x37, 0x0c, 0xac, + 0xf4, 0x33, 0x75, 0xb0, 0xdb, 0x7e, 0x33, 0x6f, + 0x12, 0xb3, 0x09, 0xbf, 0xd4, 0xf6, 0x10, 0xbb, + 0x8f, 0x20, 0xe1, 0xa1, 0x5e, 0x25, 0x3a, 0x4f, + 0xe5, 0x11, 0xa0, 0x27, 0x96, 0x8d, 0xf0, 0xb1, + 0x05, 0xa1, 0xd7, 0x3a, 0xff, 0x7c, 0x7a, 0x82, + 0x6d, 0x39, 0xf6, 0x40, 0xdf, 0xb8, 0xf5, 0x22, + 0x25, 0x9e, 0xd4, 0x02, 0x28, 0x2e, 0x2c, 0x2e, + 0x9d, 0x3a, 0x49, 0x8f, 0x51, 0x72, 0x5f, 0xe4, + 0x14, 0x1b, 0x06, 0xda, 0x55, 0x98, 0xa4, 0x2a, + 0xc1, 0xe0, 0x49, 0x4e, 0x99, 0x7d, 0x56, 0x6a, + 0x1a, 0x39, 0xb6, 0x76, 0xb9, 0x6a, 0x60, 0x03, + 0xa4, 0xc5, 0xdb, 0x84, 0xf2, 0x46, 0x58, 0x4e, + 0xe6, 0x5a, 0xf7, 0x0f, 0xf2, 0x16, 0x02, 0x78, + 0x16, 0x6d, 0xa1, 0x6d, 0x91, 0xc9, 0xb8, 0xf2, + 0xde, 0xb0, 0x27, 0x51, 0xa1, 0x08, 0x8a, 0xd6, + 0xbe, 0x4e, 0x80, 0xef, 0x96, 0x6e, 0xb7, 0x3e, + 0x66, 0xbc, 0x87, 0xca, 0xd8, 0x7c, 0x77, 0xc0, + 0xb3, 0x4a, 0x21, 0xba, 0x1d, 0xa0, 0xba, 0x6d, + 0x16, 0xca, 0x50, 0x46, 0xdc, 0x4a, 0xbd, 0xa0 + }; + + byte output[WC_SHA512_DIGEST_SIZE * 4]; /* 256 bytes */ + + /* Bad parameter tests */ + ExpectIntNE(wc_RNG_HealthTest_SHA512(0, NULL, sizeof(test1Seed), + NULL, 0, output, sizeof(output)), 0); + ExpectIntNE(wc_RNG_HealthTest_SHA512(0, test1Seed, sizeof(test1Seed), + NULL, 0, NULL, sizeof(output)), 0); + ExpectIntNE(wc_RNG_HealthTest_SHA512(0, test1Seed, sizeof(test1Seed), + NULL, 0, output, 42), 0); /* wrong output size */ + + /* Good parameter tests */ + /* No-reseed */ + ExpectIntEQ(wc_RNG_HealthTest_SHA512(0, test1Seed, sizeof(test1Seed), + NULL, 0, output, sizeof(output)), 0); + ExpectBufEQ(test1Output, output, sizeof(output)); + + /* With reseed */ + ExpectIntEQ(wc_RNG_HealthTest_SHA512(1, test2SeedA, sizeof(test2SeedA), + test2SeedB, sizeof(test2SeedB), output, sizeof(output)), 0); + ExpectBufEQ(test2Output, output, sizeof(output)); + +#endif /* HAVE_HASHDRBG && WOLFSSL_DRBG_SHA512 && !HAVE_SELFTEST && FIPS v7+ */ + return EXPECT_RESULT(); +} + diff --git a/tests/api/test_random.h b/tests/api/test_random.h index a6478b38df..0454e14c70 100644 --- a/tests/api/test_random.h +++ b/tests/api/test_random.h @@ -35,6 +35,7 @@ int test_wc_rng_new(void); int test_wc_RNG_DRBG_Reseed(void); int test_wc_RNG_TestSeed(void); int test_wc_RNG_HealthTest(void); +int test_wc_RNG_HealthTest_SHA512(void); #define TEST_RANDOM_DECLS \ TEST_DECL_GROUP("random", test_wc_InitRng), \ @@ -47,6 +48,7 @@ int test_wc_RNG_HealthTest(void); TEST_DECL_GROUP("random", test_wc_rng_new), \ TEST_DECL_GROUP("random", test_wc_RNG_DRBG_Reseed), \ TEST_DECL_GROUP("random", test_wc_RNG_TestSeed), \ - TEST_DECL_GROUP("random", test_wc_RNG_HealthTest) + TEST_DECL_GROUP("random", test_wc_RNG_HealthTest), \ + TEST_DECL_GROUP("random", test_wc_RNG_HealthTest_SHA512) #endif /* WOLFCRYPT_TEST_RANDOM_H */ diff --git a/wolfcrypt/benchmark/benchmark.c b/wolfcrypt/benchmark/benchmark.c index 5d8e8efb89..3f02fb7608 100644 --- a/wolfcrypt/benchmark/benchmark.c +++ b/wolfcrypt/benchmark/benchmark.c @@ -976,16 +976,37 @@ static WC_INLINE void bench_append_memory_info(char* buffer, size_t size, #define BENCH_SLHDSA_SHAKE192F 0x00000100 #define BENCH_SLHDSA_SHAKE256S 0x00000200 #define BENCH_SLHDSA_SHAKE256F 0x00000400 +#define BENCH_SLHDSA_SHA2_128S 0x00000800 +#define BENCH_SLHDSA_SHA2_128F 0x00001000 +#define BENCH_SLHDSA_SHA2_192S 0x00002000 +#define BENCH_SLHDSA_SHA2_192F 0x00004000 +#define BENCH_SLHDSA_SHA2_256S 0x00008000 +#define BENCH_SLHDSA_SHA2_256F 0x00010000 #define BENCH_SLHDSA (BENCH_SLHDSA_SHAKE128S | \ BENCH_SLHDSA_SHAKE128F | \ BENCH_SLHDSA_SHAKE192S | \ BENCH_SLHDSA_SHAKE192F | \ BENCH_SLHDSA_SHAKE256S | \ - BENCH_SLHDSA_SHAKE256F) + BENCH_SLHDSA_SHAKE256F | \ + BENCH_SLHDSA_SHA2_128S | \ + BENCH_SLHDSA_SHA2_128F | \ + BENCH_SLHDSA_SHA2_192S | \ + BENCH_SLHDSA_SHA2_192F | \ + BENCH_SLHDSA_SHA2_256S | \ + BENCH_SLHDSA_SHA2_256F) /* Other */ #define BENCH_RNG 0x00000001 #define BENCH_SCRYPT 0x00000002 +#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + #define BENCH_RNG_SHA512 0x00000004 +#endif +#define BENCH_RNG_INIT 0x00000008 +#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + #define BENCH_RNG_SHA512_INIT 0x00000010 +#endif #if defined(HAVE_AESGCM) || defined(HAVE_AESCCM) || \ (defined(HAVE_CHACHA) && defined(HAVE_POLY1305)) @@ -1293,6 +1314,17 @@ static const bench_alg bench_other_opt[] = { #ifndef WC_NO_RNG { "-rng", BENCH_RNG }, #endif +#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + { "-rng-sha512", BENCH_RNG_SHA512 }, +#endif +#ifndef WC_NO_RNG + { "-rng-init", BENCH_RNG_INIT }, +#endif +#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + { "-rng-sha512-init", BENCH_RNG_SHA512_INIT }, +#endif #ifdef HAVE_SCRYPT { "-scrypt", BENCH_SCRYPT }, #endif @@ -1341,6 +1373,12 @@ static const bench_pq_hash_sig_alg bench_pq_hash_sig_opt[] = { { "-slhdsa-shake192f", BENCH_SLHDSA_SHAKE192F}, { "-slhdsa-shake256s", BENCH_SLHDSA_SHAKE256S}, { "-slhdsa-shake256f", BENCH_SLHDSA_SHAKE256F}, + { "-slhdsa-sha2-128s", BENCH_SLHDSA_SHA2_128S}, + { "-slhdsa-sha2-128f", BENCH_SLHDSA_SHA2_128F}, + { "-slhdsa-sha2-192s", BENCH_SLHDSA_SHA2_192S}, + { "-slhdsa-sha2-192f", BENCH_SLHDSA_SHA2_192F}, + { "-slhdsa-sha2-256s", BENCH_SLHDSA_SHA2_256S}, + { "-slhdsa-sha2-256f", BENCH_SLHDSA_SHA2_256F}, { "-slhdsa", BENCH_SLHDSA }, #endif { NULL, 0} @@ -2058,12 +2096,7 @@ static const char* bench_result_words3[][5] = { #define BENCH_ASYM #endif -#if defined(BENCH_ASYM) -#if ((defined(HAVE_ECC) || !defined(NO_RSA) || !defined(NO_DH) || \ - defined(HAVE_CURVE25519) || defined(HAVE_ED25519) || \ - defined(HAVE_CURVE448) || defined(HAVE_ED448) || \ - defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_LMS)) && \ - !defined(WC_NO_RNG)) || defined(WOLFSSL_HAVE_MLKEM) +#if !defined(WC_NO_RNG) || defined(WOLFSSL_HAVE_MLKEM) static const char* bench_result_words2[][6] = { #ifdef BENCH_MICROSECOND { "ops took", "μsec" , "avg" , "ops/μsec", "cycles/op", @@ -2077,8 +2110,7 @@ static const char* bench_result_words2[][6] = { NULL }, /* 1 Japanese */ #endif }; -#endif -#endif +#endif /* !WC_NO_RNG || WOLFSSL_HAVE_MLKEM */ #ifdef WOLFSSL_CAAM #include @@ -3202,6 +3234,102 @@ static void bench_stats_sym_finish(const char* desc, int useDeviceID, TEST_SLEEP(); } /* bench_stats_sym_finish */ +#ifndef WC_NO_RNG +/* Report ops/sec in the same format as bench_stats_asym_finish, but without + * requiring BENCH_ASYM to be defined. Used for benchmarks like RNG init/free + * that measure operation counts rather than byte throughput. */ +static void bench_stats_ops_finish(const char* algo, int strength, + const char* desc, int count, double start, int ret) +{ + double total, each = 0, opsSec, milliEach; + const char **word = bench_result_words2[lng_index]; + char msg[256]; +#ifdef BENCH_MICROSECOND + const int digits = 5; +#else + const int digits = 3; +#endif + + XMEMSET(msg, 0, sizeof(msg)); + + total = current_time(0) - start; + +#ifdef WOLFSSL_ESPIDF + END_ESP_CYCLES +#else + END_CYCLES +#endif + + if (count > 0) + each = total / count; + if (total > 0) + opsSec = count / total; + else + opsSec = 0; + +#ifdef BENCH_MICROSECOND + milliEach = each / 1000; +#else + milliEach = each * 1000; +#endif + + SLEEP_ON_ERROR(ret); + + if (csv_format == 1) { + (void)XSNPRINTF(msg, sizeof(msg), "%s,%d,%s," FLT_FMT_PREC "," + FLT_FMT_PREC "," STATS_CLAUSE_SEPARATOR, + algo, strength, desc, + FLT_FMT_PREC_ARGS(3, milliEach), + FLT_FMT_PREC_ARGS(digits, opsSec)); + } + else { +#ifdef HAVE_GET_CYCLES + (void)XSNPRINTF(msg, sizeof(msg), + "%-6s %5d %8s %6d %s " FLT_FMT_PREC2 " %s, %s " + FLT_FMT_PREC2 " ms, " FLT_FMT_PREC2 " %s, %lu cycles", + algo, strength, desc, + count, word[0], + FLT_FMT_PREC2_ARGS(5, 3, total), word[1], word[2], + FLT_FMT_PREC2_ARGS(5, 3, milliEach), + FLT_FMT_PREC2_ARGS(digits + 6, digits, opsSec), + word[3], (unsigned long)total_cycles); +#else + (void)XSNPRINTF(msg, sizeof(msg), + "%-6s %5d %8s %6d %s " FLT_FMT_PREC2 " %s, %s " + FLT_FMT_PREC2 " ms, " FLT_FMT_PREC2 " %s", + algo, strength, desc, + count, word[0], + FLT_FMT_PREC2_ARGS(5, 3, total), word[1], word[2], + FLT_FMT_PREC2_ARGS(5, 3, milliEach), + FLT_FMT_PREC2_ARGS(digits + 6, digits, opsSec), + word[3]); +#endif + +#ifdef WOLFSSL_ESPIDF + SHOW_ESP_CYCLES_OPS(msg, sizeof(msg)); +#else + SHOW_CYCLES_OPS(msg, sizeof(msg)); +#endif + } + + printf("%s", msg); + + if (ret < 0) { + printf("%sBenchmark %s %s %d failed: %d\n", + err_prefix, algo, desc, strength, ret); + } + +#ifndef WOLFSSL_SGX + XFFLUSH(stdout); +#endif + + (void)ret; + + bench_stats_prepare(); + TEST_SLEEP(); +} /* bench_stats_ops_finish */ +#endif /* !WC_NO_RNG */ + #ifdef BENCH_ASYM #if ((defined(HAVE_ECC) || !defined(NO_RSA) || !defined(NO_DH) || \ defined(HAVE_CURVE25519) || defined(HAVE_ED25519) || \ @@ -3839,6 +3967,12 @@ static void* benchmarks_do(void* args) if (bench_all || (bench_other_algs & BENCH_RNG)) bench_rng(); #endif /* WC_NO_RNG */ +#if defined(WOLFSSL_DRBG_SHA512) && !defined(WC_NO_RNG) && \ + !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + if (bench_all || (bench_other_algs & BENCH_RNG_SHA512)) + bench_rng_sha512(); +#endif #ifndef NO_AES #ifdef HAVE_AES_CBC if (bench_all || (bench_cipher_algs & BENCH_AES_CBC)) { @@ -4401,6 +4535,36 @@ static void* benchmarks_do(void* args) bench_slhdsa(SLHDSA_SHAKE256F); } #endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128S + if (bench_pq_hash_sig_algs & BENCH_SLHDSA_SHA2_128S) { + bench_slhdsa(SLHDSA_SHA2_128S); + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128F + if (bench_pq_hash_sig_algs & BENCH_SLHDSA_SHA2_128F) { + bench_slhdsa(SLHDSA_SHA2_128F); + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192S + if (bench_pq_hash_sig_algs & BENCH_SLHDSA_SHA2_192S) { + bench_slhdsa(SLHDSA_SHA2_192S); + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192F + if (bench_pq_hash_sig_algs & BENCH_SLHDSA_SHA2_192F) { + bench_slhdsa(SLHDSA_SHA2_192F); + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256S + if (bench_pq_hash_sig_algs & BENCH_SLHDSA_SHA2_256S) { + bench_slhdsa(SLHDSA_SHA2_256S); + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256F + if (bench_pq_hash_sig_algs & BENCH_SLHDSA_SHA2_256F) { + bench_slhdsa(SLHDSA_SHA2_256F); + } +#endif #endif (void)bench_pq_hash_sig_algs; @@ -4601,6 +4765,16 @@ static void* benchmarks_do(void* args) bench_sphincsKeySign(5, SMALL_VARIANT); #endif +#ifndef WC_NO_RNG + if (bench_all || (bench_other_algs & BENCH_RNG_INIT)) + bench_rng_init(); +#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + if (bench_all || (bench_other_algs & BENCH_RNG_SHA512_INIT)) + bench_rng_sha512_init(); +#endif +#endif + exit: /* free benchmark buffers */ XFREE(bench_plain, HEAP_HINT, DYNAMIC_TYPE_WOLF_BIGINT); @@ -4733,6 +4907,19 @@ int benchmark_init(void) wc_SetSeed_Cb(WC_GENERATE_SEED_DEFAULT); #endif +#if defined(HAVE_FIPS) && FIPS_VERSION3_GE(7,0,0) + /* Pre-run all CASTs so their overhead is not captured in benchmark + * metrics. Without this, the first use of each algorithm triggers + * its CAST on-demand, inflating that algorithm's benchmark numbers. */ + { + int castRet = wc_RunAllCast_fips(); + if (castRet != 0) { + printf("%swc_RunAllCast_fips: %d CAST(s) failed, module in " + "DEGRADED mode\n", err_prefix, castRet); + } + } +#endif + bench_stats_init(); #if defined(DEBUG_WOLFSSL) && !defined(HAVE_VALGRIND) @@ -4947,6 +5134,21 @@ void bench_rng(void) WC_RNG myrng; DECLARE_MULTI_VALUE_STATS_VARS() + /* Force SHA-256 DRBG by temporarily disabling SHA-512 DRBG */ +#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + #if !defined(NO_SHA256) + ret = wc_Sha512Drbg_Disable(); + if (ret != 0) { + printf("wc_Sha512Drbg_Disable failed %d\n", ret); + return; + } + #else + printf("RNG SHA-256 DRBG (Skipped: Disabled)\n"); + return; + #endif +#endif + bench_stats_prepare(); #ifndef HAVE_FIPS @@ -4955,7 +5157,11 @@ void bench_rng(void) ret = wc_InitRng(&myrng); #endif if (ret < 0) { - printf("InitRNG failed %d\n", ret); + printf("InitRNG (SHA-256) failed %d\n", ret); +#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + wc_Sha512Drbg_Enable(); +#endif return; } @@ -4986,15 +5192,204 @@ void bench_rng(void) #endif ); exit_rng: - bench_stats_sym_finish("RNG", 0, count, bench_size, start, ret); + bench_stats_sym_finish("RNG SHA-256 DRBG", 0, count, bench_size, start, + ret); #ifdef MULTI_VALUE_STATISTICS bench_multi_value_stats(max, min, sum, squareSum, runs); #endif wc_FreeRng(&myrng); + + /* Restore SHA-512 DRBG */ +#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + wc_Sha512Drbg_Enable(); +#endif } #endif /* WC_NO_RNG */ +#if defined(WOLFSSL_DRBG_SHA512) && !defined(WC_NO_RNG) && \ + !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) +void bench_rng_sha512(void) +{ + int ret, i, count; + double start; + long pos, len, remain; + WC_RNG myrng; + DECLARE_MULTI_VALUE_STATS_VARS() + + /* Force SHA-512 DRBG by temporarily disabling SHA-256 DRBG */ +#ifndef NO_SHA256 + ret = wc_Sha256Drbg_Disable(); + if (ret != 0) { + printf("wc_Sha256Drbg_Disable failed %d\n", ret); + return; + } +#endif + + bench_stats_prepare(); + +#ifndef HAVE_FIPS + ret = wc_InitRng_ex(&myrng, HEAP_HINT, devId); +#else + ret = wc_InitRng(&myrng); +#endif + if (ret < 0) { + printf("InitRNG (SHA-512) failed %d\n", ret); +#ifndef NO_SHA256 + wc_Sha256Drbg_Enable(); +#endif + return; + } + + bench_stats_start(&count, &start); + do { + for (i = 0; i < numBlocks; i++) { + /* Split request to handle large RNG request */ + pos = 0; + remain = (int)bench_size; + while (remain > 0) { + len = remain; + if (len > RNG_MAX_BLOCK_LEN) + len = RNG_MAX_BLOCK_LEN; + ret = wc_RNG_GenerateBlock(&myrng, &bench_plain[pos], + (word32)len); + if (ret < 0) + goto exit_rng_sha512; + + remain -= len; + pos += len; + } + RECORD_MULTI_VALUE_STATS(); + } + count += i; + } while (bench_stats_check(start) +#ifdef MULTI_VALUE_STATISTICS + || runs < minimum_runs +#endif + ); +exit_rng_sha512: + bench_stats_sym_finish("RNG SHA-512 DRBG", 0, count, bench_size, start, + ret); +#ifdef MULTI_VALUE_STATISTICS + bench_multi_value_stats(max, min, sum, squareSum, runs); +#endif + + wc_FreeRng(&myrng); + + /* Restore SHA-256 DRBG */ +#ifndef NO_SHA256 + wc_Sha256Drbg_Enable(); +#endif +} +#endif /* WOLFSSL_DRBG_SHA512 && !WC_NO_RNG && !HAVE_SELFTEST && FIPS v7+ */ + +#ifndef WC_NO_RNG +void bench_rng_init(void) +{ + int ret, count; + double start; + WC_RNG myrng; + DECLARE_MULTI_VALUE_STATS_VARS() + + /* Force SHA-256 DRBG by temporarily disabling SHA-512 DRBG */ +#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + #if !defined(NO_SHA256) + ret = wc_Sha512Drbg_Disable(); + if (ret != 0) { + printf("wc_Sha512Drbg_Disable failed %d\n", ret); + return; + } + #else + printf("RNG SHA-256 Init/Free (Skipped: Disabled)\n"); + return; + #endif +#endif + + bench_stats_start(&count, &start); + do { + #ifndef HAVE_FIPS + ret = wc_InitRng_ex(&myrng, HEAP_HINT, devId); + #else + ret = wc_InitRng(&myrng); + #endif + if (ret < 0) { + printf("InitRNG (SHA-256 init bench) failed %d\n", ret); + goto exit_rng_init; + } + wc_FreeRng(&myrng); + count++; + RECORD_MULTI_VALUE_STATS(); + } while (bench_stats_check(start) +#ifdef MULTI_VALUE_STATISTICS + || runs < minimum_runs +#endif + ); +exit_rng_init: + bench_stats_ops_finish("RNG", 256, "SHA256 Init/Free", count, start, ret); +#ifdef MULTI_VALUE_STATISTICS + bench_multi_value_stats(max, min, sum, squareSum, runs); +#endif + + /* Restore SHA-512 DRBG */ +#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + wc_Sha512Drbg_Enable(); +#endif +} + +#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) +void bench_rng_sha512_init(void) +{ + int ret, count; + double start; + WC_RNG myrng; + DECLARE_MULTI_VALUE_STATS_VARS() + + /* Force SHA-512 DRBG by temporarily disabling SHA-256 DRBG */ +#ifndef NO_SHA256 + ret = wc_Sha256Drbg_Disable(); + if (ret != 0) { + printf("wc_Sha256Drbg_Disable failed %d\n", ret); + return; + } +#endif + + bench_stats_start(&count, &start); + do { + #ifndef HAVE_FIPS + ret = wc_InitRng_ex(&myrng, HEAP_HINT, devId); + #else + ret = wc_InitRng(&myrng); + #endif + if (ret < 0) { + printf("InitRNG (SHA-512 init bench) failed %d\n", ret); + goto exit_rng_sha512_init; + } + wc_FreeRng(&myrng); + count++; + RECORD_MULTI_VALUE_STATS(); + } while (bench_stats_check(start) +#ifdef MULTI_VALUE_STATISTICS + || runs < minimum_runs +#endif + ); +exit_rng_sha512_init: + bench_stats_ops_finish("RNG", 512, "SHA512 Init/Free", count, start, ret); +#ifdef MULTI_VALUE_STATISTICS + bench_multi_value_stats(max, min, sum, squareSum, runs); +#endif + + /* Restore SHA-256 DRBG */ +#ifndef NO_SHA256 + wc_Sha256Drbg_Enable(); +#endif +} +#endif /* WOLFSSL_DRBG_SHA512 && !HAVE_SELFTEST && FIPS v7+ */ +#endif /* !WC_NO_RNG */ /* ============================================================================ * Benchmark init helpers -- use id[] when WC_TEST_*_ID is defined and @@ -10851,6 +11246,7 @@ exit_encap: RESET_MULTI_VALUE_STATS_VARS(); /* MLKEM Decapsulate */ + PRIVATE_KEY_UNLOCK(); bench_stats_start(&count, &start); do { /* while free pending slots in queue, submit ops */ @@ -10868,6 +11264,7 @@ exit_encap: ); exit_decap: + PRIVATE_KEY_LOCK(); bench_stats_asym_finish(name, keySize, desc[13], 0, count, start, ret); #ifdef MULTI_VALUE_STATISTICS bench_multi_value_stats(max, min, sum, squareSum, runs); @@ -11360,6 +11757,13 @@ static void bench_lms_sign_verify(enum wc_LmsParm parm, byte* pub) case WC_LMS_PARM_L4_H5_W4: case WC_LMS_PARM_L4_H10_W4: case WC_LMS_PARM_L4_H10_W8: + case WC_LMS_PARM_L1_H25_W1: + case WC_LMS_PARM_L1_H25_W2: + case WC_LMS_PARM_L1_H25_W4: + case WC_LMS_PARM_L1_H25_W8: + case WC_LMS_PARM_L1_H10_W1: + case WC_LMS_PARM_L1_H15_W1: + case WC_LMS_PARM_L1_H20_W1: #endif #ifdef WOLFSSL_LMS_SHA256_192 @@ -11383,6 +11787,57 @@ static void bench_lms_sign_verify(enum wc_LmsParm parm, byte* pub) case WC_LMS_PARM_SHA256_192_L3_H5_W8: case WC_LMS_PARM_SHA256_192_L3_H10_W4: case WC_LMS_PARM_SHA256_192_L4_H5_W8: + case WC_LMS_PARM_SHA256_192_L1_H25_W1: + case WC_LMS_PARM_SHA256_192_L1_H25_W2: + case WC_LMS_PARM_SHA256_192_L1_H25_W4: + case WC_LMS_PARM_SHA256_192_L1_H25_W8: + case WC_LMS_PARM_SHA256_192_L1_H10_W1: + case WC_LMS_PARM_SHA256_192_L1_H15_W1: + case WC_LMS_PARM_SHA256_192_L1_H20_W1: + case WC_LMS_PARM_SHA256_192_L1_H15_W8: +#endif + +#ifdef WOLFSSL_LMS_SHAKE256 + case WC_LMS_PARM_SHAKE_L1_H5_W1: + case WC_LMS_PARM_SHAKE_L1_H5_W2: + case WC_LMS_PARM_SHAKE_L1_H5_W4: + case WC_LMS_PARM_SHAKE_L1_H5_W8: + case WC_LMS_PARM_SHAKE_L1_H10_W1: + case WC_LMS_PARM_SHAKE_L1_H10_W2: + case WC_LMS_PARM_SHAKE_L1_H10_W4: + case WC_LMS_PARM_SHAKE_L1_H10_W8: + case WC_LMS_PARM_SHAKE_L1_H15_W1: + case WC_LMS_PARM_SHAKE_L1_H15_W2: + case WC_LMS_PARM_SHAKE_L1_H15_W4: + case WC_LMS_PARM_SHAKE_L1_H15_W8: + case WC_LMS_PARM_SHAKE_L1_H20_W1: + case WC_LMS_PARM_SHAKE_L1_H20_W2: + case WC_LMS_PARM_SHAKE_L1_H20_W4: + case WC_LMS_PARM_SHAKE_L1_H20_W8: + case WC_LMS_PARM_SHAKE_L1_H25_W1: + case WC_LMS_PARM_SHAKE_L1_H25_W2: + case WC_LMS_PARM_SHAKE_L1_H25_W4: + case WC_LMS_PARM_SHAKE_L1_H25_W8: + case WC_LMS_PARM_SHAKE192_L1_H5_W1: + case WC_LMS_PARM_SHAKE192_L1_H5_W2: + case WC_LMS_PARM_SHAKE192_L1_H5_W4: + case WC_LMS_PARM_SHAKE192_L1_H5_W8: + case WC_LMS_PARM_SHAKE192_L1_H10_W1: + case WC_LMS_PARM_SHAKE192_L1_H10_W2: + case WC_LMS_PARM_SHAKE192_L1_H10_W4: + case WC_LMS_PARM_SHAKE192_L1_H10_W8: + case WC_LMS_PARM_SHAKE192_L1_H15_W1: + case WC_LMS_PARM_SHAKE192_L1_H15_W2: + case WC_LMS_PARM_SHAKE192_L1_H15_W4: + case WC_LMS_PARM_SHAKE192_L1_H15_W8: + case WC_LMS_PARM_SHAKE192_L1_H20_W1: + case WC_LMS_PARM_SHAKE192_L1_H20_W2: + case WC_LMS_PARM_SHAKE192_L1_H20_W4: + case WC_LMS_PARM_SHAKE192_L1_H20_W8: + case WC_LMS_PARM_SHAKE192_L1_H25_W1: + case WC_LMS_PARM_SHAKE192_L1_H25_W2: + case WC_LMS_PARM_SHAKE192_L1_H25_W4: + case WC_LMS_PARM_SHAKE192_L1_H25_W8: #endif default: @@ -12207,9 +12662,17 @@ void bench_slhdsa(enum SlhDsaParam param) } len = wc_SlhDsaKey_PublicSize(key) / 2 * 8; - XMEMCPY(name, "SLH-DSA-S", 10); - if ((param & 1) == 1) { - name[8] = 'F'; + if (SLHDSA_IS_SHA2(param)) { + XMEMCPY(name, "SLH-DSA-SHA2-S", 15); + if ((param & 1) == 1) { + name[13] = 'F'; + } + } + else { + XMEMCPY(name, "SLH-DSA-S", 10); + if ((param & 1) == 1) { + name[8] = 'F'; + } } bench_stats_start(&count, &start); @@ -12227,6 +12690,7 @@ void bench_slhdsa(enum SlhDsaParam param) ); bench_stats_asym_finish(name, len, "gen", 0, count, start, ret); + PRIVATE_KEY_UNLOCK(); bench_stats_start(&count, &start); do { sigLen = WC_SLHDSA_MAX_SIG_LEN; @@ -12242,6 +12706,7 @@ void bench_slhdsa(enum SlhDsaParam param) || runs < minimum_runs #endif ); + PRIVATE_KEY_LOCK(); bench_stats_asym_finish(name, len, "sign", 0, count, start, ret); outLen = (word32)sizeof(pk); @@ -12274,6 +12739,78 @@ void bench_slhdsa(enum SlhDsaParam param) ); bench_stats_asym_finish(name, len, "verify", 0, count, start, ret); + /* Internal interface: sign M' directly (no M' construction). */ + PRIVATE_KEY_UNLOCK(); + bench_stats_start(&count, &start); + do { + sigLen = WC_SLHDSA_MAX_SIG_LEN; + ret = wc_SlhDsaKey_SignMsgDeterministic(key, msg, + (word32)sizeof(msg), sig, &sigLen); + if (ret != 0) { + goto exit; + } + count++; + RECORD_MULTI_VALUE_STATS(); + } while (bench_stats_check(start) +#ifdef MULTI_VALUE_STATISTICS + || runs < minimum_runs +#endif + ); + PRIVATE_KEY_LOCK(); + bench_stats_asym_finish(name, len, "sign-msg", 0, count, start, ret); + + bench_stats_start(&count, &start); + do { + ret = wc_SlhDsaKey_VerifyMsg(key_vfy, msg, (word32)sizeof(msg), + sig, sigLen); + if (ret != 0) { + goto exit; + } + count++; + RECORD_MULTI_VALUE_STATS(); + } while (bench_stats_check(start) +#ifdef MULTI_VALUE_STATISTICS + || runs < minimum_runs +#endif + ); + bench_stats_asym_finish(name, len, "vrfy-msg", 0, count, start, ret); + + /* Pre-hash interface: hash message, then sign the hash. */ + PRIVATE_KEY_UNLOCK(); + bench_stats_start(&count, &start); + do { + sigLen = WC_SLHDSA_MAX_SIG_LEN; + ret = wc_SlhDsaKey_SignHashDeterministic(key, ctx, 0, msg, + (word32)sizeof(msg), WC_HASH_TYPE_SHA256, sig, &sigLen); + if (ret != 0) { + goto exit; + } + count++; + RECORD_MULTI_VALUE_STATS(); + } while (bench_stats_check(start) +#ifdef MULTI_VALUE_STATISTICS + || runs < minimum_runs +#endif + ); + PRIVATE_KEY_LOCK(); + bench_stats_asym_finish(name, len, "sign-pre", 0, count, start, ret); + + bench_stats_start(&count, &start); + do { + ret = wc_SlhDsaKey_VerifyHash(key_vfy, ctx, 0, msg, + (word32)sizeof(msg), WC_HASH_TYPE_SHA256, sig, sigLen); + if (ret != 0) { + goto exit; + } + count++; + RECORD_MULTI_VALUE_STATS(); + } while (bench_stats_check(start) +#ifdef MULTI_VALUE_STATISTICS + || runs < minimum_runs +#endif + ); + bench_stats_asym_finish(name, len, "vrfy-pre", 0, count, start, ret); + exit: #ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC if (key_vfy) @@ -15663,6 +16200,7 @@ void bench_dilithiumKeySign(byte level) #elif !defined WOLFSSL_DILITHIUM_NO_SIGN + PRIVATE_KEY_UNLOCK(); #ifndef WOLFSSL_NO_ML_DSA_44 if (level == 2) { ret = wc_dilithium_import_private(bench_dilithium_level2_key, @@ -15681,6 +16219,7 @@ void bench_dilithiumKeySign(byte level) sizeof_bench_dilithium_level5_key, key); } #endif + PRIVATE_KEY_LOCK(); if (ret != 0) { printf("Failed to load private key\n"); goto out; diff --git a/wolfcrypt/benchmark/benchmark.h b/wolfcrypt/benchmark/benchmark.h index dc97fe6837..7b291b2588 100644 --- a/wolfcrypt/benchmark/benchmark.h +++ b/wolfcrypt/benchmark/benchmark.h @@ -130,6 +130,13 @@ void bench_sakkeRskGen(void); void bench_sakkeValidate(void); void bench_sakke(void); void bench_rng(void); +void bench_rng_init(void); +#if defined(WOLFSSL_DRBG_SHA512) && !defined(WC_NO_RNG) && \ + !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) +void bench_rng_sha512(void); +void bench_rng_sha512_init(void); +#endif void bench_blake2b(void); void bench_blake2s(void); void bench_ascon_hash(void); diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 176e39c2fd..9a3be56616 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -4466,6 +4466,12 @@ static int ParseCRL_Extensions(DecodedCRL* dcrl, const byte* buf, word32* inOutI #ifndef WOLFSSL_NOSHA3_512 static const byte hashSha3_512hOid[] = {96, 134, 72, 1, 101, 3, 4, 2, 10}; #endif /* WOLFSSL_NOSHA3_512 */ +#ifdef WOLFSSL_SHAKE128 + static const byte hashShake128hOid[] = {96, 134, 72, 1, 101, 3, 4, 2, 11}; +#endif /* WOLFSSL_SHAKE128 */ +#ifdef WOLFSSL_SHAKE256 + static const byte hashShake256hOid[] = {96, 134, 72, 1, 101, 3, 4, 2, 12}; +#endif /* WOLFSSL_SHAKE256 */ #endif /* WOLFSSL_SHA3 */ /* hmacType */ @@ -5339,6 +5345,18 @@ const byte* OidFromId(word32 id, word32 type, word32* oidSz) *oidSz = sizeof(hashSha3_512hOid); break; #endif /* WOLFSSL_NOSHA3_512 */ + #ifdef WOLFSSL_SHAKE128 + case SHAKE128h: + oid = hashShake128hOid; + *oidSz = sizeof(hashShake128hOid); + break; + #endif /* WOLFSSL_SHAKE128 */ + #ifdef WOLFSSL_SHAKE256 + case SHAKE256h: + oid = hashShake256hOid; + *oidSz = sizeof(hashShake256hOid); + break; + #endif /* WOLFSSL_SHAKE256 */ #endif /* WOLFSSL_SHA3 */ default: break; diff --git a/wolfcrypt/src/dh.c b/wolfcrypt/src/dh.c index 72b8717a56..5e2863c343 100644 --- a/wolfcrypt/src/dh.c +++ b/wolfcrypt/src/dh.c @@ -1063,6 +1063,11 @@ static int CheckDhLN(word32 modLen, word32 divLen) if (divLen == 224 || divLen == 256) ret = 0; break; + /* Per SP 800-56Ar3 Table 2 */ + case 3072: + if (divLen == 256) + ret = 0; + break; default: break; } diff --git a/wolfcrypt/src/dilithium.c b/wolfcrypt/src/dilithium.c index 633d623f0b..15e512a3d9 100644 --- a/wolfcrypt/src/dilithium.c +++ b/wolfcrypt/src/dilithium.c @@ -138,6 +138,11 @@ #include +#if FIPS_VERSION3_GE(2,0,0) + /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */ + #define FIPS_NO_WRAPPERS +#endif + #ifndef WOLFSSL_DILITHIUM_NO_ASN1 #include #endif @@ -814,6 +819,15 @@ static int dilithium_get_hash_oid(int hash, byte* oidBuffer, word32* oidLen) oid = sha512Oid; } else +#ifndef WOLFSSL_NOSHA512_224 + if (hash == WC_HASH_TYPE_SHA512_224) { + static byte sha512_224Oid[DILITHIUM_HASH_OID_LEN] = { + 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x05 + }; + oid = sha512_224Oid; + } + else +#endif #ifndef WOLFSSL_NOSHA512_256 if (hash == WC_HASH_TYPE_SHA512_256) { static byte sha512_256Oid[DILITHIUM_HASH_OID_LEN] = { @@ -9520,7 +9534,7 @@ static void dilithium_make_pub_vec(dilithium_key* key, sword32* t1) * @return MEMORY_E when memory allocation fails. * @return Other negative when an error occurs. */ -static int dilithium_verify_mu(dilithium_key* key, const byte* mu, +static int dilithium_verify_with_mu(dilithium_key* key, const byte* mu, const byte* sig, word32 sigLen, int* res) { #ifndef WOLFSSL_DILITHIUM_VERIFY_SMALL_MEM @@ -9979,7 +9993,7 @@ static int dilithium_verify_ctx_msg(dilithium_key* key, const byte* ctx, ctx, (byte)ctxLen, msg, msgLen, mu, DILITHIUM_MU_SZ); } if (ret == 0) { - ret = dilithium_verify_mu(key, mu, sig, sigLen, res); + ret = dilithium_verify_with_mu(key, mu, sig, sigLen, res); } return ret; @@ -10023,7 +10037,7 @@ static int dilithium_verify_msg(dilithium_key* key, const byte* msg, mu, DILITHIUM_MU_SZ); } if (ret == 0) { - ret = dilithium_verify_mu(key, mu, sig, sigLen, res); + ret = dilithium_verify_with_mu(key, mu, sig, sigLen, res); } return ret; @@ -10085,7 +10099,7 @@ static int dilithium_verify_ctx_hash(dilithium_key* key, const byte* ctx, ctx, (byte)ctxLen, oidMsgHash, oidMsgHashLen, mu, DILITHIUM_MU_SZ); } if (ret == 0) { - ret = dilithium_verify_mu(key, mu, sig, sigLen, res); + ret = dilithium_verify_with_mu(key, mu, sig, sigLen, res); } return ret; @@ -10310,6 +10324,45 @@ int wc_dilithium_make_key(dilithium_key* key, WC_RNG* rng) #endif } +#ifdef HAVE_FIPS + /* Pairwise Consistency Test (PCT) per FIPS 140-3 / ISO 19790:2012 + * Section 7.10.3.3 (TE10.35.02): sign with new sk, verify with pk. + * Runs on every key generation. */ + if (ret == 0) { + static const byte pct_msg[] = "wolfSSL ML-DSA PCT"; + WC_DECLARE_VAR(pct_sig, byte, DILITHIUM_MAX_SIG_SIZE, key->heap); + word32 pct_sigSz = DILITHIUM_MAX_SIG_SIZE; + int pct_res = 0; + + WC_ALLOC_VAR_EX(pct_sig, byte, DILITHIUM_MAX_SIG_SIZE, key->heap, + DYNAMIC_TYPE_DILITHIUM, ret = MEMORY_E); + + if (ret == 0) { + ret = wc_dilithium_sign_ctx_msg(NULL, 0, pct_msg, sizeof(pct_msg), + pct_sig, &pct_sigSz, key, rng); + } + + if (ret == 0) + ret = wc_dilithium_verify_ctx_msg(pct_sig, pct_sigSz, + NULL, 0, pct_msg, sizeof(pct_msg), &pct_res, key); + + if (ret == 0 && pct_res != 1) + ret = ML_DSA_PCT_E; + + if (WC_VAR_OK(pct_sig)) + ForceZero(pct_sig, DILITHIUM_MAX_SIG_SIZE); + + WC_FREE_VAR_EX(pct_sig, key->heap, DYNAMIC_TYPE_DILITHIUM); + + /* FIPS 140-3 IG 10.3.A (TE10.35.02): a key pair that fails the PCT + * must be rendered unusable. Zeroize the generated key material so + * a caller that ignores the return value cannot use it. */ + if (ret != 0) { + wc_dilithium_free(key); + } + } +#endif /* HAVE_FIPS */ + return ret; } @@ -10338,6 +10391,9 @@ int wc_dilithium_make_key_from_seed(dilithium_key* key, const byte* seed) #endif } + /* Note: PCT is performed in wc_dilithium_make_key() which calls this + * function and has the RNG parameter needed for signing. */ + return ret; } #endif @@ -10627,7 +10683,8 @@ int wc_dilithium_sign_ctx_hash_with_seed(const byte* ctx, byte ctxLen, int ret = 0; /* Validate parameters. */ - if ((hash == NULL) || (sig == NULL) || (sigLen == NULL) || (key == NULL)) { + if ((hash == NULL) || (sig == NULL) || (sigLen == NULL) || (key == NULL) || + (seed == NULL)) { ret = BAD_FUNC_ARG; } if ((ret == 0) && (ctx == NULL) && (ctxLen > 0)) { @@ -10650,6 +10707,60 @@ int wc_dilithium_sign_ctx_hash_with_seed(const byte* ctx, byte ctxLen, return ret; } + +/* Sign using the ML-DSA internal interface with a pre-computed mu value. + * + * This implements ML-DSA.Sign_internal from FIPS 204 Section 6.2. + * The caller provides mu directly (already computed from tr||M'), bypassing + * the external message hashing step. Used by ACVP internal interface tests. + * + * mu [in] Pre-computed mu value (64 bytes). + * muLen [in] Length of mu in bytes (must be 64). + * sig [out] Buffer to write signature into. + * sigLen [in/out] On in, size of buffer. + * On out, the length of the signature in bytes. + * key [in] Dilithium key to use when signing. + * seed [in] 32-byte random seed (rnd). + * returns BAD_FUNC_ARG when a parameter is NULL or muLen is not 64, + * BUFFER_E when sigLen is too small, + * 0 otherwise. + */ +int wc_dilithium_sign_mu_with_seed(const byte* mu, word32 muLen, + byte* sig, word32 *sigLen, dilithium_key* key, const byte* seed) +{ +#ifdef WOLFSSL_WC_DILITHIUM + int ret = 0; + + /* Validate parameters. */ + if ((mu == NULL) || (sig == NULL) || (sigLen == NULL) || (key == NULL) || + (seed == NULL)) { + ret = BAD_FUNC_ARG; + } + if ((ret == 0) && (muLen != DILITHIUM_MU_SZ)) { + ret = BAD_FUNC_ARG; + } + + if (ret == 0) { + /* Build [seed||mu] buffer and call internal sign function. */ + byte seedMu[DILITHIUM_RND_SZ + DILITHIUM_MU_SZ]; + XMEMCPY(seedMu, seed, DILITHIUM_RND_SZ); + XMEMCPY(seedMu + DILITHIUM_RND_SZ, mu, DILITHIUM_MU_SZ); + ret = dilithium_sign_with_seed_mu(key, seedMu, sig, sigLen); + ForceZero(seedMu, sizeof(seedMu)); + } + + return ret; +#else + /* Internal interface not supported with liboqs backend. */ + (void)mu; + (void)muLen; + (void)sig; + (void)sigLen; + (void)key; + (void)seed; + return NOT_COMPILED_IN; +#endif +} #endif /* !WOLFSSL_DILITHIUM_NO_SIGN */ #ifndef WOLFSSL_DILITHIUM_NO_VERIFY @@ -10830,6 +10941,52 @@ int wc_dilithium_verify_ctx_hash(const byte* sig, word32 sigLen, return ret; } + +/* Verify using the ML-DSA internal interface with a pre-computed mu value. + * + * This implements ML-DSA.Verify_internal from FIPS 204 Section 6.3. + * The caller provides mu directly (already computed from tr||M'), bypassing + * the external message hashing step. Used by ACVP internal interface tests. + * + * sig [in] Signature to verify. + * sigLen [in] Size of signature in bytes. + * mu [in] Pre-computed mu value (64 bytes). + * muLen [in] Length of mu in bytes (must be 64). + * res [out] *res is set to 1 on successful verification. + * key [in] Dilithium key to use to verify. + * returns BAD_FUNC_ARG when a parameter is NULL or muLen is not 64, + * 0 otherwise. + */ +int wc_dilithium_verify_mu(const byte* sig, word32 sigLen, const byte* mu, + word32 muLen, int* res, dilithium_key* key) +{ +#ifdef WOLFSSL_WC_DILITHIUM + int ret = 0; + + /* Validate parameters. */ + if ((key == NULL) || (sig == NULL) || (mu == NULL) || (res == NULL)) { + ret = BAD_FUNC_ARG; + } + if ((ret == 0) && (muLen != DILITHIUM_MU_SZ)) { + ret = BAD_FUNC_ARG; + } + + if (ret == 0) { + ret = dilithium_verify_with_mu(key, mu, sig, sigLen, res); + } + + return ret; +#else + /* Internal interface not supported with liboqs backend. */ + (void)sig; + (void)sigLen; + (void)mu; + (void)muLen; + (void)res; + (void)key; + return NOT_COMPILED_IN; +#endif +} #endif /* WOLFSSL_DILITHIUM_NO_VERIFY */ #ifndef WC_NO_CONSTRUCTORS diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 573a690140..61f840f3cf 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -6091,6 +6091,12 @@ int wc_ecc_make_key_ex2(WC_RNG* rng, int keysize, ecc_key* key, int curve_id, ) { err = _ecc_pairwise_consistency_test(key, rng); } + /* FIPS 140-3 IG 10.3.A (TE10.35.02): a key pair that fails post- + * generation validation or PCT must be rendered unusable so a caller + * that ignores the return value cannot use it. */ + if (err != MP_OKAY) { + wc_ecc_free(key); + } #endif RESTORE_VECTOR_REGISTERS(); diff --git a/wolfcrypt/src/error.c b/wolfcrypt/src/error.c index f676c23bad..8826d9b198 100644 --- a/wolfcrypt/src/error.c +++ b/wolfcrypt/src/error.c @@ -668,6 +668,30 @@ const char* wc_GetErrorString(int error) case ALREADY_E: return "Operation was redundant or preempted"; + case ML_KEM_KAT_FIPS_E: + return "wolfCrypt FIPS ML-KEM Known Answer Test Failure"; + + case ML_DSA_KAT_FIPS_E: + return "wolfCrypt FIPS ML-DSA Known Answer Test Failure"; + + case LMS_KAT_FIPS_E: + return "wolfCrypt FIPS LMS Known Answer Test Failure"; + + case XMSS_KAT_FIPS_E: + return "wolfCrypt FIPS XMSS Known Answer Test Failure"; + + case ML_KEM_PCT_E: + return "wolfcrypt ML-KEM Pairwise Consistency Test Failure"; + + case ML_DSA_PCT_E: + return "wolfcrypt ML-DSA Pairwise Consistency Test Failure"; + + case DRBG_SHA512_KAT_FIPS_E: + return "SHA-512 DRBG Known Answer Test check FIPS error"; + + case SLH_DSA_KAT_FIPS_E: + return "SLH-DSA Known Answer Test check FIPS error"; + case SEQ_OVERFLOW_E: return "Sequence counter would overflow"; diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index 40bca5578f..2e7bd9841e 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -5809,8 +5809,9 @@ void wolfSSL_EVP_init(void) #endif /* WOLFSSL_SHA512 */ break; case WC_HASH_TYPE_SHA512_224: - #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ - defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_224) + #if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512) && \ + !defined(WOLFSSL_NOSHA512_224) ret = wc_Sha512_224Copy((wc_Sha512*)&src->hash.digest, (wc_Sha512*)&des->hash.digest); #else @@ -5818,8 +5819,9 @@ void wolfSSL_EVP_init(void) #endif break; case WC_HASH_TYPE_SHA512_256: - #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ - defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_256) + #if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512) && \ + !defined(WOLFSSL_NOSHA512_256) ret = wc_Sha512_256Copy((wc_Sha512*)&src->hash.digest, (wc_Sha512*)&des->hash.digest); #else @@ -10765,14 +10767,16 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type) #endif /* WOLFSSL_SHA512 */ break; case WC_HASH_TYPE_SHA512_224: - #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ - defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_224) + #if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512) && \ + !defined(WOLFSSL_NOSHA512_224) wc_Sha512_224Free((wc_Sha512*)&ctx->hash.digest); #endif break; case WC_HASH_TYPE_SHA512_256: - #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ - defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_256) + #if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512) && \ + !defined(WOLFSSL_NOSHA512_256) wc_Sha512_256Free((wc_Sha512*)&ctx->hash.digest); #endif break; @@ -10872,13 +10876,15 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type) ret = wolfSSL_SHA384_Init(&(ctx->hash.digest.sha384)); } else #endif - #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ + #if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && \ defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_224) if (XSTRCMP(md, WC_SN_sha512_224) == 0) { ret = wolfSSL_SHA512_224_Init(&(ctx->hash.digest.sha512)); } else #endif - #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ + #if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && \ defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_256) if (XSTRCMP(md, WC_SN_sha512_256) == 0) { ret = wolfSSL_SHA512_256_Init(&(ctx->hash.digest.sha512)); @@ -11028,8 +11034,9 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type) break; case WC_HASH_TYPE_SHA512_224: - #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ - defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_224) + #if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512) && \ + !defined(WOLFSSL_NOSHA512_224) ret = wolfSSL_SHA512_224_Update((WOLFSSL_SHA512_CTX*)&ctx->hash, data, (unsigned long)sz); #else @@ -11038,8 +11045,9 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type) break; case WC_HASH_TYPE_SHA512_256: - #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ - defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_256) + #if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512) && \ + !defined(WOLFSSL_NOSHA512_256) ret = wolfSSL_SHA512_256_Update((WOLFSSL_SHA512_CTX*)&ctx->hash, data, (unsigned long)sz); #else @@ -11188,8 +11196,9 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type) #endif /* WOLFSSL_SHA512 */ break; case WC_HASH_TYPE_SHA512_224: - #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ - defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_224) + #if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512) && \ + !defined(WOLFSSL_NOSHA512_224) ret = wolfSSL_SHA512_224_Final(md, (WOLFSSL_SHA512_CTX*)&ctx->hash); if (s) *s = WC_SHA512_224_DIGEST_SIZE; #else @@ -11197,8 +11206,9 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type) #endif break; case WC_HASH_TYPE_SHA512_256: - #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ - defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_256) + #if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512) && \ + !defined(WOLFSSL_NOSHA512_256) ret = wolfSSL_SHA512_256_Final(md, (WOLFSSL_SHA512_CTX*)&ctx->hash); if (s) *s = WC_SHA512_256_DIGEST_SIZE; #else diff --git a/wolfcrypt/src/ext_lms.c b/wolfcrypt/src/ext_lms.c index c953abcfb3..a36fc6579f 100644 --- a/wolfcrypt/src/ext_lms.c +++ b/wolfcrypt/src/ext_lms.c @@ -226,6 +226,20 @@ const char * wc_LmsKey_ParmToStr(enum wc_LmsParm lmsParm) return "LMS/HSS L4_H10_W4"; case WC_LMS_PARM_L4_H10_W8: return "LMS/HSS L4_H10_W8"; + case WC_LMS_PARM_L1_H25_W1: + return "LMS/HSS L1_H25_W1"; + case WC_LMS_PARM_L1_H25_W2: + return "LMS/HSS L1_H25_W2"; + case WC_LMS_PARM_L1_H25_W4: + return "LMS/HSS L1_H25_W4"; + case WC_LMS_PARM_L1_H25_W8: + return "LMS/HSS L1_H25_W8"; + case WC_LMS_PARM_L1_H10_W1: + return "LMS/HSS L1_H10_W1"; + case WC_LMS_PARM_L1_H15_W1: + return "LMS/HSS L1_H15_W1"; + case WC_LMS_PARM_L1_H20_W1: + return "LMS/HSS L1_H20_W1"; default: WOLFSSL_MSG("error: invalid LMS parameter"); break; @@ -383,6 +397,20 @@ int wc_LmsKey_SetLmsParm(LmsKey * key, enum wc_LmsParm lmsParm) return wc_LmsKey_SetParameters(key, 4, 10, 4); case WC_LMS_PARM_L4_H10_W8: return wc_LmsKey_SetParameters(key, 4, 10, 8); + case WC_LMS_PARM_L1_H25_W1: + return wc_LmsKey_SetParameters(key, 1, 25, 1); + case WC_LMS_PARM_L1_H25_W2: + return wc_LmsKey_SetParameters(key, 1, 25, 2); + case WC_LMS_PARM_L1_H25_W4: + return wc_LmsKey_SetParameters(key, 1, 25, 4); + case WC_LMS_PARM_L1_H25_W8: + return wc_LmsKey_SetParameters(key, 1, 25, 8); + case WC_LMS_PARM_L1_H10_W1: + return wc_LmsKey_SetParameters(key, 1, 10, 1); + case WC_LMS_PARM_L1_H15_W1: + return wc_LmsKey_SetParameters(key, 1, 15, 1); + case WC_LMS_PARM_L1_H20_W1: + return wc_LmsKey_SetParameters(key, 1, 20, 1); default: WOLFSSL_MSG("error: invalid LMS parameter set"); break; diff --git a/wolfcrypt/src/ext_mlkem.c b/wolfcrypt/src/ext_mlkem.c index 91634f494f..90ffbb1662 100644 --- a/wolfcrypt/src/ext_mlkem.c +++ b/wolfcrypt/src/ext_mlkem.c @@ -22,6 +22,12 @@ #include #if defined(WOLFSSL_HAVE_MLKEM) && !defined(WOLFSSL_WC_MLKEM) + +#if FIPS_VERSION3_GE(2,0,0) + /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */ + #define FIPS_NO_WRAPPERS +#endif + #include #ifdef NO_INLINE diff --git a/wolfcrypt/src/hash.c b/wolfcrypt/src/hash.c index 86a01999a1..8e8c33c708 100644 --- a/wolfcrypt/src/hash.c +++ b/wolfcrypt/src/hash.c @@ -79,7 +79,16 @@ enum wc_HashType wc_HashTypeConvert(int hashType) case WC_SHA512: eHashType = WC_HASH_TYPE_SHA512; break; - + #if !defined(WOLFSSL_NOSHA512_224) + case WC_SHA512_224: + eHashType = WC_HASH_TYPE_SHA512_224; + break; + #endif + #if !defined(WOLFSSL_NOSHA512_256) + case WC_SHA512_256: + eHashType = WC_HASH_TYPE_SHA512_256; + break; + #endif #endif /* WOLFSSL_SHA512 */ #ifdef WOLFSSL_SHA3 case WC_SHA3_224: @@ -424,16 +433,18 @@ int wc_HashGetDigestSize(enum wc_HashType hash_type) #endif break; case WC_HASH_TYPE_SHA512_224: - #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ - defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_224) + #if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512) && \ + !defined(WOLFSSL_NOSHA512_224) dig_size = WC_SHA512_224_DIGEST_SIZE; #else dig_size = HASH_TYPE_E; #endif break; case WC_HASH_TYPE_SHA512_256: - #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ - defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_256) + #if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512) && \ + !defined(WOLFSSL_NOSHA512_256) dig_size = WC_SHA512_256_DIGEST_SIZE; #else dig_size = HASH_TYPE_E; @@ -498,14 +509,29 @@ int wc_HashGetDigestSize(enum wc_HashType hash_type) #endif break; - /* Not Supported */ + #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128) + /* SHAKE is an XOF; default output here is 2x the security level + * (256 bits for SHAKE128, 512 bits for SHAKE256). The SHA3 digest + * macros are reused only for their bit-length value. */ + case WC_HASH_TYPE_SHAKE128: + dig_size = WC_SHA3_256_DIGEST_SIZE; + break; + #else case WC_HASH_TYPE_SHAKE128: dig_size = HASH_TYPE_E; break; + #endif + #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256) + case WC_HASH_TYPE_SHAKE256: + dig_size = WC_SHA3_512_DIGEST_SIZE; + break; + #else case WC_HASH_TYPE_SHAKE256: dig_size = HASH_TYPE_E; break; + #endif + /* Not Supported */ case WC_HASH_TYPE_NONE: dig_size = BAD_FUNC_ARG; break; @@ -580,16 +606,18 @@ int wc_HashGetBlockSize(enum wc_HashType hash_type) #endif break; case WC_HASH_TYPE_SHA512_224: - #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ - defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_224) + #if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512) && \ + !defined(WOLFSSL_NOSHA512_224) block_size = WC_SHA512_224_BLOCK_SIZE; #else block_size = HASH_TYPE_E; #endif break; case WC_HASH_TYPE_SHA512_256: - #if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ - defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_256) + #if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512) && \ + !defined(WOLFSSL_NOSHA512_256) block_size = WC_SHA512_256_BLOCK_SIZE; #else block_size = HASH_TYPE_E; @@ -654,14 +682,30 @@ int wc_HashGetBlockSize(enum wc_HashType hash_type) #endif break; - /* Not Supported */ + #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128) + /* WC_SHA3_*_BLOCK_SIZE names the Keccak rate by capacity, not a + * specific SHA-3 hash. SHAKE128 uses the 1344-bit rate (168 B); + * SHAKE256 uses the 1088-bit rate (136 B), shared with SHA3-256. + * Per FIPS 202. */ + case WC_HASH_TYPE_SHAKE128: + block_size = WC_SHA3_128_BLOCK_SIZE; + break; + #else case WC_HASH_TYPE_SHAKE128: block_size = HASH_TYPE_E; break; + #endif + #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256) + case WC_HASH_TYPE_SHAKE256: + block_size = WC_SHA3_256_BLOCK_SIZE; + break; + #else case WC_HASH_TYPE_SHAKE256: block_size = HASH_TYPE_E; break; + #endif + /* Not Supported */ case WC_HASH_TYPE_NONE: block_size = BAD_FUNC_ARG; break; @@ -740,16 +784,18 @@ int wc_Hash_ex(enum wc_HashType hash_type, const byte* data, #endif break; case WC_HASH_TYPE_SHA512_224: -#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ - defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_224) +#if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512) && \ + !defined(WOLFSSL_NOSHA512_224) ret = wc_Sha512_224Hash_ex(data, data_len, hash, heap, devId); #else ret = HASH_TYPE_E; #endif break; case WC_HASH_TYPE_SHA512_256: -#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ - defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_224) +#if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512) && \ + !defined(WOLFSSL_NOSHA512_256) ret = wc_Sha512_256Hash_ex(data, data_len, hash, heap, devId); #else ret = HASH_TYPE_E; @@ -804,26 +850,62 @@ int wc_Hash_ex(enum wc_HashType hash_type, const byte* data, #endif break; - /* Not Supported */ - case WC_HASH_TYPE_MD2: - ret = HASH_TYPE_E; - break; - case WC_HASH_TYPE_MD4: - ret = HASH_TYPE_E; - break; - case WC_HASH_TYPE_BLAKE2B: - ret = HASH_TYPE_E; - break; - case WC_HASH_TYPE_BLAKE2S: - ret = HASH_TYPE_E; + #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128) + case WC_HASH_TYPE_SHAKE128: + { + WC_DECLARE_VAR(shake, wc_Shake, 1, heap); + WC_ALLOC_VAR_EX(shake, wc_Shake, 1, heap, DYNAMIC_TYPE_TMP_BUFFER, + ret = MEMORY_E); + if (WC_VAR_OK(shake)) { + ret = wc_InitShake128(shake, heap, devId); + if (ret == 0) { + ret = wc_Shake128_Update(shake, data, data_len); + if (ret == 0) + ret = wc_Shake128_Final(shake, hash, + WC_SHA3_256_DIGEST_SIZE); + wc_Shake128_Free(shake); + } + } + WC_FREE_VAR_EX(shake, heap, DYNAMIC_TYPE_TMP_BUFFER); break; + } + #else case WC_HASH_TYPE_SHAKE128: ret = HASH_TYPE_E; break; + #endif + #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256) + case WC_HASH_TYPE_SHAKE256: + { + WC_DECLARE_VAR(shake, wc_Shake, 1, heap); + WC_ALLOC_VAR_EX(shake, wc_Shake, 1, heap, DYNAMIC_TYPE_TMP_BUFFER, + ret = MEMORY_E); + if (WC_VAR_OK(shake)) { + ret = wc_InitShake256(shake, heap, devId); + if (ret == 0) { + ret = wc_Shake256_Update(shake, data, data_len); + if (ret == 0) + ret = wc_Shake256_Final(shake, hash, + WC_SHA3_512_DIGEST_SIZE); + wc_Shake256_Free(shake); + } + } + WC_FREE_VAR_EX(shake, heap, DYNAMIC_TYPE_TMP_BUFFER); + break; + } + #else case WC_HASH_TYPE_SHAKE256: ret = HASH_TYPE_E; break; + #endif + /* Not Supported */ + case WC_HASH_TYPE_MD2: + case WC_HASH_TYPE_MD4: + case WC_HASH_TYPE_BLAKE2B: + case WC_HASH_TYPE_BLAKE2S: + ret = HASH_TYPE_E; + break; case WC_HASH_TYPE_NONE: ret = BAD_FUNC_ARG; break; @@ -940,16 +1022,18 @@ int wc_HashInit_ex(wc_HashAlg* hash, enum wc_HashType type, void* heap, #endif break; case WC_HASH_TYPE_SHA512_224: -#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ - defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_224) +#if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512) && \ + !defined(WOLFSSL_NOSHA512_224) ret = wc_InitSha512_224_ex(&hash->alg.sha512, heap, devId); #else ret = HASH_TYPE_E; #endif break; case WC_HASH_TYPE_SHA512_256: -#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ - defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_256) +#if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512) && \ + !defined(WOLFSSL_NOSHA512_256) ret = wc_InitSha512_256_ex(&hash->alg.sha512, heap, devId); #else ret = HASH_TYPE_E; @@ -992,29 +1076,33 @@ int wc_HashInit_ex(wc_HashAlg* hash, enum wc_HashType type, void* heap, #endif break; - /* not supported */ - case WC_HASH_TYPE_MD5_SHA: - ret = HASH_TYPE_E; - break; - case WC_HASH_TYPE_MD2: - ret = HASH_TYPE_E; - break; - case WC_HASH_TYPE_MD4: - ret = HASH_TYPE_E; - break; - case WC_HASH_TYPE_BLAKE2B: - ret = HASH_TYPE_E; - break; - case WC_HASH_TYPE_BLAKE2S: - ret = HASH_TYPE_E; + #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128) + case WC_HASH_TYPE_SHAKE128: + ret = wc_InitShake128(&hash->alg.sha3, heap, devId); break; + #else case WC_HASH_TYPE_SHAKE128: ret = HASH_TYPE_E; break; + #endif + #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256) + case WC_HASH_TYPE_SHAKE256: + ret = wc_InitShake256(&hash->alg.sha3, heap, devId); + break; + #else case WC_HASH_TYPE_SHAKE256: ret = HASH_TYPE_E; break; + #endif + /* not supported */ + case WC_HASH_TYPE_MD5_SHA: + case WC_HASH_TYPE_MD2: + case WC_HASH_TYPE_MD4: + case WC_HASH_TYPE_BLAKE2B: + case WC_HASH_TYPE_BLAKE2S: + ret = HASH_TYPE_E; + break; case WC_HASH_TYPE_NONE: ret = BAD_FUNC_ARG; break; @@ -1091,16 +1179,18 @@ int wc_HashUpdate(wc_HashAlg* hash, enum wc_HashType type, const byte* data, #endif break; case WC_HASH_TYPE_SHA512_224: -#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ - defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_224) +#if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512) && \ + !defined(WOLFSSL_NOSHA512_224) ret = wc_Sha512_224Update(&hash->alg.sha512, data, dataSz); #else ret = HASH_TYPE_E; #endif break; case WC_HASH_TYPE_SHA512_256: -#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ - defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_256) +#if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512) && \ + !defined(WOLFSSL_NOSHA512_256) ret = wc_Sha512_256Update(&hash->alg.sha512, data, dataSz); #else ret = HASH_TYPE_E; @@ -1143,29 +1233,33 @@ int wc_HashUpdate(wc_HashAlg* hash, enum wc_HashType type, const byte* data, #endif break; - /* not supported */ - case WC_HASH_TYPE_MD5_SHA: - ret = HASH_TYPE_E; - break; - case WC_HASH_TYPE_MD2: - ret = HASH_TYPE_E; - break; - case WC_HASH_TYPE_MD4: - ret = HASH_TYPE_E; - break; - case WC_HASH_TYPE_BLAKE2B: - ret = HASH_TYPE_E; - break; - case WC_HASH_TYPE_BLAKE2S: - ret = HASH_TYPE_E; + #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128) + case WC_HASH_TYPE_SHAKE128: + ret = wc_Shake128_Update(&hash->alg.sha3, data, dataSz); break; + #else case WC_HASH_TYPE_SHAKE128: ret = HASH_TYPE_E; break; + #endif + #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256) + case WC_HASH_TYPE_SHAKE256: + ret = wc_Shake256_Update(&hash->alg.sha3, data, dataSz); + break; + #else case WC_HASH_TYPE_SHAKE256: ret = HASH_TYPE_E; break; + #endif + /* not supported */ + case WC_HASH_TYPE_MD5_SHA: + case WC_HASH_TYPE_MD2: + case WC_HASH_TYPE_MD4: + case WC_HASH_TYPE_BLAKE2B: + case WC_HASH_TYPE_BLAKE2S: + ret = HASH_TYPE_E; + break; case WC_HASH_TYPE_NONE: ret = BAD_FUNC_ARG; break; @@ -1234,16 +1328,18 @@ int wc_HashFinal(wc_HashAlg* hash, enum wc_HashType type, byte* out) #endif break; case WC_HASH_TYPE_SHA512_224: -#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ - defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_224) +#if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512) && \ + !defined(WOLFSSL_NOSHA512_224) ret = wc_Sha512_224Final(&hash->alg.sha512, out); #else ret = HASH_TYPE_E; #endif break; case WC_HASH_TYPE_SHA512_256: -#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ - defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_256) +#if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512) && \ + !defined(WOLFSSL_NOSHA512_256) ret = wc_Sha512_256Final(&hash->alg.sha512, out); #else ret = HASH_TYPE_E; @@ -1286,29 +1382,35 @@ int wc_HashFinal(wc_HashAlg* hash, enum wc_HashType type, byte* out) #endif break; - /* not supported */ - case WC_HASH_TYPE_MD5_SHA: - ret = HASH_TYPE_E; - break; - case WC_HASH_TYPE_MD2: - ret = HASH_TYPE_E; - break; - case WC_HASH_TYPE_MD4: - ret = HASH_TYPE_E; - break; - case WC_HASH_TYPE_BLAKE2B: - ret = HASH_TYPE_E; - break; - case WC_HASH_TYPE_BLAKE2S: - ret = HASH_TYPE_E; + #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128) + case WC_HASH_TYPE_SHAKE128: + ret = wc_Shake128_Final(&hash->alg.sha3, out, + WC_SHA3_256_DIGEST_SIZE); break; + #else case WC_HASH_TYPE_SHAKE128: ret = HASH_TYPE_E; break; + #endif + #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256) + case WC_HASH_TYPE_SHAKE256: + ret = wc_Shake256_Final(&hash->alg.sha3, out, + WC_SHA3_512_DIGEST_SIZE); + break; + #else case WC_HASH_TYPE_SHAKE256: ret = HASH_TYPE_E; break; + #endif + /* not supported */ + case WC_HASH_TYPE_MD5_SHA: + case WC_HASH_TYPE_MD2: + case WC_HASH_TYPE_MD4: + case WC_HASH_TYPE_BLAKE2B: + case WC_HASH_TYPE_BLAKE2S: + ret = HASH_TYPE_E; + break; case WC_HASH_TYPE_NONE: ret = BAD_FUNC_ARG; break; @@ -1383,8 +1485,9 @@ int wc_HashFree(wc_HashAlg* hash, enum wc_HashType type) #endif break; case WC_HASH_TYPE_SHA512_224: -#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ - defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_224) +#if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512) && \ + !defined(WOLFSSL_NOSHA512_224) wc_Sha512_224Free(&hash->alg.sha512); ret = 0; #else @@ -1392,8 +1495,9 @@ int wc_HashFree(wc_HashAlg* hash, enum wc_HashType type) #endif break; case WC_HASH_TYPE_SHA512_256: -#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ - defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_256) +#if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && \ + !defined(HAVE_SELFTEST) && defined(WOLFSSL_SHA512) && \ + !defined(WOLFSSL_NOSHA512_256) wc_Sha512_256Free(&hash->alg.sha512); ret = 0; #else @@ -1442,29 +1546,35 @@ int wc_HashFree(wc_HashAlg* hash, enum wc_HashType type) #endif break; - /* not supported */ - case WC_HASH_TYPE_MD5_SHA: - ret = HASH_TYPE_E; - break; - case WC_HASH_TYPE_MD2: - ret = HASH_TYPE_E; - break; - case WC_HASH_TYPE_MD4: - ret = HASH_TYPE_E; - break; - case WC_HASH_TYPE_BLAKE2B: - ret = HASH_TYPE_E; - break; - case WC_HASH_TYPE_BLAKE2S: - ret = HASH_TYPE_E; + #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128) + case WC_HASH_TYPE_SHAKE128: + wc_Shake128_Free(&hash->alg.sha3); + ret = 0; break; + #else case WC_HASH_TYPE_SHAKE128: ret = HASH_TYPE_E; break; + #endif + #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256) + case WC_HASH_TYPE_SHAKE256: + wc_Shake256_Free(&hash->alg.sha3); + ret = 0; + break; + #else case WC_HASH_TYPE_SHAKE256: ret = HASH_TYPE_E; break; + #endif + /* not supported */ + case WC_HASH_TYPE_MD5_SHA: + case WC_HASH_TYPE_MD2: + case WC_HASH_TYPE_MD4: + case WC_HASH_TYPE_BLAKE2B: + case WC_HASH_TYPE_BLAKE2S: + ret = HASH_TYPE_E; + break; case WC_HASH_TYPE_NONE: ret = BAD_FUNC_ARG; break; @@ -1554,6 +1664,22 @@ int wc_HashSetFlags(wc_HashAlg* hash, enum wc_HashType type, word32 flags) #endif break; + case WC_HASH_TYPE_SHAKE128: +#if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128) + ret = wc_Sha3_SetFlags(&hash->alg.sha3, flags); +#else + ret = HASH_TYPE_E; +#endif + break; + + case WC_HASH_TYPE_SHAKE256: +#if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256) + ret = wc_Sha3_SetFlags(&hash->alg.sha3, flags); +#else + ret = HASH_TYPE_E; +#endif + break; + case WC_HASH_TYPE_SM3: #ifdef WOLFSSL_SM3 ret = wc_Sm3SetFlags(&hash->alg.sm3, flags); @@ -1564,30 +1690,13 @@ int wc_HashSetFlags(wc_HashAlg* hash, enum wc_HashType type, word32 flags) /* not supported */ case WC_HASH_TYPE_MD5_SHA: - ret = HASH_TYPE_E; - break; case WC_HASH_TYPE_MD2: - ret = HASH_TYPE_E; - break; case WC_HASH_TYPE_MD4: - ret = HASH_TYPE_E; - break; case WC_HASH_TYPE_BLAKE2B: - ret = HASH_TYPE_E; - break; case WC_HASH_TYPE_BLAKE2S: ret = HASH_TYPE_E; break; - case WC_HASH_TYPE_SHAKE128: - ret = HASH_TYPE_E; - break; - case WC_HASH_TYPE_SHAKE256: - ret = HASH_TYPE_E; - break; - case WC_HASH_TYPE_NONE: - ret = BAD_FUNC_ARG; - break; default: ret = BAD_FUNC_ARG; }; @@ -1670,6 +1779,22 @@ int wc_HashGetFlags(wc_HashAlg* hash, enum wc_HashType type, word32* flags) #endif break; + case WC_HASH_TYPE_SHAKE128: +#if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128) + ret = wc_Sha3_GetFlags(&hash->alg.sha3, flags); +#else + ret = HASH_TYPE_E; +#endif + break; + + case WC_HASH_TYPE_SHAKE256: +#if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256) + ret = wc_Sha3_GetFlags(&hash->alg.sha3, flags); +#else + ret = HASH_TYPE_E; +#endif + break; + case WC_HASH_TYPE_SM3: #ifdef WOLFSSL_SM3 ret = wc_Sm3GetFlags(&hash->alg.sm3, flags); @@ -1680,27 +1805,12 @@ int wc_HashGetFlags(wc_HashAlg* hash, enum wc_HashType type, word32* flags) /* not supported */ case WC_HASH_TYPE_MD5_SHA: - ret = HASH_TYPE_E; - break; case WC_HASH_TYPE_MD2: - ret = HASH_TYPE_E; - break; case WC_HASH_TYPE_MD4: - ret = HASH_TYPE_E; - break; case WC_HASH_TYPE_BLAKE2B: - ret = HASH_TYPE_E; - break; case WC_HASH_TYPE_BLAKE2S: ret = HASH_TYPE_E; break; - case WC_HASH_TYPE_SHAKE128: - ret = HASH_TYPE_E; - break; - case WC_HASH_TYPE_SHAKE256: - ret = HASH_TYPE_E; - break; - case WC_HASH_TYPE_NONE: ret = BAD_FUNC_ARG; break; @@ -1927,7 +2037,7 @@ int wc_HashGetFlags(wc_HashAlg* hash, enum wc_HashType type, word32* flags) #endif return wc_Sha512Hash_ex(data, len, hash, NULL, devId); } -#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) +#if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && !defined(HAVE_SELFTEST) #ifndef WOLFSSL_NOSHA512_224 int wc_Sha512_224Hash_ex(const byte* data, word32 len, byte* hash, void* heap, int devId) @@ -1967,9 +2077,9 @@ int wc_HashGetFlags(wc_HashAlg* hash, enum wc_HashType type, word32* flags) return wc_Sha512_224Hash_ex(data, len, hash, NULL, devId); } #endif /* !WOLFSSL_NOSHA512_224 */ -#endif /* !HAVE_FIPS && !HAVE_SELFTEST */ +#endif /* (!HAVE_FIPS || FIPS v7+) && !HAVE_SELFTEST */ -#if !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) +#if (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) && !defined(HAVE_SELFTEST) #ifndef WOLFSSL_NOSHA512_256 int wc_Sha512_256Hash_ex(const byte* data, word32 len, byte* hash, void* heap, int devId) @@ -2009,7 +2119,7 @@ int wc_HashGetFlags(wc_HashAlg* hash, enum wc_HashType type, word32* flags) return wc_Sha512_256Hash_ex(data, len, hash, NULL, devId); } #endif /* !WOLFSSL_NOSHA512_256 */ -#endif /* !HAVE_FIPS && !HAVE_SELFTEST */ +#endif /* (!HAVE_FIPS || FIPS v7+) && !HAVE_SELFTEST */ #endif /* WOLFSSL_SHA512 */ diff --git a/wolfcrypt/src/hmac.c b/wolfcrypt/src/hmac.c index cd59087bdc..b18c0e0e49 100644 --- a/wolfcrypt/src/hmac.c +++ b/wolfcrypt/src/hmac.c @@ -87,6 +87,12 @@ int wc_HmacSizeByType(int type) if (!(type == WC_MD5 || type == WC_SHA || #ifdef WOLFSSL_SM3 type == WC_SM3 || + #endif + #ifndef WOLFSSL_NOSHA512_224 + type == WC_SHA512_224 || + #endif + #ifndef WOLFSSL_NOSHA512_256 + type == WC_SHA512_256 || #endif type == WC_SHA224 || type == WC_SHA256 || type == WC_SHA384 || type == WC_SHA512 || @@ -129,6 +135,16 @@ int wc_HmacSizeByType(int type) case WC_SHA512: ret = WC_SHA512_DIGEST_SIZE; break; + #ifndef WOLFSSL_NOSHA512_224 + case WC_SHA512_224: + ret = WC_SHA512_224_DIGEST_SIZE; + break; + #endif + #ifndef WOLFSSL_NOSHA512_256 + case WC_SHA512_256: + ret = WC_SHA512_256_DIGEST_SIZE; + break; + #endif #endif /* WOLFSSL_SHA512 */ #ifdef WOLFSSL_SHA3 @@ -201,6 +217,16 @@ static int HmacKeyInitHash(wc_HmacHash* hash, int type, void* heap, int devId) case WC_SHA512: ret = wc_InitSha512_ex(&hash->sha512, heap, devId); break; + #ifndef WOLFSSL_NOSHA512_224 + case WC_SHA512_224: + ret = wc_InitSha512_224_ex(&hash->sha512, heap, devId); + break; + #endif + #ifndef WOLFSSL_NOSHA512_256 + case WC_SHA512_256: + ret = wc_InitSha512_256_ex(&hash->sha512, heap, devId); + break; + #endif #endif /* WOLFSSL_SHA512 */ #ifdef WOLFSSL_SHA3 @@ -300,6 +326,16 @@ static int HmacKeyCopyHash(byte macType, wc_HmacHash* src, wc_HmacHash* dst) case WC_SHA512: ret = wc_Sha512Copy(&src->sha512, &dst->sha512); break; + #ifndef WOLFSSL_NOSHA512_224 + case WC_SHA512_224: + ret = wc_Sha512_224Copy(&src->sha512, &dst->sha512); + break; + #endif + #ifndef WOLFSSL_NOSHA512_256 + case WC_SHA512_256: + ret = wc_Sha512_256Copy(&src->sha512, &dst->sha512); + break; + #endif #endif /* WOLFSSL_SHA512 */ #ifdef WOLFSSL_SHA3 @@ -395,6 +431,18 @@ static int HmacKeyHashUpdate(byte macType, wc_HmacHash* hash, byte* pad) case WC_SHA512: ret = wc_Sha512Update(&hash->sha512, pad, WC_SHA512_BLOCK_SIZE); break; + #ifndef WOLFSSL_NOSHA512_224 + case WC_SHA512_224: + ret = wc_Sha512_224Update(&hash->sha512, pad, + WC_SHA512_224_BLOCK_SIZE); + break; + #endif + #ifndef WOLFSSL_NOSHA512_256 + case WC_SHA512_256: + ret = wc_Sha512_256Update(&hash->sha512, pad, + WC_SHA512_256_BLOCK_SIZE); + break; + #endif #endif /* WOLFSSL_SHA512 */ #ifdef WOLFSSL_SHA3 @@ -478,6 +526,12 @@ int wc_HmacSetKey_ex(Hmac* hmac, int type, const byte* key, word32 length, !(type == WC_MD5 || type == WC_SHA || #ifdef WOLFSSL_SM3 type == WC_SM3 || + #endif + #ifndef WOLFSSL_NOSHA512_224 + type == WC_SHA512_224 || + #endif + #ifndef WOLFSSL_NOSHA512_256 + type == WC_SHA512_256 || #endif type == WC_SHA224 || type == WC_SHA256 || type == WC_SHA384 || type == WC_SHA512 || @@ -747,6 +801,46 @@ int wc_HmacSetKey_ex(Hmac* hmac, int type, const byte* key, word32 length, length = WC_SHA512_DIGEST_SIZE; } break; + #ifndef WOLFSSL_NOSHA512_224 + case WC_SHA512_224: + hmac_block_size = WC_SHA512_224_BLOCK_SIZE; + if (length <= WC_SHA512_224_BLOCK_SIZE) { + if (key != NULL) { + XMEMCPY(ip, key, length); + } + } + else { + ret = wc_Sha512_224Update(&hmac->hash.sha512, key, length); + if (ret != 0) + break; + ret = wc_Sha512_224Final(&hmac->hash.sha512, ip); + if (ret != 0) + break; + + length = WC_SHA512_224_DIGEST_SIZE; + } + break; + #endif + #ifndef WOLFSSL_NOSHA512_256 + case WC_SHA512_256: + hmac_block_size = WC_SHA512_256_BLOCK_SIZE; + if (length <= WC_SHA512_256_BLOCK_SIZE) { + if (key != NULL) { + XMEMCPY(ip, key, length); + } + } + else { + ret = wc_Sha512_256Update(&hmac->hash.sha512, key, length); + if (ret != 0) + break; + ret = wc_Sha512_256Final(&hmac->hash.sha512, ip); + if (ret != 0) + break; + + length = WC_SHA512_256_DIGEST_SIZE; + } + break; + #endif #endif /* WOLFSSL_SHA512 */ #ifdef WOLFSSL_SHA3 @@ -999,6 +1093,16 @@ int wc_HmacUpdate(Hmac* hmac, const byte* msg, word32 length) case WC_SHA512: ret = wc_Sha512Update(&hmac->hash.sha512, msg, length); break; + #ifndef WOLFSSL_NOSHA512_224 + case WC_SHA512_224: + ret = wc_Sha512_224Update(&hmac->hash.sha512, msg, length); + break; + #endif + #ifndef WOLFSSL_NOSHA512_256 + case WC_SHA512_256: + ret = wc_Sha512_256Update(&hmac->hash.sha512, msg, length); + break; + #endif #endif /* WOLFSSL_SHA512 */ #ifdef WOLFSSL_SHA3 @@ -1226,6 +1330,48 @@ int wc_HmacFinal(Hmac* hmac, byte* hash) break; ret = wc_Sha512Final(&hmac->hash.sha512, hash); break; + #ifndef WOLFSSL_NOSHA512_224 + case WC_SHA512_224: + ret = wc_Sha512_224Final(&hmac->hash.sha512, + (byte*)hmac->innerHash); + if (ret != 0) + break; + #ifndef WOLFSSL_HMAC_COPY_HASH + ret = wc_Sha512_224Update(&hmac->hash.sha512, (byte*)hmac->opad, + WC_SHA512_224_BLOCK_SIZE); + #else + ret = HmacKeyCopyHash(WC_SHA512_224, &hmac->o_hash, &hmac->hash); + #endif + if (ret != 0) + break; + ret = wc_Sha512_224Update(&hmac->hash.sha512, + (byte*)hmac->innerHash, WC_SHA512_224_DIGEST_SIZE); + if (ret != 0) + break; + ret = wc_Sha512_224Final(&hmac->hash.sha512, hash); + break; + #endif + #ifndef WOLFSSL_NOSHA512_256 + case WC_SHA512_256: + ret = wc_Sha512_256Final(&hmac->hash.sha512, + (byte*)hmac->innerHash); + if (ret != 0) + break; + #ifndef WOLFSSL_HMAC_COPY_HASH + ret = wc_Sha512_256Update(&hmac->hash.sha512, (byte*)hmac->opad, + WC_SHA512_256_BLOCK_SIZE); + #else + ret = HmacKeyCopyHash(WC_SHA512_256, &hmac->o_hash, &hmac->hash); + #endif + if (ret != 0) + break; + ret = wc_Sha512_256Update(&hmac->hash.sha512, + (byte*)hmac->innerHash, WC_SHA512_256_DIGEST_SIZE); + if (ret != 0) + break; + ret = wc_Sha512_256Final(&hmac->hash.sha512, hash); + break; + #endif #endif /* WOLFSSL_SHA512 */ #ifdef WOLFSSL_SHA3 @@ -1505,6 +1651,24 @@ void wc_HmacFree(Hmac* hmac) wc_Sha512Free(&hmac->o_hash.sha512); #endif break; + #ifndef WOLFSSL_NOSHA512_224 + case WC_SHA512_224: + wc_Sha512_224Free(&hmac->hash.sha512); + #ifdef WOLFSSL_HMAC_COPY_HASH + wc_Sha512_224Free(&hmac->i_hash.sha512); + wc_Sha512_224Free(&hmac->o_hash.sha512); + #endif + break; + #endif + #ifndef WOLFSSL_NOSHA512_256 + case WC_SHA512_256: + wc_Sha512_256Free(&hmac->hash.sha512); + #ifdef WOLFSSL_HMAC_COPY_HASH + wc_Sha512_256Free(&hmac->i_hash.sha512); + wc_Sha512_256Free(&hmac->o_hash.sha512); + #endif + break; + #endif #endif /* WOLFSSL_SHA512 */ #ifdef WOLFSSL_SHA3 diff --git a/wolfcrypt/src/random.c b/wolfcrypt/src/random.c index e15c9ce9b1..42437fd524 100644 --- a/wolfcrypt/src/random.c +++ b/wolfcrypt/src/random.c @@ -133,7 +133,12 @@ This library contains implementation for the random number generator. #ifndef WC_NO_RNG /* if not FIPS and RNG is disabled then do not compile */ -#include +#ifndef NO_SHA256 + #include +#endif +#ifdef WOLFSSL_DRBG_SHA512 + #include +#endif #ifdef WOLF_CRYPTO_CB #include @@ -332,16 +337,128 @@ enum { drbgInitV = 4 }; +#ifndef NO_SHA256 typedef struct DRBG_internal DRBG_internal; +#endif + +#ifdef WOLFSSL_DRBG_SHA512 +typedef struct DRBG_SHA512_internal DRBG_SHA512_internal; + +static int Hash512_DRBG_Reseed(DRBG_SHA512_internal* drbg, const byte* seed, + word32 seedSz, + const byte* additional, word32 additionalSz); +static int Hash512_DRBG_Generate(DRBG_SHA512_internal* drbg, byte* out, + word32 outSz, + const byte* additional, word32 additionalSz); +static int Hash512_DRBG_Instantiate(DRBG_SHA512_internal* drbg, + const byte* seed, word32 seedSz, + const byte* nonce, word32 nonceSz, + const byte* perso, word32 persoSz, + void* heap, int devId); +static int Hash512_DRBG_Uninstantiate(DRBG_SHA512_internal* drbg); +#endif + +/* Runtime DRBG disable state. + * These flags control which DRBG type is used for new WC_RNG instances and + * may be toggled at runtime (e.g. NSA Suite 2.0 threads disable SHA-256). + * A mutex protects the check-then-set in disable functions so concurrent + * calls cannot bypass the mutual-exclusion guard and disable both DRBG types. + * _InitRng also holds the mutex while reading the flags to get a consistent + * snapshot, and returns BAD_STATE_E if both are somehow disabled. */ +#ifndef NO_SHA256 +#ifdef WOLFSSL_NO_SHA256_DRBG +static int sha256DrbgDisabled = 1; +#else +static int sha256DrbgDisabled = 0; +#endif +#endif +#ifdef WOLFSSL_DRBG_SHA512 +static int sha512DrbgDisabled = 0; +#endif + +#ifndef SINGLE_THREADED +static wolfSSL_Mutex drbgStateMutex + WOLFSSL_MUTEX_INITIALIZER_CLAUSE(drbgStateMutex); +#ifndef WOLFSSL_MUTEX_INITIALIZER +static int drbgStateMutex_inited = 0; +#endif +#endif /* !SINGLE_THREADED */ + +int wc_DrbgState_MutexInit(void) +{ +#ifndef SINGLE_THREADED +#ifndef WOLFSSL_MUTEX_INITIALIZER + if (!drbgStateMutex_inited) { + int ret = wc_InitMutex(&drbgStateMutex); + if (ret != 0) + return ret; + drbgStateMutex_inited = 1; + } +#endif +#endif + return 0; +} + +int wc_DrbgState_MutexFree(void) +{ +#ifndef SINGLE_THREADED +#ifndef WOLFSSL_MUTEX_INITIALIZER + if (drbgStateMutex_inited) { + int ret = wc_FreeMutex(&drbgStateMutex); + drbgStateMutex_inited = 0; + return ret; + } +#endif +#endif + return 0; +} + +static int LockDrbgState(void) +{ +#ifndef SINGLE_THREADED + return wc_LockMutex(&drbgStateMutex); +#else + return 0; +#endif +} + +static int UnlockDrbgState(void) +{ +#ifndef SINGLE_THREADED + return wc_UnLockMutex(&drbgStateMutex); +#else + return 0; +#endif +} static int wc_RNG_HealthTestLocal(WC_RNG* rng, int reseed, void* heap, int devId); +#ifdef WOLFSSL_DRBG_SHA512 +static int wc_RNG_HealthTest_SHA512_ex_internal(DRBG_SHA512_internal* drbg, + int reseed, const byte* nonce, word32 nonceSz, + const byte* perso, word32 persoSz, + const byte* seedA, word32 seedASz, + const byte* seedB, word32 seedBSz, + const byte* additionalA, word32 additionalASz, + const byte* additionalB, word32 additionalBSz, + byte* output, word32 outputSz, + void* heap, int devId); +#endif + +/* The SHA-256 Hash_DRBG core (Hash_df, Hash_DRBG_*) operates on + * DRBG_internal, which random.h defines only when SHA-256 is compiled in. + * Wrap the whole block so a NO_SHA256 + WOLFSSL_DRBG_SHA512 build (the + * SHA-512-only DRBG configuration) still compiles. The SHA-512 DRBG core + * lives below in its own #ifdef WOLFSSL_DRBG_SHA512 section. */ +#ifndef NO_SHA256 + /* Hash Derivation Function */ /* Returns: DRBG_SUCCESS or DRBG_FAILURE */ static int Hash_df(DRBG_internal* drbg, byte* out, word32 outSz, byte type, const byte* inA, word32 inASz, - const byte* inB, word32 inBSz) + const byte* inB, word32 inBSz, + const byte* inC, word32 inCSz) { int ret = DRBG_FAILURE; byte ctr; @@ -406,6 +523,10 @@ static int Hash_df(DRBG_internal* drbg, byte* out, word32 outSz, byte type, if (inB != NULL && inBSz > 0) ret = wc_Sha256Update(sha, inB, inBSz); } + if (ret == 0) { + if (inC != NULL && inCSz > 0) + ret = wc_Sha256Update(sha, inC, inCSz); + } if (ret == 0) ret = wc_Sha256Final(sha, digest); @@ -440,7 +561,8 @@ static int Hash_df(DRBG_internal* drbg, byte* out, word32 outSz, byte type, } /* Returns: DRBG_SUCCESS or DRBG_FAILURE */ -static int Hash_DRBG_Reseed(DRBG_internal* drbg, const byte* seed, word32 seedSz) +static int Hash_DRBG_Reseed(DRBG_internal* drbg, const byte* seed, word32 seedSz, + const byte* additional, word32 additionalSz) { int ret; WC_DECLARE_VAR(newV, byte, DRBG_SEED_LEN, 0); @@ -458,13 +580,14 @@ static int Hash_DRBG_Reseed(DRBG_internal* drbg, const byte* seed, word32 seedSz XMEMSET(newV, 0, DRBG_SEED_LEN); ret = Hash_df(drbg, newV, DRBG_SEED_LEN, drbgReseed, - drbg->V, sizeof(drbg->V), seed, seedSz); + drbg->V, sizeof(drbg->V), seed, seedSz, + additional, additionalSz); if (ret == DRBG_SUCCESS) { XMEMCPY(drbg->V, newV, sizeof(drbg->V)); ForceZero(newV, DRBG_SEED_LEN); ret = Hash_df(drbg, drbg->C, sizeof(drbg->C), drbgInitC, drbg->V, - sizeof(drbg->V), NULL, 0); + sizeof(drbg->V), NULL, 0, NULL, 0); } if (ret == DRBG_SUCCESS) { drbg->reseedCtr = 1; @@ -483,6 +606,10 @@ static int Hash_DRBG_Reseed(DRBG_internal* drbg, const byte* seed, word32 seedSz return ret; } +#endif /* !NO_SHA256 - close before wc_RNG_DRBG_Reseed (dual-DRBG-aware) + * and array_add_one (shared utility) which both must + * remain available to SHA-512-only builds */ + /* Returns: DRBG_SUCCESS and DRBG_FAILURE or BAD_FUNC_ARG on fail */ int wc_RNG_DRBG_Reseed(WC_RNG* rng, const byte* seed, word32 seedSz) { @@ -490,19 +617,50 @@ int wc_RNG_DRBG_Reseed(WC_RNG* rng, const byte* seed, word32 seedSz) return BAD_FUNC_ARG; } - if (rng->drbg == NULL) { - #if defined(HAVE_INTEL_RDSEED) || defined(HAVE_INTEL_RDRAND) - if (IS_INTEL_RDRAND(intel_flags)) { - /* using RDRAND not DRBG, so return success */ - return 0; +#ifndef NO_SHA256 + if (rng->drbgType == WC_DRBG_SHA256) { + if (rng->drbg == NULL) { + #if defined(HAVE_INTEL_RDSEED) || defined(HAVE_INTEL_RDRAND) + if (IS_INTEL_RDRAND(intel_flags)) { + /* using RDRAND not DRBG, so return success */ + return 0; + } + #endif + return BAD_FUNC_ARG; } - #endif - return BAD_FUNC_ARG; + return Hash_DRBG_Reseed((DRBG_internal *)rng->drbg, seed, seedSz, + NULL, 0); } +#endif +#ifdef WOLFSSL_DRBG_SHA512 + if (rng->drbgType == WC_DRBG_SHA512) { + if (rng->drbg512 == NULL) { + #if defined(HAVE_INTEL_RDSEED) || defined(HAVE_INTEL_RDRAND) + if (IS_INTEL_RDRAND(intel_flags)) { + /* using RDRAND not DRBG, so return success */ + return 0; + } + #endif + return BAD_FUNC_ARG; + } + return Hash512_DRBG_Reseed((DRBG_SHA512_internal *)rng->drbg512, + seed, seedSz, NULL, 0); + } +#endif - return Hash_DRBG_Reseed((DRBG_internal *)rng->drbg, seed, seedSz); + /* No DRBG type matched; if using RDRAND, that's OK */ +#if defined(HAVE_INTEL_RDSEED) || defined(HAVE_INTEL_RDRAND) + if (IS_INTEL_RDRAND(intel_flags)) { + return 0; + } +#endif + + return BAD_FUNC_ARG; } +/* Generic byte-array helper -- shared by both SHA-256 and SHA-512 DRBG + * cores. Lives outside the NO_SHA256 guard so SHA-512-only builds + * still link. */ static WC_INLINE void array_add_one(byte* data, word32 dataSz) { int i; @@ -512,6 +670,8 @@ static WC_INLINE void array_add_one(byte* data, word32 dataSz) } } +#ifndef NO_SHA256 /* re-open SHA-256 Hash_DRBG core */ + /* Returns: DRBG_SUCCESS or DRBG_FAILURE */ static int Hash_gen(DRBG_internal* drbg, byte* out, word32 outSz, const byte* V) { @@ -615,6 +775,10 @@ static int Hash_gen(DRBG_internal* drbg, byte* out, word32 outSz, const byte* V) return (ret == 0) ? DRBG_SUCCESS : DRBG_FAILURE; } +#endif /* !NO_SHA256 - close to expose array_add to SHA-512 below */ + +/* Generic multi-byte add. Shared by SHA-256 and SHA-512 DRBG cores; + * lives outside the NO_SHA256 guard so SHA-512-only builds still link. */ static WC_INLINE void array_add(byte* d, word32 dLen, const byte* s, word32 sLen) { if (dLen > 0 && sLen > 0 && dLen >= sLen) { @@ -637,8 +801,11 @@ static WC_INLINE void array_add(byte* d, word32 dLen, const byte* s, word32 sLen } } +#ifndef NO_SHA256 /* re-open SHA-256 Hash_DRBG core */ + /* Returns: DRBG_SUCCESS, DRBG_NEED_RESEED, or DRBG_FAILURE */ -static int Hash_DRBG_Generate(DRBG_internal* drbg, byte* out, word32 outSz) +static int Hash_DRBG_Generate(DRBG_internal* drbg, byte* out, word32 outSz, + const byte* additional, word32 additionalSz) { int ret; #ifdef WOLFSSL_SMALL_STACK_CACHE @@ -680,6 +847,49 @@ static int Hash_DRBG_Generate(DRBG_internal* drbg, byte* out, word32 outSz) type = drbgGenerateH; reseedCtr = drbg->reseedCtr; + /* SP 800-90A 10.1.1.4 step 2: if additional_input != Null, + * w = Hash(0x02 || V || additional_input), V = (V + w) mod 2^seedlen */ + if (additional != NULL && additionalSz > 0) { + byte addType = drbgGenerateW; +#ifndef WOLFSSL_SMALL_STACK_CACHE + #if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB) + ret = wc_InitSha256_ex(sha, drbg->heap, drbg->devId); + #else + ret = wc_InitSha256(sha); + #endif + if (ret != 0) { + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SMALL_STACK_CACHE) + XFREE(digest, drbg->heap, DYNAMIC_TYPE_DIGEST); + #endif + return DRBG_FAILURE; + } +#else + ret = 0; +#endif + if (ret == 0) + ret = wc_Sha256Update(sha, &addType, sizeof(addType)); + if (ret == 0) + ret = wc_Sha256Update(sha, drbg->V, sizeof(drbg->V)); + if (ret == 0) + ret = wc_Sha256Update(sha, additional, additionalSz); + if (ret == 0) + ret = wc_Sha256Final(sha, digest); +#ifndef WOLFSSL_SMALL_STACK_CACHE + wc_Sha256Free(sha); +#endif + if (ret == 0) { + array_add(drbg->V, sizeof(drbg->V), digest, + WC_SHA256_DIGEST_SIZE); + } + else { + ForceZero(digest, WC_SHA256_DIGEST_SIZE); + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SMALL_STACK_CACHE) + XFREE(digest, drbg->heap, DYNAMIC_TYPE_DIGEST); + #endif + return DRBG_FAILURE; + } + } + ret = Hash_gen(drbg, out, outSz, drbg->V); if (ret == DRBG_SUCCESS) { #ifndef WOLFSSL_SMALL_STACK_CACHE @@ -735,15 +945,18 @@ static int Hash_DRBG_Generate(DRBG_internal* drbg, byte* out, word32 outSz) /* Returns: DRBG_SUCCESS or DRBG_FAILURE */ static int Hash_DRBG_Init(DRBG_internal* drbg, const byte* seed, word32 seedSz, - const byte* nonce, word32 nonceSz) + const byte* nonce, word32 nonceSz, + const byte* perso, word32 persoSz) { if (seed == NULL) return DRBG_FAILURE; if (Hash_df(drbg, drbg->V, sizeof(drbg->V), drbgInitV, seed, seedSz, - nonce, nonceSz) == DRBG_SUCCESS && + nonce, nonceSz, + perso, persoSz) == DRBG_SUCCESS && Hash_df(drbg, drbg->C, sizeof(drbg->C), drbgInitC, drbg->V, - sizeof(drbg->V), NULL, 0) == DRBG_SUCCESS) { + sizeof(drbg->V), NULL, 0, + NULL, 0) == DRBG_SUCCESS) { drbg->reseedCtr = 1; return DRBG_SUCCESS; @@ -754,9 +967,10 @@ static int Hash_DRBG_Init(DRBG_internal* drbg, const byte* seed, word32 seedSz, } /* Returns: DRBG_SUCCESS or DRBG_FAILURE */ -static int Hash_DRBG_Instantiate(DRBG_internal* drbg, const byte* seed, word32 seedSz, - const byte* nonce, word32 nonceSz, - void* heap, int devId) +static int Hash_DRBG_Instantiate(DRBG_internal* drbg, const byte* seed, + word32 seedSz, const byte* nonce, + word32 nonceSz, const byte* perso, + word32 persoSz, void* heap, int devId) { int ret = DRBG_FAILURE; @@ -779,7 +993,8 @@ static int Hash_DRBG_Instantiate(DRBG_internal* drbg, const byte* seed, word32 s #endif if (seed != NULL) - ret = Hash_DRBG_Init(drbg, seed, seedSz, nonce, nonceSz); + ret = Hash_DRBG_Init(drbg, seed, seedSz, nonce, nonceSz, + perso, persoSz); return ret; } @@ -803,6 +1018,445 @@ static int Hash_DRBG_Uninstantiate(DRBG_internal* drbg) return (compareSum == 0) ? DRBG_SUCCESS : DRBG_FAILURE; } +#endif /* !NO_SHA256 - SHA-256 Hash_DRBG core block */ + +/* ====================================================================== */ +/* SHA-512 Hash_DRBG (SP 800-90A Rev 1, Table 2) */ +/* */ +/* Internal state (V, C): seedlen = 888 bits = 111 bytes each */ +/* Output block length: 512 bits = 64 bytes (WC_SHA512_DIGEST_SIZE) */ +/* Security strength: 256 bits */ +/* */ +/* NOTE: The raw entropy seed gathered at instantiation / reseed is */ +/* WC_DRBG_SEED_SZ (1024 bits in FIPS builds), NOT seedlen. We overseed */ +/* to tolerate weak entropy sources. Hash_df then compresses the seed */ +/* material down to the 888-bit V and derives C from V. See random.h. */ +/* ====================================================================== */ +#ifdef WOLFSSL_DRBG_SHA512 + +#define OUTPUT_BLOCK_LEN_SHA512 (WC_SHA512_DIGEST_SIZE) /* 64 bytes */ + +/* Hash Derivation Function using SHA-512 */ +/* Returns: DRBG_SUCCESS or DRBG_FAILURE */ +static int Hash512_df(DRBG_SHA512_internal* drbg, byte* out, word32 outSz, + byte type, + const byte* inA, word32 inASz, + const byte* inB, word32 inBSz, + const byte* inC, word32 inCSz) +{ + int ret = DRBG_FAILURE; + byte ctr; + word32 i; + word32 len; + word32 bits = (outSz * 8); +#ifdef WOLFSSL_SMALL_STACK_CACHE + wc_Sha512* sha = &drbg->sha512; +#else + wc_Sha512 sha[1]; +#endif +#if defined(WOLFSSL_SMALL_STACK_CACHE) + byte* digest = drbg->digest_scratch; +#elif defined(WOLFSSL_SMALL_STACK) + byte* digest; +#else + byte digest[WC_SHA512_DIGEST_SIZE]; +#endif + + if (drbg == NULL) { + return DRBG_FAILURE; + } + +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SMALL_STACK_CACHE) + digest = (byte*)XMALLOC(WC_SHA512_DIGEST_SIZE, drbg->heap, + DYNAMIC_TYPE_DIGEST); + if (digest == NULL) + return DRBG_FAILURE; +#endif + +#ifdef LITTLE_ENDIAN_ORDER + bits = ByteReverseWord32(bits); +#endif + len = (outSz / OUTPUT_BLOCK_LEN_SHA512) + + ((outSz % OUTPUT_BLOCK_LEN_SHA512) ? 1 : 0); + + ctr = 1; + for (i = 0; i < len; i++) { +#ifndef WOLFSSL_SMALL_STACK_CACHE + #if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB) + ret = wc_InitSha512_ex(sha, drbg->heap, drbg->devId); + #else + ret = wc_InitSha512(sha); + #endif + if (ret != 0) + break; +#endif + ret = wc_Sha512Update(sha, &ctr, sizeof(ctr)); + if (ret == 0) { + ctr++; + ret = wc_Sha512Update(sha, (byte*)&bits, sizeof(bits)); + } + + if (ret == 0) { + /* churning V is the only string that doesn't have the type added */ + if (type != drbgInitV) + ret = wc_Sha512Update(sha, &type, sizeof(type)); + } + if (ret == 0) + ret = wc_Sha512Update(sha, inA, inASz); + if (ret == 0) { + if (inB != NULL && inBSz > 0) + ret = wc_Sha512Update(sha, inB, inBSz); + } + if (ret == 0) { + if (inC != NULL && inCSz > 0) + ret = wc_Sha512Update(sha, inC, inCSz); + } + if (ret == 0) + ret = wc_Sha512Final(sha, digest); + +#ifndef WOLFSSL_SMALL_STACK_CACHE + wc_Sha512Free(sha); +#endif + if (ret == 0) { + if (outSz > OUTPUT_BLOCK_LEN_SHA512) { + XMEMCPY(out, digest, OUTPUT_BLOCK_LEN_SHA512); + outSz -= OUTPUT_BLOCK_LEN_SHA512; + out += OUTPUT_BLOCK_LEN_SHA512; + } + else { + XMEMCPY(out, digest, outSz); + } + } + } + + ForceZero(digest, WC_SHA512_DIGEST_SIZE); + +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SMALL_STACK_CACHE) + XFREE(digest, drbg->heap, DYNAMIC_TYPE_DIGEST); +#endif + + return (ret == 0) ? DRBG_SUCCESS : DRBG_FAILURE; +} + +/* Returns: DRBG_SUCCESS or DRBG_FAILURE */ +static int Hash512_DRBG_Reseed(DRBG_SHA512_internal* drbg, const byte* seed, + word32 seedSz, + const byte* additional, word32 additionalSz) +{ + int ret; + WC_DECLARE_VAR(newV, byte, DRBG_SHA512_SEED_LEN, 0); + + if (drbg == NULL) { + return DRBG_FAILURE; + } + +#ifdef WOLFSSL_SMALL_STACK_CACHE + newV = drbg->seed_scratch; +#else + WC_ALLOC_VAR_EX(newV, byte, DRBG_SHA512_SEED_LEN, drbg->heap, + DYNAMIC_TYPE_TMP_BUFFER, return MEMORY_E); +#endif + XMEMSET(newV, 0, DRBG_SHA512_SEED_LEN); + + ret = Hash512_df(drbg, newV, DRBG_SHA512_SEED_LEN, drbgReseed, + drbg->V, sizeof(drbg->V), seed, seedSz, + additional, additionalSz); + if (ret == DRBG_SUCCESS) { + XMEMCPY(drbg->V, newV, sizeof(drbg->V)); + ForceZero(newV, DRBG_SHA512_SEED_LEN); + + ret = Hash512_df(drbg, drbg->C, sizeof(drbg->C), drbgInitC, drbg->V, + sizeof(drbg->V), NULL, 0, + NULL, 0); + } + if (ret == DRBG_SUCCESS) { + drbg->reseedCtr = 1; + } + +#ifndef WOLFSSL_SMALL_STACK_CACHE + WC_FREE_VAR_EX(newV, drbg->heap, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return ret; +} + +/* Returns: DRBG_SUCCESS or DRBG_FAILURE */ +static int Hash512_gen(DRBG_SHA512_internal* drbg, byte* out, word32 outSz, + const byte* V) +{ + int ret = DRBG_FAILURE; + word32 i; + word32 len; +#if defined(WOLFSSL_SMALL_STACK_CACHE) + wc_Sha512* sha = &drbg->sha512; + byte* data = drbg->seed_scratch; + byte* digest = drbg->digest_scratch; +#elif defined(WOLFSSL_SMALL_STACK) + wc_Sha512 sha[1]; + byte* data = NULL; + byte* digest = NULL; +#else + wc_Sha512 sha[1]; + byte data[DRBG_SHA512_SEED_LEN]; + byte digest[WC_SHA512_DIGEST_SIZE]; +#endif + + if (drbg == NULL) { + return DRBG_FAILURE; + } + +#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SMALL_STACK_CACHE) + data = (byte*)XMALLOC(DRBG_SHA512_SEED_LEN, drbg->heap, + DYNAMIC_TYPE_TMP_BUFFER); + digest = (byte*)XMALLOC(WC_SHA512_DIGEST_SIZE, drbg->heap, + DYNAMIC_TYPE_DIGEST); + if (data == NULL || digest == NULL) { + XFREE(digest, drbg->heap, DYNAMIC_TYPE_DIGEST); + XFREE(data, drbg->heap, DYNAMIC_TYPE_TMP_BUFFER); + return DRBG_FAILURE; + } +#endif + + /* Special case: outSz is 0 and out is NULL. Generate a block to save for + * the continuous test. */ + if (outSz == 0) { + outSz = 1; + } + + len = (outSz / OUTPUT_BLOCK_LEN_SHA512) + + ((outSz % OUTPUT_BLOCK_LEN_SHA512) ? 1 : 0); + + XMEMCPY(data, V, DRBG_SHA512_SEED_LEN); + for (i = 0; i < len; i++) { +#ifndef WOLFSSL_SMALL_STACK_CACHE + #if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB) + ret = wc_InitSha512_ex(sha, drbg->heap, drbg->devId); + #else + ret = wc_InitSha512(sha); + #endif + if (ret == 0) +#endif + ret = wc_Sha512Update(sha, data, DRBG_SHA512_SEED_LEN); + if (ret == 0) + ret = wc_Sha512Final(sha, digest); +#ifndef WOLFSSL_SMALL_STACK_CACHE + wc_Sha512Free(sha); +#endif + + if (ret == 0) { + if (out != NULL && outSz != 0) { + if (outSz >= OUTPUT_BLOCK_LEN_SHA512) { + XMEMCPY(out, digest, OUTPUT_BLOCK_LEN_SHA512); + outSz -= OUTPUT_BLOCK_LEN_SHA512; + out += OUTPUT_BLOCK_LEN_SHA512; + array_add_one(data, DRBG_SHA512_SEED_LEN); + } + else { + XMEMCPY(out, digest, outSz); + outSz = 0; + } + } + } + else { + break; + } + } + ForceZero(data, DRBG_SHA512_SEED_LEN); + +#ifndef WOLFSSL_SMALL_STACK_CACHE + WC_FREE_VAR_EX(digest, drbg->heap, DYNAMIC_TYPE_DIGEST); + WC_FREE_VAR_EX(data, drbg->heap, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return (ret == 0) ? DRBG_SUCCESS : DRBG_FAILURE; +} + +/* Returns: DRBG_SUCCESS, DRBG_NEED_RESEED, or DRBG_FAILURE */ +static int Hash512_DRBG_Generate(DRBG_SHA512_internal* drbg, byte* out, + word32 outSz, + const byte* additional, word32 additionalSz) +{ + int ret; +#ifdef WOLFSSL_SMALL_STACK_CACHE + wc_Sha512* sha = &drbg->sha512; +#else + wc_Sha512 sha[1]; +#endif + byte type; + word64 reseedCtr; + + if (drbg == NULL) { + return DRBG_FAILURE; + } + + if (drbg->reseedCtr >= WC_RESEED_INTERVAL) { + return DRBG_NEED_RESEED; + } + else { + #if defined(WOLFSSL_SMALL_STACK_CACHE) + byte* digest = drbg->digest_scratch; + #elif defined(WOLFSSL_SMALL_STACK) + byte* digest = (byte*)XMALLOC(WC_SHA512_DIGEST_SIZE, drbg->heap, + DYNAMIC_TYPE_DIGEST); + if (digest == NULL) + return DRBG_FAILURE; + #else + byte digest[WC_SHA512_DIGEST_SIZE]; + #endif + + type = drbgGenerateH; + reseedCtr = drbg->reseedCtr; + + /* SP 800-90A Section 10.1.1.4 step 2: + * If additional_input != Null, w = Hash(0x02 || V || additional_input), + * V = (V + w) mod 2^seedlen */ + ret = DRBG_SUCCESS; + if (additional != NULL && additionalSz > 0) { + byte addType = drbgGenerateW; /* 0x02 */ +#ifndef WOLFSSL_SMALL_STACK_CACHE + #if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB) + ret = wc_InitSha512_ex(sha, drbg->heap, drbg->devId); + #else + ret = wc_InitSha512(sha); + #endif + if (ret == 0) +#endif + ret = wc_Sha512Update(sha, &addType, sizeof(addType)); + if (ret == 0) + ret = wc_Sha512Update(sha, drbg->V, sizeof(drbg->V)); + if (ret == 0) + ret = wc_Sha512Update(sha, additional, additionalSz); + if (ret == 0) + ret = wc_Sha512Final(sha, digest); +#ifndef WOLFSSL_SMALL_STACK_CACHE + wc_Sha512Free(sha); +#endif + if (ret == 0) + array_add(drbg->V, sizeof(drbg->V), digest, + WC_SHA512_DIGEST_SIZE); + } + + if (ret == 0) + ret = Hash512_gen(drbg, out, outSz, drbg->V); + if (ret == DRBG_SUCCESS) { +#ifndef WOLFSSL_SMALL_STACK_CACHE + #if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB) + ret = wc_InitSha512_ex(sha, drbg->heap, drbg->devId); + #else + ret = wc_InitSha512(sha); + #endif + if (ret == 0) +#endif + ret = wc_Sha512Update(sha, &type, sizeof(type)); + if (ret == 0) + ret = wc_Sha512Update(sha, drbg->V, sizeof(drbg->V)); + if (ret == 0) + ret = wc_Sha512Final(sha, digest); + +#ifndef WOLFSSL_SMALL_STACK_CACHE + wc_Sha512Free(sha); +#endif + + if (ret == 0) { + array_add(drbg->V, sizeof(drbg->V), digest, + WC_SHA512_DIGEST_SIZE); + array_add(drbg->V, sizeof(drbg->V), drbg->C, sizeof(drbg->C)); + #ifdef LITTLE_ENDIAN_ORDER + reseedCtr = ByteReverseWord64(reseedCtr); + #endif + array_add(drbg->V, sizeof(drbg->V), + (byte*)&reseedCtr, sizeof(reseedCtr)); + ret = DRBG_SUCCESS; + } + drbg->reseedCtr++; + } + ForceZero(digest, WC_SHA512_DIGEST_SIZE); + #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SMALL_STACK_CACHE) + XFREE(digest, drbg->heap, DYNAMIC_TYPE_DIGEST); + #endif + } + + return (ret == 0) ? DRBG_SUCCESS : DRBG_FAILURE; +} + +/* Returns: DRBG_SUCCESS or DRBG_FAILURE */ +static int Hash512_DRBG_Init(DRBG_SHA512_internal* drbg, const byte* seed, + word32 seedSz, const byte* nonce, word32 nonceSz, + const byte* perso, word32 persoSz) +{ + if (seed == NULL) + return DRBG_FAILURE; + + if (Hash512_df(drbg, drbg->V, sizeof(drbg->V), drbgInitV, seed, seedSz, + nonce, nonceSz, + perso, persoSz) == DRBG_SUCCESS && + Hash512_df(drbg, drbg->C, sizeof(drbg->C), drbgInitC, drbg->V, + sizeof(drbg->V), NULL, 0, + NULL, 0) == DRBG_SUCCESS) { + + drbg->reseedCtr = 1; + return DRBG_SUCCESS; + } + else { + return DRBG_FAILURE; + } +} + +/* Returns: DRBG_SUCCESS or DRBG_FAILURE */ +static int Hash512_DRBG_Instantiate(DRBG_SHA512_internal* drbg, + const byte* seed, word32 seedSz, + const byte* nonce, word32 nonceSz, + const byte* perso, word32 persoSz, + void* heap, int devId) +{ + int ret = DRBG_FAILURE; + + XMEMSET(drbg, 0, sizeof(DRBG_SHA512_internal)); + drbg->heap = heap; +#if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB) + drbg->devId = devId; +#else + (void)devId; +#endif + +#ifdef WOLFSSL_SMALL_STACK_CACHE + #if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB) + ret = wc_InitSha512_ex(&drbg->sha512, drbg->heap, drbg->devId); + #else + ret = wc_InitSha512(&drbg->sha512); + #endif + if (ret != 0) + return ret; +#endif + + if (seed != NULL) + ret = Hash512_DRBG_Init(drbg, seed, seedSz, nonce, nonceSz, + perso, persoSz); + return ret; +} + +/* Returns: DRBG_SUCCESS or DRBG_FAILURE */ +static int Hash512_DRBG_Uninstantiate(DRBG_SHA512_internal* drbg) +{ + word32 i; + int compareSum = 0; + byte* compareDrbg = (byte*)drbg; + +#ifdef WOLFSSL_SMALL_STACK_CACHE + wc_Sha512Free(&drbg->sha512); +#endif + + ForceZero(drbg, sizeof(DRBG_SHA512_internal)); + + for (i = 0; i < sizeof(DRBG_SHA512_internal); i++) { + compareSum |= compareDrbg[i] ^ 0; + } + + return (compareSum == 0) ? DRBG_SUCCESS : DRBG_FAILURE; +} + +#endif /* WOLFSSL_DRBG_SHA512 */ + /* FIPS 140-3 IG 10.3.A / SP800-90B Health Tests for Seed Data * @@ -947,6 +1601,96 @@ int wc_RNG_TestSeed(const byte* seed, word32 seedSz) return ret; } +/* Runtime DRBG disable/enable API -- only available in non-selftest and + * FIPS v7+ builds (older FIPS/selftest random.c doesn't have these) */ +#if !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) +#ifndef NO_SHA256 +int wc_Sha256Drbg_Disable(void) +{ + int ret; +#ifdef WOLFSSL_DRBG_SHA512 + ret = LockDrbgState(); + if (ret != 0) + return ret; + if (sha512DrbgDisabled) { + UnlockDrbgState(); + return BAD_STATE_E; /* can't disable both */ + } + sha256DrbgDisabled = 1; + UnlockDrbgState(); + return 0; +#else + (void)ret; + return NOT_COMPILED_IN; +#endif +} + +int wc_Sha256Drbg_Enable(void) +{ + int ret = LockDrbgState(); + if (ret != 0) + return ret; + sha256DrbgDisabled = 0; + UnlockDrbgState(); + return 0; +} + +int wc_Sha256Drbg_IsDisabled(void) +{ + int val; + if (LockDrbgState() != 0) + return 1; /* fail-safe: report disabled on mutex error */ + val = sha256DrbgDisabled; + UnlockDrbgState(); + return val; +} +#else +/* When SHA-256 is not compiled in, these are stubs */ +int wc_Sha256Drbg_Disable(void) { return NOT_COMPILED_IN; } +int wc_Sha256Drbg_Enable(void) { return 0; } +int wc_Sha256Drbg_IsDisabled(void) { return 1; } /* always disabled */ +#endif /* !NO_SHA256 */ +#endif /* !HAVE_SELFTEST && (!HAVE_FIPS || FIPS v7+) */ + +#ifdef WOLFSSL_DRBG_SHA512 +int wc_Sha512Drbg_Disable(void) +{ + int ret = LockDrbgState(); + if (ret != 0) + return ret; +#ifndef NO_SHA256 + if (sha256DrbgDisabled) { + UnlockDrbgState(); + return BAD_STATE_E; /* can't disable both */ + } +#endif + sha512DrbgDisabled = 1; + UnlockDrbgState(); + return 0; +} + +int wc_Sha512Drbg_Enable(void) +{ + int ret = LockDrbgState(); + if (ret != 0) + return ret; + sha512DrbgDisabled = 0; + UnlockDrbgState(); + return 0; +} + +int wc_Sha512Drbg_IsDisabled(void) +{ + int val; + if (LockDrbgState() != 0) + return 1; /* fail-safe: report disabled on mutex error */ + val = sha512DrbgDisabled; + UnlockDrbgState(); + return val; +} +#endif /* WOLFSSL_DRBG_SHA512 */ + #endif /* HAVE_HASHDRBG */ /* End NIST DRBG Code */ @@ -997,11 +1741,51 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz, #ifdef HAVE_HASHDRBG /* init the DBRG to known values */ +#ifndef NO_SHA256 rng->drbg = NULL; #ifdef WOLFSSL_SMALL_STACK_CACHE rng->drbg_scratch = NULL; #endif +#endif +#ifdef WOLFSSL_DRBG_SHA512 + rng->drbg512 = NULL; + #ifdef WOLFSSL_SMALL_STACK_CACHE + rng->drbg512_scratch = NULL; + rng->health_check_scratch_512 = NULL; + #endif +#endif +#ifdef WOLFSSL_SMALL_STACK_CACHE + rng->newSeed_buf = NULL; +#ifndef NO_SHA256 + rng->health_check_scratch = NULL; +#endif +#endif rng->status = DRBG_NOT_INIT; + + /* Select DRBG type: prefer SHA-512 unless disabled or not compiled. + * Hold the mutex for a consistent snapshot of both disable flags. */ +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + ret = LockDrbgState(); + if (ret != 0) + return ret; +#ifdef WOLFSSL_DRBG_SHA512 + if (!sha512DrbgDisabled) + rng->drbgType = WC_DRBG_SHA512; + else +#endif +#ifndef NO_SHA256 + if (!sha256DrbgDisabled) + rng->drbgType = WC_DRBG_SHA256; + else +#endif + { + UnlockDrbgState(); + return BAD_STATE_E; /* no DRBG available */ + } + UnlockDrbgState(); +#else + rng->drbgType = WC_DRBG_SHA256; +#endif #endif #if defined(HAVE_INTEL_RDSEED) || defined(HAVE_INTEL_RDRAND) || \ @@ -1057,54 +1841,110 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz, seedSz = MAX_SEED_SZ; } -#if !defined(WOLFSSL_NO_MALLOC) || defined(WOLFSSL_STATIC_MEMORY) - rng->drbg = - (struct DRBG*)XMALLOC(sizeof(DRBG_internal), rng->heap, - DYNAMIC_TYPE_RNG); - if (rng->drbg == NULL) { - #if defined(DEBUG_WOLFSSL) - WOLFSSL_MSG_EX("_InitRng XMALLOC failed to allocate %d bytes", - sizeof(DRBG_internal)); - #endif - ret = MEMORY_E; - rng->status = DRBG_FAILED; - } -#else - rng->drbg = (struct DRBG*)&rng->drbg_data; -#endif /* WOLFSSL_NO_MALLOC or WOLFSSL_STATIC_MEMORY */ - -#ifdef WOLFSSL_SMALL_STACK_CACHE - if (ret == 0) { - rng->drbg_scratch = - (DRBG_internal *)XMALLOC(sizeof(DRBG_internal), rng->heap, - DYNAMIC_TYPE_RNG); - if (rng->drbg_scratch == NULL) { -#if defined(DEBUG_WOLFSSL) +#ifndef NO_SHA256 + if (rng->drbgType == WC_DRBG_SHA256) { + #if !defined(WOLFSSL_NO_MALLOC) || defined(WOLFSSL_STATIC_MEMORY) + rng->drbg = + (struct DRBG*)XMALLOC(sizeof(DRBG_internal), rng->heap, + DYNAMIC_TYPE_RNG); + if (rng->drbg == NULL) { + #if defined(DEBUG_WOLFSSL) WOLFSSL_MSG_EX("_InitRng XMALLOC failed to allocate %d bytes", sizeof(DRBG_internal)); -#endif + #endif ret = MEMORY_E; rng->status = DRBG_FAILED; } - } + #else + rng->drbg = (struct DRBG*)&rng->drbg_data; + #endif /* WOLFSSL_NO_MALLOC or WOLFSSL_STATIC_MEMORY */ - if (ret == 0) { - ret = Hash_DRBG_Instantiate((DRBG_internal *)rng->drbg_scratch, - NULL /* seed */, 0, NULL /* nonce */, 0, rng->heap, devId); - if (ret == 0) - drbg_scratch_instantiated = 1; - } + #ifdef WOLFSSL_SMALL_STACK_CACHE + if (ret == 0) { + rng->drbg_scratch = + (DRBG_internal *)XMALLOC(sizeof(DRBG_internal), rng->heap, + DYNAMIC_TYPE_RNG); + if (rng->drbg_scratch == NULL) { + #if defined(DEBUG_WOLFSSL) + WOLFSSL_MSG_EX("_InitRng XMALLOC failed to allocate %d bytes", + sizeof(DRBG_internal)); + #endif + ret = MEMORY_E; + rng->status = DRBG_FAILED; + } + } - if (ret == 0) { - rng->health_check_scratch = - (byte *)XMALLOC(RNG_HEALTH_TEST_CHECK_SIZE, rng->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (rng->health_check_scratch == NULL) { + if (ret == 0) { + ret = Hash_DRBG_Instantiate((DRBG_internal *)rng->drbg_scratch, + NULL, 0, NULL, 0, NULL, 0, rng->heap, devId); + if (ret == 0) + drbg_scratch_instantiated = 1; + } + + if (ret == 0) { + rng->health_check_scratch = + (byte *)XMALLOC(RNG_HEALTH_TEST_CHECK_SIZE, rng->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (rng->health_check_scratch == NULL) { + ret = MEMORY_E; + rng->status = DRBG_FAILED; + } + } + #endif /* WOLFSSL_SMALL_STACK_CACHE */ + } /* WC_DRBG_SHA256 */ +#endif /* !NO_SHA256 */ + +#ifdef WOLFSSL_DRBG_SHA512 + if (rng->drbgType == WC_DRBG_SHA512) { + #if !defined(WOLFSSL_NO_MALLOC) || defined(WOLFSSL_STATIC_MEMORY) + rng->drbg512 = + (struct DRBG_SHA512*)XMALLOC(sizeof(DRBG_SHA512_internal), + rng->heap, DYNAMIC_TYPE_RNG); + if (rng->drbg512 == NULL) { + #if defined(DEBUG_WOLFSSL) + WOLFSSL_MSG_EX("_InitRng XMALLOC failed to allocate %d bytes", + sizeof(DRBG_SHA512_internal)); + #endif ret = MEMORY_E; rng->status = DRBG_FAILED; } - } + #else + rng->drbg512 = (struct DRBG_SHA512*)&rng->drbg512_data; + #endif + #ifdef WOLFSSL_SMALL_STACK_CACHE + if (ret == 0) { + rng->drbg512_scratch = + (DRBG_SHA512_internal *)XMALLOC(sizeof(DRBG_SHA512_internal), + rng->heap, DYNAMIC_TYPE_RNG); + if (rng->drbg512_scratch == NULL) { + ret = MEMORY_E; + rng->status = DRBG_FAILED; + } + } + + if (ret == 0) { + ret = Hash512_DRBG_Instantiate(rng->drbg512_scratch, + NULL, 0, NULL, 0, NULL, 0, rng->heap, devId); + if (ret == 0) + drbg_scratch_instantiated = 1; + } + + if (ret == 0) { + rng->health_check_scratch_512 = + (byte *)XMALLOC(RNG_HEALTH_TEST_CHECK_SIZE_SHA512, rng->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (rng->health_check_scratch_512 == NULL) { + ret = MEMORY_E; + rng->status = DRBG_FAILED; + } + } + #endif /* WOLFSSL_SMALL_STACK_CACHE */ + } /* WC_DRBG_SHA512 */ +#endif /* WOLFSSL_DRBG_SHA512 */ + + /* newSeed_buf shared by both DRBG types for PollAndReSeed */ +#ifdef WOLFSSL_SMALL_STACK_CACHE if (ret == 0) { rng->newSeed_buf = (byte*)XMALLOC(SEED_SZ + SEED_BLOCK_SZ, rng->heap, DYNAMIC_TYPE_SEED); @@ -1185,14 +2025,29 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz, } #endif - if (ret == DRBG_SUCCESS) - ret = Hash_DRBG_Instantiate((DRBG_internal *)rng->drbg, - #if defined(HAVE_FIPS) || !defined(WOLFSSL_RNG_USE_FULL_SEED) - seed + SEED_BLOCK_SZ, seedSz - SEED_BLOCK_SZ, - #else - seed, seedSz, - #endif - nonce, nonceSz, rng->heap, devId); + if (ret == DRBG_SUCCESS) { +#ifndef NO_SHA256 + if (rng->drbgType == WC_DRBG_SHA256) + ret = Hash_DRBG_Instantiate((DRBG_internal *)rng->drbg, + #if defined(HAVE_FIPS) || !defined(WOLFSSL_RNG_USE_FULL_SEED) + seed + SEED_BLOCK_SZ, seedSz - SEED_BLOCK_SZ, + #else + seed, seedSz, + #endif + nonce, nonceSz, NULL, 0, rng->heap, devId); +#endif +#ifdef WOLFSSL_DRBG_SHA512 + if (rng->drbgType == WC_DRBG_SHA512) + ret = Hash512_DRBG_Instantiate( + (DRBG_SHA512_internal *)rng->drbg512, + #if defined(HAVE_FIPS) || !defined(WOLFSSL_RNG_USE_FULL_SEED) + seed + SEED_BLOCK_SZ, seedSz - SEED_BLOCK_SZ, + #else + seed, seedSz, + #endif + nonce, nonceSz, NULL, 0, rng->heap, devId); +#endif + } } /* ret == 0 */ #ifdef WOLFSSL_SMALL_STACK @@ -1204,29 +2059,56 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz, WC_FREE_VAR_EX(seed, rng->heap, DYNAMIC_TYPE_SEED); if (ret != DRBG_SUCCESS) { - #if !defined(WOLFSSL_NO_MALLOC) || defined(WOLFSSL_STATIC_MEMORY) - XFREE(rng->drbg, rng->heap, DYNAMIC_TYPE_RNG); + #ifndef NO_SHA256 + if (rng->drbgType == WC_DRBG_SHA256) { + #if !defined(WOLFSSL_NO_MALLOC) || defined(WOLFSSL_STATIC_MEMORY) + XFREE(rng->drbg, rng->heap, DYNAMIC_TYPE_RNG); + #endif + rng->drbg = NULL; + #ifdef WOLFSSL_SMALL_STACK_CACHE + XFREE(rng->health_check_scratch, rng->heap, + DYNAMIC_TYPE_TMP_BUFFER); + rng->health_check_scratch = NULL; + if (drbg_scratch_instantiated) + (void)Hash_DRBG_Uninstantiate( + (DRBG_internal *)rng->drbg_scratch); + XFREE(rng->drbg_scratch, rng->heap, DYNAMIC_TYPE_RNG); + rng->drbg_scratch = NULL; + #endif + } + #endif /* !NO_SHA256 */ + #ifdef WOLFSSL_DRBG_SHA512 + if (rng->drbgType == WC_DRBG_SHA512) { + #if !defined(WOLFSSL_NO_MALLOC) || defined(WOLFSSL_STATIC_MEMORY) + XFREE(rng->drbg512, rng->heap, DYNAMIC_TYPE_RNG); + #endif + rng->drbg512 = NULL; + #ifdef WOLFSSL_SMALL_STACK_CACHE + XFREE(rng->health_check_scratch_512, rng->heap, + DYNAMIC_TYPE_TMP_BUFFER); + rng->health_check_scratch_512 = NULL; + if (drbg_scratch_instantiated) + (void)Hash512_DRBG_Uninstantiate(rng->drbg512_scratch); + XFREE(rng->drbg512_scratch, rng->heap, DYNAMIC_TYPE_RNG); + rng->drbg512_scratch = NULL; + #endif + } #endif - rng->drbg = NULL; #ifdef WOLFSSL_SMALL_STACK_CACHE - XFREE(rng->health_check_scratch, rng->heap, DYNAMIC_TYPE_TMP_BUFFER); - rng->health_check_scratch = NULL; - XFREE(rng->newSeed_buf, rng->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(rng->newSeed_buf, rng->heap, DYNAMIC_TYPE_SEED); rng->newSeed_buf = NULL; - if (drbg_scratch_instantiated) - (void)Hash_DRBG_Uninstantiate((DRBG_internal *)rng->drbg_scratch); - XFREE(rng->drbg_scratch, rng->heap, DYNAMIC_TYPE_RNG); - rng->drbg_scratch = NULL; #endif } /* else wc_RNG_HealthTestLocal was successful */ if (ret == DRBG_SUCCESS) { #ifdef WOLFSSL_CHECK_MEM_ZERO - #ifdef HAVE_HASHDRBG - struct DRBG_internal* drbg = (struct DRBG_internal*)rng->drbg; - wc_MemZero_Add("DRBG V", &drbg->V, sizeof(drbg->V)); - wc_MemZero_Add("DRBG C", &drbg->C, sizeof(drbg->C)); + #ifndef NO_SHA256 + if (rng->drbgType == WC_DRBG_SHA256) { + struct DRBG_internal* drbg = (struct DRBG_internal*)rng->drbg; + wc_MemZero_Add("DRBG V", &drbg->V, sizeof(drbg->V)); + wc_MemZero_Add("DRBG C", &drbg->C, sizeof(drbg->C)); + } #endif #endif @@ -1387,9 +2269,20 @@ static int PollAndReSeed(WC_RNG* rng) "err %d.", ret); #endif } - if (ret == DRBG_SUCCESS) - ret = Hash_DRBG_Reseed((DRBG_internal *)rng->drbg, - newSeed + SEED_BLOCK_SZ, SEED_SZ); + if (ret == DRBG_SUCCESS) { +#ifndef NO_SHA256 + if (rng->drbgType == WC_DRBG_SHA256) + ret = Hash_DRBG_Reseed((DRBG_internal *)rng->drbg, + newSeed + SEED_BLOCK_SZ, SEED_SZ, + NULL, 0); +#endif +#ifdef WOLFSSL_DRBG_SHA512 + if (rng->drbgType == WC_DRBG_SHA512) + ret = Hash512_DRBG_Reseed( + (DRBG_SHA512_internal *)rng->drbg512, + newSeed + SEED_BLOCK_SZ, SEED_SZ, NULL, 0); +#endif + } #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SMALL_STACK_CACHE) if (newSeed != NULL) { ForceZero(newSeed, SEED_SZ + SEED_BLOCK_SZ); @@ -1485,11 +2378,35 @@ int wc_RNG_GenerateBlock(WC_RNG* rng, byte* output, word32 sz) } #endif - ret = Hash_DRBG_Generate((DRBG_internal *)rng->drbg, output, sz); - if (ret == DRBG_NEED_RESEED) { - ret = PollAndReSeed(rng); - if (ret == DRBG_SUCCESS) - ret = Hash_DRBG_Generate((DRBG_internal *)rng->drbg, output, sz); +#ifndef NO_SHA256 + if (rng->drbgType == WC_DRBG_SHA256) { + ret = Hash_DRBG_Generate((DRBG_internal *)rng->drbg, output, sz, + NULL, 0); + if (ret == DRBG_NEED_RESEED) { + ret = PollAndReSeed(rng); + if (ret == DRBG_SUCCESS) + ret = Hash_DRBG_Generate((DRBG_internal *)rng->drbg, output, + sz, NULL, 0); + } + } + else +#endif +#ifdef WOLFSSL_DRBG_SHA512 + if (rng->drbgType == WC_DRBG_SHA512) { + ret = Hash512_DRBG_Generate((DRBG_SHA512_internal *)rng->drbg512, + output, sz, NULL, 0); + if (ret == DRBG_NEED_RESEED) { + ret = PollAndReSeed(rng); + if (ret == DRBG_SUCCESS) + ret = Hash512_DRBG_Generate( + (DRBG_SHA512_internal *)rng->drbg512, output, sz, + NULL, 0); + } + } + else +#endif + { + ret = DRBG_FAILURE; } if (ret == DRBG_SUCCESS) { @@ -1574,6 +2491,7 @@ int wc_FreeRng(WC_RNG* rng) #endif #ifdef HAVE_HASHDRBG +#ifndef NO_SHA256 if (rng->drbg != NULL) { if (Hash_DRBG_Uninstantiate((DRBG_internal *)rng->drbg) != DRBG_SUCCESS) ret = RNG_FAILURE_E; @@ -1587,17 +2505,57 @@ int wc_FreeRng(WC_RNG* rng) } #ifdef WOLFSSL_SMALL_STACK_CACHE + /* Scratch buffers are tracked independently of rng->drbg so that a + * partial-construction failure path that nulled rng->drbg early + * (or any future restructure that does the same) cannot leak them. + * Free on their own NULL check rather than nesting under drbg. */ if (rng->drbg_scratch != NULL) { - if (Hash_DRBG_Uninstantiate((DRBG_internal *)rng->drbg_scratch) != DRBG_SUCCESS) + if (Hash_DRBG_Uninstantiate((DRBG_internal *)rng->drbg_scratch) + != DRBG_SUCCESS) ret = RNG_FAILURE_E; XFREE(rng->drbg_scratch, rng->heap, DYNAMIC_TYPE_RNG); rng->drbg_scratch = NULL; } - XFREE(rng->health_check_scratch, rng->heap, DYNAMIC_TYPE_RNG); - rng->health_check_scratch = NULL; - XFREE(rng->newSeed_buf, rng->heap, DYNAMIC_TYPE_RNG); - rng->newSeed_buf = NULL; + if (rng->health_check_scratch != NULL) { + XFREE(rng->health_check_scratch, rng->heap, DYNAMIC_TYPE_TMP_BUFFER); + rng->health_check_scratch = NULL; + } #endif +#endif /* !NO_SHA256 */ + +#ifdef WOLFSSL_DRBG_SHA512 + if (rng->drbg512 != NULL) { + if (Hash512_DRBG_Uninstantiate( + (DRBG_SHA512_internal *)rng->drbg512) != DRBG_SUCCESS) + ret = RNG_FAILURE_E; + + #if !defined(WOLFSSL_NO_MALLOC) || defined(WOLFSSL_STATIC_MEMORY) + XFREE(rng->drbg512, rng->heap, DYNAMIC_TYPE_RNG); + #endif + rng->drbg512 = NULL; + } + + #ifdef WOLFSSL_SMALL_STACK_CACHE + /* Same independence rationale as the SHA-256 scratch above. */ + if (rng->drbg512_scratch != NULL) { + if (Hash512_DRBG_Uninstantiate(rng->drbg512_scratch) + != DRBG_SUCCESS) + ret = RNG_FAILURE_E; + XFREE(rng->drbg512_scratch, rng->heap, DYNAMIC_TYPE_RNG); + rng->drbg512_scratch = NULL; + } + if (rng->health_check_scratch_512 != NULL) { + XFREE(rng->health_check_scratch_512, rng->heap, + DYNAMIC_TYPE_TMP_BUFFER); + rng->health_check_scratch_512 = NULL; + } + #endif +#endif /* WOLFSSL_DRBG_SHA512 */ + +#ifdef WOLFSSL_SMALL_STACK_CACHE + XFREE(rng->newSeed_buf, rng->heap, DYNAMIC_TYPE_SEED); + rng->newSeed_buf = NULL; +#endif rng->status = DRBG_NOT_INIT; #endif /* HAVE_HASHDRBG */ @@ -1621,6 +2579,10 @@ int wc_FreeRng(WC_RNG* rng) } #ifdef HAVE_HASHDRBG +/* The original wc_RNG_HealthTest{,_ex} entry points operate on the SHA-256 + * Hash_DRBG (DRBG_internal). Gate them out under NO_SHA256; SHA-512-only + * builds use wc_RNG_HealthTest_SHA512_ex declared further down. */ +#ifndef NO_SHA256 int wc_RNG_HealthTest(int reseed, const byte* seedA, word32 seedASz, const byte* seedB, word32 seedBSz, byte* output, word32 outputSz) @@ -1657,18 +2619,19 @@ static int wc_RNG_HealthTest_ex_internal(DRBG_internal* drbg, (void)heap; (void)devId; - if (Hash_DRBG_Init(drbg, seedA, seedASz, nonce, nonceSz) != 0) { + if (Hash_DRBG_Init(drbg, seedA, seedASz, nonce, nonceSz, + NULL, 0) != 0) { goto exit_rng_ht; } #else if (Hash_DRBG_Instantiate(drbg, seedA, seedASz, nonce, nonceSz, - heap, devId) != 0) { + NULL, 0, heap, devId) != 0) { goto exit_rng_ht; } #endif if (reseed) { - if (Hash_DRBG_Reseed(drbg, seedB, seedBSz) != 0) { + if (Hash_DRBG_Reseed(drbg, seedB, seedBSz, NULL, 0) != 0) { goto exit_rng_ht; } } @@ -1678,11 +2641,11 @@ static int wc_RNG_HealthTest_ex_internal(DRBG_internal* drbg, * answer test checks the second block of DRBG out of * the generator to ensure the internal state is updated * as expected. */ - if (Hash_DRBG_Generate(drbg, output, outputSz) != 0) { + if (Hash_DRBG_Generate(drbg, output, outputSz, NULL, 0) != 0) { goto exit_rng_ht; } - if (Hash_DRBG_Generate(drbg, output, outputSz) != 0) { + if (Hash_DRBG_Generate(drbg, output, outputSz, NULL, 0) != 0) { goto exit_rng_ht; } @@ -1725,7 +2688,8 @@ int wc_RNG_HealthTest_ex(int reseed, const byte* nonce, word32 nonceSz, #ifdef WOLFSSL_SMALL_STACK_CACHE ret = Hash_DRBG_Instantiate(drbg, - NULL /* seed */, 0, NULL /* nonce */, 0, heap, devId); + NULL /* seed */, 0, NULL /* nonce */, 0, + NULL /* perso */, 0, heap, devId); if (ret == 0) #endif { @@ -1740,6 +2704,7 @@ int wc_RNG_HealthTest_ex(int reseed, const byte* nonce, word32 nonceSz, return ret; } +#endif /* !NO_SHA256 - wc_RNG_HealthTest{,_ex,_ex_internal} */ const FLASH_QUALIFIER byte seedA_data[] = { @@ -1792,10 +2757,181 @@ const FLASH_QUALIFIER byte outputB_data[] = { }; +/* SHA-512 DRBG KAT vectors for local health test. + * Source: NIST CAVP Hash_DRBG.rsp, [SHA-512], PredictionResistance=False, + * EntropyInputLen=256, NonceLen=128, PersonalizationStringLen=0, + * AdditionalInputLen=0, ReturnedBitsLen=2048. */ +#ifdef WOLFSSL_DRBG_SHA512 + +/* Reseed test vectors (COUNT=0 from reseed section) */ +static const byte sha512_seedA_data[] = { + /* EntropyInput (32 bytes) || Nonce (16 bytes) */ + 0x31, 0x44, 0xe1, 0x7a, 0x10, 0xc8, 0x56, 0x12, + 0x97, 0x64, 0xf5, 0x8f, 0xd8, 0xe4, 0x23, 0x10, + 0x20, 0x54, 0x69, 0x96, 0xc0, 0xbf, 0x6c, 0xff, + 0x8e, 0x91, 0xc2, 0x4e, 0xe0, 0x9b, 0xe3, 0x33, + 0xb1, 0x6f, 0xcb, 0x1c, 0xf0, 0xc0, 0x10, 0xf3, + 0x1f, 0xea, 0xb7, 0x33, 0x58, 0x8b, 0x8e, 0x04 +}; +static const byte sha512_reseedSeedA_data[] = { + /* EntropyInputReseed (32 bytes) */ + 0xa0, 0xb3, 0x58, 0x4c, 0x2c, 0x84, 0x12, 0xf6, + 0x18, 0x40, 0x68, 0x34, 0x40, 0x4d, 0x1e, 0xb0, + 0xce, 0x99, 0x9b, 0xa2, 0x89, 0x66, 0x05, 0x4d, + 0x7e, 0x49, 0x7e, 0x0d, 0xb6, 0x08, 0xb9, 0x67 +}; +static const byte sha512_outputA_data[] = { + 0xef, 0xa3, 0x5d, 0xd0, 0x36, 0x2a, 0xdb, 0x76, + 0x26, 0x45, 0x6b, 0x36, 0xfa, 0xc7, 0x4d, 0x3c, + 0x28, 0xd0, 0x1d, 0x92, 0x64, 0x20, 0x27, 0x5a, + 0x28, 0xbe, 0xa9, 0xc9, 0xdd, 0x75, 0x47, 0xc1, + 0x5e, 0x79, 0x31, 0x85, 0x2a, 0xc1, 0x27, 0x70, + 0x76, 0x56, 0x75, 0x35, 0x23, 0x9c, 0x1f, 0x42, + 0x9c, 0x7f, 0x75, 0xcf, 0x74, 0xc2, 0x26, 0x7d, + 0xeb, 0x6a, 0x3e, 0x59, 0x6c, 0xf3, 0x26, 0x15, + 0x6c, 0x79, 0x69, 0x41, 0x28, 0x3b, 0x8d, 0x58, + 0x3f, 0x17, 0x1c, 0x2f, 0x6e, 0x33, 0x23, 0xf7, + 0x55, 0x5e, 0x1b, 0x18, 0x1f, 0xfd, 0xa3, 0x05, + 0x07, 0x21, 0x0c, 0xb1, 0xf5, 0x89, 0xb2, 0x3c, + 0xd7, 0x18, 0x80, 0xfd, 0x44, 0x37, 0x0c, 0xac, + 0xf4, 0x33, 0x75, 0xb0, 0xdb, 0x7e, 0x33, 0x6f, + 0x12, 0xb3, 0x09, 0xbf, 0xd4, 0xf6, 0x10, 0xbb, + 0x8f, 0x20, 0xe1, 0xa1, 0x5e, 0x25, 0x3a, 0x4f, + 0xe5, 0x11, 0xa0, 0x27, 0x96, 0x8d, 0xf0, 0xb1, + 0x05, 0xa1, 0xd7, 0x3a, 0xff, 0x7c, 0x7a, 0x82, + 0x6d, 0x39, 0xf6, 0x40, 0xdf, 0xb8, 0xf5, 0x22, + 0x25, 0x9e, 0xd4, 0x02, 0x28, 0x2e, 0x2c, 0x2e, + 0x9d, 0x3a, 0x49, 0x8f, 0x51, 0x72, 0x5f, 0xe4, + 0x14, 0x1b, 0x06, 0xda, 0x55, 0x98, 0xa4, 0x2a, + 0xc1, 0xe0, 0x49, 0x4e, 0x99, 0x7d, 0x56, 0x6a, + 0x1a, 0x39, 0xb6, 0x76, 0xb9, 0x6a, 0x60, 0x03, + 0xa4, 0xc5, 0xdb, 0x84, 0xf2, 0x46, 0x58, 0x4e, + 0xe6, 0x5a, 0xf7, 0x0f, 0xf2, 0x16, 0x02, 0x78, + 0x16, 0x6d, 0xa1, 0x6d, 0x91, 0xc9, 0xb8, 0xf2, + 0xde, 0xb0, 0x27, 0x51, 0xa1, 0x08, 0x8a, 0xd6, + 0xbe, 0x4e, 0x80, 0xef, 0x96, 0x6e, 0xb7, 0x3e, + 0x66, 0xbc, 0x87, 0xca, 0xd8, 0x7c, 0x77, 0xc0, + 0xb3, 0x4a, 0x21, 0xba, 0x1d, 0xa0, 0xba, 0x6d, + 0x16, 0xca, 0x50, 0x46, 0xdc, 0x4a, 0xbd, 0xa0 +}; + +/* No-reseed test vectors (COUNT=0 from no-reseed section) */ +static const byte sha512_seedB_data[] = { + /* EntropyInput (32 bytes) || Nonce (16 bytes) */ + 0x6b, 0x50, 0xa7, 0xd8, 0xf8, 0xa5, 0x5d, 0x7a, + 0x3d, 0xf8, 0xbb, 0x40, 0xbc, 0xc3, 0xb7, 0x22, + 0xd8, 0x70, 0x8d, 0xe6, 0x7f, 0xda, 0x01, 0x0b, + 0x03, 0xc4, 0xc8, 0x4d, 0x72, 0x09, 0x6f, 0x8c, + 0x3e, 0xc6, 0x49, 0xcc, 0x62, 0x56, 0xd9, 0xfa, + 0x31, 0xdb, 0x7a, 0x29, 0x04, 0xaa, 0xf0, 0x25 +}; +static const byte sha512_outputB_data[] = { + 0x95, 0xb7, 0xf1, 0x7e, 0x98, 0x02, 0xd3, 0x57, + 0x73, 0x92, 0xc6, 0xa9, 0xc0, 0x80, 0x83, 0xb6, + 0x7d, 0xd1, 0x29, 0x22, 0x65, 0xb5, 0xf4, 0x2d, + 0x23, 0x7f, 0x1c, 0x55, 0xbb, 0x9b, 0x10, 0xbf, + 0xcf, 0xd8, 0x2c, 0x77, 0xa3, 0x78, 0xb8, 0x26, + 0x6a, 0x00, 0x99, 0x14, 0x3b, 0x3c, 0x2d, 0x64, + 0x61, 0x1e, 0xee, 0xb6, 0x9a, 0xcd, 0xc0, 0x55, + 0x95, 0x7c, 0x13, 0x9e, 0x8b, 0x19, 0x0c, 0x7a, + 0x06, 0x95, 0x5f, 0x2c, 0x79, 0x7c, 0x27, 0x78, + 0xde, 0x94, 0x03, 0x96, 0xa5, 0x01, 0xf4, 0x0e, + 0x91, 0x39, 0x6a, 0xcf, 0x8d, 0x7e, 0x45, 0xeb, + 0xdb, 0xb5, 0x3b, 0xbf, 0x8c, 0x97, 0x52, 0x30, + 0xd2, 0xf0, 0xff, 0x91, 0x06, 0xc7, 0x61, 0x19, + 0xae, 0x49, 0x8e, 0x7f, 0xbc, 0x03, 0xd9, 0x0f, + 0x8e, 0x4c, 0x51, 0x62, 0x7a, 0xed, 0x5c, 0x8d, + 0x42, 0x63, 0xd5, 0xd2, 0xb9, 0x78, 0x87, 0x3a, + 0x0d, 0xe5, 0x96, 0xee, 0x6d, 0xc7, 0xf7, 0xc2, + 0x9e, 0x37, 0xee, 0xe8, 0xb3, 0x4c, 0x90, 0xdd, + 0x1c, 0xf6, 0xa9, 0xdd, 0xb2, 0x2b, 0x4c, 0xbd, + 0x08, 0x6b, 0x14, 0xb3, 0x5d, 0xe9, 0x3d, 0xa2, + 0xd5, 0xcb, 0x18, 0x06, 0x69, 0x8c, 0xbd, 0x7b, + 0xbb, 0x67, 0xbf, 0xe3, 0xd3, 0x1f, 0xd2, 0xd1, + 0xdb, 0xd2, 0xa1, 0xe0, 0x58, 0xa3, 0xeb, 0x99, + 0xd7, 0xe5, 0x1f, 0x1a, 0x93, 0x8e, 0xed, 0x5e, + 0x1c, 0x1d, 0xe2, 0x3a, 0x6b, 0x43, 0x45, 0xd3, + 0x19, 0x14, 0x09, 0xf9, 0x2f, 0x39, 0xb3, 0x67, + 0x0d, 0x8d, 0xbf, 0xb6, 0x35, 0xd8, 0xe6, 0xa3, + 0x69, 0x32, 0xd8, 0x10, 0x33, 0xd1, 0x44, 0x8d, + 0x63, 0xb4, 0x03, 0xdd, 0xf8, 0x8e, 0x12, 0x1b, + 0x6e, 0x81, 0x9a, 0xc3, 0x81, 0x22, 0x6c, 0x13, + 0x21, 0xe4, 0xb0, 0x86, 0x44, 0xf6, 0x72, 0x7c, + 0x36, 0x8c, 0x5a, 0x9f, 0x7a, 0x4b, 0x3e, 0xe2 +}; +#endif /* WOLFSSL_DRBG_SHA512 */ + + static int wc_RNG_HealthTestLocal(WC_RNG* rng, int reseed, void* heap, int devId) { int ret = 0; + +#ifdef WOLFSSL_DRBG_SHA512 + /* SHA-512 DRBG health test path */ + if (rng->drbgType == WC_DRBG_SHA512) { + #ifdef WOLFSSL_SMALL_STACK_CACHE + byte *check512 = rng->health_check_scratch_512; + DRBG_SHA512_internal* drbg512 = rng->drbg512_scratch; + #else + WC_DECLARE_VAR(check512, byte, RNG_HEALTH_TEST_CHECK_SIZE_SHA512, 0); + WC_DECLARE_VAR(drbg512, DRBG_SHA512_internal, 1, 0); + + WC_ALLOC_VAR_EX(check512, byte, RNG_HEALTH_TEST_CHECK_SIZE_SHA512, + heap, DYNAMIC_TYPE_TMP_BUFFER, return MEMORY_E); + WC_ALLOC_VAR_EX(drbg512, DRBG_SHA512_internal, 1, heap, + DYNAMIC_TYPE_TMP_BUFFER, WC_DO_NOTHING); + #ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC + if (drbg512 == NULL) { + WC_FREE_VAR_EX(check512, heap, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } + #endif + #endif + + if (reseed) { + /* Reseed test with NIST CAVP SHA-512 vectors */ + ret = wc_RNG_HealthTest_SHA512_ex_internal( + drbg512, 1, NULL, 0, NULL, 0, + sha512_seedA_data, sizeof(sha512_seedA_data), + sha512_reseedSeedA_data, + sizeof(sha512_reseedSeedA_data), + NULL, 0, NULL, 0, + check512, RNG_HEALTH_TEST_CHECK_SIZE_SHA512, + heap, devId); + if (ret == 0) { + if (ConstantCompare(check512, sha512_outputA_data, + RNG_HEALTH_TEST_CHECK_SIZE_SHA512) != 0) + ret = -1; + } + } + else { + /* No-reseed test with NIST CAVP SHA-512 vectors */ + ret = wc_RNG_HealthTest_SHA512_ex_internal( + drbg512, 0, NULL, 0, NULL, 0, + sha512_seedB_data, sizeof(sha512_seedB_data), + NULL, 0, + NULL, 0, NULL, 0, + check512, RNG_HEALTH_TEST_CHECK_SIZE_SHA512, + heap, devId); + if (ret == 0) { + if (ConstantCompare(check512, sha512_outputB_data, + RNG_HEALTH_TEST_CHECK_SIZE_SHA512) != 0) + ret = -1; + } + } + + #ifndef WOLFSSL_SMALL_STACK_CACHE + WC_FREE_VAR_EX(check512, heap, DYNAMIC_TYPE_TMP_BUFFER); + WC_FREE_VAR_EX(drbg512, heap, DYNAMIC_TYPE_TMP_BUFFER); + #endif + return ret; + } +#endif /* WOLFSSL_DRBG_SHA512 */ + + /* SHA-256 DRBG health test path (original) */ +#ifndef NO_SHA256 + { #ifdef WOLFSSL_SMALL_STACK_CACHE byte *check = rng->health_check_scratch; DRBG_internal* drbg = (DRBG_internal *)rng->drbg_scratch; @@ -1933,10 +3069,409 @@ static int wc_RNG_HealthTestLocal(WC_RNG* rng, int reseed, void* heap, WC_FREE_VAR_EX(check, heap, DYNAMIC_TYPE_TMP_BUFFER); WC_FREE_VAR_EX(drbg, heap, DYNAMIC_TYPE_TMP_BUFFER); #endif + } /* SHA-256 path */ +#endif /* !NO_SHA256 */ return ret; } +/* ====================================================================== */ +/* SHA-512 Health Test API */ +/* ====================================================================== */ +#ifdef WOLFSSL_DRBG_SHA512 + +static int wc_RNG_HealthTest_SHA512_ex_internal(DRBG_SHA512_internal* drbg, + int reseed, const byte* nonce, word32 nonceSz, + const byte* perso, word32 persoSz, + const byte* seedA, word32 seedASz, + const byte* seedB, word32 seedBSz, + const byte* additionalA, word32 additionalASz, + const byte* additionalB, word32 additionalBSz, + byte* output, word32 outputSz, + void* heap, int devId) +{ + int ret = -1; + + if (seedA == NULL || output == NULL) { + return BAD_FUNC_ARG; + } + + if (reseed != 0 && seedB == NULL) { + return BAD_FUNC_ARG; + } + + if (outputSz != RNG_HEALTH_TEST_CHECK_SIZE_SHA512) { + return ret; + } + +#ifdef WOLFSSL_SMALL_STACK_CACHE + (void)heap; + (void)devId; + + if (Hash512_DRBG_Init(drbg, seedA, seedASz, nonce, nonceSz, + perso, persoSz) != 0) { + goto exit_rng_ht512; + } +#else + if (Hash512_DRBG_Instantiate(drbg, seedA, seedASz, nonce, nonceSz, + perso, persoSz, heap, devId) != 0) { + goto exit_rng_ht512; + } +#endif + + if (reseed) { + if (Hash512_DRBG_Reseed(drbg, seedB, seedBSz, NULL, 0) != 0) { + goto exit_rng_ht512; + } + } + + /* First generate: output discarded per NIST DRBGVS procedure */ + if (Hash512_DRBG_Generate(drbg, output, outputSz, + additionalA, additionalASz) != 0) { + goto exit_rng_ht512; + } + + /* Second generate: this is the actual test output */ + if (Hash512_DRBG_Generate(drbg, output, outputSz, + additionalB, additionalBSz) != 0) { + goto exit_rng_ht512; + } + + ret = 0; + +exit_rng_ht512: + +#ifndef WOLFSSL_SMALL_STACK_CACHE + if (Hash512_DRBG_Uninstantiate(drbg) != 0) { + ret = -1; + } +#endif + + return ret; +} + + +/* Extended API with personalization string and additional input + * for ACVP testing */ +int wc_RNG_HealthTest_SHA512_ex(int reseed, + const byte* nonce, word32 nonceSz, + const byte* persoString, word32 persoStringSz, + const byte* seedA, word32 seedASz, + const byte* seedB, word32 seedBSz, + const byte* additionalA, word32 additionalASz, + const byte* additionalB, word32 additionalBSz, + byte* output, word32 outputSz, + void* heap, int devId) +{ + int ret = -1; + DRBG_SHA512_internal* drbg; +#ifndef WOLFSSL_SMALL_STACK + DRBG_SHA512_internal drbg_var; +#endif + + if (seedA == NULL || output == NULL) { + return BAD_FUNC_ARG; + } + + if (outputSz != RNG_HEALTH_TEST_CHECK_SIZE_SHA512) { + return ret; + } + +#ifdef WOLFSSL_SMALL_STACK + drbg = (DRBG_SHA512_internal*)XMALLOC(sizeof(DRBG_SHA512_internal), heap, + DYNAMIC_TYPE_RNG); + if (drbg == NULL) { + return MEMORY_E; + } +#else + drbg = &drbg_var; +#endif + + /* SP 800-90A Sec 10.1.1.2: personalization string is concatenated + * with entropy during instantiation via Hash_df. */ + ret = Hash512_DRBG_Instantiate(drbg, seedA, seedASz, nonce, nonceSz, + persoString, persoStringSz, heap, devId); + if (ret != 0) { + goto exit_sha512_ex; + } + + if (reseed) { + if (seedB != NULL && seedBSz > 0) { + ret = Hash512_DRBG_Reseed(drbg, seedB, seedBSz, NULL, 0); + if (ret != 0) goto exit_sha512_ex; + } + } + + /* First generate (output discarded per NIST procedure) */ + ret = Hash512_DRBG_Generate(drbg, output, outputSz, + additionalA, additionalASz); + if (ret != 0) goto exit_sha512_ex; + + /* Second generate (this is the actual output) */ + ret = Hash512_DRBG_Generate(drbg, output, outputSz, + additionalB, additionalBSz); + +exit_sha512_ex: + (void)Hash512_DRBG_Uninstantiate(drbg); + +#ifdef WOLFSSL_SMALL_STACK + XFREE(drbg, heap, DYNAMIC_TYPE_RNG); +#endif + + return (ret == DRBG_SUCCESS) ? 0 : -1; +} + + +/* Simple API matching wc_RNG_HealthTest() pattern - entropy+nonce only */ +int wc_RNG_HealthTest_SHA512(int reseed, + const byte* seedA, word32 seedASz, + const byte* seedB, word32 seedBSz, + byte* output, word32 outputSz) +{ + int ret = -1; + DRBG_SHA512_internal* drbg; +#ifndef WOLFSSL_SMALL_STACK + DRBG_SHA512_internal drbg_var; +#endif + +#ifdef WOLFSSL_SMALL_STACK + drbg = (DRBG_SHA512_internal*)XMALLOC(sizeof(DRBG_SHA512_internal), NULL, + DYNAMIC_TYPE_RNG); + if (drbg == NULL) { + return MEMORY_E; + } +#else + drbg = &drbg_var; +#endif + +#ifdef WOLFSSL_SMALL_STACK_CACHE + ret = Hash512_DRBG_Instantiate(drbg, + NULL /* seed */, 0, NULL /* nonce */, 0, + NULL, 0, NULL, INVALID_DEVID); + if (ret == 0) +#endif + { + ret = wc_RNG_HealthTest_SHA512_ex_internal( + drbg, reseed, NULL, 0, NULL, 0, + seedA, seedASz, seedB, seedBSz, + NULL, 0, NULL, 0, + output, outputSz, NULL, INVALID_DEVID); +#ifdef WOLFSSL_SMALL_STACK_CACHE + Hash512_DRBG_Uninstantiate(drbg); +#endif + } + WC_FREE_VAR_EX(drbg, NULL, DYNAMIC_TYPE_RNG); + + return ret; +} + +#endif /* WOLFSSL_DRBG_SHA512 */ + +#ifndef NO_SHA256 +/* Extended SHA-256 Hash_DRBG health test per SP 800-90A. + * Supports flexible output sizes, prediction resistance, personalization + * strings, and additional input. + * + * predResistance=0: Instantiate(entropyA, nonce, perso) -> + * Reseed(entropyB, additionalReseed) -> + * Gen1(additionalA, discard) -> Gen2(additionalB, keep) + * predResistance=1: Instantiate(entropyA, nonce, perso) -> + * Reseed(entropyB, additionalA)+Gen1(NULL, discard) -> + * Reseed(entropyC, additionalB)+Gen2(NULL, keep) + */ +int wc_RNG_HealthTest_SHA256_ex( + int predResistance, + const byte* nonce, word32 nonceSz, + const byte* persoString, word32 persoStringSz, + const byte* entropyA, word32 entropyASz, + const byte* entropyB, word32 entropyBSz, + const byte* entropyC, word32 entropyCsz, + const byte* additionalA, word32 additionalASz, + const byte* additionalB, word32 additionalBSz, + const byte* additionalReseed, word32 additionalReseedSz, + byte* output, word32 outputSz, + void* heap, int devId) +{ + int ret; + DRBG_internal* drbg; +#ifndef WOLFSSL_SMALL_STACK + DRBG_internal drbg_var; +#endif + + if (entropyA == NULL || output == NULL || outputSz == 0) { + return BAD_FUNC_ARG; + } + +#ifdef WOLFSSL_SMALL_STACK + drbg = (DRBG_internal*)XMALLOC(sizeof(DRBG_internal), heap, + DYNAMIC_TYPE_RNG); + if (drbg == NULL) { + return MEMORY_E; + } +#else + drbg = &drbg_var; +#endif + + /* Instantiate with entropy, nonce, personalization string */ + ret = Hash_DRBG_Instantiate(drbg, entropyA, entropyASz, nonce, nonceSz, + persoString, persoStringSz, heap, devId); + if (ret != 0) goto exit_sha256_ex; + + if (predResistance) { + /* Prediction resistance mode per SP 800-90A 9.3.1: + * additional_input is passed to Reseed, Generate gets NULL */ + + /* Reseed 1 with additionalA, then Generate 1 with NULL (discard) */ + if (entropyB != NULL && entropyBSz > 0) { + ret = Hash_DRBG_Reseed(drbg, entropyB, entropyBSz, + additionalA, additionalASz); + if (ret != 0) goto exit_sha256_ex; + } + ret = Hash_DRBG_Generate(drbg, output, outputSz, NULL, 0); + if (ret != 0) goto exit_sha256_ex; + + /* Reseed 2 with additionalB, then Generate 2 with NULL (keep) */ + if (entropyC != NULL && entropyCsz > 0) { + ret = Hash_DRBG_Reseed(drbg, entropyC, entropyCsz, + additionalB, additionalBSz); + if (ret != 0) goto exit_sha256_ex; + } + ret = Hash_DRBG_Generate(drbg, output, outputSz, NULL, 0); + } + else { + /* Standard mode: explicit reseed, then two generates */ + if (entropyB != NULL && entropyBSz > 0) { + ret = Hash_DRBG_Reseed(drbg, entropyB, entropyBSz, + additionalReseed, additionalReseedSz); + if (ret != 0) goto exit_sha256_ex; + } + + /* Generate 1 (output discarded per NIST DRBGVS procedure) */ + ret = Hash_DRBG_Generate(drbg, output, outputSz, + additionalA, additionalASz); + if (ret != 0) goto exit_sha256_ex; + + /* Generate 2 (this is the actual test output) */ + ret = Hash_DRBG_Generate(drbg, output, outputSz, + additionalB, additionalBSz); + } + +exit_sha256_ex: + (void)Hash_DRBG_Uninstantiate(drbg); + +#ifdef WOLFSSL_SMALL_STACK + XFREE(drbg, heap, DYNAMIC_TYPE_RNG); +#endif + + return ret; +} +#endif /* !NO_SHA256 */ + + +#ifdef WOLFSSL_DRBG_SHA512 +/* Extended SHA-512 Hash_DRBG health test per SP 800-90A. + * Supports flexible output sizes and prediction resistance mode. + * + * Per SP 800-90A Section 9.3.1, when prediction resistance is requested, + * the additional_input is consumed by the Reseed step and the subsequent + * Generate uses NULL additional_input. + * + * predResistance=0: Instantiate -> + * Reseed(entropyB, additionalReseed) -> + * Gen1(additionalA, discard) -> Gen2(additionalB, keep) + * predResistance=1: Instantiate -> + * Reseed(entropyB, additionalA)+Gen1(NULL, discard) -> + * Reseed(entropyC, additionalB)+Gen2(NULL, keep) + */ +int wc_RNG_HealthTest_SHA512_ex2( + int predResistance, + const byte* nonce, word32 nonceSz, + const byte* persoString, word32 persoStringSz, + const byte* entropyA, word32 entropyASz, + const byte* entropyB, word32 entropyBSz, + const byte* entropyC, word32 entropyCsz, + const byte* additionalA, word32 additionalASz, + const byte* additionalB, word32 additionalBSz, + const byte* additionalReseed, word32 additionalReseedSz, + byte* output, word32 outputSz, + void* heap, int devId) +{ + int ret; + DRBG_SHA512_internal* drbg; +#ifndef WOLFSSL_SMALL_STACK + DRBG_SHA512_internal drbg_var; +#endif + + if (entropyA == NULL || output == NULL || outputSz == 0) { + return BAD_FUNC_ARG; + } + +#ifdef WOLFSSL_SMALL_STACK + drbg = (DRBG_SHA512_internal*)XMALLOC(sizeof(DRBG_SHA512_internal), heap, + DYNAMIC_TYPE_RNG); + if (drbg == NULL) { + return MEMORY_E; + } +#else + drbg = &drbg_var; +#endif + + /* Instantiate with entropy, nonce, personalization string */ + ret = Hash512_DRBG_Instantiate(drbg, entropyA, entropyASz, nonce, nonceSz, + persoString, persoStringSz, heap, devId); + if (ret != 0) goto exit_sha512_ex2; + + if (predResistance) { + /* Prediction resistance mode per SP 800-90A 9.3.1: + * additional_input is passed to Reseed, Generate gets NULL */ + + /* Reseed 1 with additionalA, then Generate 1 with NULL (discard) */ + if (entropyB != NULL && entropyBSz > 0) { + ret = Hash512_DRBG_Reseed(drbg, entropyB, entropyBSz, + additionalA, additionalASz); + if (ret != 0) goto exit_sha512_ex2; + } + ret = Hash512_DRBG_Generate(drbg, output, outputSz, NULL, 0); + if (ret != 0) goto exit_sha512_ex2; + + /* Reseed 2 with additionalB, then Generate 2 with NULL (keep) */ + if (entropyC != NULL && entropyCsz > 0) { + ret = Hash512_DRBG_Reseed(drbg, entropyC, entropyCsz, + additionalB, additionalBSz); + if (ret != 0) goto exit_sha512_ex2; + } + ret = Hash512_DRBG_Generate(drbg, output, outputSz, NULL, 0); + } + else { + /* Standard mode: explicit reseed, then two generates */ + if (entropyB != NULL && entropyBSz > 0) { + ret = Hash512_DRBG_Reseed(drbg, entropyB, entropyBSz, + additionalReseed, additionalReseedSz); + if (ret != 0) goto exit_sha512_ex2; + } + + /* Generate 1 (output discarded per NIST DRBGVS procedure) */ + ret = Hash512_DRBG_Generate(drbg, output, outputSz, + additionalA, additionalASz); + if (ret != 0) goto exit_sha512_ex2; + + /* Generate 2 (this is the actual test output) */ + ret = Hash512_DRBG_Generate(drbg, output, outputSz, + additionalB, additionalBSz); + } + +exit_sha512_ex2: + (void)Hash512_DRBG_Uninstantiate(drbg); + +#ifdef WOLFSSL_SMALL_STACK + XFREE(drbg, heap, DYNAMIC_TYPE_RNG); +#endif + + return (ret == DRBG_SUCCESS) ? 0 : -1; +} + +#endif /* WOLFSSL_DRBG_SHA512 */ + #endif /* HAVE_HASHDRBG */ diff --git a/wolfcrypt/src/rng_bank.c b/wolfcrypt/src/rng_bank.c index 61a0ce479b..a57b1a2edc 100644 --- a/wolfcrypt/src/rng_bank.c +++ b/wolfcrypt/src/rng_bank.c @@ -26,6 +26,51 @@ #include #include +/* Helpers to access reseedCtr / null-check the active DRBG. The shape of + * struct WC_RNG and the DRBG_*_internal types varies by which DRBGs are + * compiled in; random.h gates the SHA-256 side on !NO_SHA256 and the SHA-512 + * side on WOLFSSL_DRBG_SHA512, so all three live combinations are handled + * separately here. */ +#if defined(WOLFSSL_DRBG_SHA512) && !defined(NO_SHA256) + /* Both DRBGs compiled in: dispatch on the runtime drbgType. */ + #define WC_RNG_BANK_RESEED_CTR(rng_ptr) \ + (((rng_ptr)->drbgType == WC_DRBG_SHA512) \ + ? ((struct DRBG_SHA512_internal *)(rng_ptr)->drbg512)->reseedCtr \ + : ((struct DRBG_internal *)(rng_ptr)->drbg)->reseedCtr) + #define WC_RNG_BANK_SET_RESEED_CTR(rng_ptr, val) \ + do { \ + if ((rng_ptr)->drbgType == WC_DRBG_SHA512) \ + ((struct DRBG_SHA512_internal *)(rng_ptr)->drbg512)->reseedCtr \ + = (val); \ + else \ + ((struct DRBG_internal *)(rng_ptr)->drbg)->reseedCtr = (val); \ + } while (0) + #define WC_RNG_BANK_DRBG_NULL(rng_ptr) \ + ((rng_ptr)->drbg == NULL && (rng_ptr)->drbg512 == NULL) +#elif defined(WOLFSSL_DRBG_SHA512) + /* SHA-512 DRBG only (NO_SHA256 defined); the SHA-256 struct and + * rng->drbg field do not exist in this build. */ + #define WC_RNG_BANK_RESEED_CTR(rng_ptr) \ + (((struct DRBG_SHA512_internal *)(rng_ptr)->drbg512)->reseedCtr) + #define WC_RNG_BANK_SET_RESEED_CTR(rng_ptr, val) \ + do { \ + ((struct DRBG_SHA512_internal *)(rng_ptr)->drbg512)->reseedCtr \ + = (val); \ + } while (0) + #define WC_RNG_BANK_DRBG_NULL(rng_ptr) \ + ((rng_ptr)->drbg512 == NULL) +#else + /* SHA-256 DRBG only (the historical default). */ + #define WC_RNG_BANK_RESEED_CTR(rng_ptr) \ + (((struct DRBG_internal *)(rng_ptr)->drbg)->reseedCtr) + #define WC_RNG_BANK_SET_RESEED_CTR(rng_ptr, val) \ + do { \ + ((struct DRBG_internal *)(rng_ptr)->drbg)->reseedCtr = (val); \ + } while (0) + #define WC_RNG_BANK_DRBG_NULL(rng_ptr) \ + ((rng_ptr)->drbg == NULL) +#endif + WOLFSSL_API int wc_rng_bank_init( struct wc_rng_bank *ctx, int n_rngs, @@ -472,7 +517,7 @@ WOLFSSL_API int wc_rng_bank_checkout( *rng_inst = &bank->rngs[preferred_inst_offset]; if ((! (flags & WC_RNG_BANK_FLAG_CAN_WAIT)) && - (((struct DRBG_internal *)(*rng_inst)->rng.drbg)->reseedCtr >= + (WC_RNG_BANK_RESEED_CTR(&(*rng_inst)->rng) >= WC_RESEED_INTERVAL) && (flags & WC_RNG_BANK_FLAG_CAN_FAIL_OVER_INST) && (n_rngs_tried < bank->n_rngs)) @@ -482,7 +527,7 @@ WOLFSSL_API int wc_rng_bank_checkout( else { #ifdef WC_VERBOSE_RNG if ((! (flags & WC_RNG_BANK_FLAG_CAN_WAIT)) && - (((struct DRBG_internal *)(*rng_inst)->rng.drbg)->reseedCtr >= + (WC_RNG_BANK_RESEED_CTR(&(*rng_inst)->rng) >= WC_RESEED_INTERVAL)) { WOLFSSL_DEBUG_PRINTF( @@ -648,11 +693,12 @@ WOLFSSL_API int wc_rng_bank_inst_reinit( bank = default_rng_bank; #endif + /* rng_inst NULL check handled by rng_inst_matches_bank() */ ret = rng_inst_matches_bank(bank, rng_inst); if (ret < 0) return BAD_FUNC_ARG; - if (rng_inst->rng.drbg == NULL) + if (WC_RNG_BANK_DRBG_NULL(&rng_inst->rng)) { return BAD_FUNC_ARG; } @@ -734,7 +780,7 @@ WOLFSSL_API int wc_rng_bank_seed(struct wc_rng_bank *bank, #endif break; } - else if (drbg->rng.drbg == NULL) { + else if (WC_RNG_BANK_DRBG_NULL(&drbg->rng)) { #ifdef WC_VERBOSE_RNG WOLFSSL_DEBUG_PRINTF( "WARNING: wc_rng_bank_seed(): inst#%d has null .drbg.\n", n); @@ -793,8 +839,7 @@ WOLFSSL_API int wc_rng_bank_reseed(struct wc_rng_bank *bank, if (ret != 0) return ret; - ((struct DRBG_internal *)drbg->rng.drbg)->reseedCtr = - WC_RESEED_INTERVAL; + WC_RNG_BANK_SET_RESEED_CTR(&drbg->rng, WC_RESEED_INTERVAL); if (flags & WC_RNG_BANK_FLAG_CAN_WAIT) { byte scratch[4]; diff --git a/wolfcrypt/src/rsa.c b/wolfcrypt/src/rsa.c index a2dae120f9..b3fbb83fe0 100644 --- a/wolfcrypt/src/rsa.c +++ b/wolfcrypt/src/rsa.c @@ -1137,6 +1137,62 @@ static int RsaMGF1(enum wc_HashType hType, byte* seed, word32 seedSz, } #endif /* SHA2 Hashes */ +#if defined(WOLFSSL_SHA3) && \ + (defined(WOLFSSL_SHAKE128) || defined(WOLFSSL_SHAKE256)) +/* SHAKE XOF used directly as mask generation function (not MGF1). + * Per FIPS 186-5, SHAKE can be used as the MGF for RSA-PSS. */ +static int RsaMGF_SHAKE(enum wc_HashType shakeType, byte* seed, word32 seedSz, + byte* out, word32 outSz, void* heap) +{ + WC_DECLARE_VAR(shake, wc_Shake, 1, heap); + int ret; + + (void)heap; + (void)shakeType; + + WC_ALLOC_VAR_EX(shake, wc_Shake, 1, heap, DYNAMIC_TYPE_TMP_BUFFER, + return MEMORY_E); + +#ifdef WOLFSSL_SHAKE128 + if (shakeType == WC_HASH_TYPE_SHAKE128) + ret = wc_InitShake128(shake, heap, INVALID_DEVID); + else +#endif +#ifdef WOLFSSL_SHAKE256 + if (shakeType == WC_HASH_TYPE_SHAKE256) + ret = wc_InitShake256(shake, heap, INVALID_DEVID); + else +#endif + ret = BAD_FUNC_ARG; + + if (ret == 0) { +#ifdef WOLFSSL_SHAKE128 + if (shakeType == WC_HASH_TYPE_SHAKE128) { + ret = wc_Shake128_Update(shake, seed, seedSz); + if (ret == 0) + ret = wc_Shake128_Final(shake, out, outSz); + wc_Shake128_Free(shake); + } + else +#endif +#ifdef WOLFSSL_SHAKE256 + if (shakeType == WC_HASH_TYPE_SHAKE256) { + ret = wc_Shake256_Update(shake, seed, seedSz); + if (ret == 0) + ret = wc_Shake256_Final(shake, out, outSz); + wc_Shake256_Free(shake); + } + else +#endif + { + ret = BAD_FUNC_ARG; + } + } + WC_FREE_VAR_EX(shake, heap, DYNAMIC_TYPE_TMP_BUFFER); + return ret; +} +#endif /* WOLFSSL_SHA3 && (WOLFSSL_SHAKE128 || WOLFSSL_SHAKE256) */ + /* helper function to direct which mask generation function is used switched on type input */ @@ -1182,6 +1238,52 @@ static int RsaMGF(int type, byte* seed, word32 seedSz, byte* out, heap); break; #endif + #endif + #ifdef WOLFSSL_SHA3 + #ifndef WOLFSSL_NOSHA3_224 + case WC_MGF1SHA3_224: + ret = RsaMGF1(WC_HASH_TYPE_SHA3_224, seed, seedSz, out, outSz, + heap); + break; + #endif + #ifndef WOLFSSL_NOSHA3_256 + case WC_MGF1SHA3_256: + ret = RsaMGF1(WC_HASH_TYPE_SHA3_256, seed, seedSz, out, outSz, + heap); + break; + #endif + #ifndef WOLFSSL_NOSHA3_384 + case WC_MGF1SHA3_384: + ret = RsaMGF1(WC_HASH_TYPE_SHA3_384, seed, seedSz, out, outSz, + heap); + break; + #endif + #ifndef WOLFSSL_NOSHA3_512 + case WC_MGF1SHA3_512: + ret = RsaMGF1(WC_HASH_TYPE_SHA3_512, seed, seedSz, out, outSz, + heap); + break; + #endif + #endif /* WOLFSSL_SHA3 */ + #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128) + case WC_MGF1SHAKE128: + ret = RsaMGF1(WC_HASH_TYPE_SHAKE128, seed, seedSz, out, outSz, + heap); + break; + case WC_MGFSHAKE128: + ret = RsaMGF_SHAKE(WC_HASH_TYPE_SHAKE128, seed, seedSz, out, outSz, + heap); + break; + #endif + #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256) + case WC_MGF1SHAKE256: + ret = RsaMGF1(WC_HASH_TYPE_SHAKE256, seed, seedSz, out, outSz, + heap); + break; + case WC_MGFSHAKE256: + ret = RsaMGF_SHAKE(WC_HASH_TYPE_SHAKE256, seed, seedSz, out, outSz, + heap); + break; #endif default: WOLFSSL_MSG("Unknown MGF type: check build options"); @@ -2115,22 +2217,65 @@ int wc_hash2mgf(enum wc_HashType hType) return WC_MGF1SHA512; #else break; +#endif + case WC_HASH_TYPE_SHA512_224: +#if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_224) + return WC_MGF1SHA512_224; +#else + break; +#endif + case WC_HASH_TYPE_SHA512_256: +#if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_256) + return WC_MGF1SHA512_256; +#else + break; #endif case WC_HASH_TYPE_MD2: case WC_HASH_TYPE_MD4: case WC_HASH_TYPE_MD5: case WC_HASH_TYPE_MD5_SHA: - case WC_HASH_TYPE_SHA512_224: - case WC_HASH_TYPE_SHA512_256: case WC_HASH_TYPE_SHA3_224: +#if defined(WOLFSSL_SHA3) && !defined(WOLFSSL_NOSHA3_224) + return WC_MGF1SHA3_224; +#else + break; +#endif case WC_HASH_TYPE_SHA3_256: +#if defined(WOLFSSL_SHA3) && !defined(WOLFSSL_NOSHA3_256) + return WC_MGF1SHA3_256; +#else + break; +#endif case WC_HASH_TYPE_SHA3_384: +#if defined(WOLFSSL_SHA3) && !defined(WOLFSSL_NOSHA3_384) + return WC_MGF1SHA3_384; +#else + break; +#endif case WC_HASH_TYPE_SHA3_512: +#if defined(WOLFSSL_SHA3) && !defined(WOLFSSL_NOSHA3_512) + return WC_MGF1SHA3_512; +#else + break; +#endif case WC_HASH_TYPE_BLAKE2B: case WC_HASH_TYPE_BLAKE2S: case WC_HASH_TYPE_SM3: + break; +#ifdef WOLFSSL_SHAKE128 case WC_HASH_TYPE_SHAKE128: + return WC_MGF1SHAKE128; +#else + case WC_HASH_TYPE_SHAKE128: + break; +#endif +#ifdef WOLFSSL_SHAKE256 case WC_HASH_TYPE_SHAKE256: + return WC_MGF1SHAKE256; +#else + case WC_HASH_TYPE_SHAKE256: + break; +#endif default: break; } diff --git a/wolfcrypt/src/sha256.c b/wolfcrypt/src/sha256.c index fe094274a3..78240b21cf 100644 --- a/wolfcrypt/src/sha256.c +++ b/wolfcrypt/src/sha256.c @@ -252,6 +252,7 @@ static int InitSha256(wc_Sha256* sha256) sha256->digest[7] = 0x5BE0CD19L; sha256->buffLen = 0; + XMEMSET(sha256->buffer, 0, sizeof(sha256->buffer)); sha256->loLen = 0; sha256->hiLen = 0; #ifdef WOLFSSL_HASH_FLAGS @@ -2101,6 +2102,7 @@ static WC_INLINE int Transform_Sha256_Len(wc_Sha256* sha256, const byte* data, sha224->digest[7] = 0xbefa4fa4; sha224->buffLen = 0; + XMEMSET(sha224->buffer, 0, sizeof(sha224->buffer)); sha224->loLen = 0; sha224->hiLen = 0; diff --git a/wolfcrypt/src/sha3.c b/wolfcrypt/src/sha3.c index d8f702523d..d89827ea4c 100644 --- a/wolfcrypt/src/sha3.c +++ b/wolfcrypt/src/sha3.c @@ -642,6 +642,7 @@ static int InitSha3(wc_Sha3* sha3) for (i = 0; i < 25; i++) sha3->s[i] = 0; + XMEMSET(sha3->t, 0, sizeof(sha3->t)); sha3->i = 0; #ifdef WOLFSSL_HASH_FLAGS sha3->flags = 0; diff --git a/wolfcrypt/src/sha512.c b/wolfcrypt/src/sha512.c index 44b9764cda..425ad745c2 100644 --- a/wolfcrypt/src/sha512.c +++ b/wolfcrypt/src/sha512.c @@ -348,6 +348,7 @@ static int InitSha512(wc_Sha512* sha512) sha512->digest[7] = W64LIT(0x5be0cd19137e2179); sha512->buffLen = 0; + XMEMSET(sha512->buffer, 0, sizeof(sha512->buffer)); sha512->loLen = 0; sha512->hiLen = 0; @@ -403,6 +404,7 @@ static int InitSha512_224(wc_Sha512* sha512) sha512->digest[7] = W64LIT(0x1112e6ad91d692a1); sha512->buffLen = 0; + XMEMSET(sha512->buffer, 0, sizeof(sha512->buffer)); sha512->loLen = 0; sha512->hiLen = 0; @@ -460,6 +462,7 @@ static int InitSha512_256(wc_Sha512* sha512) sha512->digest[7] = W64LIT(0x0eb72ddc81c52ca2); sha512->buffLen = 0; + XMEMSET(sha512->buffer, 0, sizeof(sha512->buffer)); sha512->loLen = 0; sha512->hiLen = 0; @@ -1967,6 +1970,7 @@ static int InitSha384(wc_Sha384* sha384) sha384->digest[7] = W64LIT(0x47b5481dbefa4fa4); sha384->buffLen = 0; + XMEMSET(sha384->buffer, 0, sizeof(sha384->buffer)); sha384->loLen = 0; sha384->hiLen = 0; diff --git a/wolfcrypt/src/wc_lms.c b/wolfcrypt/src/wc_lms.c index 2a3c1edc46..6192dcdba7 100644 --- a/wolfcrypt/src/wc_lms.c +++ b/wolfcrypt/src/wc_lms.c @@ -22,6 +22,11 @@ #include #if defined(WOLFSSL_HAVE_LMS) && defined(WOLFSSL_WC_LMS) + +#if FIPS_VERSION3_GE(2,0,0) + /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */ + #define FIPS_NO_WRAPPERS +#endif #include #ifdef NO_INLINE @@ -109,12 +114,25 @@ static int wc_lmskey_state_init(LmsState* state, const LmsParams* params) /* Keep a reference to the parameters for use in operations. */ state->params = params; +#ifdef WOLFSSL_LMS_SHAKE256 + if (LMS_IS_SHAKE(params->lmOtsType)) { + ret = wc_InitShake256(LMS_STATE_SHAKE(state), NULL, INVALID_DEVID); + if (ret == 0) { + ret = wc_InitShake256(LMS_STATE_SHAKE_K(state), NULL, INVALID_DEVID); + if (ret != 0) { + wc_Shake256_Free(LMS_STATE_SHAKE(state)); + } + } + return ret; + } +#endif + /* Initialize the two hash algorithms. */ - ret = wc_InitSha256(&state->hash); + ret = wc_InitSha256(LMS_STATE_HASH(state)); if (ret == 0) { - ret = wc_InitSha256(&state->hash_k); + ret = wc_InitSha256(LMS_STATE_HASH_K(state)); if (ret != 0) { - wc_Sha256Free(&state->hash); + wc_Sha256Free(LMS_STATE_HASH(state)); } } @@ -127,8 +145,15 @@ static int wc_lmskey_state_init(LmsState* state, const LmsParams* params) */ static void wc_lmskey_state_free(LmsState* state) { - wc_Sha256Free(&state->hash_k); - wc_Sha256Free(&state->hash); +#ifdef WOLFSSL_LMS_SHAKE256 + if (LMS_IS_SHAKE(state->params->lmOtsType)) { + wc_Shake256_Free(LMS_STATE_SHAKE_K(state)); + wc_Shake256_Free(LMS_STATE_SHAKE(state)); + return; + } +#endif + wc_Sha256Free(LMS_STATE_HASH_K(state)); + wc_Sha256Free(LMS_STATE_HASH(state)); } /* Supported LMS parameters. */ @@ -276,6 +301,35 @@ static const wc_LmsParamsMap wc_lms_map[] = { WC_SHA256_DIGEST_SIZE) }, #endif #endif +#if LMS_MAX_HEIGHT >= 25 + { WC_LMS_PARM_L1_H25_W1 , "LMS/HSS_L1_H25_W1", + LMS_PARAMS(1, 25, 1, 1, LMS_SHA256_M32_H25, LMOTS_SHA256_N32_W1, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_L1_H25_W2 , "LMS/HSS_L1_H25_W2", + LMS_PARAMS(1, 25, 2, 1, LMS_SHA256_M32_H25, LMOTS_SHA256_N32_W2, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_L1_H25_W4 , "LMS/HSS_L1_H25_W4", + LMS_PARAMS(1, 25, 4, 2, LMS_SHA256_M32_H25, LMOTS_SHA256_N32_W4, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_L1_H25_W8 , "LMS/HSS_L1_H25_W8", + LMS_PARAMS(1, 25, 8, 3, LMS_SHA256_M32_H25, LMOTS_SHA256_N32_W8, + WC_SHA256_DIGEST_SIZE) }, +#endif +#if LMS_MAX_HEIGHT >= 10 + { WC_LMS_PARM_L1_H10_W1 , "LMS/HSS_L1_H10_W1", + LMS_PARAMS(1, 10, 1, 1, LMS_SHA256_M32_H10, LMOTS_SHA256_N32_W1, + WC_SHA256_DIGEST_SIZE) }, +#endif +#if LMS_MAX_HEIGHT >= 15 + { WC_LMS_PARM_L1_H15_W1 , "LMS/HSS_L1_H15_W1", + LMS_PARAMS(1, 15, 1, 1, LMS_SHA256_M32_H15, LMOTS_SHA256_N32_W1, + WC_SHA256_DIGEST_SIZE) }, +#endif +#if LMS_MAX_HEIGHT >= 20 + { WC_LMS_PARM_L1_H20_W1 , "LMS/HSS_L1_H20_W1", + LMS_PARAMS(1, 20, 1, 1, LMS_SHA256_M32_H20, LMOTS_SHA256_N32_W1, + WC_SHA256_DIGEST_SIZE) }, +#endif #endif /* !WOLFSSL_NO_LMS_SHA256_256 */ #ifdef WOLFSSL_LMS_SHA256_192 @@ -356,7 +410,193 @@ static const wc_LmsParamsMap wc_lms_map[] = { LMS_PARAMS(1, 20, 8, 4, LMS_SHA256_M24_H20, LMOTS_SHA256_N24_W8, WC_SHA256_192_DIGEST_SIZE) }, #endif +#if LMS_MAX_HEIGHT >= 25 + { WC_LMS_PARM_SHA256_192_L1_H25_W1 , "LMS/HSS_SHA256/192_L1_H25_W1", + LMS_PARAMS(1, 25, 1, 2, LMS_SHA256_M24_H25, LMOTS_SHA256_N24_W1, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHA256_192_L1_H25_W2 , "LMS/HSS_SHA256/192_L1_H25_W2", + LMS_PARAMS(1, 25, 2, 2, LMS_SHA256_M24_H25, LMOTS_SHA256_N24_W2, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHA256_192_L1_H25_W4 , "LMS/HSS_SHA256/192_L1_H25_W4", + LMS_PARAMS(1, 25, 4, 3, LMS_SHA256_M24_H25, LMOTS_SHA256_N24_W4, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHA256_192_L1_H25_W8 , "LMS/HSS_SHA256/192_L1_H25_W8", + LMS_PARAMS(1, 25, 8, 4, LMS_SHA256_M24_H25, LMOTS_SHA256_N24_W8, + WC_SHA256_192_DIGEST_SIZE) }, +#endif +#if LMS_MAX_HEIGHT >= 10 + { WC_LMS_PARM_SHA256_192_L1_H10_W1 , "LMS/HSS_SHA256/192_L1_H10_W1", + LMS_PARAMS(1, 10, 1, 2, LMS_SHA256_M24_H10, LMOTS_SHA256_N24_W1, + WC_SHA256_192_DIGEST_SIZE) }, +#endif +#if LMS_MAX_HEIGHT >= 15 + { WC_LMS_PARM_SHA256_192_L1_H15_W1 , "LMS/HSS_SHA256/192_L1_H15_W1", + LMS_PARAMS(1, 15, 1, 2, LMS_SHA256_M24_H15, LMOTS_SHA256_N24_W1, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHA256_192_L1_H15_W8 , "LMS/HSS_SHA256/192_L1_H15_W8", + LMS_PARAMS(1, 15, 8, 4, LMS_SHA256_M24_H15, LMOTS_SHA256_N24_W8, + WC_SHA256_192_DIGEST_SIZE) }, +#endif +#if LMS_MAX_HEIGHT >= 20 + { WC_LMS_PARM_SHA256_192_L1_H20_W1 , "LMS/HSS_SHA256/192_L1_H20_W1", + LMS_PARAMS(1, 20, 1, 2, LMS_SHA256_M24_H20, LMOTS_SHA256_N24_W1, + WC_SHA256_192_DIGEST_SIZE) }, +#endif #endif /* WOLFSSL_LMS_SHA256_192 */ + +#ifdef WOLFSSL_LMS_SHAKE256 +#ifndef WOLFSSL_NO_LMS_SHAKE256_256 + /* SHAKE256/256 L1 H5 */ + { WC_LMS_PARM_SHAKE_L1_H5_W1 , "LMS/HSS_SHAKE256/256_L1_H5_W1", + LMS_PARAMS(1, 5, 1, 1, LMS_SHAKE_M32_H5 , LMOTS_SHAKE_N32_W1, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE_L1_H5_W2 , "LMS/HSS_SHAKE256/256_L1_H5_W2", + LMS_PARAMS(1, 5, 2, 1, LMS_SHAKE_M32_H5 , LMOTS_SHAKE_N32_W2, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE_L1_H5_W4 , "LMS/HSS_SHAKE256/256_L1_H5_W4", + LMS_PARAMS(1, 5, 4, 2, LMS_SHAKE_M32_H5 , LMOTS_SHAKE_N32_W4, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE_L1_H5_W8 , "LMS/HSS_SHAKE256/256_L1_H5_W8", + LMS_PARAMS(1, 5, 8, 3, LMS_SHAKE_M32_H5 , LMOTS_SHAKE_N32_W8, + WC_SHA256_DIGEST_SIZE) }, +#if LMS_MAX_HEIGHT >= 10 + /* SHAKE256/256 L1 H10 */ + { WC_LMS_PARM_SHAKE_L1_H10_W1 , "LMS/HSS_SHAKE256/256_L1_H10_W1", + LMS_PARAMS(1, 10, 1, 1, LMS_SHAKE_M32_H10, LMOTS_SHAKE_N32_W1, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE_L1_H10_W2 , "LMS/HSS_SHAKE256/256_L1_H10_W2", + LMS_PARAMS(1, 10, 2, 1, LMS_SHAKE_M32_H10, LMOTS_SHAKE_N32_W2, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE_L1_H10_W4 , "LMS/HSS_SHAKE256/256_L1_H10_W4", + LMS_PARAMS(1, 10, 4, 2, LMS_SHAKE_M32_H10, LMOTS_SHAKE_N32_W4, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE_L1_H10_W8 , "LMS/HSS_SHAKE256/256_L1_H10_W8", + LMS_PARAMS(1, 10, 8, 3, LMS_SHAKE_M32_H10, LMOTS_SHAKE_N32_W8, + WC_SHA256_DIGEST_SIZE) }, +#endif +#if LMS_MAX_HEIGHT >= 15 + /* SHAKE256/256 L1 H15 */ + { WC_LMS_PARM_SHAKE_L1_H15_W1 , "LMS/HSS_SHAKE256/256_L1_H15_W1", + LMS_PARAMS(1, 15, 1, 1, LMS_SHAKE_M32_H15, LMOTS_SHAKE_N32_W1, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE_L1_H15_W2 , "LMS/HSS_SHAKE256/256_L1_H15_W2", + LMS_PARAMS(1, 15, 2, 1, LMS_SHAKE_M32_H15, LMOTS_SHAKE_N32_W2, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE_L1_H15_W4 , "LMS/HSS_SHAKE256/256_L1_H15_W4", + LMS_PARAMS(1, 15, 4, 2, LMS_SHAKE_M32_H15, LMOTS_SHAKE_N32_W4, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE_L1_H15_W8 , "LMS/HSS_SHAKE256/256_L1_H15_W8", + LMS_PARAMS(1, 15, 8, 3, LMS_SHAKE_M32_H15, LMOTS_SHAKE_N32_W8, + WC_SHA256_DIGEST_SIZE) }, +#endif +#if LMS_MAX_HEIGHT >= 20 + /* SHAKE256/256 L1 H20 */ + { WC_LMS_PARM_SHAKE_L1_H20_W1 , "LMS/HSS_SHAKE256/256_L1_H20_W1", + LMS_PARAMS(1, 20, 1, 1, LMS_SHAKE_M32_H20, LMOTS_SHAKE_N32_W1, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE_L1_H20_W2 , "LMS/HSS_SHAKE256/256_L1_H20_W2", + LMS_PARAMS(1, 20, 2, 1, LMS_SHAKE_M32_H20, LMOTS_SHAKE_N32_W2, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE_L1_H20_W4 , "LMS/HSS_SHAKE256/256_L1_H20_W4", + LMS_PARAMS(1, 20, 4, 2, LMS_SHAKE_M32_H20, LMOTS_SHAKE_N32_W4, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE_L1_H20_W8 , "LMS/HSS_SHAKE256/256_L1_H20_W8", + LMS_PARAMS(1, 20, 8, 3, LMS_SHAKE_M32_H20, LMOTS_SHAKE_N32_W8, + WC_SHA256_DIGEST_SIZE) }, +#endif +#if LMS_MAX_HEIGHT >= 25 + /* SHAKE256/256 L1 H25 */ + { WC_LMS_PARM_SHAKE_L1_H25_W1 , "LMS/HSS_SHAKE256/256_L1_H25_W1", + LMS_PARAMS(1, 25, 1, 1, LMS_SHAKE_M32_H25, LMOTS_SHAKE_N32_W1, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE_L1_H25_W2 , "LMS/HSS_SHAKE256/256_L1_H25_W2", + LMS_PARAMS(1, 25, 2, 1, LMS_SHAKE_M32_H25, LMOTS_SHAKE_N32_W2, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE_L1_H25_W4 , "LMS/HSS_SHAKE256/256_L1_H25_W4", + LMS_PARAMS(1, 25, 4, 2, LMS_SHAKE_M32_H25, LMOTS_SHAKE_N32_W4, + WC_SHA256_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE_L1_H25_W8 , "LMS/HSS_SHAKE256/256_L1_H25_W8", + LMS_PARAMS(1, 25, 8, 3, LMS_SHAKE_M32_H25, LMOTS_SHAKE_N32_W8, + WC_SHA256_DIGEST_SIZE) }, +#endif +#endif /* !WOLFSSL_NO_LMS_SHAKE256_256 */ + +#ifdef WOLFSSL_LMS_SHAKE256 + /* SHAKE256/192 L1 H5 */ + { WC_LMS_PARM_SHAKE192_L1_H5_W1 , "LMS/HSS_SHAKE256/192_L1_H5_W1", + LMS_PARAMS(1, 5, 1, 2, LMS_SHAKE_M24_H5 , LMOTS_SHAKE_N24_W1, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE192_L1_H5_W2 , "LMS/HSS_SHAKE256/192_L1_H5_W2", + LMS_PARAMS(1, 5, 2, 2, LMS_SHAKE_M24_H5 , LMOTS_SHAKE_N24_W2, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE192_L1_H5_W4 , "LMS/HSS_SHAKE256/192_L1_H5_W4", + LMS_PARAMS(1, 5, 4, 3, LMS_SHAKE_M24_H5 , LMOTS_SHAKE_N24_W4, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE192_L1_H5_W8 , "LMS/HSS_SHAKE256/192_L1_H5_W8", + LMS_PARAMS(1, 5, 8, 4, LMS_SHAKE_M24_H5 , LMOTS_SHAKE_N24_W8, + WC_SHA256_192_DIGEST_SIZE) }, +#if LMS_MAX_HEIGHT >= 10 + /* SHAKE256/192 L1 H10 */ + { WC_LMS_PARM_SHAKE192_L1_H10_W1 , "LMS/HSS_SHAKE256/192_L1_H10_W1", + LMS_PARAMS(1, 10, 1, 2, LMS_SHAKE_M24_H10, LMOTS_SHAKE_N24_W1, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE192_L1_H10_W2 , "LMS/HSS_SHAKE256/192_L1_H10_W2", + LMS_PARAMS(1, 10, 2, 2, LMS_SHAKE_M24_H10, LMOTS_SHAKE_N24_W2, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE192_L1_H10_W4 , "LMS/HSS_SHAKE256/192_L1_H10_W4", + LMS_PARAMS(1, 10, 4, 3, LMS_SHAKE_M24_H10, LMOTS_SHAKE_N24_W4, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE192_L1_H10_W8 , "LMS/HSS_SHAKE256/192_L1_H10_W8", + LMS_PARAMS(1, 10, 8, 4, LMS_SHAKE_M24_H10, LMOTS_SHAKE_N24_W8, + WC_SHA256_192_DIGEST_SIZE) }, +#endif +#if LMS_MAX_HEIGHT >= 15 + /* SHAKE256/192 L1 H15 */ + { WC_LMS_PARM_SHAKE192_L1_H15_W1 , "LMS/HSS_SHAKE256/192_L1_H15_W1", + LMS_PARAMS(1, 15, 1, 2, LMS_SHAKE_M24_H15, LMOTS_SHAKE_N24_W1, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE192_L1_H15_W2 , "LMS/HSS_SHAKE256/192_L1_H15_W2", + LMS_PARAMS(1, 15, 2, 2, LMS_SHAKE_M24_H15, LMOTS_SHAKE_N24_W2, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE192_L1_H15_W4 , "LMS/HSS_SHAKE256/192_L1_H15_W4", + LMS_PARAMS(1, 15, 4, 3, LMS_SHAKE_M24_H15, LMOTS_SHAKE_N24_W4, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE192_L1_H15_W8 , "LMS/HSS_SHAKE256/192_L1_H15_W8", + LMS_PARAMS(1, 15, 8, 4, LMS_SHAKE_M24_H15, LMOTS_SHAKE_N24_W8, + WC_SHA256_192_DIGEST_SIZE) }, +#endif +#if LMS_MAX_HEIGHT >= 20 + /* SHAKE256/192 L1 H20 */ + { WC_LMS_PARM_SHAKE192_L1_H20_W1 , "LMS/HSS_SHAKE256/192_L1_H20_W1", + LMS_PARAMS(1, 20, 1, 2, LMS_SHAKE_M24_H20, LMOTS_SHAKE_N24_W1, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE192_L1_H20_W2 , "LMS/HSS_SHAKE256/192_L1_H20_W2", + LMS_PARAMS(1, 20, 2, 2, LMS_SHAKE_M24_H20, LMOTS_SHAKE_N24_W2, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE192_L1_H20_W4 , "LMS/HSS_SHAKE256/192_L1_H20_W4", + LMS_PARAMS(1, 20, 4, 3, LMS_SHAKE_M24_H20, LMOTS_SHAKE_N24_W4, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE192_L1_H20_W8 , "LMS/HSS_SHAKE256/192_L1_H20_W8", + LMS_PARAMS(1, 20, 8, 4, LMS_SHAKE_M24_H20, LMOTS_SHAKE_N24_W8, + WC_SHA256_192_DIGEST_SIZE) }, +#endif +#if LMS_MAX_HEIGHT >= 25 + /* SHAKE256/192 L1 H25 */ + { WC_LMS_PARM_SHAKE192_L1_H25_W1 , "LMS/HSS_SHAKE256/192_L1_H25_W1", + LMS_PARAMS(1, 25, 1, 2, LMS_SHAKE_M24_H25, LMOTS_SHAKE_N24_W1, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE192_L1_H25_W2 , "LMS/HSS_SHAKE256/192_L1_H25_W2", + LMS_PARAMS(1, 25, 2, 2, LMS_SHAKE_M24_H25, LMOTS_SHAKE_N24_W2, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE192_L1_H25_W4 , "LMS/HSS_SHAKE256/192_L1_H25_W4", + LMS_PARAMS(1, 25, 4, 3, LMS_SHAKE_M24_H25, LMOTS_SHAKE_N24_W4, + WC_SHA256_192_DIGEST_SIZE) }, + { WC_LMS_PARM_SHAKE192_L1_H25_W8 , "LMS/HSS_SHAKE256/192_L1_H25_W8", + LMS_PARAMS(1, 25, 8, 4, LMS_SHAKE_M24_H25, LMOTS_SHAKE_N24_W8, + WC_SHA256_192_DIGEST_SIZE) }, +#endif +#endif /* WOLFSSL_LMS_SHAKE256 (M24 entries) */ +#endif /* WOLFSSL_LMS_SHAKE256 */ }; /* Number of parameter sets supported. */ #define WC_LMS_MAP_LEN ((int)(sizeof(wc_lms_map) / sizeof(*wc_lms_map))) @@ -1292,7 +1532,7 @@ int wc_LmsKey_Verify(LmsKey* key, const byte* sig, word32 sigSz, ret = wc_lmskey_state_init(state, key->params); if (ret == 0) { /* Verify signature of message with public key. */ - ret = wc_hss_verify(state, key->pub, msg, msgSz, sig); + ret = wc_hss_verify(state, key->pub, msg, msgSz, sig, sigSz); wc_lmskey_state_free(state); } ForceZero(state, sizeof(LmsState)); diff --git a/wolfcrypt/src/wc_lms_impl.c b/wolfcrypt/src/wc_lms_impl.c index d0baf82183..a6fc89da7f 100644 --- a/wolfcrypt/src/wc_lms_impl.c +++ b/wolfcrypt/src/wc_lms_impl.c @@ -594,6 +594,69 @@ static WC_INLINE int wc_lms_hash_sha256_192_final(wc_Sha256* sha256, byte* hash) } #endif /* WOLFSSL_LMS_SHA256_192 */ +#ifdef WOLFSSL_LMS_SHAKE256 +/* Hash data using SHAKE256 and compute result. + * + * @param [in] shake SHAKE256 hash object. + * @param [in] data Data to hash. + * @param [in] len Length of data to hash. + * @param [out] hash Hash output. + * @param [in] hashLen Length of hash output. + * @return 0 on success. + */ +static WC_INLINE int wc_lms_shake256_hash(wc_Shake* shake, byte* data, + word32 len, byte* hash, word32 hashLen) +{ + int ret; + + ret = wc_Shake256_Update(shake, data, len); + if (ret == 0) { + ret = wc_Shake256_Final(shake, hash, hashLen); + } + + return ret; +} + +/* Update hash with first data using SHAKE256. + * + * @param [in] shake SHAKE256 hash object. + * @param [in] data Data to hash. + * @param [in] len Length of data to hash. + * @return 0 on success. + */ +static WC_INLINE int wc_lms_shake256_hash_first(wc_Shake* shake, + const byte* data, word32 len) +{ + return wc_Shake256_Update(shake, data, len); +} + +/* Update hash with further data using SHAKE256. + * + * @param [in] shake SHAKE256 hash object. + * @param [in] data Data to hash. + * @param [in] len Length of data to hash. + * @return 0 on success. + */ +static WC_INLINE int wc_lms_shake256_hash_update(wc_Shake* shake, + const byte* data, word32 len) +{ + return wc_Shake256_Update(shake, data, len); +} + +/* Finalize SHAKE256 hash. + * + * @param [in] shake SHAKE256 hash object. + * @param [out] hash Hash output. + * @param [in] hashLen Length of hash output. + * @return 0 on success. + */ +static WC_INLINE int wc_lms_shake256_hash_final(wc_Shake* shake, byte* hash, + word32 hashLen) +{ + return wc_Shake256_Final(shake, hash, hashLen); +} +#endif /* WOLFSSL_LMS_SHAKE256 */ + /*************************************** * LM-OTS APIs **************************************/ @@ -809,33 +872,59 @@ static int wc_lmots_msg_hash(LmsState* state, const byte* msg, word32 msgSz, /* I || u32str(q) || u16str(D_MESG) */ c16toa(LMS_D_MESG, ip); - /* H(I || u32str(q) || u16str(D_MESG) || ...) */ - ret = wc_lms_hash_first(&state->hash, buffer, LMS_MSG_PRE_LEN); - if (ret == 0) { - /* H(... || C || ...) */ - ret = wc_lms_hash_update(&state->hash, c, state->params->hash_len); - } - if (ret == 0) { - /* H(... || message) */ - ret = wc_lms_hash_update(&state->hash, msg, msgSz); - } -#ifdef WOLFSSL_LMS_SHA256_192 - if ((ret == 0) && - ((state->params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192)) { - /* Q = H(...) */ - ret = wc_lms_hash_sha256_192_final(&state->hash, q); - } - else -#endif -#ifndef WOLFSSL_NO_LMS_SHA256_256 - if (ret == 0) { - /* Q = H(...) */ - ret = wc_lms_hash_final(&state->hash, q); +#ifdef WOLFSSL_LMS_SHAKE256 + if (LMS_IS_SHAKE(state->params->lmOtsType)) { + /* H(I || u32str(q) || u16str(D_MESG) || ...) */ + ret = wc_lms_shake256_hash_first(LMS_STATE_SHAKE(state), buffer, + LMS_MSG_PRE_LEN); + if (ret == 0) { + /* H(... || C || ...) */ + ret = wc_lms_shake256_hash_update(LMS_STATE_SHAKE(state), c, + state->params->hash_len); + } + if (ret == 0) { + /* H(... || message) */ + ret = wc_lms_shake256_hash_update(LMS_STATE_SHAKE(state), msg, msgSz); + } + if (ret == 0) { + /* Q = H(...) */ + ret = wc_lms_shake256_hash_final(LMS_STATE_SHAKE(state), q, + state->params->hash_len); + } } else #endif { - ret = NOT_COMPILED_IN; + /* H(I || u32str(q) || u16str(D_MESG) || ...) */ + ret = wc_lms_hash_first(LMS_STATE_HASH(state), buffer, LMS_MSG_PRE_LEN); + if (ret == 0) { + /* H(... || C || ...) */ + ret = wc_lms_hash_update(LMS_STATE_HASH(state), c, + state->params->hash_len); + } + if (ret == 0) { + /* H(... || message) */ + ret = wc_lms_hash_update(LMS_STATE_HASH(state), msg, msgSz); + } + #ifdef WOLFSSL_LMS_SHA256_192 + if ((ret == 0) && + ((state->params->lmOtsType & LMS_HASH_MASK) == + LMS_SHA256_192)) { + /* Q = H(...) */ + ret = wc_lms_hash_sha256_192_final(LMS_STATE_HASH(state), q); + } + else + #endif + #ifndef WOLFSSL_NO_LMS_SHA256_256 + if (ret == 0) { + /* Q = H(...) */ + ret = wc_lms_hash_final(LMS_STATE_HASH(state), q); + } + else + #endif + { + ret = NOT_COMPILED_IN; + } } return ret; @@ -896,7 +985,12 @@ static int wc_lmots_compute_y_from_seed(LmsState* state, const byte* seed, params->ls, a); } #ifndef WC_LMS_FULL_HASH - if (ret == 0) { +#ifdef WOLFSSL_LMS_SHAKE256 + if ((ret == 0) && !LMS_IS_SHAKE(params->lmOtsType)) +#else + if (ret == 0) +#endif + { #ifdef WOLFSSL_LMS_SHA256_192 if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { /* Put in padding for final block. */ @@ -921,18 +1015,27 @@ static int wc_lmots_compute_y_from_seed(LmsState* state, const byte* seed, * = H(I || u32str(q) || u16str(i) || u8str(0xff) || SEED). */ c16toa(i, ip); *jp = LMS_D_FIXED; +#ifdef WOLFSSL_LMS_SHAKE256 + if (LMS_IS_SHAKE(params->lmOtsType)) { + XMEMCPY(tmp, seed, params->hash_len); + ret = wc_lms_shake256_hash(LMS_STATE_SHAKE(state), buffer, + LMS_HASH_BUFFER_LEN(params->hash_len), tmp, params->hash_len); + } + else +#endif + { #ifndef WC_LMS_FULL_HASH #ifdef WOLFSSL_LMS_SHA256_192 if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { XMEMCPY(tmp, seed, WC_SHA256_192_DIGEST_SIZE); - ret = wc_lms_sha256_192_hash_block(&state->hash, buffer, tmp); + ret = wc_lms_sha256_192_hash_block(LMS_STATE_HASH(state), buffer, tmp); } else #endif { #ifndef WOLFSSL_NO_LMS_SHA256_256 XMEMCPY(tmp, seed, WC_SHA256_DIGEST_SIZE); - ret = wc_lms_hash_block(&state->hash, buffer, tmp); + ret = wc_lms_hash_block(LMS_STATE_HASH(state), buffer, tmp); #else ret = NOT_COMPILED_IN; #endif @@ -941,7 +1044,7 @@ static int wc_lmots_compute_y_from_seed(LmsState* state, const byte* seed, #ifdef WOLFSSL_LMS_SHA256_192 if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { XMEMCPY(tmp, seed, WC_SHA256_192_DIGEST_SIZE); - ret = wc_lms_hash_sha256_192(&state->hash, buffer, + ret = wc_lms_hash_sha256_192(LMS_STATE_HASH(state), buffer, LMS_HASH_BUFFER_LEN(WC_SHA256_192_DIGEST_SIZE), tmp); } else @@ -949,29 +1052,39 @@ static int wc_lmots_compute_y_from_seed(LmsState* state, const byte* seed, { #ifndef WOLFSSL_NO_LMS_SHA256_256 XMEMCPY(tmp, seed, WC_SHA256_DIGEST_SIZE); - ret = wc_lms_hash(&state->hash, buffer, + ret = wc_lms_hash(LMS_STATE_HASH(state), buffer, LMS_HASH_BUFFER_LEN(WC_SHA256_DIGEST_SIZE), tmp); #else ret = NOT_COMPILED_IN; #endif } #endif /* !WC_LMS_FULL_HASH */ + } /* Apply the hash function coefficient number of times. */ for (j = 0; (ret == 0) && (j < a[i]); j++) { /* I || u32str(q) || u16str(i) || u8str(j) || tmp */ *jp = j; /* tmp = H(I || u32str(q) || u16str(i) || u8str(j) || tmp) */ + #ifdef WOLFSSL_LMS_SHAKE256 + if (LMS_IS_SHAKE(params->lmOtsType)) { + ret = wc_lms_shake256_hash(LMS_STATE_SHAKE(state), buffer, + LMS_HASH_BUFFER_LEN(params->hash_len), tmp, + params->hash_len); + } + else + #endif + { #ifndef WC_LMS_FULL_HASH #ifdef WOLFSSL_LMS_SHA256_192 if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { - ret = wc_lms_sha256_192_hash_block(&state->hash, buffer, tmp); + ret = wc_lms_sha256_192_hash_block(LMS_STATE_HASH(state), buffer, tmp); } else #endif { #ifndef WOLFSSL_NO_LMS_SHA256_256 - ret = wc_lms_hash_block(&state->hash, buffer, tmp); + ret = wc_lms_hash_block(LMS_STATE_HASH(state), buffer, tmp); #else ret = NOT_COMPILED_IN; #endif @@ -979,20 +1092,21 @@ static int wc_lmots_compute_y_from_seed(LmsState* state, const byte* seed, #else #ifdef WOLFSSL_LMS_SHA256_192 if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { - ret = wc_lms_hash_sha256_192(&state->hash, buffer, + ret = wc_lms_hash_sha256_192(LMS_STATE_HASH(state), buffer, LMS_HASH_BUFFER_LEN(WC_SHA256_192_DIGEST_SIZE), tmp); } else #endif { #ifndef WOLFSSL_NO_LMS_SHA256_256 - ret = wc_lms_hash(&state->hash, buffer, + ret = wc_lms_hash(LMS_STATE_HASH(state), buffer, LMS_HASH_BUFFER_LEN(WC_SHA256_DIGEST_SIZE), tmp); #else ret = NOT_COMPILED_IN; #endif } #endif /* !WC_LMS_FULL_HASH */ + } } if (ret == 0) { @@ -1055,107 +1169,163 @@ static int wc_lmots_compute_kc_from_sig(LmsState* state, const byte* msg, /* I || u32str(q) || u16str(D_PBLC). */ c16toa(LMS_D_PBLC, ip); - /* H(I || u32str(q) || u16str(D_PBLC) || ...). */ - ret = wc_lms_hash_first(&state->hash_k, buffer, LMS_K_PRE_LEN); - if (ret == 0) { - /* Q = H(I || u32str(q) || u16str(D_MESG) || C || message) */ - ret = wc_lmots_msg_hash(state, msg, msgSz, c, q); - } - if (ret == 0) { - /* Calculate checksum list all coefficients. */ - ret = wc_lmots_q_expand(q, (word8)params->hash_len, params->width, - params->ls, a); - } -#ifndef WC_LMS_FULL_HASH - if (ret == 0) { - #ifdef WOLFSSL_LMS_SHA256_192 - if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { - /* Put in padding for final block. */ - LMS_SHA256_SET_LEN_47(buffer); +#ifdef WOLFSSL_LMS_SHAKE256 + if (LMS_IS_SHAKE(params->lmOtsType)) { + /* H(I || u32str(q) || u16str(D_PBLC) || ...). */ + ret = wc_lms_shake256_hash_first(LMS_STATE_SHAKE_K(state), buffer, + LMS_K_PRE_LEN); + if (ret == 0) { + /* Q = H(I || u32str(q) || u16str(D_MESG) || C || message) */ + ret = wc_lmots_msg_hash(state, msg, msgSz, c, q); } - else - #endif - { - #ifndef WOLFSSL_NO_LMS_SHA256_256 - /* Put in padding for final block. */ - LMS_SHA256_SET_LEN_55(buffer); - #endif + if (ret == 0) { + /* Calculate checksum list all coefficients. */ + ret = wc_lmots_q_expand(q, (word8)params->hash_len, params->width, + params->ls, a); } - } -#endif /* !WC_LMS_FULL_HASH */ - /* Compute z for each coefficient. */ - for (i = 0; (ret == 0) && (i < params->p); i++) { - unsigned int j; + /* Compute z for each coefficient. */ + for (i = 0; (ret == 0) && (i < params->p); i++) { + unsigned int j; - /* I || u32(str) || u16str(i) || ... */ - c16toa(i, ip); + /* I || u32(str) || u16str(i) || ... */ + c16toa(i, ip); - /* tmp = y[i]. - * I || u32(str) || u16str(i) || ... || tmp */ - XMEMCPY(tmp, sig_y, params->hash_len); - sig_y += params->hash_len; + /* tmp = y[i]. + * I || u32(str) || u16str(i) || ... || tmp */ + XMEMCPY(tmp, sig_y, params->hash_len); + sig_y += params->hash_len; - /* Finish iterations of hash from coefficient to max. */ - for (j = a[i]; (ret == 0) && (j < max); j++) { - /* I || u32str(q) || u16str(i) || u8str(j) || tmp */ - *jp = (word8)j; - /* tmp = H(I || u32str(q) || u16str(i) || u8str(j) || tmp) */ - #ifndef WC_LMS_FULL_HASH - #ifdef WOLFSSL_LMS_SHA256_192 - if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { - ret = wc_lms_sha256_192_hash_block(&state->hash, buffer, tmp); + /* Finish iterations of hash from coefficient to max. */ + for (j = a[i]; (ret == 0) && (j < max); j++) { + /* I || u32str(q) || u16str(i) || u8str(j) || tmp */ + *jp = (word8)j; + /* tmp = H(I || u32str(q) || u16str(i) || u8str(j) || tmp) */ + ret = wc_lms_shake256_hash(LMS_STATE_SHAKE(state), buffer, + LMS_HASH_BUFFER_LEN(params->hash_len), tmp, + params->hash_len); } - else - #endif - { - #ifndef WOLFSSL_NO_LMS_SHA256_256 - ret = wc_lms_hash_block(&state->hash, buffer, tmp); - #else - ret = NOT_COMPILED_IN; - #endif + + if (ret == 0) { + /* H(... || z[i] || ...) (for calculating Kc). */ + ret = wc_lms_shake256_hash_update(LMS_STATE_SHAKE_K(state), tmp, + params->hash_len); } - /* Apply the hash function coefficient number of times. */ - #else - #ifdef WOLFSSL_LMS_SHA256_192 - if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { - ret = wc_lms_hash_sha256_192(&state->hash, buffer, - LMS_HASH_BUFFER_LEN(WC_SHA256_192_DIGEST_SIZE), tmp); - } - else - #endif - { - #ifndef WOLFSSL_NO_LMS_SHA256_256 - ret = wc_lms_hash(&state->hash, buffer, - LMS_HASH_BUFFER_LEN(WC_SHA256_DIGEST_SIZE), tmp); - #else - ret = NOT_COMPILED_IN; - #endif - } - #endif /* !WC_LMS_FULL_HASH */ } if (ret == 0) { - /* H(... || z[i] || ...) (for calculating Kc). */ - ret = wc_lms_hash_update(&state->hash_k, tmp, params->hash_len); + /* Kc = H(...) */ + ret = wc_lms_shake256_hash_final(LMS_STATE_SHAKE_K(state), kc, + params->hash_len); } } - -#ifdef WOLFSSL_LMS_SHA256_192 - if ((ret == 0) && - ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192)) { - /* Kc = H(...) */ - ret = wc_lms_hash_sha256_192_final(&state->hash_k, kc); - } else #endif - if (ret == 0) { - #ifndef WOLFSSL_NO_LMS_SHA256_256 - /* Kc = H(...) */ - ret = wc_lms_hash_final(&state->hash_k, kc); - #else - ret = NOT_COMPILED_IN; + { + /* H(I || u32str(q) || u16str(D_PBLC) || ...). */ + ret = wc_lms_hash_first(LMS_STATE_HASH_K(state), buffer, LMS_K_PRE_LEN); + if (ret == 0) { + /* Q = H(I || u32str(q) || u16str(D_MESG) || C || message) */ + ret = wc_lmots_msg_hash(state, msg, msgSz, c, q); + } + if (ret == 0) { + /* Calculate checksum list all coefficients. */ + ret = wc_lmots_q_expand(q, (word8)params->hash_len, params->width, + params->ls, a); + } +#ifndef WC_LMS_FULL_HASH + if (ret == 0) { + #ifdef WOLFSSL_LMS_SHA256_192 + if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { + /* Put in padding for final block. */ + LMS_SHA256_SET_LEN_47(buffer); + } + else + #endif + { + #ifndef WOLFSSL_NO_LMS_SHA256_256 + /* Put in padding for final block. */ + LMS_SHA256_SET_LEN_55(buffer); + #endif + } + } +#endif /* !WC_LMS_FULL_HASH */ + + /* Compute z for each coefficient. */ + for (i = 0; (ret == 0) && (i < params->p); i++) { + unsigned int j; + + /* I || u32(str) || u16str(i) || ... */ + c16toa(i, ip); + + /* tmp = y[i]. + * I || u32(str) || u16str(i) || ... || tmp */ + XMEMCPY(tmp, sig_y, params->hash_len); + sig_y += params->hash_len; + + /* Finish iterations of hash from coefficient to max. */ + for (j = a[i]; (ret == 0) && (j < max); j++) { + /* I || u32str(q) || u16str(i) || u8str(j) || tmp */ + *jp = (word8)j; + /* tmp = H(I || u32str(q) || u16str(i) || u8str(j) || tmp) */ + #ifndef WC_LMS_FULL_HASH + #ifdef WOLFSSL_LMS_SHA256_192 + if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { + ret = wc_lms_sha256_192_hash_block(LMS_STATE_HASH(state), buffer, + tmp); + } + else + #endif + { + #ifndef WOLFSSL_NO_LMS_SHA256_256 + ret = wc_lms_hash_block(LMS_STATE_HASH(state), buffer, tmp); + #else + ret = NOT_COMPILED_IN; + #endif + } + /* Apply the hash function coefficient number of times. */ + #else + #ifdef WOLFSSL_LMS_SHA256_192 + if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { + ret = wc_lms_hash_sha256_192(LMS_STATE_HASH(state), buffer, + LMS_HASH_BUFFER_LEN(WC_SHA256_192_DIGEST_SIZE), tmp); + } + else + #endif + { + #ifndef WOLFSSL_NO_LMS_SHA256_256 + ret = wc_lms_hash(LMS_STATE_HASH(state), buffer, + LMS_HASH_BUFFER_LEN(WC_SHA256_DIGEST_SIZE), tmp); + #else + ret = NOT_COMPILED_IN; + #endif + } + #endif /* !WC_LMS_FULL_HASH */ + } + + if (ret == 0) { + /* H(... || z[i] || ...) (for calculating Kc). */ + ret = wc_lms_hash_update(LMS_STATE_HASH_K(state), tmp, + params->hash_len); + } + } + + #ifdef WOLFSSL_LMS_SHA256_192 + if ((ret == 0) && + ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192)) { + /* Kc = H(...) */ + ret = wc_lms_hash_sha256_192_final(LMS_STATE_HASH_K(state), kc); + } + else #endif + if (ret == 0) { + #ifndef WOLFSSL_NO_LMS_SHA256_256 + /* Kc = H(...) */ + ret = wc_lms_hash_final(LMS_STATE_HASH_K(state), kc); + #else + ret = NOT_COMPILED_IN; + #endif + } } return ret; @@ -1199,123 +1369,170 @@ static int wc_lmots_make_public_hash(LmsState* state, const byte* seed, byte* k) /* I || u32str(q) || u16str(D_PBLC). */ c16toa(LMS_D_PBLC, ip); - /* K = H(I || u32str(q) || u16str(D_PBLC) || ...) */ - ret = wc_lms_hash_first(&state->hash_k, buffer, LMS_K_PRE_LEN); +#ifdef WOLFSSL_LMS_SHAKE256 + if (LMS_IS_SHAKE(params->lmOtsType)) { + /* K = H(I || u32str(q) || u16str(D_PBLC) || ...) */ + ret = wc_lms_shake256_hash_first(LMS_STATE_SHAKE_K(state), buffer, + LMS_K_PRE_LEN); -#ifndef WC_LMS_FULL_HASH -#ifdef WOLFSSL_LMS_SHA256_192 - if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { - /* Put in padding for final block. */ - LMS_SHA256_SET_LEN_47(buffer); + for (i = 0; (ret == 0) && (i < params->p); i++) { + unsigned int j; + + /* tmp = x[i] + * = H(I || u32str(q) || u16str(i) || u8str(0xff) || SEED). */ + c16toa(i, ip); + *jp = LMS_D_FIXED; + XMEMCPY(tmp, seed, params->hash_len); + ret = wc_lms_shake256_hash(LMS_STATE_SHAKE(state), buffer, + LMS_HASH_BUFFER_LEN(params->hash_len), tmp, params->hash_len); + /* Do all iterations to calculate y. */ + for (j = 0; (ret == 0) && (j < max); j++) { + /* I || u32str(q) || u16str(i) || u8str(j) || tmp */ + *jp = (word8)j; + /* tmp = H(I || u32str(q) || u16str(i) || u8str(j) || tmp) */ + ret = wc_lms_shake256_hash(LMS_STATE_SHAKE(state), buffer, + LMS_HASH_BUFFER_LEN(params->hash_len), tmp, + params->hash_len); + } + if (ret == 0) { + /* K = H(... || y[i] || ...) */ + ret = wc_lms_shake256_hash_update(LMS_STATE_SHAKE_K(state), tmp, + params->hash_len); + } + } + if (ret == 0) { + /* K = H(I || u32str(q) || u16str(D_PBLC) || + * y[0] || ... || y[p-1]) */ + ret = wc_lms_shake256_hash_final(LMS_STATE_SHAKE_K(state), k, + params->hash_len); + } } else #endif { - #ifndef WOLFSSL_NO_LMS_SHA256_256 - /* Put in padding for final block. */ - LMS_SHA256_SET_LEN_55(buffer); - #endif - } -#endif /* !WC_LMS_FULL_HASH */ + /* K = H(I || u32str(q) || u16str(D_PBLC) || ...) */ + ret = wc_lms_hash_first(LMS_STATE_HASH_K(state), buffer, LMS_K_PRE_LEN); - for (i = 0; (ret == 0) && (i < params->p); i++) { - unsigned int j; - - /* tmp = x[i] - * = H(I || u32str(q) || u16str(i) || u8str(0xff) || SEED). */ - c16toa(i, ip); - *jp = LMS_D_FIXED; #ifndef WC_LMS_FULL_HASH #ifdef WOLFSSL_LMS_SHA256_192 if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { - XMEMCPY(tmp, seed, WC_SHA256_192_DIGEST_SIZE); - ret = wc_lms_sha256_192_hash_block(&state->hash, buffer, tmp); + /* Put in padding for final block. */ + LMS_SHA256_SET_LEN_47(buffer); } else #endif { #ifndef WOLFSSL_NO_LMS_SHA256_256 - XMEMCPY(tmp, seed, WC_SHA256_DIGEST_SIZE); - ret = wc_lms_hash_block(&state->hash, buffer, tmp); - #else - ret = NOT_COMPILED_IN; - #endif - } -#else - #ifdef WOLFSSL_LMS_SHA256_192 - if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { - XMEMCPY(tmp, seed, WC_SHA256_192_DIGEST_SIZE); - ret = wc_lms_hash_sha256_192(&state->hash, buffer, - LMS_HASH_BUFFER_LEN(WC_SHA256_192_DIGEST_SIZE), tmp); - } - else - #endif - { - #ifndef WOLFSSL_NO_LMS_SHA256_256 - XMEMCPY(tmp, seed, WC_SHA256_DIGEST_SIZE); - ret = wc_lms_hash(&state->hash, buffer, - LMS_HASH_BUFFER_LEN(WC_SHA256_DIGEST_SIZE), tmp); - #else - ret = NOT_COMPILED_IN; + /* Put in padding for final block. */ + LMS_SHA256_SET_LEN_55(buffer); #endif } #endif /* !WC_LMS_FULL_HASH */ - /* Do all iterations to calculate y. */ - for (j = 0; (ret == 0) && (j < max); j++) { - /* I || u32str(q) || u16str(i) || u8str(j) || tmp */ - *jp = (word8)j; - /* tmp = H(I || u32str(q) || u16str(i) || u8str(j) || tmp) */ - #ifndef WC_LMS_FULL_HASH + + for (i = 0; (ret == 0) && (i < params->p); i++) { + unsigned int j; + + /* tmp = x[i] + * = H(I || u32str(q) || u16str(i) || u8str(0xff) || SEED). */ + c16toa(i, ip); + *jp = LMS_D_FIXED; +#ifndef WC_LMS_FULL_HASH #ifdef WOLFSSL_LMS_SHA256_192 if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { - ret = wc_lms_sha256_192_hash_block(&state->hash, buffer, tmp); + XMEMCPY(tmp, seed, WC_SHA256_192_DIGEST_SIZE); + ret = wc_lms_sha256_192_hash_block(LMS_STATE_HASH(state), buffer, tmp); } else #endif { #ifndef WOLFSSL_NO_LMS_SHA256_256 - ret = wc_lms_hash_block(&state->hash, buffer, tmp); + XMEMCPY(tmp, seed, WC_SHA256_DIGEST_SIZE); + ret = wc_lms_hash_block(LMS_STATE_HASH(state), buffer, tmp); #else ret = NOT_COMPILED_IN; #endif } - #else +#else #ifdef WOLFSSL_LMS_SHA256_192 if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { - ret = wc_lms_hash_sha256_192(&state->hash, buffer, + XMEMCPY(tmp, seed, WC_SHA256_192_DIGEST_SIZE); + ret = wc_lms_hash_sha256_192(LMS_STATE_HASH(state), buffer, LMS_HASH_BUFFER_LEN(WC_SHA256_192_DIGEST_SIZE), tmp); } else #endif { #ifndef WOLFSSL_NO_LMS_SHA256_256 - ret = wc_lms_hash(&state->hash, buffer, + XMEMCPY(tmp, seed, WC_SHA256_DIGEST_SIZE); + ret = wc_lms_hash(LMS_STATE_HASH(state), buffer, LMS_HASH_BUFFER_LEN(WC_SHA256_DIGEST_SIZE), tmp); #else ret = NOT_COMPILED_IN; #endif } - #endif /* !WC_LMS_FULL_HASH */ +#endif /* !WC_LMS_FULL_HASH */ + /* Do all iterations to calculate y. */ + for (j = 0; (ret == 0) && (j < max); j++) { + /* I || u32str(q) || u16str(i) || u8str(j) || tmp */ + *jp = (word8)j; + /* tmp = H(I || u32str(q) || u16str(i) || u8str(j) || tmp) */ + #ifndef WC_LMS_FULL_HASH + #ifdef WOLFSSL_LMS_SHA256_192 + if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { + ret = wc_lms_sha256_192_hash_block(LMS_STATE_HASH(state), buffer, + tmp); + } + else + #endif + { + #ifndef WOLFSSL_NO_LMS_SHA256_256 + ret = wc_lms_hash_block(LMS_STATE_HASH(state), buffer, tmp); + #else + ret = NOT_COMPILED_IN; + #endif + } + #else + #ifdef WOLFSSL_LMS_SHA256_192 + if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { + ret = wc_lms_hash_sha256_192(LMS_STATE_HASH(state), buffer, + LMS_HASH_BUFFER_LEN(WC_SHA256_192_DIGEST_SIZE), tmp); + } + else + #endif + { + #ifndef WOLFSSL_NO_LMS_SHA256_256 + ret = wc_lms_hash(LMS_STATE_HASH(state), buffer, + LMS_HASH_BUFFER_LEN(WC_SHA256_DIGEST_SIZE), tmp); + #else + ret = NOT_COMPILED_IN; + #endif + } + #endif /* !WC_LMS_FULL_HASH */ + } + if (ret == 0) { + /* K = H(... || y[i] || ...) */ + ret = wc_lms_hash_update(LMS_STATE_HASH_K(state), tmp, + params->hash_len); + } } - if (ret == 0) { - /* K = H(... || y[i] || ...) */ - ret = wc_lms_hash_update(&state->hash_k, tmp, params->hash_len); + #ifdef WOLFSSL_LMS_SHA256_192 + if ((ret == 0) && + ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192)) { + /* K = H(I || u32str(q) || u16str(D_PBLC) || + * y[0] || ... || y[p-1]) */ + ret = wc_lms_hash_sha256_192_final(LMS_STATE_HASH_K(state), k); } - } -#ifdef WOLFSSL_LMS_SHA256_192 - if ((ret == 0) && ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192)) { - /* K = H(I || u32str(q) || u16str(D_PBLC) || y[0] || ... || y[p-1]) */ - ret = wc_lms_hash_sha256_192_final(&state->hash_k, k); - } - else -#endif - if (ret == 0) { - #ifndef WOLFSSL_NO_LMS_SHA256_256 - /* K = H(I || u32str(q) || u16str(D_PBLC) || y[0] || ... || y[p-1]) */ - ret = wc_lms_hash_final(&state->hash_k, k); - #else - ret = NOT_COMPILED_IN; + else #endif + if (ret == 0) { + #ifndef WOLFSSL_NO_LMS_SHA256_256 + /* K = H(I || u32str(q) || u16str(D_PBLC) || + * y[0] || ... || y[p-1]) */ + ret = wc_lms_hash_final(LMS_STATE_HASH_K(state), k); + #else + ret = NOT_COMPILED_IN; + #endif + } } return ret; @@ -1473,6 +1690,19 @@ static int wc_lmots_sign(LmsState* state, const byte* seed, const byte* msg, c16toa(LMS_D_C, ip); /* I || u32str(q) || u16str(0xFFFD) || u8str(0xFF) || ... */ *jp = LMS_D_FIXED; +#ifdef WOLFSSL_LMS_SHAKE256 + if (LMS_IS_SHAKE(state->params->lmOtsType)) { + /* I || u32str(q) || u16str(0xFFFD) || u8str(0xFF) || SEED */ + XMEMCPY(tmp, seed, state->params->hash_len); + /* C = H(I || u32str(q) || u16str(0xFFFD) || u8str(0xFF) || SEED) + * sig = u32str(type) || C || ... */ + ret = wc_lms_shake256_hash(LMS_STATE_SHAKE(state), buffer, + LMS_HASH_BUFFER_LEN(state->params->hash_len), sig_c, + state->params->hash_len); + } + else +#endif + { #ifndef WC_LMS_FULL_HASH #ifdef WOLFSSL_LMS_SHA256_192 if ((state->params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { @@ -1482,7 +1712,7 @@ static int wc_lmots_sign(LmsState* state, const byte* seed, const byte* msg, * sig = u32str(type) || C || ... */ /* Put in padding for final block. */ LMS_SHA256_SET_LEN_47(buffer); - ret = wc_lms_sha256_192_hash_block(&state->hash, buffer, sig_c); + ret = wc_lms_sha256_192_hash_block(LMS_STATE_HASH(state), buffer, sig_c); } else #endif @@ -1494,7 +1724,7 @@ static int wc_lmots_sign(LmsState* state, const byte* seed, const byte* msg, * sig = u32str(type) || C || ... */ /* Put in padding for final block. */ LMS_SHA256_SET_LEN_55(buffer); - ret = wc_lms_hash_block(&state->hash, buffer, sig_c); + ret = wc_lms_hash_block(LMS_STATE_HASH(state), buffer, sig_c); #else ret = NOT_COMPILED_IN; #endif @@ -1506,7 +1736,7 @@ static int wc_lmots_sign(LmsState* state, const byte* seed, const byte* msg, XMEMCPY(tmp, seed, WC_SHA256_192_DIGEST_SIZE); /* C = H(I || u32str(q) || u16str(0xFFFD) || u8str(0xFF) || SEED) * sig = u32str(type) || C || ... */ - ret = wc_lms_hash_sha256_192(&state->hash, buffer, + ret = wc_lms_hash_sha256_192(LMS_STATE_HASH(state), buffer, LMS_HASH_BUFFER_LEN(WC_SHA256_192_DIGEST_SIZE), sig_c); } else @@ -1517,13 +1747,14 @@ static int wc_lmots_sign(LmsState* state, const byte* seed, const byte* msg, XMEMCPY(tmp, seed, WC_SHA256_DIGEST_SIZE); /* C = H(I || u32str(q) || u16str(0xFFFD) || u8str(0xFF) || SEED) * sig = u32str(type) || C || ... */ - ret = wc_lms_hash(&state->hash, buffer, + ret = wc_lms_hash(LMS_STATE_HASH(state), buffer, LMS_HASH_BUFFER_LEN(WC_SHA256_DIGEST_SIZE), sig_c); #else ret = NOT_COMPILED_IN; #endif } #endif /* !WC_LMS_FULL_HASH */ + } if (ret == 0) { byte* sig_y = sig_c + state->params->hash_len; @@ -1671,19 +1902,28 @@ static int wc_lms_leaf_hash(LmsState* state, const byte* seed, word32 i, /* I || u32str(r) || u16str(D_LEAF) || OTS_PUB_HASH[i] */ c16toa(LMS_D_LEAF, dp); /* temp = H(I || u32str(r) || u16str(D_LEAF) || OTS_PUB_HASH[i]) */ +#ifdef WOLFSSL_LMS_SHAKE256 + if (LMS_IS_SHAKE(state->params->lmOtsType)) { + ret = wc_lms_shake256_hash(LMS_STATE_SHAKE(state), buffer, + LMS_SEED_HASH_LEN(state->params->hash_len), leaf, + state->params->hash_len); + } + else +#endif + { #ifndef WC_LMS_FULL_HASH /* Put in padding for final block. */ #ifdef WOLFSSL_LMS_SHA256_192 if ((state->params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { LMS_SHA256_SET_LEN_46(buffer); - ret = wc_lms_sha256_192_hash_block(&state->hash, buffer, leaf); + ret = wc_lms_sha256_192_hash_block(LMS_STATE_HASH(state), buffer, leaf); } else #endif { #ifndef WOLFSSL_NO_LMS_SHA256_256 LMS_SHA256_SET_LEN_54(buffer); - ret = wc_lms_hash_block(&state->hash, buffer, leaf); + ret = wc_lms_hash_block(LMS_STATE_HASH(state), buffer, leaf); #else ret = NOT_COMPILED_IN; #endif @@ -1691,20 +1931,21 @@ static int wc_lms_leaf_hash(LmsState* state, const byte* seed, word32 i, #else #ifdef WOLFSSL_LMS_SHA256_192 if ((state->params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { - ret = wc_lms_hash_sha256_192(&state->hash, buffer, + ret = wc_lms_hash_sha256_192(LMS_STATE_HASH(state), buffer, LMS_SEED_HASH_LEN(WC_SHA256_192_DIGEST_SIZE), leaf); } else #endif { #ifndef WOLFSSL_NO_LMS_SHA256_256 - ret = wc_lms_hash(&state->hash, buffer, + ret = wc_lms_hash(LMS_STATE_HASH(state), buffer, LMS_SEED_HASH_LEN(WC_SHA256_DIGEST_SIZE), leaf); #else ret = NOT_COMPILED_IN; #endif } #endif /* !WC_LMS_FULL_HASH */ + } } return ret; @@ -1735,13 +1976,25 @@ static int wc_lms_interior_hash(LmsState* state, byte* sp, word32 r, /* I || u32str(r) || u16str(D_INTR) || ... || temp */ c32toa(r, rp); +#ifdef WOLFSSL_LMS_SHAKE256 + if (LMS_IS_SHAKE(state->params->lmOtsType)) { + /* left_side = pop(data stack) + * I || u32str(r) || u16str(D_INTR) || left_side || temp */ + XMEMCPY(left, sp, state->params->hash_len); + /* temp = H(I || u32str(r) || u16str(D_INTR) || left_side || temp) */ + ret = wc_lms_shake256_hash(LMS_STATE_SHAKE(state), buffer, + LMS_NODE_HASH_LEN(state->params->hash_len), node, + state->params->hash_len); + } + else +#endif #ifdef WOLFSSL_LMS_SHA256_192 if ((state->params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { /* left_side = pop(data stack) * I || u32str(r) || u16str(D_INTR) || left_side || temp */ XMEMCPY(left, sp, WC_SHA256_192_DIGEST_SIZE); /* temp = H(I || u32str(r) || u16str(D_INTR) || left_side || temp) */ - ret = wc_lms_hash_sha256_192(&state->hash, buffer, + ret = wc_lms_hash_sha256_192(LMS_STATE_HASH(state), buffer, LMS_NODE_HASH_LEN(WC_SHA256_192_DIGEST_SIZE), node); } else @@ -1752,7 +2005,7 @@ static int wc_lms_interior_hash(LmsState* state, byte* sp, word32 r, * I || u32str(r) || u16str(D_INTR) || left_side || temp */ XMEMCPY(left, sp, WC_SHA256_DIGEST_SIZE); /* temp = H(I || u32str(r) || u16str(D_INTR) || left_side || temp) */ - ret = wc_lms_hash(&state->hash, buffer, + ret = wc_lms_hash(LMS_STATE_HASH(state), buffer, LMS_NODE_HASH_LEN(WC_SHA256_DIGEST_SIZE), node); #else ret = NOT_COMPILED_IN; @@ -2304,6 +2557,19 @@ static int wc_lms_compute_root(LmsState* state, word32 q, const byte* kc, c16toa(LMS_D_LEAF, ip); XMEMCPY(node, kc, params->hash_len); /* Put tmp into offset required for first iteration. */ +#ifdef WOLFSSL_LMS_SHAKE256 + if (LMS_IS_SHAKE(params->lmOtsType)) { + b[0][0] = node; + b[0][1] = node + params->hash_len; + b[1][0] = node + params->hash_len; + b[1][1] = node; + ret = wc_lms_shake256_hash(LMS_STATE_SHAKE(state), buffer, + LMS_SEED_HASH_LEN(params->hash_len), b[r & 1][0], + params->hash_len); + } + else +#endif + { #ifndef WC_LMS_FULL_HASH /* Put in padding for final block. */ #ifdef WOLFSSL_LMS_SHA256_192 @@ -2313,7 +2579,7 @@ static int wc_lms_compute_root(LmsState* state, word32 q, const byte* kc, b[1][0] = node + WC_SHA256_192_DIGEST_SIZE; b[1][1] = node; LMS_SHA256_SET_LEN_46(buffer); - ret = wc_lms_sha256_192_hash_block(&state->hash, buffer, b[r & 1][0]); + ret = wc_lms_sha256_192_hash_block(LMS_STATE_HASH(state), buffer, b[r & 1][0]); } else #endif @@ -2324,7 +2590,7 @@ static int wc_lms_compute_root(LmsState* state, word32 q, const byte* kc, b[1][0] = node + WC_SHA256_DIGEST_SIZE; b[1][1] = node; LMS_SHA256_SET_LEN_54(buffer); - ret = wc_lms_hash_block(&state->hash, buffer, b[r & 1][0]); + ret = wc_lms_hash_block(LMS_STATE_HASH(state), buffer, b[r & 1][0]); #else ret = NOT_COMPILED_IN; #endif @@ -2336,7 +2602,7 @@ static int wc_lms_compute_root(LmsState* state, word32 q, const byte* kc, b[0][1] = node + WC_SHA256_192_DIGEST_SIZE; b[1][0] = node + WC_SHA256_192_DIGEST_SIZE; b[1][1] = node; - ret = wc_lms_hash_sha256_192(&state->hash, buffer, + ret = wc_lms_hash_sha256_192(LMS_STATE_HASH(state), buffer, LMS_SEED_HASH_LEN(WC_SHA256_192_DIGEST_SIZE), b[r & 1][0]); } else @@ -2347,13 +2613,14 @@ static int wc_lms_compute_root(LmsState* state, word32 q, const byte* kc, b[0][1] = node + WC_SHA256_DIGEST_SIZE; b[1][0] = node + WC_SHA256_DIGEST_SIZE; b[1][1] = node; - ret = wc_lms_hash(&state->hash, buffer, + ret = wc_lms_hash(LMS_STATE_HASH(state), buffer, LMS_SEED_HASH_LEN(WC_SHA256_DIGEST_SIZE), b[r & 1][0]); #else ret = NOT_COMPILED_IN; #endif } #endif /* !WC_LMS_FULL_HASH */ + } if (ret == 0) { int i; @@ -2362,6 +2629,32 @@ static int wc_lms_compute_root(LmsState* state, word32 q, const byte* kc, c16toa(LMS_D_INTR, ip); /* Do all but last height. */ + #ifdef WOLFSSL_LMS_SHAKE256 + if (LMS_IS_SHAKE(params->lmOtsType)) { + for (i = 0; (ret == 0) && (i < params->height - 1); i++) { + /* Put path into offset required. */ + XMEMCPY(b[r & 1][1], path, params->hash_len); + path += params->hash_len; + + /* node_num = node_num / 2 */ + r >>= 1; + /* H(...||u32str(node_num/2)||..) */ + c32toa(r, rp); + ret = wc_lms_shake256_hash(LMS_STATE_SHAKE(state), buffer, + LMS_NODE_HASH_LEN(params->hash_len), b[r & 1][0], + params->hash_len); + } + if (ret == 0) { + /* Last height. */ + XMEMCPY(b[r & 1][1], path, params->hash_len); + r >>= 1; + c32toa(r, rp); + ret = wc_lms_shake256_hash(LMS_STATE_SHAKE(state), buffer, + LMS_NODE_HASH_LEN(params->hash_len), tc, params->hash_len); + } + } + else + #endif #ifdef WOLFSSL_LMS_SHA256_192 if ((params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { for (i = 0; (ret == 0) && (i < params->height - 1); i++) { @@ -2377,7 +2670,7 @@ static int wc_lms_compute_root(LmsState* state, word32 q, const byte* kc, * or * tmp = H(I||u32str(node_num/2)||u16str(D_INTR)||tmp||path[i]) * Put tmp result into offset required for next iteration. */ - ret = wc_lms_hash_sha256_192(&state->hash, buffer, + ret = wc_lms_hash_sha256_192(LMS_STATE_HASH(state), buffer, LMS_NODE_HASH_LEN(WC_SHA256_192_DIGEST_SIZE), b[r & 1][0]); } if (ret == 0) { @@ -2392,7 +2685,7 @@ static int wc_lms_compute_root(LmsState* state, word32 q, const byte* kc, * or * tmp = H(I||u32str(node_num/2)||u16str(D_INTR)||tmp||path[i]) * Put tmp result into Tc.*/ - ret = wc_lms_hash_sha256_192(&state->hash, buffer, + ret = wc_lms_hash_sha256_192(LMS_STATE_HASH(state), buffer, LMS_NODE_HASH_LEN(WC_SHA256_192_DIGEST_SIZE), tc); } } @@ -2413,7 +2706,7 @@ static int wc_lms_compute_root(LmsState* state, word32 q, const byte* kc, * or * tmp = H(I||u32str(node_num/2)||u16str(D_INTR)||tmp||path[i]) * Put tmp result into offset required for next iteration. */ - ret = wc_lms_hash(&state->hash, buffer, + ret = wc_lms_hash(LMS_STATE_HASH(state), buffer, LMS_NODE_HASH_LEN(WC_SHA256_DIGEST_SIZE), b[r & 1][0]); } if (ret == 0) { @@ -2428,7 +2721,7 @@ static int wc_lms_compute_root(LmsState* state, word32 q, const byte* kc, * or * tmp = H(I||u32str(node_num/2)||u16str(D_INTR)||tmp||path[i]) * Put tmp result into Tc.*/ - ret = wc_lms_hash(&state->hash, buffer, + ret = wc_lms_hash(LMS_STATE_HASH(state), buffer, LMS_NODE_HASH_LEN(WC_SHA256_DIGEST_SIZE), tc); } #else @@ -2477,7 +2770,7 @@ static int wc_lms_compute_root(LmsState* state, word32 q, const byte* kc, * @param [in] sig LMS signature. */ static int wc_lms_verify(LmsState* state, const byte* pub, const byte* msg, - word32 msgSz, const byte* sig) + word32 msgSz, const byte* sig, word32 sigSz) { int ret; const LmsParams* params = state->params; @@ -2487,6 +2780,17 @@ static int wc_lms_verify(LmsState* state, const byte* pub, const byte* msg, const byte* sig_q = sig; byte tc[LMS_MAX_NODE_LEN]; byte* kc = tc; + /* Bytes consumed by this LMS signature: q || lmots_type || C || y[p] || + * lms_type || path[height]. wc_lms_verify reads exactly this much from + * sig; the caller (wc_hss_verify or wc_LmsKey_Verify) has guaranteed + * sigSz covers it, but check defensively here as well. */ + const word32 lms_sig_required = LMS_Q_LEN + LMS_TYPE_LEN + + params->hash_len + params->p * params->hash_len + LMS_TYPE_LEN + + params->height * params->hash_len; + + if (sigSz < lms_sig_required) { + return BUFFER_E; + } /* Algorithm 6. Step 3. */ /* Check the public key LMS type matches parameters. */ @@ -2503,6 +2807,33 @@ static int wc_lms_verify(LmsState* state, const byte* pub, const byte* msg, ret = wc_lmots_calc_kc(state, pub + LMS_TYPE_LEN, msg, msgSz, sig_lmots, kc); } + if (ret == 0) { + /* Algorithm 6a. Step 3.d-e: Check LMS type in signature matches + * the expected type from the public key. + * + * Bounds: the upfront sigSz check above guarantees the 4-byte + * lms_type field at this offset is within the buffer. + * + * Mask: params->lmsType holds wolfSSL-internal flags (0xf000) + * identifying the hash family alongside the RFC 8554 type code + * (low 12 bits, LMS_H_W_MASK). The wire format strips the + * private flags (see encoder lines 2483, 2510, 1559), so the + * comparison is against the RFC type code only. This is safe so + * long as the low-12-bit codes remain globally distinct across + * hash families (they are today: 0x05-0x09 SHA-256/M32, + * 0x0a-0x0e SHA-256/M24, 0x0f-0x13 SHAKE/M32, etc.). Any future + * parameter set that introduces a collision in the low 12 bits + * would require this check to compare the full lmsType, not the + * masked form. */ + const byte* sig_lms_type = sig + LMS_Q_LEN + LMS_TYPE_LEN + + params->hash_len + params->p * params->hash_len; + word32 sigType; + + ato32(sig_lms_type, &sigType); + if (sigType != (params->lmsType & LMS_H_W_MASK)) { + ret = SIG_TYPE_E; + } + } if (ret == 0) { /* Algorithm 6a. Step 2.j. */ const byte* sig_path = sig + LMS_Q_LEN + LMS_TYPE_LEN + @@ -2559,12 +2890,24 @@ static int wc_hss_derive_seed_i(LmsState* state, const byte* id, /* parent's I || q || D_CHILD_SEED || D_FIXED || parent's SEED */ XMEMCPY(tmp, seed, state->params->hash_len); /* SEED = H(parent's I || q || D_CHILD_SEED || D_FIXED || parent's SEED) */ +#ifdef WOLFSSL_LMS_SHAKE256 + if (LMS_IS_SHAKE(state->params->lmOtsType)) { + ret = wc_lms_shake256_hash(LMS_STATE_SHAKE(state), buffer, + LMS_HASH_BUFFER_LEN(state->params->hash_len), seed_i, + state->params->hash_len); + if (ret == 0) { + seed_i += state->params->hash_len; + } + } + else +#endif + { #ifndef WC_LMS_FULL_HASH #ifdef WOLFSSL_LMS_SHA256_192 if ((state->params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { /* Put in padding for final block. */ LMS_SHA256_SET_LEN_47(buffer); - ret = wc_lms_sha256_192_hash_block(&state->hash, buffer, seed_i); + ret = wc_lms_sha256_192_hash_block(LMS_STATE_HASH(state), buffer, seed_i); if (ret == 0) { seed_i += WC_SHA256_192_DIGEST_SIZE; } @@ -2575,7 +2918,7 @@ static int wc_hss_derive_seed_i(LmsState* state, const byte* id, #ifndef WOLFSSL_NO_LMS_SHA256_256 /* Put in padding for final block. */ LMS_SHA256_SET_LEN_55(buffer); - ret = wc_lms_hash_block(&state->hash, buffer, seed_i); + ret = wc_lms_hash_block(LMS_STATE_HASH(state), buffer, seed_i); if (ret == 0) { seed_i += WC_SHA256_DIGEST_SIZE; } @@ -2586,35 +2929,45 @@ static int wc_hss_derive_seed_i(LmsState* state, const byte* id, #else #ifdef WOLFSSL_LMS_SHA256_192 if ((state->params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { - ret = wc_lms_hash_sha256_192(&state->hash, buffer, + ret = wc_lms_hash_sha256_192(LMS_STATE_HASH(state), buffer, LMS_HASH_BUFFER_LEN(WC_SHA256_192_DIGEST_SIZE), seed_i); } else #endif { #ifndef WOLFSSL_NO_LMS_SHA256_256 - ret = wc_lms_hash(&state->hash, buffer, + ret = wc_lms_hash(LMS_STATE_HASH(state), buffer, LMS_HASH_BUFFER_LEN(WC_SHA256_DIGEST_SIZE), seed_i); #else ret = NOT_COMPILED_IN; #endif } #endif /* !WC_LMS_FULL_HASH */ + } if (ret == 0) { /* parent's I || q || D_CHILD_I || D_FIXED || parent's SEED */ c16toa(LMS_D_CHILD_I, ip); /* I = H(parent's I || q || D_CHILD_I || D_FIXED || parent's SEED) */ +#ifdef WOLFSSL_LMS_SHAKE256 + if (LMS_IS_SHAKE(state->params->lmOtsType)) { + ret = wc_lms_shake256_hash(LMS_STATE_SHAKE(state), buffer, + LMS_HASH_BUFFER_LEN(state->params->hash_len), tmp, + state->params->hash_len); + } + else +#endif + { #ifndef WC_LMS_FULL_HASH #ifdef WOLFSSL_LMS_SHA256_192 if ((state->params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { - ret = wc_lms_sha256_192_hash_block(&state->hash, buffer, tmp); + ret = wc_lms_sha256_192_hash_block(LMS_STATE_HASH(state), buffer, tmp); } else #endif { #ifndef WOLFSSL_NO_LMS_SHA256_256 - ret = wc_lms_hash_block(&state->hash, buffer, tmp); + ret = wc_lms_hash_block(LMS_STATE_HASH(state), buffer, tmp); #else ret = NOT_COMPILED_IN; #endif @@ -2622,20 +2975,21 @@ static int wc_hss_derive_seed_i(LmsState* state, const byte* id, #else #ifdef WOLFSSL_LMS_SHA256_192 if ((state->params->lmOtsType & LMS_HASH_MASK) == LMS_SHA256_192) { - ret = wc_lms_hash_sha256_192(&state->hash, buffer, + ret = wc_lms_hash_sha256_192(LMS_STATE_HASH(state), buffer, LMS_HASH_BUFFER_LEN(WC_SHA256_192_DIGEST_SIZE), tmp); } else #endif { #ifndef WOLFSSL_NO_LMS_SHA256_256 - ret = wc_lms_hash(&state->hash, buffer, + ret = wc_lms_hash(LMS_STATE_HASH(state), buffer, LMS_HASH_BUFFER_LEN(WC_SHA256_DIGEST_SIZE), tmp); #else ret = NOT_COMPILED_IN; #endif } #endif /* !WC_LMS_FULL_HASH */ + } /* Copy part of hash as new I into private key. */ XMEMCPY(seed_i, tmp, LMS_I_LEN); } @@ -3685,13 +4039,25 @@ int wc_hss_sigsleft(const LmsParams* params, const byte* priv_raw) * @return SIG_VERIFY_E on failure. */ int wc_hss_verify(LmsState* state, const byte* pub, const byte* msg, - word32 msgSz, const byte* sig) + word32 msgSz, const byte* sig, word32 sigSz) { const LmsParams* params = state->params; int ret = 0; word32 nspk; const byte* key = pub + LMS_L_LEN; word32 levels; + word32 sigRem; + /* Bytes consumed by one LMS signature in the HSS chain (matches the + * lms_sig_required calculation in wc_lms_verify). */ + const word32 lms_sig_bytes = LMS_Q_LEN + LMS_TYPE_LEN + + params->hash_len + params->p * params->hash_len + LMS_TYPE_LEN + + params->height * params->hash_len; + const word32 next_pubkey_bytes = LMS_PUBKEY_LEN(params->hash_len); + + /* Need at least the leading L (number of signed public keys). */ + if (sigSz < LMS_L_LEN) { + return BUFFER_E; + } /* Get number of levels from public key. */ ato32(pub, &levels); @@ -3699,6 +4065,7 @@ int wc_hss_verify(LmsState* state, const byte* pub, const byte* msg, ato32(sig, &nspk); /* Line 6 (First iteration): Move to start of next signature. */ sig += LMS_L_LEN; + sigRem = sigSz - LMS_L_LEN; /* Line 2: Verify that pub and signature match in levels. */ if (nspk + 1 != levels) { @@ -3710,22 +4077,32 @@ int wc_hss_verify(LmsState* state, const byte* pub, const byte* msg, /* Line 5: For all but last LMS signature. */ for (i = 0; (ret == 0) && (i < nspk); i++) { + const byte* pubList; + + /* Defensive bounds: each non-final iteration consumes one + * LMS signature plus the next-level public key. */ + if (sigRem < lms_sig_bytes + next_pubkey_bytes) { + ret = BUFFER_E; + break; + } + /* Line 7: Get start of public key in signature. */ - const byte* pubList = sig + LMS_Q_LEN + LMS_TYPE_LEN + - params->hash_len + params->p * params->hash_len + LMS_TYPE_LEN + - params->height * params->hash_len; + pubList = sig + lms_sig_bytes; /* Line 8: Verify the LMS signature with public key as message. */ ret = wc_lms_verify(state, key, pubList, - LMS_PUBKEY_LEN(params->hash_len), sig); + next_pubkey_bytes, sig, lms_sig_bytes); /* Line 10: Next key is from signature. */ key = pubList; /* Line 6: Move to start of next signature. */ - sig = pubList + LMS_PUBKEY_LEN(params->hash_len); + sig = pubList + next_pubkey_bytes; + sigRem -= (lms_sig_bytes + next_pubkey_bytes); } } if (ret == 0) { - /* Line 12: Verify bottom tree with real message. */ - ret = wc_lms_verify(state, key, msg, msgSz, sig); + /* Line 12: Verify bottom tree with real message. The bottom-tree + * LMS signature consumes exactly the remaining sigSz; pass that + * as the bound and let wc_lms_verify enforce its own minimum. */ + ret = wc_lms_verify(state, key, msg, msgSz, sig, sigRem); } return ret; diff --git a/wolfcrypt/src/wc_mlkem.c b/wolfcrypt/src/wc_mlkem.c index 74c4260a1c..9e40b2ba18 100644 --- a/wolfcrypt/src/wc_mlkem.c +++ b/wolfcrypt/src/wc_mlkem.c @@ -78,6 +78,11 @@ #undef WOLFSSL_RISCV_ASM #endif +#if FIPS_VERSION3_GE(2,0,0) + /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */ + #define FIPS_NO_WRAPPERS +#endif + #include #include #include @@ -636,6 +641,50 @@ int wc_MlKemKey_MakeKey(MlKemKey* key, WC_RNG* rng) ret = wc_KyberKey_MakeKeyWithRandom(key, rand, sizeof(rand)); } +#ifdef HAVE_FIPS + /* Pairwise Consistency Test (PCT) per FIPS 140-3 / ISO 19790:2012 + * Section 7.10.3.3: encapsulate with ek, decapsulate with dk, + * verify shared secrets match. */ + if (ret == 0) { + WC_DECLARE_VAR(pct_ct, byte, WC_ML_KEM_MAX_CIPHER_TEXT_SIZE, + key->heap); + byte pct_ss1[WC_ML_KEM_SS_SZ]; + byte pct_ss2[WC_ML_KEM_SS_SZ]; + word32 ctSz = 0; + + WC_ALLOC_VAR_EX(pct_ct, byte, WC_ML_KEM_MAX_CIPHER_TEXT_SIZE, + key->heap, DYNAMIC_TYPE_TMP_BUFFER, ret = MEMORY_E); + + if (ret == 0) + ret = wc_MlKemKey_CipherTextSize(key, &ctSz); + + if (ret == 0) + ret = wc_MlKemKey_Encapsulate(key, pct_ct, pct_ss1, rng); + + if (ret == 0) + ret = wc_MlKemKey_Decapsulate(key, pct_ss2, pct_ct, ctSz); + + if (ret == 0) { + if (XMEMCMP(pct_ss1, pct_ss2, WC_ML_KEM_SS_SZ) != 0) + ret = ML_KEM_PCT_E; + } + + ForceZero(pct_ss1, sizeof(pct_ss1)); + ForceZero(pct_ss2, sizeof(pct_ss2)); + if (WC_VAR_OK(pct_ct)) + ForceZero(pct_ct, WC_ML_KEM_MAX_CIPHER_TEXT_SIZE); + + WC_FREE_VAR_EX(pct_ct, key->heap, DYNAMIC_TYPE_TMP_BUFFER); + + /* FIPS 140-3 IG 10.3.A (TE10.35.02): a key pair that fails the PCT + * must be rendered unusable. Zeroize the generated key material so + * a caller that ignores the return value cannot use it. */ + if (ret != 0) { + wc_MlKemKey_Free(key); + } + } +#endif /* HAVE_FIPS */ + /* Ensure seeds are zeroized. */ ForceZero((void*)rand, (word32)sizeof(rand)); @@ -868,6 +917,9 @@ int wc_MlKemKey_MakeKeyWithRandom(MlKemKey* key, const unsigned char* rand, } #endif + /* Note: PCT is performed in wc_MlKemKey_MakeKey() which calls this + * function and has the RNG parameter needed for encapsulation. */ + return ret; } #endif /* !WOLFSSL_MLKEM_NO_MAKE_KEY */ diff --git a/wolfcrypt/src/wc_port.c b/wolfcrypt/src/wc_port.c index ba740423ea..389d8ddf21 100644 --- a/wolfcrypt/src/wc_port.c +++ b/wolfcrypt/src/wc_port.c @@ -106,6 +106,9 @@ Threading/Mutex options: #ifdef WOLFSSL_ASYNC_CRYPT #include #endif +#if defined(HAVE_HASHDRBG) && !defined(WC_NO_RNG) + #include +#endif #ifdef FREESCALE_LTC_TFM #include @@ -334,6 +337,16 @@ int wolfCrypt_Init(void) } #endif + #if defined(HAVE_HASHDRBG) && !defined(WC_NO_RNG) && \ + !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + ret = wc_DrbgState_MutexInit(); + if (ret != 0) { + WOLFSSL_MSG("DRBG state mutex init failed"); + return ret; + } + #endif + #if defined(FREESCALE_LTC_TFM) || defined(FREESCALE_LTC_ECC) ret = ksdk_port_init(); if (ret != 0) { @@ -641,6 +654,12 @@ int wolfCrypt_Cleanup(void) wc_CryptoCb_Cleanup(); #endif + #if defined(HAVE_HASHDRBG) && !defined(WC_NO_RNG) && \ + !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + wc_DrbgState_MutexFree(); + #endif + #if defined(WOLFSSL_MEM_FAIL_COUNT) && defined(WOLFCRYPT_ONLY) wc_MemFailCount_Free(); #endif diff --git a/wolfcrypt/src/wc_slhdsa.c b/wolfcrypt/src/wc_slhdsa.c index 65926a4334..402b484746 100644 --- a/wolfcrypt/src/wc_slhdsa.c +++ b/wolfcrypt/src/wc_slhdsa.c @@ -21,6 +21,11 @@ #include +#if FIPS_VERSION3_GE(2,0,0) + /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */ + #define FIPS_NO_WRAPPERS +#endif + #include #ifdef WOLFSSL_HAVE_SLHDSA @@ -35,6 +40,11 @@ #endif #include #include +#ifdef WOLFSSL_SLHDSA_SHA2 + #include + #include + #include +#endif #if defined(USE_INTEL_SPEEDUP) /* CPU information for Intel. */ @@ -370,6 +380,27 @@ static const SlhDsaParameters SlhDsaParams[] = #ifndef WOLFSSL_SLHDSA_PARAM_NO_256F SLHDSA_PARAMETERS(SLHDSA_SHAKE256F, 32, 68, 17, 4, 9, 35), #endif +#ifdef WOLFSSL_SLHDSA_SHA2 + /* n, h, d, h_m, a, k */ +#ifndef WOLFSSL_SLHDSA_PARAM_NO_SHA2_128S + SLHDSA_PARAMETERS(SLHDSA_SHA2_128S, 16, 63, 7, 9, 12, 14), +#endif +#ifndef WOLFSSL_SLHDSA_PARAM_NO_SHA2_128F + SLHDSA_PARAMETERS(SLHDSA_SHA2_128F, 16, 66, 22, 3, 6, 33), +#endif +#ifndef WOLFSSL_SLHDSA_PARAM_NO_SHA2_192S + SLHDSA_PARAMETERS(SLHDSA_SHA2_192S, 24, 63, 7, 9, 14, 17), +#endif +#ifndef WOLFSSL_SLHDSA_PARAM_NO_SHA2_192F + SLHDSA_PARAMETERS(SLHDSA_SHA2_192F, 24, 66, 22, 3, 8, 33), +#endif +#ifndef WOLFSSL_SLHDSA_PARAM_NO_SHA2_256S + SLHDSA_PARAMETERS(SLHDSA_SHA2_256S, 32, 64, 8, 8, 14, 22), +#endif +#ifndef WOLFSSL_SLHDSA_PARAM_NO_SHA2_256F + SLHDSA_PARAMETERS(SLHDSA_SHA2_256F, 32, 68, 17, 4, 9, 35), +#endif +#endif /* WOLFSSL_SLHDSA_SHA2 */ }; /* Number of parameters in array. */ @@ -597,6 +628,732 @@ static int slhdsakey_hash_shake_4(wc_Shake* shake, const byte* data1, #endif } +/****************************************************************************** + * SHA2 Hash Functions (FIPS 205, Section 11.2) + ******************************************************************************/ + +#ifdef WOLFSSL_SLHDSA_SHA2 + +/* Size of compressed HashAddress (ADRS^c) per FIPS 205 Section 11.2. */ +#define SLHDSA_HAC_SZ 22 + +/* Encode a compressed HashAddress (ADRS^c). + * + * FIPS 205. Section 11.2. + * Byte 0: low byte of adrs[0] (layer) + * Bytes 1-8: adrs[2..3] (low 8 bytes of tree address) + * Byte 9: low byte of adrs[4] (type) + * Bytes 10-21: adrs[5..7] (remaining 12 bytes, verbatim) + * + * @param [in] adrs HashAddress to encode (8 x word32). + * @param [out] address Buffer to encode into (22 bytes). + */ +static void HA_Encode_Compressed(const word32* adrs, byte* address) +{ + /* Byte 0: low byte of layer address. */ + address[0] = (byte)adrs[0]; + /* Bytes 1-4: adrs[2] (tree address high word). */ + c32toa(adrs[2], address + 1); + /* Bytes 5-8: adrs[3] (tree address low word). */ + c32toa(adrs[3], address + 5); + /* Byte 9: low byte of type. */ + address[9] = (byte)adrs[4]; + /* Bytes 10-13: adrs[5] (key pair address / padding). */ + c32toa(adrs[5], address + 10); + /* Bytes 14-17: adrs[6] (chain address / tree height). */ + c32toa(adrs[6], address + 14); + /* Bytes 18-21: adrs[7] (hash address / tree index). */ + c32toa(adrs[7], address + 18); +} + +/* Pre-compute SHA2 midstates for PK.seed. + * + * SHA-256: PK.seed || pad(64 - n) is exactly one 64-byte block. + * SHA-512: PK.seed || pad(128 - n) is exactly one 128-byte block. + * + * @param [in, out] key SLH-DSA key with pk_seed set at key->sk[2*n]. + * @return 0 on success. + */ +static int slhdsakey_precompute_sha2_midstates(SlhDsaKey* key) +{ + int ret; + byte n = key->params->n; + const byte* pk_seed = key->sk + 2 * n; + byte block[WC_SHA512_BLOCK_SIZE]; + + /* SHA-256 midstate: PK.seed || zeros to fill 64-byte block. */ + XMEMSET(block, 0, WC_SHA256_BLOCK_SIZE); + XMEMCPY(block, pk_seed, n); + ret = wc_InitSha256(&key->hash.sha2.sha256_mid); + if (ret == 0) { + ret = wc_Sha256Update(&key->hash.sha2.sha256_mid, block, + WC_SHA256_BLOCK_SIZE); + } + + /* SHA-512 midstate: PK.seed || zeros to fill 128-byte block. + * Only needed for categories 3 and 5 (n > 16). */ + if ((ret == 0) && (n > 16)) { + XMEMSET(block, 0, WC_SHA512_BLOCK_SIZE); + XMEMCPY(block, pk_seed, n); + ret = wc_InitSha512(&key->hash.sha2.sha512_mid); + if (ret == 0) { + ret = wc_Sha512Update(&key->hash.sha2.sha512_mid, block, + WC_SHA512_BLOCK_SIZE); + } + } + + return ret; +} + +/* SHA2 F function. + * + * FIPS 205. Section 11.2. + * F(PK.seed, ADRS, M1) = Trunc_n(SHA-256(PK.seed||pad(64-n)||ADRS^c||M1)) + * + * Uses pre-computed midstate for the first block. + * + * @param [in] key SLH-DSA key (SHA2 hash objects + midstate). + * @param [in] pk_seed Public key seed (unused - midstate). + * @param [in] adrs HashAddress. + * @param [in] m Message of n bytes. + * @param [in] n Number of bytes in hash output. + * @param [out] hash Buffer to hold hash output. + * @return 0 on success. + */ +static int slhdsakey_hash_f_sha2(SlhDsaKey* key, const byte* pk_seed, + const word32* adrs, const byte* m, byte n, byte* hash) +{ + int ret; + byte address[SLHDSA_HAC_SZ]; + byte digest[WC_SHA256_DIGEST_SIZE]; + + (void)pk_seed; + + /* Encode compressed address. */ + HA_Encode_Compressed(adrs, address); + + /* Restore SHA-256 midstate. */ + ret = wc_Sha256Copy(&key->hash.sha2.sha256_mid, &key->hash.sha2.sha256); + if (ret == 0) { + /* Update with compressed ADRS and message. */ + ret = wc_Sha256Update(&key->hash.sha2.sha256, address, SLHDSA_HAC_SZ); + } + if (ret == 0) { + ret = wc_Sha256Update(&key->hash.sha2.sha256, m, n); + } + if (ret == 0) { + ret = wc_Sha256Final(&key->hash.sha2.sha256, digest); + } + if (ret == 0) { + /* Truncate to n bytes. */ + XMEMCPY(hash, digest, n); + } + + return ret; +} + +/* SHA2 H function. + * + * FIPS 205. Section 11.2. + * Cat 1: H(PK.seed, ADRS, M2) = Trunc_n(SHA-256(PK.seed||pad||ADRS^c||M2)) + * Cat 3,5: H(PK.seed, ADRS, M2) = Trunc_n(SHA-512(PK.seed||pad||ADRS^c||M2)) + * + * @param [in] key SLH-DSA key. + * @param [in] pk_seed Public key seed (unused - midstate). + * @param [in] adrs HashAddress. + * @param [in] node Message of 2n bytes. + * @param [in] n Number of bytes in hash output. + * @param [out] hash Buffer to hold hash output. + * @return 0 on success. + */ +static int slhdsakey_hash_h_sha2(SlhDsaKey* key, const byte* pk_seed, + const word32* adrs, const byte* node, byte n, byte* hash) +{ + int ret; + byte address[SLHDSA_HAC_SZ]; + + (void)pk_seed; + + /* Encode compressed address. */ + HA_Encode_Compressed(adrs, address); + + if (n == WC_SLHDSA_N_128) { + /* Category 1: use SHA-256. */ + byte digest[WC_SHA256_DIGEST_SIZE]; + + ret = wc_Sha256Copy(&key->hash.sha2.sha256_mid, + &key->hash.sha2.sha256); + if (ret == 0) { + ret = wc_Sha256Update(&key->hash.sha2.sha256, address, + SLHDSA_HAC_SZ); + } + if (ret == 0) { + ret = wc_Sha256Update(&key->hash.sha2.sha256, node, 2 * n); + } + if (ret == 0) { + ret = wc_Sha256Final(&key->hash.sha2.sha256, digest); + } + if (ret == 0) { + XMEMCPY(hash, digest, n); + } + } + else { + /* Categories 3, 5: use SHA-512. */ + byte digest[WC_SHA512_DIGEST_SIZE]; + + ret = wc_Sha512Copy(&key->hash.sha2.sha512_mid, + &key->hash.sha2.sha512); + if (ret == 0) { + ret = wc_Sha512Update(&key->hash.sha2.sha512, address, + SLHDSA_HAC_SZ); + } + if (ret == 0) { + ret = wc_Sha512Update(&key->hash.sha2.sha512, node, 2 * n); + } + if (ret == 0) { + ret = wc_Sha512Final(&key->hash.sha2.sha512, digest); + } + if (ret == 0) { + XMEMCPY(hash, digest, n); + } + } + + return ret; +} + +/* SHA2 H function with two separate n-byte halves. + * + * Same as slhdsakey_hash_h_sha2 but M2 = m1 || m2. + * + * @param [in] key SLH-DSA key. + * @param [in] pk_seed Public key seed (unused - midstate). + * @param [in] adrs HashAddress. + * @param [in] m1 First n bytes of message. + * @param [in] m2 Second n bytes of message. + * @param [in] n Number of bytes in hash output. + * @param [out] hash Buffer to hold hash output. + * @return 0 on success. + */ +static int slhdsakey_hash_h_2_sha2(SlhDsaKey* key, const byte* pk_seed, + const word32* adrs, const byte* m1, const byte* m2, byte n, byte* hash) +{ + int ret; + byte address[SLHDSA_HAC_SZ]; + + (void)pk_seed; + + /* Encode compressed address. */ + HA_Encode_Compressed(adrs, address); + + if (n == WC_SLHDSA_N_128) { + /* Category 1: use SHA-256. */ + byte digest[WC_SHA256_DIGEST_SIZE]; + + ret = wc_Sha256Copy(&key->hash.sha2.sha256_mid, + &key->hash.sha2.sha256); + if (ret == 0) { + ret = wc_Sha256Update(&key->hash.sha2.sha256, address, + SLHDSA_HAC_SZ); + } + if (ret == 0) { + ret = wc_Sha256Update(&key->hash.sha2.sha256, m1, n); + } + if (ret == 0) { + ret = wc_Sha256Update(&key->hash.sha2.sha256, m2, n); + } + if (ret == 0) { + ret = wc_Sha256Final(&key->hash.sha2.sha256, digest); + } + if (ret == 0) { + XMEMCPY(hash, digest, n); + } + } + else { + /* Categories 3, 5: use SHA-512. */ + byte digest[WC_SHA512_DIGEST_SIZE]; + + ret = wc_Sha512Copy(&key->hash.sha2.sha512_mid, + &key->hash.sha2.sha512); + if (ret == 0) { + ret = wc_Sha512Update(&key->hash.sha2.sha512, address, + SLHDSA_HAC_SZ); + } + if (ret == 0) { + ret = wc_Sha512Update(&key->hash.sha2.sha512, m1, n); + } + if (ret == 0) { + ret = wc_Sha512Update(&key->hash.sha2.sha512, m2, n); + } + if (ret == 0) { + ret = wc_Sha512Final(&key->hash.sha2.sha512, digest); + } + if (ret == 0) { + XMEMCPY(hash, digest, n); + } + } + + return ret; +} + +/* SHA2 PRF function. + * + * FIPS 205. Section 11.2. + * PRF(PK.seed, SK.seed, ADRS) = + * Trunc_n(SHA-256(PK.seed || pad(64-n) || ADRS^c || SK.seed)) + * + * @param [in] key SLH-DSA key. + * @param [in] pk_seed Public key seed (unused - midstate). + * @param [in] sk_seed Private key seed. + * @param [in] adrs HashAddress. + * @param [in] n Number of bytes in hash output. + * @param [out] hash Buffer to hold hash output. + * @return 0 on success. + */ +static int slhdsakey_hash_prf_sha2(SlhDsaKey* key, const byte* pk_seed, + const byte* sk_seed, const word32* adrs, byte n, byte* hash) +{ + int ret; + byte address[SLHDSA_HAC_SZ]; + byte digest[WC_SHA256_DIGEST_SIZE]; + + (void)pk_seed; + + /* Encode compressed address. */ + HA_Encode_Compressed(adrs, address); + + /* Restore SHA-256 midstate. */ + ret = wc_Sha256Copy(&key->hash.sha2.sha256_mid, &key->hash.sha2.sha256); + if (ret == 0) { + ret = wc_Sha256Update(&key->hash.sha2.sha256, address, SLHDSA_HAC_SZ); + } + if (ret == 0) { + ret = wc_Sha256Update(&key->hash.sha2.sha256, sk_seed, n); + } + if (ret == 0) { + ret = wc_Sha256Final(&key->hash.sha2.sha256, digest); + } + if (ret == 0) { + XMEMCPY(hash, digest, n); + } + + return ret; +} + +/* SHA2 T_l streaming: start with address. + * + * Restores midstate then updates with compressed ADRS. + * + * @param [in] key SLH-DSA key. + * @param [in] pk_seed Public key seed (unused - midstate). + * @param [in] adrs HashAddress. + * @param [in] n Number of bytes of hash output (determines cat). + * @return 0 on success. + */ +static int slhdsakey_hash_start_addr_sha2(SlhDsaKey* key, + const byte* pk_seed, const word32* adrs, byte n) +{ + int ret; + byte address[SLHDSA_HAC_SZ]; + + (void)pk_seed; + + HA_Encode_Compressed(adrs, address); + + if (n == WC_SLHDSA_N_128) { + /* Category 1: SHA-256 -- use sha256_2 (T_l must not collide with + * sha256 which is used by F and H). */ + ret = wc_Sha256Copy(&key->hash.sha2.sha256_mid, + &key->hash.sha2.sha256_2); + if (ret == 0) { + ret = wc_Sha256Update(&key->hash.sha2.sha256_2, address, + SLHDSA_HAC_SZ); + } + } + else { + /* Categories 3, 5: SHA-512 -- use sha512_2 (T_l must not collide + * with sha512 which is used by H). */ + ret = wc_Sha512Copy(&key->hash.sha2.sha512_mid, + &key->hash.sha2.sha512_2); + if (ret == 0) { + ret = wc_Sha512Update(&key->hash.sha2.sha512_2, address, + SLHDSA_HAC_SZ); + } + } + + return ret; +} + +/* SHA2 T_l streaming: update with data. + * + * @param [in] key SLH-DSA key. + * @param [in] data Data to hash. + * @param [in] len Length of data. + * @return 0 on success. + */ +static int slhdsakey_hash_update_sha2(SlhDsaKey* key, const byte* data, + word32 len) +{ + if (key->params->n == WC_SLHDSA_N_128) { + return wc_Sha256Update(&key->hash.sha2.sha256_2, data, len); + } + else { + return wc_Sha512Update(&key->hash.sha2.sha512_2, data, len); + } +} + +/* SHA2 T_l streaming: finalize. + * + * @param [in] key SLH-DSA key. + * @param [out] hash Output buffer. + * @param [in] len Desired output length (truncate to n). + * @return 0 on success. + */ +static int slhdsakey_hash_final_sha2(SlhDsaKey* key, byte* hash, word32 len) +{ + int ret; + byte n = key->params->n; + + if (n == WC_SLHDSA_N_128) { + byte digest[WC_SHA256_DIGEST_SIZE]; + ret = wc_Sha256Final(&key->hash.sha2.sha256_2, digest); + if (ret == 0) { + XMEMCPY(hash, digest, (len < n) ? len : n); + } + } + else { + byte digest[WC_SHA512_DIGEST_SIZE]; + ret = wc_Sha512Final(&key->hash.sha2.sha512_2, digest); + if (ret == 0) { + XMEMCPY(hash, digest, (len < n) ? len : n); + } + } + + return ret; +} + +/* Local MGF1 implementation for H_msg. + * + * FIPS 205. Section 11.2. + * H_msg uses MGF1-SHA-256/512(R || PK.seed || digest, m) where m is the + * required output length. + * + * @param [in] key SLH-DSA key (for hash objects). + * @param [in] seed Seed data for MGF1. + * @param [in] seedLen Length of seed. + * @param [out] out Output buffer. + * @param [in] outLen Required output length. + * @return 0 on success. + */ +static int slhdsakey_mgf1_sha2(SlhDsaKey* key, const byte* seed, + word32 seedLen, byte* out, word32 outLen) +{ + int ret = 0; + word32 counter = 0; + word32 done = 0; + byte n = key->params->n; + + while ((ret == 0) && (done < outLen)) { + byte cBuf[4]; + word32 left = outLen - done; + + c32toa(counter, cBuf); + + if (n == WC_SLHDSA_N_128) { + /* Category 1: MGF1-SHA-256. */ + byte digest[WC_SHA256_DIGEST_SIZE]; + word32 cpLen = (left < WC_SHA256_DIGEST_SIZE) ? + left : WC_SHA256_DIGEST_SIZE; + + ret = wc_InitSha256(&key->hash.sha2.sha256_2); + if (ret == 0) { + ret = wc_Sha256Update(&key->hash.sha2.sha256_2, seed, seedLen); + } + if (ret == 0) { + ret = wc_Sha256Update(&key->hash.sha2.sha256_2, cBuf, 4); + } + if (ret == 0) { + ret = wc_Sha256Final(&key->hash.sha2.sha256_2, digest); + } + if (ret == 0) { + XMEMCPY(out + done, digest, cpLen); + done += cpLen; + } + } + else { + /* Categories 3, 5: MGF1-SHA-512. */ + byte digest[WC_SHA512_DIGEST_SIZE]; + word32 cpLen = (left < WC_SHA512_DIGEST_SIZE) ? + left : WC_SHA512_DIGEST_SIZE; + + ret = wc_InitSha512(&key->hash.sha2.sha512_2); + if (ret == 0) { + ret = wc_Sha512Update(&key->hash.sha2.sha512_2, seed, seedLen); + } + if (ret == 0) { + ret = wc_Sha512Update(&key->hash.sha2.sha512_2, cBuf, 4); + } + if (ret == 0) { + ret = wc_Sha512Final(&key->hash.sha2.sha512_2, digest); + } + if (ret == 0) { + XMEMCPY(out + done, digest, cpLen); + done += cpLen; + } + } + counter++; + } + + return ret; +} + +/* SHA2 PRF_msg function. + * + * FIPS 205. Section 11.2. + * PRF_msg(SK.prf, opt_rand, M) = + * Trunc_n(HMAC-SHA-256/512(SK.prf, opt_rand || M)) + * + * @param [in] key SLH-DSA key. + * @param [in] sk_prf SK.prf seed. + * @param [in] opt_rand Random or PK.seed. + * @param [in] hdr Message header (2 bytes). + * @param [in] ctx Context data (may be NULL). + * @param [in] ctxSz Context data length. + * @param [in] msg Message data. + * @param [in] msgSz Message data length. + * @param [in] n Number of bytes in hash output. + * @param [out] hash Buffer to hold hash output. + * @return 0 on success. + */ +static int slhdsakey_prf_msg_sha2(SlhDsaKey* key, const byte* sk_prf, + const byte* opt_rand, const byte* hdr, const byte* ctx, byte ctxSz, + const byte* msg, word32 msgSz, byte n, byte* hash) +{ + int ret; + Hmac hmac; + int hmacType; + byte digest[WC_SHA512_DIGEST_SIZE]; + + if (n == WC_SLHDSA_N_128) { + hmacType = WC_SHA256; + } + else { + hmacType = WC_SHA512; + } + + ret = wc_HmacInit(&hmac, key->heap, INVALID_DEVID); + if (ret == 0) { + ret = wc_HmacSetKey(&hmac, hmacType, sk_prf, n); + } + if (ret == 0) { + ret = wc_HmacUpdate(&hmac, opt_rand, n); + } + if ((ret == 0) && (hdr != NULL)) { + ret = wc_HmacUpdate(&hmac, hdr, 2); + } + if ((ret == 0) && (ctxSz > 0) && (ctx != NULL)) { + ret = wc_HmacUpdate(&hmac, ctx, ctxSz); + } + if (ret == 0) { + ret = wc_HmacUpdate(&hmac, msg, msgSz); + } + if (ret == 0) { + ret = wc_HmacFinal(&hmac, digest); + } + wc_HmacFree(&hmac); + + if (ret == 0) { + XMEMCPY(hash, digest, n); + } + + return ret; +} + +/* SHA2 H_msg function. + * + * FIPS 205. Section 11.2. + * H_msg(R, PK.seed, PK.root, M) = MGF1-SHA-256/512( + * R || PK.seed || SHA-256/512(R || PK.seed || PK.root || M), m) + * + * @param [in] key SLH-DSA key. + * @param [in] r Randomizer (n bytes from signature). + * @param [in] hdr Message header (2 bytes). + * @param [in] ctx Context data (may be NULL). + * @param [in] ctxSz Context data length. + * @param [in] msg Message data. + * @param [in] msgSz Message data length. + * @param [out] md Output message digest. + * @param [in] mdLen Required digest length (dl1+dl2+dl3). + * @return 0 on success. + */ +static int slhdsakey_h_msg_sha2(SlhDsaKey* key, const byte* r, + const byte* hdr, const byte* ctx, byte ctxSz, const byte* msg, + word32 msgSz, byte* md, word32 mdLen) +{ + int ret; + byte n = key->params->n; + const byte* pk_seed = key->sk + 2 * n; + const byte* pk_root = key->sk + 3 * n; + + if (n == WC_SLHDSA_N_128) { + /* Category 1: SHA-256 + MGF1-SHA-256. */ + byte innerHash[WC_SHA256_DIGEST_SIZE]; + /* Seed for MGF1: R || PK.seed || innerHash. */ + byte mgfSeed[32 + 16 + WC_SHA256_DIGEST_SIZE]; + + /* Step 1: innerHash = SHA-256(R || PK.seed || PK.root || M). */ + ret = wc_InitSha256(&key->hash.sha2.sha256_2); + if (ret == 0) { + ret = wc_Sha256Update(&key->hash.sha2.sha256_2, r, n); + } + if (ret == 0) { + ret = wc_Sha256Update(&key->hash.sha2.sha256_2, pk_seed, n); + } + if (ret == 0) { + ret = wc_Sha256Update(&key->hash.sha2.sha256_2, pk_root, n); + } + if ((ret == 0) && (hdr != NULL)) { + ret = wc_Sha256Update(&key->hash.sha2.sha256_2, hdr, 2); + } + if ((ret == 0) && (ctxSz > 0) && (ctx != NULL)) { + ret = wc_Sha256Update(&key->hash.sha2.sha256_2, ctx, ctxSz); + } + if (ret == 0) { + ret = wc_Sha256Update(&key->hash.sha2.sha256_2, msg, msgSz); + } + if (ret == 0) { + ret = wc_Sha256Final(&key->hash.sha2.sha256_2, innerHash); + } + + /* Step 2: MGF1-SHA-256(R || PK.seed || innerHash, mdLen). */ + if (ret == 0) { + XMEMCPY(mgfSeed, r, n); + XMEMCPY(mgfSeed + n, pk_seed, n); + XMEMCPY(mgfSeed + 2 * n, innerHash, WC_SHA256_DIGEST_SIZE); + ret = slhdsakey_mgf1_sha2(key, mgfSeed, + 2 * n + WC_SHA256_DIGEST_SIZE, md, mdLen); + } + } + else { + /* Categories 3, 5: SHA-512 + MGF1-SHA-512. */ + byte innerHash[WC_SHA512_DIGEST_SIZE]; + /* Seed for MGF1: R || PK.seed || innerHash. */ + byte mgfSeed[32 + 32 + WC_SHA512_DIGEST_SIZE]; + + /* Step 1: innerHash = SHA-512(R || PK.seed || PK.root || M). */ + ret = wc_InitSha512(&key->hash.sha2.sha512_2); + if (ret == 0) { + ret = wc_Sha512Update(&key->hash.sha2.sha512_2, r, n); + } + if (ret == 0) { + ret = wc_Sha512Update(&key->hash.sha2.sha512_2, pk_seed, n); + } + if (ret == 0) { + ret = wc_Sha512Update(&key->hash.sha2.sha512_2, pk_root, n); + } + if ((ret == 0) && (hdr != NULL)) { + ret = wc_Sha512Update(&key->hash.sha2.sha512_2, hdr, 2); + } + if ((ret == 0) && (ctxSz > 0) && (ctx != NULL)) { + ret = wc_Sha512Update(&key->hash.sha2.sha512_2, ctx, ctxSz); + } + if (ret == 0) { + ret = wc_Sha512Update(&key->hash.sha2.sha512_2, msg, msgSz); + } + if (ret == 0) { + ret = wc_Sha512Final(&key->hash.sha2.sha512_2, innerHash); + } + + /* Step 2: MGF1-SHA-512(R || PK.seed || innerHash, mdLen). */ + if (ret == 0) { + XMEMCPY(mgfSeed, r, n); + XMEMCPY(mgfSeed + n, pk_seed, n); + XMEMCPY(mgfSeed + 2 * n, innerHash, WC_SHA512_DIGEST_SIZE); + ret = slhdsakey_mgf1_sha2(key, mgfSeed, + 2 * n + WC_SHA512_DIGEST_SIZE, md, mdLen); + } + } + + return ret; +} + +#endif /* WOLFSSL_SLHDSA_SHA2 */ + +/****************************************************************************** + * Dispatching Hash Macros + ******************************************************************************/ + +/* When WOLFSSL_SLHDSA_SHA2 is defined, macros dispatch between SHAKE and SHA2 + * based on the key's parameter set. When not defined, macros call SHAKE + * directly (zero overhead). */ + +#ifdef WOLFSSL_SLHDSA_SHA2 + +/* SHAKE wrapper functions for SHA2 dispatch macros. */ +static int slhdsakey_hash_f_shake(SlhDsaKey* key, const byte* pk_seed, + const word32* adrs, const byte* m, byte n, byte* hash) +{ +#ifndef WOLFSSL_WC_SLHDSA_SMALL + return slhdsakey_hash_shake_3(&key->hash.shk.shake, pk_seed, n, adrs, m, + n, hash, n); +#else + return slhdsakey_hash_shake_4(&key->hash.shk.shake, pk_seed, n, adrs, m, + n, NULL, 0, hash, n); +#endif +} + +static int slhdsakey_hash_h_shake(SlhDsaKey* key, const byte* pk_seed, + const word32* adrs, const byte* node, byte n, byte* hash) +{ +#ifndef WOLFSSL_WC_SLHDSA_SMALL + return slhdsakey_hash_shake_3(&key->hash.shk.shake, pk_seed, n, adrs, node, + 2 * n, hash, n); +#else + return slhdsakey_hash_shake_4(&key->hash.shk.shake, pk_seed, n, adrs, node, + 2 * n, NULL, 0, hash, n); +#endif +} + +static int slhdsakey_hash_h_2_shake(SlhDsaKey* key, const byte* pk_seed, + const word32* adrs, const byte* m1, const byte* m2, byte n, byte* hash) +{ + return slhdsakey_hash_shake_4(&key->hash.shk.shake, pk_seed, n, adrs, m1, + n, m2, n, hash, n); +} + +static int slhdsakey_hash_prf_shake(SlhDsaKey* key, const byte* pk_seed, + const byte* sk_seed, const word32* adrs, byte n, byte* hash) +{ +#ifndef WOLFSSL_WC_SLHDSA_SMALL + return slhdsakey_hash_shake_3(&key->hash.shk.shake, pk_seed, n, adrs, + sk_seed, n, hash, n); +#else + return slhdsakey_hash_shake_4(&key->hash.shk.shake, pk_seed, n, adrs, + sk_seed, n, NULL, 0, hash, n); +#endif +} + +#define HASH_PRF(k, pk_seed, sk_seed, adrs, n, o) \ + (SLHDSA_IS_SHA2((k)->params->param) ? \ + slhdsakey_hash_prf_sha2(k, pk_seed, sk_seed, adrs, n, o) : \ + slhdsakey_hash_prf_shake(k, pk_seed, sk_seed, adrs, n, o)) + +#define HASH_F(k, pk_seed, adrs, m, n, o) \ + (SLHDSA_IS_SHA2((k)->params->param) ? \ + slhdsakey_hash_f_sha2(k, pk_seed, adrs, m, n, o) : \ + slhdsakey_hash_f_shake(k, pk_seed, adrs, m, n, o)) + +#define HASH_H(k, pk_seed, adrs, node, n, o) \ + (SLHDSA_IS_SHA2((k)->params->param) ? \ + slhdsakey_hash_h_sha2(k, pk_seed, adrs, node, n, o) : \ + slhdsakey_hash_h_shake(k, pk_seed, adrs, node, n, o)) + +#define HASH_H_2(k, pk_seed, adrs, m1, m2, n, o) \ + (SLHDSA_IS_SHA2((k)->params->param) ? \ + slhdsakey_hash_h_2_sha2(k, pk_seed, adrs, m1, m2, n, o) : \ + slhdsakey_hash_h_2_shake(k, pk_seed, adrs, m1, m2, n, o)) + +#else /* !WOLFSSL_SLHDSA_SHA2 */ + #ifndef WOLFSSL_WC_SLHDSA_SMALL /* PRF hash. * @@ -606,7 +1363,7 @@ static int slhdsakey_hash_shake_4(wc_Shake* shake, const byte* data1, * FIPS 205. Section 11.1. * PRF(PK.seed, SK.seed, ADRS) = SHAKE256(PK.seed || ADRS || SK.seed, 8n) * - * @param [in] shake SHAKE-256 object. + * @param [in] key SLH-DSA key. * @param [in] pk_seed Public key seed. * @param [in] sk_seed Private key seed. * @param [in] adrs HashAddress. @@ -615,128 +1372,70 @@ static int slhdsakey_hash_shake_4(wc_Shake* shake, const byte* data1, * @return 0 on success. * @return SHAKE-256 error return code on digest failure. */ -#define HASH_PRF(shake, pk_seed, sk_seed, adrs, n, hash) \ - slhdsakey_hash_shake_3(shake, pk_seed, n, adrs, sk_seed, n, hash, n) -/* Hash F. - * - * FIPS 205. Section 4.1. - * F(PK.seed, ADRS, M1) (Bn x B32 x Bn -> Bn ) is a hash function that takes - * an n-byte message as input and produces an n-byte output. - * FIPS 205. Section 11.1. - * F(PK.seed, ADRS, M1) = SHAKE256(PK.seed || ADRS || M1, 8n) - * - * @param [in] shake SHAKE-256 object. - * @param [in] pk_seed Public key seed. - * @param [in] adrs HashAddress. - * @param [in] m Message of n bytes. - * @param [in] n Number of bytes in hash output. - * @param [out] hash Buffer to hold hash output. - * @return 0 on success. - * @return SHAKE-256 error return code on digest failure. - */ -#define HASH_F(shake, pk_seed, adrs, m, n, hash) \ - slhdsakey_hash_shake_3(shake, pk_seed, n, adrs, m, n, hash, n) -/* Hash H. - * - * FIPS 205. Section 4.1. - * H(PK.seed, ADRS, M2) (Bn x B32 x B2n -> Bn ) is a special case of Tl that - * takes a 2n-byte message as input. - * FIPS 205. Section 11.1. - * H(PK.seed, ADRS, M2) = SHAKE256(PK.seed || ADRS || M2, 8n) - * - * @param [in] shake SHAKE-256 object. - * @param [in] pk_seed Public key seed. - * @param [in] adrs HashAddress. - * @param [in] m Message of 2*n bytes. - * @param [in] n Number of bytes in hash output. - * @param [out] hash Buffer to hold hash output. - * @return 0 on success. - * @return SHAKE-256 error return code on digest failure. - */ -#define HASH_H(shake, pk_seed, adrs, node, n, hash) \ - slhdsakey_hash_shake_3(shake, pk_seed, n, adrs, node, 2 * (n), hash, (n)) +#define HASH_PRF(k, pk_seed, sk_seed, adrs, n, o) \ + slhdsakey_hash_shake_3(&(k)->hash.shk.shake, pk_seed, n, adrs, \ + sk_seed, n, o, n) +/* Hash F. */ +#define HASH_F(k, pk_seed, adrs, m, n, o) \ + slhdsakey_hash_shake_3(&(k)->hash.shk.shake, pk_seed, n, adrs, m, n, \ + o, n) +/* Hash H. */ +#define HASH_H(k, pk_seed, adrs, node, n, o) \ + slhdsakey_hash_shake_3(&(k)->hash.shk.shake, pk_seed, n, adrs, node, \ + 2 * (n), o, (n)) #else -/* PRF hash. - * - * FIPS 205. Section 4.1. - * PRF(PK.seed, SK.seed, ADRS) (Bn x Bn x B32 -> Bn) is a PRF that is used to - * generate the secret values in WOTS+ and FORS private keys. - * FIPS 205. Section 11.1. - * F(PK.seed, SK.seed, ADRS) = SHAKE256(PK.seed || ADRS || SK.seed, 8n) - * - * @param [in] shake SHAKE-256 object. - * @param [in] pk_seed Public key seed. - * @param [in] sk_seed Private key seed. - * @param [in] adrs HashAddress. - * @param [in] n Number of bytes in hash output. - * @param [out] hash Buffer to hold hash output. - * @return 0 on success. - * @return SHAKE-256 error return code on digest failure. - */ -#define HASH_PRF(shake, pk_seed, sk_seed, adrs, n, hash) \ - slhdsakey_hash_shake_4(shake, pk_seed, n, adrs, sk_seed, n, NULL, 0, \ - hash, n) -/* Hash F. - * - * FIPS 205. Section 4.1. - * F(PK.seed, ADRS, M1) (Bn x B32 x Bn -> Bn ) is a hash function that takes - * an n-byte message as input and produces an n-byte output. - * FIPS 205. Section 11.1. - * F(PK.seed, ADRS, M1) = SHAKE256(PK.seed || ADRS || M1, 8n) - * - * @param [in] shake SHAKE-256 object. - * @param [in] pk_seed Public key seed. - * @param [in] adrs HashAddress. - * @param [in] m Message of n bytes. - * @param [in] n Number of bytes in hash output. - * @param [out] hash Buffer to hold hash output. - * @return 0 on success. - * @return SHAKE-256 error return code on digest failure. - */ -#define HASH_F(shake, pk_seed, adrs, m, n, hash) \ - slhdsakey_hash_shake_4(shake, pk_seed, n, adrs, m, n, NULL, 0, hash, n) -/* Hash H. - * - * FIPS 205. Section 4.1. - * H(PK.seed, ADRS, M2) (Bn x B32 x B2n -> Bn ) is a special case of Tl that - * takes a 2n-byte message as input. - * FIPS 205. Section 11.1. - * H(PK.seed, ADRS, M2) = SHAKE256(PK.seed || ADRS || M2, 8n) - * - * @param [in] shake SHAKE-256 object. - * @param [in] pk_seed Public key seed. - * @param [in] adrs HashAddress. - * @param [in] m Message of 2*n bytes. - * @param [in] n Number of bytes in hash output. - * @param [out] hash Buffer to hold hash output. - * @return 0 on success. - * @return SHAKE-256 error return code on digest failure. - */ -#define HASH_H(shake, pk_seed, adrs, node, n, hash) \ - slhdsakey_hash_shake_4(shake, pk_seed, n, adrs, node, 2 * n, NULL, 0, \ - hash, n) +/* PRF hash. */ +#define HASH_PRF(k, pk_seed, sk_seed, adrs, n, o) \ + slhdsakey_hash_shake_4(&(k)->hash.shk.shake, pk_seed, n, adrs, \ + sk_seed, n, NULL, 0, o, n) +/* Hash F. */ +#define HASH_F(k, pk_seed, adrs, m, n, o) \ + slhdsakey_hash_shake_4(&(k)->hash.shk.shake, pk_seed, n, adrs, m, n, \ + NULL, 0, o, n) +/* Hash H. */ +#define HASH_H(k, pk_seed, adrs, node, n, o) \ + slhdsakey_hash_shake_4(&(k)->hash.shk.shake, pk_seed, n, adrs, node, \ + 2 * n, NULL, 0, o, n) #endif -/* Hash H with 2n byte message as two separate n byte parameters. - * - * FIPS 205. Section 4.1. - * H(PK.seed, ADRS, M2) (Bn x B32 x B2n -> Bn ) is a special case of Tl that - * takes a 2n-byte message as input. - * FIPS 205. Section 11.1. - * H(PK.seed, ADRS, M2) = SHAKE256(PK.seed || ADRS || M2, 8n) - * - * @param [in] shake SHAKE-256 object. - * @param [in] pk_seed Public key seed. - * @param [in] adrs HashAddress. - * @param [in] m1 First n bytes of message. - * @param [in] m2 Second n bytes of message. - * @param [in] n Number of bytes in hash output. - * @param [out] hash Buffer to hold hash output. - * @return 0 on success. - * @return SHAKE-256 error return code on digest failure. - */ -#define HASH_H_2(shake, pk_seed, adrs, m1, m2, n, hash) \ - slhdsakey_hash_shake_4(shake, pk_seed, n, adrs, m1, n, m2, n, hash, n) +/* Hash H with 2n byte message as two separate n byte parameters. */ +#define HASH_H_2(k, pk_seed, adrs, m1, m2, n, o) \ + slhdsakey_hash_shake_4(&(k)->hash.shk.shake, pk_seed, n, adrs, m1, n, \ + m2, n, o, n) + +#endif /* WOLFSSL_SLHDSA_SHA2 */ + +/* T_l streaming dispatch macros for the secondary hash (used by WOTS+ pk + * compression and FORS root computation). */ +#ifdef WOLFSSL_SLHDSA_SHA2 + +#define HASH_T_START_ADDR(k, pk_seed, adrs, n) \ + (SLHDSA_IS_SHA2((k)->params->param) ? \ + slhdsakey_hash_start_addr_sha2(k, pk_seed, adrs, n) : \ + slhdsakey_hash_start_addr(&(k)->hash.shk.shake2, pk_seed, adrs, n)) + +#define HASH_T_UPDATE(k, d, l) \ + (SLHDSA_IS_SHA2((k)->params->param) ? \ + slhdsakey_hash_update_sha2(k, d, l) : \ + slhdsakey_hash_update(&(k)->hash.shk.shake2, d, l)) + +#define HASH_T_FINAL(k, o, l) \ + (SLHDSA_IS_SHA2((k)->params->param) ? \ + slhdsakey_hash_final_sha2(k, o, l) : \ + slhdsakey_hash_final(&(k)->hash.shk.shake2, o, l)) + +#else + +#define HASH_T_START_ADDR(k, pk_seed, adrs, n) \ + slhdsakey_hash_start_addr(&(k)->hash.shk.shake2, pk_seed, adrs, n) + +#define HASH_T_UPDATE(k, d, l) \ + slhdsakey_hash_update(&(k)->hash.shk.shake2, d, l) + +#define HASH_T_FINAL(k, o, l) \ + slhdsakey_hash_final(&(k)->hash.shk.shake2, o, l) + +#endif /* WOLFSSL_SLHDSA_SHA2 */ /* Start hashing with SHAKE-256. * @@ -925,13 +1624,13 @@ static int slhdsakey_chain(SlhDsaKey* key, const byte* x, byte i, byte s, /* Set the hash address for first iteration. */ HA_SetHashAddress(adrs, i); /* First iteration of hash using input and writing to output buffers. */ - ret = HASH_F(&key->shake, pk_seed, adrs, x, n, node); + ret = HASH_F(key, pk_seed, adrs, x, n, node); if (ret == 0) { for (j = i + 1; j < i + s; j++) { /* Set the hash address. */ HA_SetHashAddress(adrs, j); /* Iterate hash using output buffer as input. */ - ret = HASH_F(&key->shake, pk_seed, adrs, node, n, node); + ret = HASH_F(key, pk_seed, adrs, node, n, node); if (ret != 0) { break; } @@ -2139,7 +2838,7 @@ static int slhdsakey_wots_pkgen_chain_x4_16(SlhDsaKey* key, const byte* sk_seed, } } if (ret == 0) { - ret = slhdsakey_hash_update(&key->shake2, sk, len * 16); + ret = HASH_T_UPDATE(key, sk, len * 16); } WC_FREE_VAR_EX(sk, key->heap, DYNAMIC_TYPE_SLHDSA); @@ -2207,7 +2906,7 @@ static int slhdsakey_wots_pkgen_chain_x4_24(SlhDsaKey* key, const byte* sk_seed, } } if (ret == 0) { - ret = slhdsakey_hash_update(&key->shake2, sk, len * 24); + ret = HASH_T_UPDATE(key, sk, len * 24); } WC_FREE_VAR_EX(sk, key->heap, DYNAMIC_TYPE_SLHDSA); @@ -2275,7 +2974,7 @@ static int slhdsakey_wots_pkgen_chain_x4_32(SlhDsaKey* key, const byte* sk_seed, } } if (ret == 0) { - ret = slhdsakey_hash_update(&key->shake2, sk, len * 32); + ret = HASH_T_UPDATE(key, sk, len * 32); } WC_FREE_VAR_EX(sk, key->heap, DYNAMIC_TYPE_SLHDSA); @@ -2322,7 +3021,7 @@ static int slhdsakey_wots_pkgen_chain_x4(SlhDsaKey* key, const byte* sk_seed, HA_Encode(adrs, addr); #if !defined(WOLFSSL_SLHDSA_PARAM_NO_128) - if (n == 16) { + if (n == WC_SLHDSA_N_128) { ret = slhdsakey_wots_pkgen_chain_x4_16(key, sk_seed, pk_seed, addr, sk_addr); } @@ -2396,7 +3095,7 @@ static int slhdsakey_wots_pkgen_chain_c(SlhDsaKey* key, const byte* sk_seed, /* Step 5. Set chain address for WOTS PRF. */ HA_SetChainAddress(sk_adrs, i); /* Step 6. PRF hash seeds and chain address. */ - ret = HASH_PRF(&key->shake, pk_seed, sk_seed, sk_adrs, n, + ret = HASH_PRF(key, pk_seed, sk_seed, sk_adrs, n, sk + i * n); if (ret != 0) { break; @@ -2413,7 +3112,7 @@ static int slhdsakey_wots_pkgen_chain_c(SlhDsaKey* key, const byte* sk_seed, } if (ret == 0) { /* Step 13: Compress public key. */ - ret = slhdsakey_hash_update(&key->shake2, sk, len * n); + ret = HASH_T_UPDATE(key, sk, len * n); } WC_FREE_VAR_EX(sk, key->heap, DYNAMIC_TYPE_SLHDSA); #else @@ -2424,7 +3123,7 @@ static int slhdsakey_wots_pkgen_chain_c(SlhDsaKey* key, const byte* sk_seed, /* Step 5. Set chain address for WOTS PRF. */ HA_SetChainAddress(sk_adrs, i); /* Step 6. PRF hash seeds and chain address. */ - ret = HASH_PRF(&key->shake, pk_seed, sk_seed, sk_adrs, n, sk); + ret = HASH_PRF(key, pk_seed, sk_seed, sk_adrs, n, sk); if (ret != 0) { break; } @@ -2437,7 +3136,7 @@ static int slhdsakey_wots_pkgen_chain_c(SlhDsaKey* key, const byte* sk_seed, } /* Step 13: Compress public key - for each tmp. */ - ret = slhdsakey_hash_update(&key->shake2, sk, n); + ret = HASH_T_UPDATE(key, sk, n); if (ret != 0) { break; } @@ -2482,7 +3181,7 @@ static int slhdsakey_wots_pkgen(SlhDsaKey* key, const byte* sk_seed, HA_Copy(wotspk_adrs, adrs); HA_SetTypeAndClearNotKPA(wotspk_adrs, HA_WOTS_PK); /* Step 13. Start hash with public key seed and address. */ - ret = slhdsakey_hash_start_addr(&key->shake2, pk_seed, wotspk_adrs, n); + ret = HASH_T_START_ADDR(key, pk_seed, wotspk_adrs, n); } if (ret == 0) { HashAddress sk_adrs; @@ -2492,7 +3191,9 @@ static int slhdsakey_wots_pkgen(SlhDsaKey* key, const byte* sk_seed, HA_SetTypeAndClearNotKPA(sk_adrs, HA_WOTS_PRF); /* Steps 4-10,13: Generate hashes and update the public key hash. */ #if defined(USE_INTEL_SPEEDUP) && !defined(WOLFSSL_WC_SLHDSA_SMALL) - if (IS_INTEL_AVX2(cpuid_flags) && (SAVE_VECTOR_REGISTERS2() == 0)) { + if (!SLHDSA_IS_SHA2(key->params->param) && + IS_INTEL_AVX2(cpuid_flags) && + (SAVE_VECTOR_REGISTERS2() == 0)) { ret = slhdsakey_wots_pkgen_chain_x4(key, sk_seed, pk_seed, adrs, sk_adrs); RESTORE_VECTOR_REGISTERS(); @@ -2506,7 +3207,7 @@ static int slhdsakey_wots_pkgen(SlhDsaKey* key, const byte* sk_seed, } if (ret == 0) { /* Step 13: Output hash of compressed public key. */ - ret = slhdsakey_hash_final(&key->shake2, node, n); + ret = HASH_T_FINAL(key, node, n); } return ret; @@ -2798,7 +3499,7 @@ static int slhdsakey_wots_sign_chain_x4(SlhDsaKey* key, const byte* msg, HA_Encode(adrs, addr); #if !defined(WOLFSSL_SLHDSA_PARAM_NO_128) - if (n == 16) { + if (n == WC_SLHDSA_N_128) { ret = slhdsakey_wots_sign_chain_x4_16(key, msg, sk_seed, pk_seed, adrs, addr, sk_addr, sig); } @@ -2895,7 +3596,9 @@ static int slhdsakey_wots_sign(SlhDsaKey* key, const byte* m, HA_SetTypeAndClearNotKPA(sk_adrs, HA_WOTS_PRF); #if defined(USE_INTEL_SPEEDUP) && !defined(WOLFSSL_WC_SLHDSA_SMALL) /* Steps 11-17: Generate signature from msg. */ - if (IS_INTEL_AVX2(cpuid_flags) && (SAVE_VECTOR_REGISTERS2() == 0)) { + if (!SLHDSA_IS_SHA2(key->params->param) && + IS_INTEL_AVX2(cpuid_flags) && + (SAVE_VECTOR_REGISTERS2() == 0)) { ret = slhdsakey_wots_sign_chain_x4(key, msg, sk_seed, pk_seed, adrs, sk_adrs, sig); RESTORE_VECTOR_REGISTERS(); @@ -2908,7 +3611,7 @@ static int slhdsakey_wots_sign(SlhDsaKey* key, const byte* m, /* Step 12: Set chain address for WOTS PRF. */ HA_SetChainAddress(sk_adrs, i); /* Step 13. PRF hash seeds and chain address. */ - ret = HASH_PRF(&key->shake, pk_seed, sk_seed, sk_adrs, n, sig); + ret = HASH_PRF(key, pk_seed, sk_seed, sk_adrs, n, sig); if (ret != 0) { break; } @@ -3195,7 +3898,7 @@ static int slhdsakey_wots_pk_from_sig_x4(SlhDsaKey* key, const byte* sig, WC_ALLOC_VAR_EX(nodes, byte, SLHDSA_MAX_MSG_SZ * SLHDSA_MAX_N, key->heap, DYNAMIC_TYPE_SLHDSA, ret = MEMORY_E); #if !defined(WOLFSSL_SLHDSA_PARAM_NO_128) - if ((ret == 0) && (n == 16)) { + if ((ret == 0) && (n == WC_SLHDSA_N_128)) { ii = 0; for (j = 0; j <= SLHDSA_WM1; j++) { for (i = 0; i < len; i++) { @@ -3281,14 +3984,14 @@ static int slhdsakey_wots_pk_from_sig_x4(SlhDsaKey* key, const byte* sig, if (ret == 0) { HA_Copy(wotspk_adrs, adrs); HA_SetTypeAndClearNotKPA(wotspk_adrs, HA_WOTS_PK); - ret = slhdsakey_hash_start_addr(&key->shake2, pk_seed, wotspk_adrs, n); + ret = HASH_T_START_ADDR(key, pk_seed, wotspk_adrs, n); } if (ret == 0) { - ret = slhdsakey_hash_update(&key->shake2, nodes, len * n); + ret = HASH_T_UPDATE(key, nodes, len * n); sig += len * n; } if (ret == 0) { - ret = slhdsakey_hash_final(&key->shake2, pk_sig, n); + ret = HASH_T_FINAL(key, pk_sig, n); } WC_FREE_VAR_EX(nodes, key->heap, DYNAMIC_TYPE_SLHDSA); @@ -3354,15 +4057,15 @@ static int slhdsakey_wots_pk_from_sig_c(SlhDsaKey* key, const byte* sig, HA_Copy(wotspk_adrs, adrs); HA_SetTypeAndClearNotKPA(wotspk_adrs, HA_WOTS_PK); /* Step 15: Hash the public key seed and WOTS PK address ... */ - ret = slhdsakey_hash_start_addr(&key->shake2, pk_seed, wotspk_adrs, n); + ret = HASH_T_START_ADDR(key, pk_seed, wotspk_adrs, n); } if (ret == 0) { /* Step 15: Update with the nodes ... */ - ret = slhdsakey_hash_update(&key->shake2, nodes, len * n); + ret = HASH_T_UPDATE(key, nodes, len * n); } if (ret == 0) { /* Step 15: Generate root node - public key signature. */ - ret = slhdsakey_hash_final(&key->shake2, pk_sig, n); + ret = HASH_T_FINAL(key, pk_sig, n); } WC_FREE_VAR_EX(nodes, key->heap, DYNAMIC_TYPE_SLHDSA); @@ -3408,7 +4111,7 @@ static int slhdsakey_wots_pk_from_sig_c(SlhDsaKey* key, const byte* sig, HA_Copy(wotspk_adrs, adrs); HA_SetTypeAndClearNotKPA(wotspk_adrs, HA_WOTS_PK); /* Step 15: Hash the public key seed and WOTS PK address ... */ - ret = slhdsakey_hash_start_addr(&key->shake2, pk_seed, wotspk_adrs, n); + ret = HASH_T_START_ADDR(key, pk_seed, wotspk_adrs, n); if (ret == 0) { /* Step 8: For each value in msg. */ for (i = 0; i < len; i++) { @@ -3421,7 +4124,7 @@ static int slhdsakey_wots_pk_from_sig_c(SlhDsaKey* key, const byte* sig, break; } /* Step 15: Update with node ... */ - ret = slhdsakey_hash_update(&key->shake2, node, n); + ret = HASH_T_UPDATE(key, node, n); if (ret != 0) { break; } @@ -3431,7 +4134,7 @@ static int slhdsakey_wots_pk_from_sig_c(SlhDsaKey* key, const byte* sig, } if (ret == 0) { /* Step 15: Generate root node - public key signature. */ - ret = slhdsakey_hash_final(&key->shake2, pk_sig, n); + ret = HASH_T_FINAL(key, pk_sig, n); } return ret; @@ -3491,7 +4194,9 @@ static int slhdsakey_wots_pk_from_sig(SlhDsaKey* key, const byte* sig, /* Steps 8-16. */ #if defined(USE_INTEL_SPEEDUP) && !defined(WOLFSSL_WC_SLHDSA_SMALL) - if (IS_INTEL_AVX2(cpuid_flags) && (SAVE_VECTOR_REGISTERS2() == 0)) { + if (!SLHDSA_IS_SHA2(key->params->param) && + IS_INTEL_AVX2(cpuid_flags) && + (SAVE_VECTOR_REGISTERS2() == 0)) { ret = slhdsakey_wots_pk_from_sig_x4(key, sig, msg, pk_seed, adrs, pk_sig); RESTORE_VECTOR_REGISTERS(); @@ -3587,7 +4292,7 @@ static int slhdsakey_xmss_node(SlhDsaKey* key, const byte* sk_seed, int i, HA_SetTreeHeight(adrs, z - k); HA_SetTreeIndex(adrs, (m * i + j) >> (z - k)); /* Step 11: Calculate node from two below. */ - ret = HASH_H(&key->shake, pk_seed, adrs, nodes + k * n, + ret = HASH_H(key, pk_seed, adrs, nodes + k * n, n, nodes + (k - 1 + ((j >> (z-k)) & 1)) * n); if (ret != 0) { break; @@ -3608,7 +4313,7 @@ static int slhdsakey_xmss_node(SlhDsaKey* key, const byte* sk_seed, int i, HA_SetTreeHeight(adrs, z); HA_SetTreeIndex(adrs, i); /* Step 11: Calculate node from two below. */ - ret = HASH_H(&key->shake, pk_seed, adrs, nodes, n, node); + ret = HASH_H(key, pk_seed, adrs, nodes, n, node); } } @@ -3679,7 +4384,7 @@ static int slhdsakey_xmss_node(SlhDsaKey* key, const byte* sk_seed, int i, HA_SetTreeHeight(adrs, z); HA_SetTreeIndex(adrs, i); /* Step 11: Calculate node from two below. */ - ret = HASH_H(&key->shake, pk_seed, adrs, nodes, n, node); + ret = HASH_H(key, pk_seed, adrs, nodes, n, node); } } @@ -3829,11 +4534,11 @@ static int slhdsakey_xmss_pk_from_sig(SlhDsaKey* key, word32 idx, /* Step 10: Check which order to put nodes. */ if (side == 0) { /* Steps 12,17: Calculate node with sig node on right. */ - ret = HASH_H_2(&key->shake, pk_seed, adrs, node, auth, n, node); + ret = HASH_H_2(key, pk_seed, adrs, node, auth, n, node); } else { /* Steps 15,17: Calculate node with sig node on left. */ - ret = HASH_H_2(&key->shake, pk_seed, adrs, auth, node, n, node); + ret = HASH_H_2(key, pk_seed, adrs, auth, node, n, node); } if (ret != 0) { break; @@ -4076,7 +4781,7 @@ static int slhdsakey_fors_sk_gen(SlhDsaKey* key, const byte* sk_seed, /* Step 4: Set tree index. */ HA_SetTreeIndex(sk_adrs, idx); /* Step 5: Hash seeds and address. */ - return HASH_PRF(&key->shake, pk_seed, sk_seed, sk_adrs, key->params->n, + return HASH_PRF(key, pk_seed, sk_seed, sk_adrs, key->params->n, node); } @@ -4297,7 +5002,7 @@ static int slhdsakey_fors_node_x4_z0(SlhDsaKey* key, const byte* sk_seed, /* Step 4: Set tree index. */ HA_SetTreeIndex(adrs, i); /* Step 5: Compute node from public key seed, address and value. */ - ret = HASH_F(&key->shake, pk_seed, adrs, node, n, node); + ret = HASH_F(key, pk_seed, adrs, node, n, node); } return ret; @@ -4349,7 +5054,7 @@ static int slhdsakey_fors_node_x4_z1(SlhDsaKey* key, const byte* sk_seed, /* Step 4: Set tree index. */ HA_SetTreeIndex(adrs, 2 * i + 0); /* Step 5: Compute node from public key seed, address and value. */ - ret = HASH_F(&key->shake, pk_seed, adrs, nodes, n, nodes); + ret = HASH_F(key, pk_seed, adrs, nodes, n, nodes); } /* Step 8: Compute right node. */ if (ret == 0) { @@ -4361,7 +5066,7 @@ static int slhdsakey_fors_node_x4_z1(SlhDsaKey* key, const byte* sk_seed, /* Step 4: Set tree index. */ HA_SetTreeIndex(adrs, 2 * i + 1); /* Step 5: Compute node from public key seed, address and value. */ - ret = HASH_F(&key->shake, pk_seed, adrs, nodes + n, n, nodes + n); + ret = HASH_F(key, pk_seed, adrs, nodes + n, n, nodes + n); } if (ret == 0) { /* Step 9: Set tree height. */ @@ -4369,7 +5074,7 @@ static int slhdsakey_fors_node_x4_z1(SlhDsaKey* key, const byte* sk_seed, /* Step 10: Set tree index. */ HA_SetTreeIndex(adrs, i); /* Step 11: Compute node from public key seed, address and nodes. */ - ret = HASH_H(&key->shake, pk_seed, adrs, nodes, n, node); + ret = HASH_H(key, pk_seed, adrs, nodes, n, node); } return ret; @@ -4480,14 +5185,14 @@ static int slhdsakey_fors_node_x4_low(SlhDsaKey* key, const byte* sk_seed, /* Step 10: Set tree index. */ HA_SetTreeIndex(adrs, 2 * i + 0); /* Step 11: Compute node from public key seed, address and nodes. */ - ret = HASH_H(&key->shake, pk_seed, adrs, nodes, n, nodes); + ret = HASH_H(key, pk_seed, adrs, nodes, n, nodes); } /* Step 8: Compute right node. */ if (ret == 0) { /* Step 10: Set tree index. */ HA_SetTreeIndex(adrs, 2 * i + 1); /* Step 11: Compute node from public key seed, address and nodes. */ - ret = HASH_H(&key->shake, pk_seed, adrs, nodes + 2 * n, n, + ret = HASH_H(key, pk_seed, adrs, nodes + 2 * n, n, nodes + 1 * n); } if (ret == 0) { @@ -4496,7 +5201,7 @@ static int slhdsakey_fors_node_x4_low(SlhDsaKey* key, const byte* sk_seed, /* Step 10: Set tree index. */ HA_SetTreeIndex(adrs, i); /* Step 11: Compute node from public key seed, address and nodes. */ - ret = HASH_H(&key->shake, pk_seed, adrs, nodes, n, node); + ret = HASH_H(key, pk_seed, adrs, nodes, n, node); } WC_FREE_VAR_EX(nodes, key->heap, DYNAMIC_TYPE_SLHDSA); @@ -4592,14 +5297,14 @@ static int slhdsakey_fors_node_x4_high(SlhDsaKey* key, const byte* sk_seed, /* Step 10: Set tree index. */ HA_SetTreeIndex(adrs, 2 * i + 0); /* Step 11: Compute node from public key seed, address and nodes. */ - ret = HASH_H(&key->shake, pk_seed, adrs, nodes, n, nodes); + ret = HASH_H(key, pk_seed, adrs, nodes, n, nodes); } /* Step 8: Compute right node. */ if ((ret == 0) && (z2 > 1)) { /* Step 10: Set tree index. */ HA_SetTreeIndex(adrs, 2 * i + 1); /* Step 11: Compute node from public key seed, address and nodes. */ - ret = HASH_H(&key->shake, pk_seed, adrs, nodes + 2 * n, n, + ret = HASH_H(key, pk_seed, adrs, nodes + 2 * n, n, nodes + 1 * n); } if (ret == 0) { @@ -4608,7 +5313,7 @@ static int slhdsakey_fors_node_x4_high(SlhDsaKey* key, const byte* sk_seed, /* Step 10: Set tree index. */ HA_SetTreeIndex(adrs, i); /* Step 11: Compute node from public key seed, address and nodes. */ - ret = HASH_H(&key->shake, pk_seed, adrs, nodes, n, node); + ret = HASH_H(key, pk_seed, adrs, nodes, n, node); } WC_FREE_VAR_EX(nodes, key->heap, DYNAMIC_TYPE_SLHDSA); @@ -4725,7 +5430,7 @@ static int slhdsakey_fors_node_c(SlhDsaKey* key, const byte* sk_seed, word32 i, /* Step 4: Set tree index. */ HA_SetTreeIndex(adrs, i); /* Step 5: Compute node from public key seed, address and value. */ - ret = HASH_F(&key->shake, pk_seed, adrs, node, n, node); + ret = HASH_F(key, pk_seed, adrs, node, n, node); } } /* Step 6: Non leaf node. */ @@ -4754,7 +5459,7 @@ static int slhdsakey_fors_node_c(SlhDsaKey* key, const byte* sk_seed, word32 i, HA_SetTreeIndex(adrs, m * i + j); /* Step 5: Compute node from public key seed, address and value. */ - ret = HASH_F(&key->shake, pk_seed, adrs, nodes + o, n, + ret = HASH_F(key, pk_seed, adrs, nodes + o, n, nodes + o); if (ret != 0) { break; @@ -4771,7 +5476,7 @@ static int slhdsakey_fors_node_c(SlhDsaKey* key, const byte* sk_seed, word32 i, HA_SetTreeIndex(adrs, (m * i + j) >> (z - k)); /* Step 11: Compute node from public key seed, address * and left and right nodes. */ - ret = HASH_H(&key->shake, pk_seed, adrs, nodes + k * n, + ret = HASH_H(key, pk_seed, adrs, nodes + k * n, n, nodes + (k - 1 + ((j >> (z-k)) & 1)) * n); if (ret != 0) { break; @@ -4790,7 +5495,7 @@ static int slhdsakey_fors_node_c(SlhDsaKey* key, const byte* sk_seed, word32 i, HA_SetTreeIndex(adrs, i); /* Step 11: Compute node from public key seed, address * and nodes. */ - ret = HASH_H(&key->shake, pk_seed, adrs, nodes, n, node); + ret = HASH_H(key, pk_seed, adrs, nodes, n, node); } } @@ -4847,7 +5552,7 @@ static int slhdsakey_fors_node_c(SlhDsaKey* key, const byte* sk_seed, word32 i, /* Step 4: Set tree index. */ HA_SetTreeIndex(adrs, i); /* Step 5: Compute node from public key seed, address and value. */ - ret = HASH_F(&key->shake, pk_seed, adrs, node, n, node); + ret = HASH_F(key, pk_seed, adrs, node, n, node); } } else { @@ -4867,7 +5572,7 @@ static int slhdsakey_fors_node_c(SlhDsaKey* key, const byte* sk_seed, word32 i, /* Step 10: Set tree index. */ HA_SetTreeIndex(adrs, i); /* Step 11: Compute node from public key seed, address and nodes. */ - ret = HASH_H(&key->shake, pk_seed, adrs, nodes, n, node); + ret = HASH_H(key, pk_seed, adrs, nodes, n, node); } } @@ -4928,7 +5633,9 @@ static int slhdsakey_fors_sign(SlhDsaKey* key, const byte* md, sig_fors += n; #if defined(USE_INTEL_SPEEDUP) && !defined(WOLFSSL_WC_SLHDSA_SMALL) - if (IS_INTEL_AVX2(cpuid_flags) && CAN_SAVE_VECTOR_REGISTERS()) { + if (!SLHDSA_IS_SHA2(key->params->param) && + IS_INTEL_AVX2(cpuid_flags) && + CAN_SAVE_VECTOR_REGISTERS()) { word16 idx = indices[i]; /* Step 5: For each bit: */ for (j = 0; j < a; j++) { @@ -5275,7 +5982,7 @@ static int slhdsakey_fors_pk_from_sig_x4(SlhDsaKey* key, const byte* sig_fors, /* Step 5: Set tree index for address. */ HA_SetTreeIndex(adrs, idx); /* Step 6: Compute node from public key seed, address and value. */ - ret = HASH_F(&key->shake, pk_seed, adrs, sig_fors, n, node + i * n); + ret = HASH_F(key, pk_seed, adrs, sig_fors, n, node + i * n); if (ret != 0) { break; } @@ -5296,12 +6003,12 @@ static int slhdsakey_fors_pk_from_sig_x4(SlhDsaKey* key, const byte* sig_fors, /* Step 10: Check which side node is on. */ if (side == 0) { /* Step 12: Hash node || auth node. */ - ret = HASH_H_2(&key->shake, pk_seed, adrs, node + i * n, + ret = HASH_H_2(key, pk_seed, adrs, node + i * n, sig_fors, n, node + i * n); } else { /* Step 15: Hash auth node || node. */ - ret = HASH_H_2(&key->shake, pk_seed, adrs, sig_fors, + ret = HASH_H_2(key, pk_seed, adrs, sig_fors, node + i * n, n, node + i * n); } if (ret != 0) { @@ -5317,7 +6024,7 @@ static int slhdsakey_fors_pk_from_sig_x4(SlhDsaKey* key, const byte* sig_fors, } if (ret == 0) { /* Step 24: Add more root nodes to hash ... */ - ret = slhdsakey_hash_update(&key->shake2, node, i * n); + ret = HASH_T_UPDATE(key, node, i * n); } WC_FREE_VAR_EX(node, key->heap, DYNAMIC_TYPE_SLHDSA); @@ -5394,7 +6101,7 @@ static int slhdsakey_fors_pk_from_sig_c(SlhDsaKey* key, const byte* sig_fors, /* Step 5: Set tree index for address. */ HA_SetTreeIndex(adrs, idx); /* Step 6: Compute node from public key seed, address and value. */ - ret = HASH_F(&key->shake, pk_seed, adrs, sig_fors, n, node + i * n); + ret = HASH_F(key, pk_seed, adrs, sig_fors, n, node + i * n); if (ret != 0) { break; } @@ -5415,12 +6122,12 @@ static int slhdsakey_fors_pk_from_sig_c(SlhDsaKey* key, const byte* sig_fors, /* Step 10: Check which side node is on. */ if (bit == 0) { /* Step 12: Hash node || auth node. */ - ret = HASH_H_2(&key->shake, pk_seed, adrs, node + i * n, + ret = HASH_H_2(key, pk_seed, adrs, node + i * n, sig_fors, n, node + i * n); } else { /* Step 15: Hash auth node || node. */ - ret = HASH_H_2(&key->shake, pk_seed, adrs, sig_fors, + ret = HASH_H_2(key, pk_seed, adrs, sig_fors, node + i * n, n, node + i * n); } if (ret != 0) { @@ -5436,7 +6143,7 @@ static int slhdsakey_fors_pk_from_sig_c(SlhDsaKey* key, const byte* sig_fors, } if (ret == 0) { /* Step 24: Add more root nodes to hash ... */ - ret = slhdsakey_hash_update(&key->shake2, node, i * n); + ret = HASH_T_UPDATE(key, node, i * n); } WC_FREE_VAR_EX(node, key->heap, DYNAMIC_TYPE_SLHDSA); @@ -5505,7 +6212,7 @@ static int slhdsakey_fors_pk_from_sig_c(SlhDsaKey* key, const byte* sig_fors, /* Step 5: Set tree index for address. */ HA_SetTreeIndex(adrs, idx); /* Step 6: Compute node from public key seed, address and value. */ - ret = HASH_F(&key->shake, pk_seed, adrs, sig_fors, n, node); + ret = HASH_F(key, pk_seed, adrs, sig_fors, n, node); if (ret != 0) { break; } @@ -5526,12 +6233,12 @@ static int slhdsakey_fors_pk_from_sig_c(SlhDsaKey* key, const byte* sig_fors, /* Step 10: Check which side node is on. */ if (bit == 0) { /* Step 12: Hash node || auth node. */ - ret = HASH_H_2(&key->shake, pk_seed, adrs, node, sig_fors, n, + ret = HASH_H_2(key, pk_seed, adrs, node, sig_fors, n, node); } else { /* Step 15: Hash auth node || node. */ - ret = HASH_H_2(&key->shake, pk_seed, adrs, sig_fors, node, n, + ret = HASH_H_2(key, pk_seed, adrs, sig_fors, node, n, node); } if (ret != 0) { @@ -5542,7 +6249,7 @@ static int slhdsakey_fors_pk_from_sig_c(SlhDsaKey* key, const byte* sig_fors, } if (ret == 0) { /* Step 24: Add root node to hash ... */ - ret = slhdsakey_hash_update(&key->shake2, node, n); + ret = HASH_T_UPDATE(key, node, n); } if (ret != 0) { break; @@ -5595,11 +6302,12 @@ static int slhdsakey_fors_pk_from_sig(SlhDsaKey* key, const byte* sig_fors, /* Steps 22-23: Set type and clear all but key pair address. */ HA_SetTypeAndClearNotKPA(forspk_adrs, HA_FORS_ROOTS); /* Step 24: Add public key seed and FORS roots address to hash ... */ - ret = slhdsakey_hash_start_addr(&key->shake2, pk_seed, forspk_adrs, n); + ret = HASH_T_START_ADDR(key, pk_seed, forspk_adrs, n); /* Steps 2-20: Compute roots and add to hash. */ #if defined(USE_INTEL_SPEEDUP) && !defined(WOLFSSL_WC_SLHDSA_SMALL) - if ((ret == 0) && IS_INTEL_AVX2(cpuid_flags) && + if ((ret == 0) && !SLHDSA_IS_SHA2(key->params->param) && + IS_INTEL_AVX2(cpuid_flags) && (SAVE_VECTOR_REGISTERS2() == 0)) { ret = slhdsakey_fors_pk_from_sig_x4(key, sig_fors, indices, pk_seed, adrs); @@ -5614,7 +6322,7 @@ static int slhdsakey_fors_pk_from_sig(SlhDsaKey* key, const byte* sig_fors, if (ret == 0) { /* Step 24. Compute FORS public key. */ - ret = slhdsakey_hash_final(&key->shake2, pk_fors, n); + ret = HASH_T_FINAL(key, pk_fors, n); } return ret; @@ -5664,15 +6372,7 @@ int wc_SlhDsaKey_Init(SlhDsaKey* key, enum SlhDsaParam param, void* heap, /* Zeroize key. */ XMEMSET(key, 0, sizeof(SlhDsaKey)); - /* Initialize SHAKE-256 object. */ - ret = wc_InitShake256(&key->shake, key->heap, INVALID_DEVID); - } - if (ret == 0) { - /* Initialize second SHAKE-256 object. */ - ret = wc_InitShake256(&key->shake2, key->heap, INVALID_DEVID); - } - if (ret == 0) { - /* Set the parameters into key. */ + /* Set the parameters into key early so SLHDSA_IS_SHA2 works. */ key->params = &SlhDsaParams[idx]; /* Set heap hint to use with all allocations. */ key->heap = heap; @@ -5680,6 +6380,32 @@ int wc_SlhDsaKey_Init(SlhDsaKey* key, enum SlhDsaParam param, void* heap, /* Set device id. */ key->devId = devId; #endif + +#ifdef WOLFSSL_SLHDSA_SHA2 + if (SLHDSA_IS_SHA2(param)) { + /* Initialize SHA2 hash objects. */ + ret = wc_InitSha256(&key->hash.sha2.sha256); + if (ret == 0) { + ret = wc_InitSha256(&key->hash.sha2.sha256_2); + } + if ((ret == 0) && (key->params->n > 16)) { + ret = wc_InitSha512(&key->hash.sha2.sha512); + if (ret == 0) { + ret = wc_InitSha512(&key->hash.sha2.sha512_2); + } + } + } + else +#endif + { + /* Initialize SHAKE-256 objects. */ + ret = wc_InitShake256(&key->hash.shk.shake, key->heap, + INVALID_DEVID); + if (ret == 0) { + ret = wc_InitShake256(&key->hash.shk.shake2, key->heap, + INVALID_DEVID); + } + } } (void)devId; @@ -5701,9 +6427,25 @@ void wc_SlhDsaKey_Free(SlhDsaKey* key) if ((key != NULL) && (key->params != NULL)) { /* Ensure the private key data is zeroized. */ ForceZero(key->sk, key->params->n * 2); - /* Dispose of the SHAKE-256 objects. */ - wc_Shake256_Free(&key->shake2); - wc_Shake256_Free(&key->shake); +#ifdef WOLFSSL_SLHDSA_SHA2 + if (SLHDSA_IS_SHA2(key->params->param)) { + /* Dispose of the SHA2 hash objects. */ + wc_Sha256Free(&key->hash.sha2.sha256); + wc_Sha256Free(&key->hash.sha2.sha256_2); + wc_Sha256Free(&key->hash.sha2.sha256_mid); + if (key->params->n > 16) { + wc_Sha512Free(&key->hash.sha2.sha512); + wc_Sha512Free(&key->hash.sha2.sha512_2); + wc_Sha512Free(&key->hash.sha2.sha512_mid); + } + } + else +#endif + { + /* Dispose of the SHAKE-256 objects. */ + wc_Shake256_Free(&key->hash.shk.shake2); + wc_Shake256_Free(&key->hash.shk.shake); + } } } @@ -5890,6 +6632,16 @@ int wc_SlhDsaKey_MakeKeyWithRandom(SlhDsaKey* key, const byte* sk_seed, XMEMCPY(key->sk + 2 * n, pk_seed, n); } +#ifdef WOLFSSL_SLHDSA_SHA2 + /* Pre-compute SHA2 midstates now that PK.seed is set. */ + if (SLHDSA_IS_SHA2(key->params->param)) { + ret = slhdsakey_precompute_sha2_midstates(key); + } + if (ret != 0) { + return ret; + } +#endif + /* Step 1: Set address to all zeroes. */ HA_Init(adrs); /* Step 2: Set the address layer to the top of the subtree. */ @@ -5965,36 +6717,113 @@ static int slhdsakey_sign(SlhDsaKey* key, byte* md, byte* sig) return ret; } -/* Generate a pure SLH-DSA signature. +/* Lower-level sign: slh_sign_internal(M, SK, addrnd). * - * FIPS 205. Section 10.2.2. Algorithm 22. - * slh_sign(M, ctx, SK) - * 1: if |ctx| > 255 then - * 2: return falsity - * > return an error indication if the context string is too long - * 3: end if - * 4: addrnd <-$- Bn > skip lines 4 through 7 for the deterministic variant - * 5: if addrnd = NULL then - * 6: return falsity - * > return an error indication if random bit generation failed - * 7: end if - * 8: M' <- toByte(0, 1) || toByte(|ctx|, 1) || ctx || M - * > omit addrnd for the deterministic variant - * 9: SIG <- slh_sign_internal(M', SK, addrnd) - * 10: return SIG + * Takes M directly and performs PRF_msg, H_msg, and the FORS + hypertree + * signing -- Algorithm 19 without the M' construction of Algorithm 22. * * FIPS 205. Section 9.2. Algorithm 19. * slh_sign_internal(M, SK, addrnd) - * ... * 2: opt_rand <- addrnd - * > substitute opt_rand <- PK.seed for the deterministic variant - * 3: R <- PRFmsg (SK.prf, opt_rand, M) > generate randomizer + * 3: R <- PRFmsg(SK.prf, opt_rand, M) * 4: SIG <- R - * 5: digest <- Hmsg(R, PK.seed, PK.root, M) > compute message digest - * 6: md <- digest [0 : upper(k.a / 8)] > first upper(k.a / 8)] bytes + * 5: digest <- Hmsg(R, PK.seed, PK.root, M) + * 6: md <- digest[0 : upper(k*a / 8)] * ... * - * Note: ctx length is of type byte which means it can never be more than 255. + * @param [in] key SLH-DSA key (private key must be set). + * @param [in] m Message (goes directly to PRF_msg and H_msg). + * @param [in] mSz Length of message in bytes. + * @param [out] sig Buffer to hold signature. + * @param [in, out] sigSz On in, buffer length. On out, signature length. + * @param [in] addRnd opt_rand (PK.seed for deterministic). + * @return 0 on success. + */ +static int slhdsakey_sign_internal_msg(SlhDsaKey* key, const byte* m, + word32 mSz, byte* sig, word32* sigSz, const byte* addRnd) +{ + int ret = 0; + + /* Validate parameters. */ + if ((key == NULL) || (key->params == NULL) || (m == NULL) || + (sig == NULL) || (sigSz == NULL) || (addRnd == NULL)) { + ret = BAD_FUNC_ARG; + } + else if (*sigSz < key->params->sigLen) { + ret = BAD_LENGTH_E; + } + else if ((key->flags & WC_SLHDSA_FLAG_PRIVATE) == 0) { + ret = MISSING_KEY; + } + if (ret == 0) { + byte md[SLHDSA_MAX_MD]; + byte n = key->params->n; + +#ifdef WOLFSSL_SLHDSA_SHA2 + if (SLHDSA_IS_SHA2(key->params->param)) { + /* SHA2: PRF_msg = Trunc_n(HMAC(SK.prf, opt_rand || M)). + * Internal interface: no M' header, pass whole M directly. */ + ret = slhdsakey_prf_msg_sha2(key, key->sk + n, addRnd, + NULL, NULL, 0, m, mSz, n, sig); + if (ret == 0) { + /* SHA2: H_msg via MGF1. No header for internal interface. */ + ret = slhdsakey_h_msg_sha2(key, sig, + NULL, NULL, 0, m, mSz, + md, key->params->dl1 + key->params->dl2 + + key->params->dl3); + sig += n; + } + } + else +#endif + { + /* SHAKE: PRF_msg = SHAKE256(SK.prf || opt_rand || M, 8n). */ + { + wc_Shake tmpShake; + ret = wc_InitShake256(&tmpShake, NULL, INVALID_DEVID); + if (ret == 0) ret = wc_Shake256_Update(&tmpShake, key->sk + n, n); + if (ret == 0) ret = wc_Shake256_Update(&tmpShake, addRnd, n); + if (ret == 0) ret = wc_Shake256_Update(&tmpShake, m, mSz); + if (ret == 0) ret = wc_Shake256_Final(&tmpShake, sig, n); + wc_Shake256_Free(&tmpShake); + } + /* SHAKE: H_msg = SHAKE256(R || PK.seed || PK.root || M, ...). */ + if (ret == 0) { + ret = wc_InitShake256(&key->hash.shk.shake, NULL, INVALID_DEVID); + } + if (ret == 0) { + ret = wc_Shake256_Update(&key->hash.shk.shake, sig, n); + sig += n; + } + if (ret == 0) { + ret = wc_Shake256_Update(&key->hash.shk.shake, + key->sk + 2 * n, 2 * n); + } + if (ret == 0) { + ret = wc_Shake256_Update(&key->hash.shk.shake, m, mSz); + } + if (ret == 0) { + ret = wc_Shake256_Final(&key->hash.shk.shake, md, + key->params->dl1 + key->params->dl2 + key->params->dl3); + } + } + if (ret == 0) { + ret = slhdsakey_sign(key, md, sig); + } + if (ret == 0) { + *sigSz = key->params->sigLen; + } + } + + return ret; +} + +/* Upper-level sign: construct M' from ctx + msg, then call internal. + * + * FIPS 205. Section 10.2.2. Algorithm 22. + * slh_sign(M, ctx, SK) + * 8: M' <- toByte(0, 1) || toByte(|ctx|, 1) || ctx || M + * 9: SIG <- slh_sign_internal(M', SK, addrnd) * * @param [in] key SLH-DSA key. * @param [in] ctx Context of signing. @@ -6004,6 +6833,7 @@ static int slhdsakey_sign(SlhDsaKey* key, byte* md, byte* sig) * @param [out] sig Buffer to hold signature. * @param [in, out] sigSz On in, length of signature buffer. * On out, length of signature data. + * @param [in] addRnd opt_rand (PK.seed for deterministic, random otherwise). * @return 0 on success. * @return BAD_FUNC_ARG when key, key's parameters, msg, sig, sigSz or addRnd * is NULL. @@ -6043,58 +6873,69 @@ static int slhdsakey_sign_external(SlhDsaKey* key, const byte* ctx, byte ctxSz, byte hdr[2]; byte n = key->params->n; - /* Alg 22, Step 8: Set first two bytes to pass to hash ... */ + /* Alg 22, Step 8: M' = toByte(0,1) || toByte(|ctx|,1) || ctx || M. + * We stream the M' components into PRF_msg and H_msg. */ hdr[0] = 0; hdr[1] = ctxSz; - /* Alg 19, Step 3: Start hash with private key PRF seed ... */ - ret = slhdsakey_hash_start(&key->shake, key->sk + n, n); - if (ret == 0) { - /* Alg 19, Step 3: Add addrnd to hash ... */ - ret = slhdsakey_hash_update(&key->shake, addRnd, n); +#ifdef WOLFSSL_SLHDSA_SHA2 + if (SLHDSA_IS_SHA2(key->params->param)) { + /* SHA2: PRF_msg via HMAC. */ + ret = slhdsakey_prf_msg_sha2(key, key->sk + n, addRnd, hdr, ctx, + ctxSz, msg, msgSz, n, sig); + if (ret == 0) { + /* SHA2: H_msg via MGF1. */ + ret = slhdsakey_h_msg_sha2(key, sig, hdr, ctx, ctxSz, msg, + msgSz, md, key->params->dl1 + key->params->dl2 + + key->params->dl3); + /* Move over randomizer. */ + sig += n; + } } - if (ret == 0) { - /* Alg 19, Step 3: Add M' header ... */ - ret = slhdsakey_hash_update(&key->shake, hdr, sizeof(hdr)); - } - if ((ret == 0) && (ctxSz > 0)) { - /* Alg 19, Step 3: Add ctx ... */ - ret = slhdsakey_hash_update(&key->shake, ctx, ctxSz); - } - if (ret == 0) { - /* Alg 19, Step 3: Add M ... */ - ret = slhdsakey_hash_update(&key->shake, msg, msgSz); - } - if (ret == 0) { - /* Alg 19, Steps 3-4: Compute randomizer into signature. */ - ret = slhdsakey_hash_final(&key->shake, sig, n); - } - if (ret == 0) { - /* Alg 19, Step 5: Start hash with signature ... */ - ret = slhdsakey_hash_start(&key->shake, sig, n); - /* Move over randomizer. */ - sig += n; - } - if (ret == 0) { - /* Alg 19, Step 5: Add public key seed and root ... */ - ret = slhdsakey_hash_update(&key->shake, key->sk + 2 * n, 2 * n); - } - if (ret == 0) { - /* Alg 19, Step 5: Add M' header ... */ - ret = slhdsakey_hash_update(&key->shake, hdr, sizeof(hdr)); - } - if ((ret == 0) && (ctxSz > 0)) { - /* Alg 19, Step 5: Add ctx ... */ - ret = slhdsakey_hash_update(&key->shake, ctx, ctxSz); - } - if (ret == 0) { - /* Alg 19, Step 5: Add M ... */ - ret = slhdsakey_hash_update(&key->shake, msg, msgSz); - } - if (ret == 0) { - /* Alg 19, Steps 5-6: Compute digest of required length. */ - ret = slhdsakey_hash_final(&key->shake, md, key->params->dl1 + - key->params->dl2 + key->params->dl3); + else +#endif + { + /* SHAKE: PRF_msg streaming with M' = hdr || ctx || msg. */ + ret = slhdsakey_hash_start(&key->hash.shk.shake, key->sk + n, n); + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, addRnd, n); + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, hdr, + sizeof(hdr)); + } + if ((ret == 0) && (ctxSz > 0)) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, ctx, ctxSz); + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, msg, msgSz); + } + if (ret == 0) { + ret = slhdsakey_hash_final(&key->hash.shk.shake, sig, n); + } + /* SHAKE: H_msg streaming. */ + if (ret == 0) { + ret = slhdsakey_hash_start(&key->hash.shk.shake, sig, n); + sig += n; + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, + key->sk + 2 * n, 2 * n); + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, hdr, + sizeof(hdr)); + } + if ((ret == 0) && (ctxSz > 0)) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, ctx, ctxSz); + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, msg, msgSz); + } + if (ret == 0) { + ret = slhdsakey_hash_final(&key->hash.shk.shake, md, + key->params->dl1 + key->params->dl2 + key->params->dl3); + } } if (ret == 0) { /* Alg 19. Steps 7-19 */ @@ -6226,6 +7067,51 @@ int wc_SlhDsaKey_Sign(SlhDsaKey* key, const byte* ctx, byte ctxSz, return ret; } + +/* Sign using internal interface -- M' provided directly (deterministic). + * + * opt_rand = PK.seed for the deterministic variant. + * + * @param [in] key SLH-DSA key. + * @param [in] mprime M' message (already in internal format). + * @param [in] mprimeSz Length of M' in bytes. + * @param [out] sig Buffer to hold signature. + * @param [in, out] sigSz On in, buffer length. On out, signature length. + * @return 0 on success. + */ +int wc_SlhDsaKey_SignMsgDeterministic(SlhDsaKey* key, const byte* mprime, + word32 mprimeSz, byte* sig, word32* sigSz) +{ + int ret; + + if ((key == NULL) || (key->params == NULL)) { + ret = BAD_FUNC_ARG; + } + else { + ret = slhdsakey_sign_internal_msg(key, mprime, mprimeSz, sig, sigSz, + key->sk + 2 * key->params->n); + } + + return ret; +} + +/* Sign using internal interface -- M' provided directly (with explicit random). + * + * @param [in] key SLH-DSA key. + * @param [in] mprime M' message (already in internal format). + * @param [in] mprimeSz Length of M' in bytes. + * @param [out] sig Buffer to hold signature. + * @param [in, out] sigSz On in, buffer length. On out, signature length. + * @param [in] addRnd opt_rand value. + * @return 0 on success. + */ +int wc_SlhDsaKey_SignMsgWithRandom(SlhDsaKey* key, const byte* mprime, + word32 mprimeSz, byte* sig, word32* sigSz, const byte* addRnd) +{ + return slhdsakey_sign_internal_msg(key, mprime, mprimeSz, sig, sigSz, + addRnd); +} + #endif /* Verify SLH-DSA signature. @@ -6337,34 +7223,41 @@ int wc_SlhDsaKey_Verify(SlhDsaKey* key, const byte* ctx, byte ctxSz, if (ret == 0) { byte md[SLHDSA_MAX_MD]; byte n = key->params->n; + byte hdr[2]; - /* Alg 20, Step 8: Hash randomizer ... */ - ret = slhdsakey_hash_start(&key->shake, sig, n); - if (ret == 0) { - /* Alg 20, Step 8: Update hash with public key seed and root ... */ - ret = slhdsakey_hash_update(&key->shake, key->sk + 2 * n, 2 * n); - } - if (ret == 0) { - byte hdr[2]; + /* Alg 23, Step 4: Make M' header. */ + hdr[0] = 0; + hdr[1] = ctxSz; - /* Alg 23, Step 4: Make M' header. */ - hdr[0] = 0; - hdr[1] = ctxSz; - /* Alg 20, Step 8: Update hash with M' header ... */ - ret = slhdsakey_hash_update(&key->shake, hdr, sizeof(hdr)); +#ifdef WOLFSSL_SLHDSA_SHA2 + if (SLHDSA_IS_SHA2(key->params->param)) { + /* SHA2: H_msg via MGF1 (no PRF_msg for verify). */ + ret = slhdsakey_h_msg_sha2(key, sig, hdr, ctx, ctxSz, msg, msgSz, + md, key->params->dl1 + key->params->dl2 + key->params->dl3); } - if ((ret == 0) && (ctxSz > 0)) { - /* Alg 20, Step 8: Update hash with context ... */ - ret = slhdsakey_hash_update(&key->shake, ctx, ctxSz); - } - if (ret == 0) { - /* Alg 20, Step 8: Update hash with message ... */ - ret = slhdsakey_hash_update(&key->shake, msg, msgSz); - } - if (ret == 0) { - /* Alg 20, Step 8: Compute message digest. */ - ret = slhdsakey_hash_final(&key->shake, md, key->params->dl1 + - key->params->dl2 + key->params->dl3); + else +#endif + { + /* SHAKE: H_msg streaming. */ + ret = slhdsakey_hash_start(&key->hash.shk.shake, sig, n); + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, + key->sk + 2 * n, 2 * n); + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, hdr, + sizeof(hdr)); + } + if ((ret == 0) && (ctxSz > 0)) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, ctx, ctxSz); + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, msg, msgSz); + } + if (ret == 0) { + ret = slhdsakey_hash_final(&key->hash.shk.shake, md, + key->params->dl1 + key->params->dl2 + key->params->dl3); + } } if (ret == 0) { /* Alg 23, Step 5: Verify M'. @@ -6376,6 +7269,73 @@ int wc_SlhDsaKey_Verify(SlhDsaKey* key, const byte* ctx, byte ctxSz, return ret; } +/* Verify SLH-DSA signature using internal interface -- M' provided directly. + * + * FIPS 205. Section 9.3. Algorithm 20. + * slh_verify_internal(M', SIG, PK) + * + * @param [in] key SLH-DSA key. + * @param [in] mprime M' message (already in internal format). + * @param [in] mprimeSz Length of M' in bytes. + * @param [in] sig Signature data. + * @param [in] sigSz Length of signature in bytes. + * @return 0 on success. + * @return SIG_VERIFY_E on verification failure. + */ +int wc_SlhDsaKey_VerifyMsg(SlhDsaKey* key, const byte* mprime, + word32 mprimeSz, const byte* sig, word32 sigSz) +{ + int ret = 0; + + /* Validate parameters. */ + if ((key == NULL) || (key->params == NULL) || (mprime == NULL) || + (sig == NULL)) { + ret = BAD_FUNC_ARG; + } + else if (sigSz != key->params->sigLen) { + ret = BAD_LENGTH_E; + } + else if ((key->flags & WC_SLHDSA_FLAG_PUBLIC) == 0) { + ret = MISSING_KEY; + } + if (ret == 0) { + byte md[SLHDSA_MAX_MD]; + byte n = key->params->n; + +#ifdef WOLFSSL_SLHDSA_SHA2 + if (SLHDSA_IS_SHA2(key->params->param)) { + /* SHA2: H_msg. Internal interface: no M' header, pass whole + * message directly. */ + ret = slhdsakey_h_msg_sha2(key, sig, + NULL, NULL, 0, mprime, mprimeSz, + md, key->params->dl1 + key->params->dl2 + key->params->dl3); + } + else +#endif + { + /* SHAKE: H_msg = SHAKE(R || PK.seed || PK.root || M). */ + ret = slhdsakey_hash_start(&key->hash.shk.shake, sig, n); + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, + key->sk + 2 * n, 2 * n); + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, + mprime, mprimeSz); + } + if (ret == 0) { + ret = slhdsakey_hash_final(&key->hash.shk.shake, md, + key->params->dl1 + key->params->dl2 + key->params->dl3); + } + } + if (ret == 0) { + ret = slhdsakey_verify(key, md, sig); + } + } + + return ret; +} + #ifdef WOLFSSL_SHA224 /* OID for SHA-224 for hash signing/verification. */ static const byte slhdsakey_oid_sha224[] = { @@ -6424,6 +7384,32 @@ static const byte slhdsakey_oid_shake256[] = { 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0c }; #endif +#ifdef WOLFSSL_SHA3 +#ifndef WOLFSSL_NOSHA3_224 +/* OID for SHA3-224 for hash signing/verification. */ +static const byte slhdsakey_oid_sha3_224[] = { + 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x07 +}; +#endif +#ifndef WOLFSSL_NOSHA3_256 +/* OID for SHA3-256 for hash signing/verification. */ +static const byte slhdsakey_oid_sha3_256[] = { + 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08 +}; +#endif +#ifndef WOLFSSL_NOSHA3_384 +/* OID for SHA3-384 for hash signing/verification. */ +static const byte slhdsakey_oid_sha3_384[] = { + 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09 +}; +#endif +#ifndef WOLFSSL_NOSHA3_512 +/* OID for SHA3-512 for hash signing/verification. */ +static const byte slhdsakey_oid_sha3_512[] = { + 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0a +}; +#endif +#endif /* Pre-hash the message with the hash specified. * @@ -6507,6 +7493,40 @@ static int slhdsakey_prehash_msg(const byte* msg, word32 msgSz, *phLen = WC_SHA3_512_DIGEST_SIZE; ret = wc_Shake256Hash(msg, msgSz, ph, WC_SHA3_512_DIGEST_SIZE); break; + #endif + #ifdef WOLFSSL_SHA3 + #ifndef WOLFSSL_NOSHA3_224 + case WC_HASH_TYPE_SHA3_224: + *oid = slhdsakey_oid_sha3_224; + *oidLen = (byte)sizeof(slhdsakey_oid_sha3_224); + *phLen = WC_SHA3_224_DIGEST_SIZE; + ret = wc_Sha3_224Hash(msg, msgSz, ph); + break; + #endif + #ifndef WOLFSSL_NOSHA3_256 + case WC_HASH_TYPE_SHA3_256: + *oid = slhdsakey_oid_sha3_256; + *oidLen = (byte)sizeof(slhdsakey_oid_sha3_256); + *phLen = WC_SHA3_256_DIGEST_SIZE; + ret = wc_Sha3_256Hash(msg, msgSz, ph); + break; + #endif + #ifndef WOLFSSL_NOSHA3_384 + case WC_HASH_TYPE_SHA3_384: + *oid = slhdsakey_oid_sha3_384; + *oidLen = (byte)sizeof(slhdsakey_oid_sha3_384); + *phLen = WC_SHA3_384_DIGEST_SIZE; + ret = wc_Sha3_384Hash(msg, msgSz, ph); + break; + #endif + #ifndef WOLFSSL_NOSHA3_512 + case WC_HASH_TYPE_SHA3_512: + *oid = slhdsakey_oid_sha3_512; + *oidLen = (byte)sizeof(slhdsakey_oid_sha3_512); + *phLen = WC_SHA3_512_DIGEST_SIZE; + ret = wc_Sha3_512Hash(msg, msgSz, ph); + break; + #endif #endif default: ret = NOT_COMPILED_IN; @@ -6626,62 +7646,74 @@ static int slhdsakey_signhash_external(SlhDsaKey* key, const byte* ctx, hdr[0] = 1; hdr[1] = ctxSz; - /* Alg 19, Step 3: Start hash with private key PRF seed ... */ - ret = slhdsakey_hash_start(&key->shake, key->sk + n, n); - if (ret == 0) { - /* Alg 19, Step 3: Add addrnd to hash ... */ - ret = slhdsakey_hash_update(&key->shake, addRnd, n); +#ifdef WOLFSSL_SLHDSA_SHA2 + if (SLHDSA_IS_SHA2(key->params->param)) { + /* SHA2: Build oid||ph as message for PRF_msg/H_msg. */ + byte phMsg[80]; /* Max: 11 byte OID + 64 byte hash */ + word32 phMsgLen = oidLen + phLen; + + XMEMCPY(phMsg, oid, oidLen); + XMEMCPY(phMsg + oidLen, ph, phLen); + + ret = slhdsakey_prf_msg_sha2(key, key->sk + n, addRnd, hdr, ctx, + ctxSz, phMsg, phMsgLen, n, sig); + if (ret == 0) { + ret = slhdsakey_h_msg_sha2(key, sig, hdr, ctx, ctxSz, phMsg, + phMsgLen, md, key->params->dl1 + key->params->dl2 + + key->params->dl3); + sig += n; + } } - if (ret == 0) { - /* Alg 19, Step 3: Add M' header ... */ - ret = slhdsakey_hash_update(&key->shake, hdr, sizeof(hdr)); - } - if ((ret == 0) && (ctxSz > 0)) { - /* Alg 19, Step 3: Add ctx ... */ - ret = slhdsakey_hash_update(&key->shake, ctx, ctxSz); - } - if (ret == 0) { - /* Alg 23, Step 24, Alg 19, Step 3: Add M' OID ... */ - ret = slhdsakey_hash_update(&key->shake, oid, oidLen); - } - if (ret == 0) { - /* Alg 23, Step 24, Alg 19, Step 3: Add M' pre-hash ... */ - ret = slhdsakey_hash_update(&key->shake, ph, phLen); - } - if (ret == 0) { - /* Alg 19, Step 3-4: Compute randomizer into signature. */ - ret = slhdsakey_hash_final(&key->shake, sig, n); - } - if (ret == 0) { - /* Alg 19, Step 5: Start hash with signature ... */ - ret = slhdsakey_hash_start(&key->shake, sig, n); - /* Move over randomizer. */ - sig += n; - } - if (ret == 0) { - /* Alg 19, Step 5: Add public key seed and root ... */ - ret = slhdsakey_hash_update(&key->shake, key->sk + 2 * n, 2 * n); - } - if (ret == 0) { - /* Alg 19, Step 5: Add M' header ... */ - ret = slhdsakey_hash_update(&key->shake, hdr, sizeof(hdr)); - } - if ((ret == 0) && (ctxSz > 0)) { - /* Alg 19, Step 5: Add ctx ... */ - ret = slhdsakey_hash_update(&key->shake, ctx, ctxSz); - } - if (ret == 0) { - /* Alg 23, Step 24, Alg 19, Step 5: Add M' OID ... */ - ret = slhdsakey_hash_update(&key->shake, oid, oidLen); - } - if (ret == 0) { - /* Alg 23, Step 24, Alg 19, Step 5: Add M' pre-hash ... */ - ret = slhdsakey_hash_update(&key->shake, ph, phLen); - } - if (ret == 0) { - /* Alg 19, Steps 5-6: Compute digest of required length. */ - ret = slhdsakey_hash_final(&key->shake, md, key->params->dl1 + - key->params->dl2 + key->params->dl3); + else +#endif + { + /* SHAKE: PRF_msg streaming. */ + ret = slhdsakey_hash_start(&key->hash.shk.shake, key->sk + n, n); + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, addRnd, n); + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, hdr, + sizeof(hdr)); + } + if ((ret == 0) && (ctxSz > 0)) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, ctx, ctxSz); + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, oid, oidLen); + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, ph, phLen); + } + if (ret == 0) { + ret = slhdsakey_hash_final(&key->hash.shk.shake, sig, n); + } + /* SHAKE: H_msg streaming. */ + if (ret == 0) { + ret = slhdsakey_hash_start(&key->hash.shk.shake, sig, n); + sig += n; + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, + key->sk + 2 * n, 2 * n); + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, hdr, + sizeof(hdr)); + } + if ((ret == 0) && (ctxSz > 0)) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, ctx, ctxSz); + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, oid, oidLen); + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, ph, phLen); + } + if (ret == 0) { + ret = slhdsakey_hash_final(&key->hash.shk.shake, md, + key->params->dl1 + key->params->dl2 + key->params->dl3); + } } if (ret == 0) { /* Alg 19. Steps 7-19 */ @@ -6919,37 +7951,51 @@ int wc_SlhDsaKey_VerifyHash(SlhDsaKey* key, const byte* ctx, byte ctxSz, if (ret == 0) { byte n = key->params->n; byte md[SLHDSA_MAX_MD]; + byte hdr[2]; - /* Alg 20, Step 8: Hash randomizer ... */ - ret = slhdsakey_hash_start(&key->shake, sig, n); - if (ret == 0) { - /* Alg 20, Step 8: Update hash with public key seed and root ... */ - ret = slhdsakey_hash_update(&key->shake, key->sk + 2 * n, 2 * n); - } - if (ret == 0) { - byte hdr[2]; + /* Alg 24, Step 20: Make M' header. */ + hdr[0] = 1; + hdr[1] = ctxSz; - /* Alg 24, Step 20: Make M' header. */ - hdr[0] = 1; - hdr[1] = ctxSz; - ret = slhdsakey_hash_update(&key->shake, hdr, sizeof(hdr)); +#ifdef WOLFSSL_SLHDSA_SHA2 + if (SLHDSA_IS_SHA2(key->params->param)) { + /* SHA2: Build oid||ph as message for H_msg. */ + byte phMsg[80]; /* Max: 11 byte OID + 64 byte hash */ + word32 phMsgLen = oidLen + phLen; + + XMEMCPY(phMsg, oid, oidLen); + XMEMCPY(phMsg + oidLen, ph, phLen); + + ret = slhdsakey_h_msg_sha2(key, sig, hdr, ctx, ctxSz, phMsg, + phMsgLen, md, key->params->dl1 + key->params->dl2 + + key->params->dl3); } - if ((ret == 0) && (ctxSz > 0)) { - /* Alg 20, Step 8: Update hash with message ... */ - ret = slhdsakey_hash_update(&key->shake, ctx, ctxSz); - } - if (ret == 0) { - /* Alg 24, Step 20; Alg 20, Step 8: Update with M' OID ... */ - ret = slhdsakey_hash_update(&key->shake, oid, oidLen); - } - if (ret == 0) { - /* Alg 24, Step 20; Alg 20, Step 8: Update with M' pre-hash ... */ - ret = slhdsakey_hash_update(&key->shake, ph, phLen); - } - if (ret == 0) { - /* Alg 20, Step 8: Compute message digest. */ - ret = slhdsakey_hash_final(&key->shake, md, key->params->dl1 + - key->params->dl2 + key->params->dl3); + else +#endif + { + /* SHAKE: H_msg streaming. */ + ret = slhdsakey_hash_start(&key->hash.shk.shake, sig, n); + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, + key->sk + 2 * n, 2 * n); + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, hdr, + sizeof(hdr)); + } + if ((ret == 0) && (ctxSz > 0)) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, ctx, ctxSz); + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, oid, oidLen); + } + if (ret == 0) { + ret = slhdsakey_hash_update(&key->hash.shk.shake, ph, phLen); + } + if (ret == 0) { + ret = slhdsakey_hash_final(&key->hash.shk.shake, md, + key->params->dl1 + key->params->dl2 + key->params->dl3); + } } if (ret == 0) { /* Alg 24, Step 21: Verify M'. @@ -6989,6 +8035,11 @@ int wc_SlhDsaKey_ImportPrivate(SlhDsaKey* key, const byte* priv, word32 privLen) /* Copy private and public key data into SLH-DSA key object. */ XMEMCPY(key->sk, priv, 4 * key->params->n); key->flags = WC_SLHDSA_FLAG_BOTH_KEYS; +#ifdef WOLFSSL_SLHDSA_SHA2 + if (SLHDSA_IS_SHA2(key->params->param)) { + ret = slhdsakey_precompute_sha2_midstates(key); + } +#endif } return ret; @@ -7020,6 +8071,11 @@ int wc_SlhDsaKey_ImportPublic(SlhDsaKey* key, const byte* pub, word32 pubLen) /* Copy public key data into SLH-DSA key object. */ XMEMCPY(key->sk + 2 * key->params->n, pub, 2 * key->params->n); key->flags = WC_SLHDSA_FLAG_PUBLIC; +#ifdef WOLFSSL_SLHDSA_SHA2 + if (SLHDSA_IS_SHA2(key->params->param)) { + ret = slhdsakey_precompute_sha2_midstates(key); + } +#endif } return ret; @@ -7235,6 +8291,26 @@ int wc_SlhDsaKey_PrivateSizeFromParam(enum SlhDsaParam param) case SLHDSA_SHAKE256F: ret = WC_SLHDSA_SHAKE256F_PRIV_LEN; break; +#ifdef WOLFSSL_SLHDSA_SHA2 + case SLHDSA_SHA2_128S: + ret = WC_SLHDSA_SHA2_128S_PRIV_LEN; + break; + case SLHDSA_SHA2_128F: + ret = WC_SLHDSA_SHA2_128F_PRIV_LEN; + break; + case SLHDSA_SHA2_192S: + ret = WC_SLHDSA_SHA2_192S_PRIV_LEN; + break; + case SLHDSA_SHA2_192F: + ret = WC_SLHDSA_SHA2_192F_PRIV_LEN; + break; + case SLHDSA_SHA2_256S: + ret = WC_SLHDSA_SHA2_256S_PRIV_LEN; + break; + case SLHDSA_SHA2_256F: + ret = WC_SLHDSA_SHA2_256F_PRIV_LEN; + break; +#endif default: ret = NOT_COMPILED_IN; break; @@ -7273,6 +8349,26 @@ int wc_SlhDsaKey_PublicSizeFromParam(enum SlhDsaParam param) case SLHDSA_SHAKE256F: ret = WC_SLHDSA_SHAKE256F_PUB_LEN; break; +#ifdef WOLFSSL_SLHDSA_SHA2 + case SLHDSA_SHA2_128S: + ret = WC_SLHDSA_SHA2_128S_PUB_LEN; + break; + case SLHDSA_SHA2_128F: + ret = WC_SLHDSA_SHA2_128F_PUB_LEN; + break; + case SLHDSA_SHA2_192S: + ret = WC_SLHDSA_SHA2_192S_PUB_LEN; + break; + case SLHDSA_SHA2_192F: + ret = WC_SLHDSA_SHA2_192F_PUB_LEN; + break; + case SLHDSA_SHA2_256S: + ret = WC_SLHDSA_SHA2_256S_PUB_LEN; + break; + case SLHDSA_SHA2_256F: + ret = WC_SLHDSA_SHA2_256F_PUB_LEN; + break; +#endif default: ret = NOT_COMPILED_IN; break; @@ -7310,6 +8406,26 @@ int wc_SlhDsaKey_SigSizeFromParam(enum SlhDsaParam param) case SLHDSA_SHAKE256F: ret = WC_SLHDSA_SHAKE256F_SIG_LEN; break; +#ifdef WOLFSSL_SLHDSA_SHA2 + case SLHDSA_SHA2_128S: + ret = WC_SLHDSA_SHA2_128S_SIG_LEN; + break; + case SLHDSA_SHA2_128F: + ret = WC_SLHDSA_SHA2_128F_SIG_LEN; + break; + case SLHDSA_SHA2_192S: + ret = WC_SLHDSA_SHA2_192S_SIG_LEN; + break; + case SLHDSA_SHA2_192F: + ret = WC_SLHDSA_SHA2_192F_SIG_LEN; + break; + case SLHDSA_SHA2_256S: + ret = WC_SLHDSA_SHA2_256S_SIG_LEN; + break; + case SLHDSA_SHA2_256F: + ret = WC_SLHDSA_SHA2_256F_SIG_LEN; + break; +#endif default: ret = NOT_COMPILED_IN; break; diff --git a/wolfcrypt/src/wc_xmss.c b/wolfcrypt/src/wc_xmss.c index ef7248d209..dfc6375e4e 100644 --- a/wolfcrypt/src/wc_xmss.c +++ b/wolfcrypt/src/wc_xmss.c @@ -22,6 +22,11 @@ #include #ifdef WOLFSSL_HAVE_XMSS + +#if FIPS_VERSION3_GE(2,0,0) + /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */ + #define FIPS_NO_WRAPPERS +#endif #include #ifdef NO_INLINE diff --git a/wolfcrypt/src/wolfentropy.c b/wolfcrypt/src/wolfentropy.c index c05e56f657..30c67d167e 100644 --- a/wolfcrypt/src/wolfentropy.c +++ b/wolfcrypt/src/wolfentropy.c @@ -354,19 +354,37 @@ static word64 entropy_state[ENTROPY_NUM_WORDS + EXTRA_ENTROPY_WORDS] = {0}; /* Using memory will take different amount of times depending on the CPU's * caches and business. + * + * Returns int (not void) because the SHA-3 conditioning calls go through + * FIPS wrappers. When the FIPS module is in FAILED state (e.g. integrity + * hash mismatch during first build before fips-hash.sh), every SHA-3 call + * returns FIPS_NOT_ALLOWED_E. Without checking these returns, this function + * would silently loop through all ENTROPY_NUM_UPDATES iterations on every + * noise sample, each iteration firing the FIPS error callback -- producing + * tens of thousands of spurious error reports during Entropy_Init(). + * + * Non-FIPS builds never hit this path because SHA-3 calls always succeed + * without a CAST gate. We use int returns unconditionally (rather than + * void in non-FIPS, int in FIPS) to maintain a common ABI in case these + * functions become public API as wolfentropy matures. */ -static void Entropy_MemUse(void) +static int Entropy_MemUse(void) { int i; static byte d[WC_SHA3_256_DIGEST_SIZE]; int j; + int ret; for (j = 0; j < ENTROPY_NUM_UPDATES; j++) { /* Hash the first 32 64-bit words of state. */ - wc_Sha3_256_Update(&entropyHash, (byte*)entropy_state, + ret = wc_Sha3_256_Update(&entropyHash, (byte*)entropy_state, sizeof(*entropy_state) * ENTROPY_NUM_64BIT_WORDS); + if (ret != 0) + return ret; /* Get pseudo-random indices. */ - wc_Sha3_256_Final(&entropyHash, d); + ret = wc_Sha3_256_Final(&entropyHash, d); + if (ret != 0) + return ret; for (i = 0; i < ENTROPY_NUM_64BIT_WORDS; i++) { /* Choose a 64-bit word from a pseudo-random block.*/ @@ -378,6 +396,8 @@ static void Entropy_MemUse(void) entropy_state[i] += entropy_state[idx]; } } + + return 0; } @@ -390,34 +410,40 @@ static word64 entropy_last_time = 0; * * Called to test raw entropy. * - * @return 64-bit value that is the noise. + * @param [out] sample 64-bit noise value (time delta). + * @return 0 on success. + * @return Negative on failure (e.g. FIPS module not operational). */ -static word64 Entropy_GetSample(void) +static int Entropy_GetSample(word64* sample) { word64 now; - word64 ret; + int ret = 0; #ifdef HAVE_FIPS /* First sample must be disregard when in FIPS. */ if (entropy_last_time == 0) { /* Get sample which triggers CAST in FIPS mode. */ - Entropy_MemUse(); + ret = Entropy_MemUse(); + if (ret != 0) + return ret; /* Start entropy time after CASTs. */ entropy_last_time = Entropy_TimeHiRes(); } #endif /* Use memory such that it will take an unpredictable amount of time. */ - Entropy_MemUse(); + ret = Entropy_MemUse(); + if (ret != 0) + return ret; /* Get the time now to subtract from previous end time. */ now = Entropy_TimeHiRes(); /* Calculate time diff since last sampling. */ - ret = now - entropy_last_time; + *sample = now - entropy_last_time; /* Store last time. */ entropy_last_time = now; - return ret; + return 0; } /* Get as many samples of noise as required. @@ -426,18 +452,29 @@ static word64 Entropy_GetSample(void) * * @param [out] noise Buffer to hold samples. * @param [in] samples Number of one byte samples to get. + * @return 0 on success. + * @return Negative on hash failure (e.g. FIPS module not operational). */ -static void Entropy_GetNoise(unsigned char* noise, int samples) +static int Entropy_GetNoise(unsigned char* noise, int samples) { int i; + int ret; + word64 sample; /* Do it once to get things going. */ - Entropy_MemUse(); + ret = Entropy_MemUse(); + if (ret != 0) + return ret; /* Get as many samples as required. */ for (i = 0; i < samples; i++) { - noise[i] = (byte)Entropy_GetSample(); + ret = Entropy_GetSample(&sample); + if (ret != 0) + return ret; + noise[i] = (byte)sample; } + + return 0; } /* Generate raw entropy for performing assessment. @@ -458,7 +495,7 @@ int wc_Entropy_GetRawEntropy(unsigned char* raw, int cnt) if (ret == 0) #endif { - Entropy_GetNoise(raw, cnt); + ret = Entropy_GetNoise(raw, cnt); } #ifdef ENTROPY_MEMUSE_THREADED /* Stop the counter thread to avoid thrashing the system. */ @@ -670,7 +707,7 @@ static int Entropy_HealthTest_Startup(void) Entropy_HealthTest_Reset(); /* Fill initial sample buffer with noise. */ - Entropy_GetNoise(initial, ENTROPY_INITIAL_COUNT); + ret = Entropy_GetNoise(initial, ENTROPY_INITIAL_COUNT); /* Health check initial noise. */ for (i = 0; (ret == 0) && (i < ENTROPY_INITIAL_COUNT); i++) { ret = Entropy_HealthTest_Repetition(initial[i]); @@ -799,7 +836,7 @@ int wc_Entropy_Get(int bits, unsigned char* entropy, word32 len) } /* Get raw entropy noise. */ - Entropy_GetNoise(noise, noise_len); + ret = Entropy_GetNoise(noise, noise_len); /* Health check each noise value. */ for (i = 0; (ret == 0) && (i < noise_len); i++) { ret = Entropy_HealthTest_Repetition(noise[i]); diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 1d6eb27822..56d4a7c220 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -1261,6 +1261,15 @@ static void myFipsCb(int ok, int err, const char* hash) if (err == WC_NO_ERR_TRACE(IN_CORE_FIPS_E)) { printf("In core integrity hash check failure, copy above hash\n"); printf("into verifyCore[] in fips_test.c and rebuild\n"); +#ifdef TEST_ALWAYS_RUN_TO_END + /* When TEST_ALWAYS_RUN_TO_END is defined, testwolfcrypt tries to + * run every test even after failures. But with a wrong integrity + * hash the FIPS module is in FAILED state and every API call will + * fail, fire this callback, and produce millions of lines of + * redundant output. Exit now -- the hash has been printed for + * fips-hash.sh to extract, and no test can possibly pass. */ + exit(IN_CORE_FIPS_E); +#endif } #ifdef REALLY_LONG_DRBG_CONTINUOUS_TEST only_run_cb_once = 0; @@ -1273,9 +1282,13 @@ static void myFipsCb(int ok, int err, const char* hash) } #endif /* HAVE_FIPS && !WOLFSSL_KERNEL_MODE */ -#if defined(HAVE_FIPS) && FIPS_VERSION3_LT(6,0,0) && !defined(WC_NO_CONSTRUCTORS) +/* Polyfill for old FIPS modules whose headers don't declare the + * constructor/destructor helpers. Skip when the current headers + * already provide them (WC_AES_NEW_API_AVAILABLE / WC_RSA_NEW_API_AVAILABLE). */ +#if defined(HAVE_FIPS) && FIPS_VERSION3_LT(6,0,0) && \ + !defined(WC_NO_CONSTRUCTORS) -#if !defined(NO_AES) +#if !defined(NO_AES) && !defined(WC_AES_NEW_API_AVAILABLE) static WC_MAYBE_UNUSED Aes* wc_AesNew(void* heap, int thisDevId, int *result_code) { int ret; @@ -1333,9 +1346,9 @@ static WC_MAYBE_UNUSED Aes* wc_AesNew_Id(unsigned char* id, int len, } #endif /* WOLF_PRIVATE_KEY_ID */ -#endif /* !NO_AES */ +#endif /* !NO_AES && !WC_AES_NEW_API_AVAILABLE */ -#if !defined(NO_RSA) +#if !defined(NO_RSA) && !defined(WC_RSA_NEW_API_AVAILABLE) static WC_MAYBE_UNUSED RsaKey* wc_NewRsaKey(void* heap, int thisDevId, int *result_code) { int ret; @@ -1391,9 +1404,9 @@ static WC_MAYBE_UNUSED RsaKey* wc_NewRsaKey_Id(unsigned char* id, int len, return key; } #endif /* WOLF_PRIVATE_KEY_ID */ -#endif /* !NO_RSA */ +#endif /* !NO_RSA && !WC_RSA_NEW_API_AVAILABLE */ -#endif /* FIPS_VERSION3_LT(6,0,0) && !WC_NO_CONSTRUCTORS */ +#endif /* HAVE_FIPS && FIPS_VERSION3_LT(6,0,0) && !WC_NO_CONSTRUCTORS */ /* AES/RSA New helpers -- placed after the FIPS polyfill block so wc_AesNew / * wc_NewRsaKey are visible from either the library or the polyfill above. @@ -3127,17 +3140,21 @@ options: [-s max_relative_stack_bytes] [-m max_relative_heap_memory_bytes]\n\ #endif #ifdef WOLFSSL_HAVE_MLKEM + PRIVATE_KEY_UNLOCK(); if ( (ret = mlkem_test()) != 0) TEST_FAIL("MLKEM test failed!\n", ret); else TEST_PASS("MLKEM test passed!\n"); + PRIVATE_KEY_LOCK(); #endif #ifdef HAVE_DILITHIUM + PRIVATE_KEY_UNLOCK(); if ( (ret = dilithium_test()) != 0) TEST_FAIL("DILITHIUM test failed!\n", ret); else TEST_PASS("DILITHIUM test passed!\n"); + PRIVATE_KEY_LOCK(); #endif #if defined(WOLFSSL_HAVE_XMSS) @@ -4039,8 +4056,6 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t error_test(void) int first; int last; } missing[] = { - { -124, -124 }, - { -167, -169 }, { WC_SPAN1_LAST_E - 1, WC_SPAN2_FIRST_E + 1 }, { WC_SPAN2_LAST_E - 1, WC_SPAN2_MIN_CODE_E } }; @@ -8055,17 +8070,20 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hash_test(void) if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) { ERROR_OUT(WC_TEST_RET_ENC_I(i), out); } + /* // NOLINTBEGIN(clang-analyzer-optin.core.EnumCastOutOfRange) */ ret = wc_HashInit(hash, (enum wc_HashType)typesBad[i]); if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) ERROR_OUT(WC_TEST_RET_ENC_I(i), out); - ret = wc_HashUpdate(hash, (enum wc_HashType)typesBad[i], data, sizeof(data)); + ret = wc_HashUpdate(hash, (enum wc_HashType)typesBad[i], + data, sizeof(data)); if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) ERROR_OUT(WC_TEST_RET_ENC_I(i), out); ret = wc_HashFinal(hash, (enum wc_HashType)typesBad[i], out); if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) ERROR_OUT(WC_TEST_RET_ENC_I(i), out); ret = wc_HashFree(hash, (enum wc_HashType)typesBad[i]); + /* // NOLINTEND(clang-analyzer-optin.core.EnumCastOutOfRange) */ if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) ERROR_OUT(WC_TEST_RET_ENC_I(i), out); @@ -21186,14 +21204,50 @@ static wc_test_ret_t _rng_test(WC_RNG* rng) WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { #endif - ((struct DRBG_internal *)rng->drbg)->reseedCtr = WC_RESEED_INTERVAL; + /* The else-branch references the SHA-256 DRBG (rng->drbg / + * struct DRBG_internal) which only exists when SHA-256 is + * compiled in. Gate the else keyword and the SHA-256 fallback + * body together so a NO_SHA256 + WOLFSSL_DRBG_SHA512 build (in + * which drbgType is always WC_DRBG_SHA512) still compiles. */ + #if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + if (rng->drbgType == WC_DRBG_SHA512) { + ((struct DRBG_SHA512_internal *)rng->drbg512)->reseedCtr = + WC_RESEED_INTERVAL; + } + #ifndef NO_SHA256 + else + #endif + #endif + #ifndef NO_SHA256 + { + ((struct DRBG_internal *)rng->drbg)->reseedCtr = + WC_RESEED_INTERVAL; + } + #endif ret = wc_RNG_GenerateBlock(rng, block, sizeof(block)); if (ret != 0) return WC_TEST_RET_ENC_EC(ret); - if (((struct DRBG_internal *)rng->drbg)->reseedCtr == WC_RESEED_INTERVAL) - return WC_TEST_RET_ENC_NC; + #if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + if (rng->drbgType == WC_DRBG_SHA512) { + if (((struct DRBG_SHA512_internal *)rng->drbg512)->reseedCtr == + WC_RESEED_INTERVAL) + return WC_TEST_RET_ENC_NC; + } + #ifndef NO_SHA256 + else + #endif + #endif + #ifndef NO_SHA256 + { + if (((struct DRBG_internal *)rng->drbg)->reseedCtr == + WC_RESEED_INTERVAL) + return WC_TEST_RET_ENC_NC; + } + #endif #ifdef WOLF_CRYPTO_CB } #endif @@ -21444,6 +21498,12 @@ out: WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_test(void) { + /* SHA-256 Hash_DRBG known-answer vectors. wc_RNG_HealthTest is + * gated on !NO_SHA256 in random.h (it operates on DRBG_internal), + * so the data and calls are gated together to keep SHA-512-only + * builds clean of unused-variable warnings. SHA-512 vectors below + * have their own WOLFSSL_DRBG_SHA512 guard. */ +#ifndef NO_SHA256 WOLFSSL_SMALL_STACK_STATIC const byte test1Entropy[] = { 0xa6, 0x5a, 0xd0, 0xf3, 0x45, 0xdb, 0x4e, 0x0e, 0xff, 0xe8, 0x75, 0xc3, @@ -21492,11 +21552,13 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_test(void) 0x82, 0xc9, 0x55, 0xa8, 0x19, 0x69, 0xe0, 0x69, 0xfa, 0x8c, 0xe0, 0x07, 0xa1, 0x80, 0x18, 0x3a, 0x07, 0xdf, 0xae, 0x17 }; +#endif /* !NO_SHA256 - SHA-256 DRBG KAT vector data */ byte output[32 * 4]; wc_test_ret_t ret; WOLFSSL_ENTER("random_test"); +#ifndef NO_SHA256 ret = wc_RNG_HealthTest(0, test1Entropy, sizeof(test1Entropy), NULL, 0, output, sizeof(output)); if (ret != 0) @@ -21513,6 +21575,153 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_test(void) if (XMEMCMP(test2Output, output, sizeof(output)) != 0) return WC_TEST_RET_ENC_NC; +#else + (void)ret; /* may not be reassigned before use under NO_SHA256 */ +#endif /* !NO_SHA256 - SHA-256 DRBG KAT calls */ + +#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + /* SHA-512 DRBG Health Tests using NIST CAVP test vectors. + * Source: NIST CAVP drbgtestvectors.zip, Hash_DRBG.rsp, [SHA-512], + * https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm- + * Validation-Program/documents/drbg/drbgtestvectors.zip */ + { + /* No-reseed test: drbgvectors_no_reseed/Hash_DRBG.rsp, [SHA-512], + * PredictionResistance=False, EntropyInputLen=256, NonceLen=128, + * PersonalizationStringLen=0, AdditionalInputLen=0, + * ReturnedBitsLen=2048, COUNT=0. + * EntropyInput || Nonce concatenated as seedA. */ + WOLFSSL_SMALL_STACK_STATIC const byte sha512test1Entropy[] = + { + /* EntropyInput (32 bytes) */ + 0x6b, 0x50, 0xa7, 0xd8, 0xf8, 0xa5, 0x5d, 0x7a, + 0x3d, 0xf8, 0xbb, 0x40, 0xbc, 0xc3, 0xb7, 0x22, + 0xd8, 0x70, 0x8d, 0xe6, 0x7f, 0xda, 0x01, 0x0b, + 0x03, 0xc4, 0xc8, 0x4d, 0x72, 0x09, 0x6f, 0x8c, + /* Nonce (16 bytes) */ + 0x3e, 0xc6, 0x49, 0xcc, 0x62, 0x56, 0xd9, 0xfa, + 0x31, 0xdb, 0x7a, 0x29, 0x04, 0xaa, 0xf0, 0x25 + }; + WOLFSSL_SMALL_STACK_STATIC const byte sha512test1Output[] = + { + 0x95, 0xb7, 0xf1, 0x7e, 0x98, 0x02, 0xd3, 0x57, + 0x73, 0x92, 0xc6, 0xa9, 0xc0, 0x80, 0x83, 0xb6, + 0x7d, 0xd1, 0x29, 0x22, 0x65, 0xb5, 0xf4, 0x2d, + 0x23, 0x7f, 0x1c, 0x55, 0xbb, 0x9b, 0x10, 0xbf, + 0xcf, 0xd8, 0x2c, 0x77, 0xa3, 0x78, 0xb8, 0x26, + 0x6a, 0x00, 0x99, 0x14, 0x3b, 0x3c, 0x2d, 0x64, + 0x61, 0x1e, 0xee, 0xb6, 0x9a, 0xcd, 0xc0, 0x55, + 0x95, 0x7c, 0x13, 0x9e, 0x8b, 0x19, 0x0c, 0x7a, + 0x06, 0x95, 0x5f, 0x2c, 0x79, 0x7c, 0x27, 0x78, + 0xde, 0x94, 0x03, 0x96, 0xa5, 0x01, 0xf4, 0x0e, + 0x91, 0x39, 0x6a, 0xcf, 0x8d, 0x7e, 0x45, 0xeb, + 0xdb, 0xb5, 0x3b, 0xbf, 0x8c, 0x97, 0x52, 0x30, + 0xd2, 0xf0, 0xff, 0x91, 0x06, 0xc7, 0x61, 0x19, + 0xae, 0x49, 0x8e, 0x7f, 0xbc, 0x03, 0xd9, 0x0f, + 0x8e, 0x4c, 0x51, 0x62, 0x7a, 0xed, 0x5c, 0x8d, + 0x42, 0x63, 0xd5, 0xd2, 0xb9, 0x78, 0x87, 0x3a, + 0x0d, 0xe5, 0x96, 0xee, 0x6d, 0xc7, 0xf7, 0xc2, + 0x9e, 0x37, 0xee, 0xe8, 0xb3, 0x4c, 0x90, 0xdd, + 0x1c, 0xf6, 0xa9, 0xdd, 0xb2, 0x2b, 0x4c, 0xbd, + 0x08, 0x6b, 0x14, 0xb3, 0x5d, 0xe9, 0x3d, 0xa2, + 0xd5, 0xcb, 0x18, 0x06, 0x69, 0x8c, 0xbd, 0x7b, + 0xbb, 0x67, 0xbf, 0xe3, 0xd3, 0x1f, 0xd2, 0xd1, + 0xdb, 0xd2, 0xa1, 0xe0, 0x58, 0xa3, 0xeb, 0x99, + 0xd7, 0xe5, 0x1f, 0x1a, 0x93, 0x8e, 0xed, 0x5e, + 0x1c, 0x1d, 0xe2, 0x3a, 0x6b, 0x43, 0x45, 0xd3, + 0x19, 0x14, 0x09, 0xf9, 0x2f, 0x39, 0xb3, 0x67, + 0x0d, 0x8d, 0xbf, 0xb6, 0x35, 0xd8, 0xe6, 0xa3, + 0x69, 0x32, 0xd8, 0x10, 0x33, 0xd1, 0x44, 0x8d, + 0x63, 0xb4, 0x03, 0xdd, 0xf8, 0x8e, 0x12, 0x1b, + 0x6e, 0x81, 0x9a, 0xc3, 0x81, 0x22, 0x6c, 0x13, + 0x21, 0xe4, 0xb0, 0x86, 0x44, 0xf6, 0x72, 0x7c, + 0x36, 0x8c, 0x5a, 0x9f, 0x7a, 0x4b, 0x3e, 0xe2 + }; + + /* Reseed test: drbgvectors_pr_false/Hash_DRBG.rsp, [SHA-512], + * PredictionResistance=False, EntropyInputLen=256, NonceLen=128, + * PersonalizationStringLen=0, AdditionalInputLen=0, + * ReturnedBitsLen=2048, COUNT=0. */ + WOLFSSL_SMALL_STACK_STATIC const byte sha512test2EntropyA[] = + { + /* EntropyInput (32 bytes) */ + 0x31, 0x44, 0xe1, 0x7a, 0x10, 0xc8, 0x56, 0x12, + 0x97, 0x64, 0xf5, 0x8f, 0xd8, 0xe4, 0x23, 0x10, + 0x20, 0x54, 0x69, 0x96, 0xc0, 0xbf, 0x6c, 0xff, + 0x8e, 0x91, 0xc2, 0x4e, 0xe0, 0x9b, 0xe3, 0x33, + /* Nonce (16 bytes) */ + 0xb1, 0x6f, 0xcb, 0x1c, 0xf0, 0xc0, 0x10, 0xf3, + 0x1f, 0xea, 0xb7, 0x33, 0x58, 0x8b, 0x8e, 0x04 + }; + WOLFSSL_SMALL_STACK_STATIC const byte sha512test2EntropyB[] = + { + /* EntropyInputReseed (32 bytes) */ + 0xa0, 0xb3, 0x58, 0x4c, 0x2c, 0x84, 0x12, 0xf6, + 0x18, 0x40, 0x68, 0x34, 0x40, 0x4d, 0x1e, 0xb0, + 0xce, 0x99, 0x9b, 0xa2, 0x89, 0x66, 0x05, 0x4d, + 0x7e, 0x49, 0x7e, 0x0d, 0xb6, 0x08, 0xb9, 0x67 + }; + WOLFSSL_SMALL_STACK_STATIC const byte sha512test2Output[] = + { + 0xef, 0xa3, 0x5d, 0xd0, 0x36, 0x2a, 0xdb, 0x76, + 0x26, 0x45, 0x6b, 0x36, 0xfa, 0xc7, 0x4d, 0x3c, + 0x28, 0xd0, 0x1d, 0x92, 0x64, 0x20, 0x27, 0x5a, + 0x28, 0xbe, 0xa9, 0xc9, 0xdd, 0x75, 0x47, 0xc1, + 0x5e, 0x79, 0x31, 0x85, 0x2a, 0xc1, 0x27, 0x70, + 0x76, 0x56, 0x75, 0x35, 0x23, 0x9c, 0x1f, 0x42, + 0x9c, 0x7f, 0x75, 0xcf, 0x74, 0xc2, 0x26, 0x7d, + 0xeb, 0x6a, 0x3e, 0x59, 0x6c, 0xf3, 0x26, 0x15, + 0x6c, 0x79, 0x69, 0x41, 0x28, 0x3b, 0x8d, 0x58, + 0x3f, 0x17, 0x1c, 0x2f, 0x6e, 0x33, 0x23, 0xf7, + 0x55, 0x5e, 0x1b, 0x18, 0x1f, 0xfd, 0xa3, 0x05, + 0x07, 0x21, 0x0c, 0xb1, 0xf5, 0x89, 0xb2, 0x3c, + 0xd7, 0x18, 0x80, 0xfd, 0x44, 0x37, 0x0c, 0xac, + 0xf4, 0x33, 0x75, 0xb0, 0xdb, 0x7e, 0x33, 0x6f, + 0x12, 0xb3, 0x09, 0xbf, 0xd4, 0xf6, 0x10, 0xbb, + 0x8f, 0x20, 0xe1, 0xa1, 0x5e, 0x25, 0x3a, 0x4f, + 0xe5, 0x11, 0xa0, 0x27, 0x96, 0x8d, 0xf0, 0xb1, + 0x05, 0xa1, 0xd7, 0x3a, 0xff, 0x7c, 0x7a, 0x82, + 0x6d, 0x39, 0xf6, 0x40, 0xdf, 0xb8, 0xf5, 0x22, + 0x25, 0x9e, 0xd4, 0x02, 0x28, 0x2e, 0x2c, 0x2e, + 0x9d, 0x3a, 0x49, 0x8f, 0x51, 0x72, 0x5f, 0xe4, + 0x14, 0x1b, 0x06, 0xda, 0x55, 0x98, 0xa4, 0x2a, + 0xc1, 0xe0, 0x49, 0x4e, 0x99, 0x7d, 0x56, 0x6a, + 0x1a, 0x39, 0xb6, 0x76, 0xb9, 0x6a, 0x60, 0x03, + 0xa4, 0xc5, 0xdb, 0x84, 0xf2, 0x46, 0x58, 0x4e, + 0xe6, 0x5a, 0xf7, 0x0f, 0xf2, 0x16, 0x02, 0x78, + 0x16, 0x6d, 0xa1, 0x6d, 0x91, 0xc9, 0xb8, 0xf2, + 0xde, 0xb0, 0x27, 0x51, 0xa1, 0x08, 0x8a, 0xd6, + 0xbe, 0x4e, 0x80, 0xef, 0x96, 0x6e, 0xb7, 0x3e, + 0x66, 0xbc, 0x87, 0xca, 0xd8, 0x7c, 0x77, 0xc0, + 0xb3, 0x4a, 0x21, 0xba, 0x1d, 0xa0, 0xba, 0x6d, + 0x16, 0xca, 0x50, 0x46, 0xdc, 0x4a, 0xbd, 0xa0 + }; + + byte output512[WC_SHA512_DIGEST_SIZE * 4]; /* 256 bytes */ + + /* Test 1: SHA-512 DRBG no-reseed */ + ret = wc_RNG_HealthTest_SHA512(0, + sha512test1Entropy, sizeof(sha512test1Entropy), + NULL, 0, + output512, sizeof(output512)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + if (XMEMCMP(sha512test1Output, output512, sizeof(output512)) != 0) + return WC_TEST_RET_ENC_NC; + + /* Test 2: SHA-512 DRBG with reseed */ + ret = wc_RNG_HealthTest_SHA512(1, + sha512test2EntropyA, sizeof(sha512test2EntropyA), + sha512test2EntropyB, sizeof(sha512test2EntropyB), + output512, sizeof(output512)); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + if (XMEMCMP(sha512test2Output, output512, sizeof(output512)) != 0) + return WC_TEST_RET_ENC_NC; + } +#endif /* WOLFSSL_DRBG_SHA512 && !HAVE_SELFTEST && FIPS v7+ */ /* Basic RNG generate block test */ if ((ret = random_rng_test()) != 0) @@ -21753,8 +21962,20 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_bank_test(void) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); for (i = 0; i < bank->n_rngs; ++i) { + #if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + word64 bankReseedCtr; + if (bank->rngs[i].rng.drbgType == WC_DRBG_SHA512) + bankReseedCtr = ((struct DRBG_SHA512_internal *) + bank->rngs[i].rng.drbg512)->reseedCtr; + else + bankReseedCtr = ((struct DRBG_internal *) + bank->rngs[i].rng.drbg)->reseedCtr; + if (bankReseedCtr != WC_RESEED_INTERVAL) + #else if (((struct DRBG_internal *)bank->rngs[i].rng.drbg) ->reseedCtr != WC_RESEED_INTERVAL) + #endif { ERROR_OUT(WC_TEST_RET_ENC_I(i), out); } @@ -53670,6 +53891,77 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test_verify_only(void) #endif /* if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_SMALL_STACK) */ #if defined(WOLFSSL_HAVE_SLHDSA) + +#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY +/* KeyGen KAT: deterministic key generation cross-validated against NIST CAVP + * vectors. Verifies that MakeKeyWithRandom produces the expected sk and pk + * for a given parameter set. */ +static wc_test_ret_t slhdsa_keygen_kat(enum SlhDsaParam param, + const byte* sk_seed, word32 sk_seed_sz, + const byte* sk_prf, word32 sk_prf_sz, + const byte* pk_seed, word32 pk_seed_sz, + const byte* expected_sk, word32 expected_sk_sz, + const byte* expected_pk, word32 expected_pk_sz) +{ + int ret; + WC_DECLARE_VAR(key, SlhDsaKey, 1, HEAP_HINT); + byte sk_out[WC_SLHDSA_MAX_PRIV_LEN]; + byte pk_out[WC_SLHDSA_MAX_PUB_LEN]; + word32 outLen; + + WC_ALLOC_VAR_EX(key, SlhDsaKey, 1, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER, return WC_TEST_RET_ENC_EC(MEMORY_E)); + XMEMSET(key, 0, sizeof(*key)); + + ret = wc_SlhDsaKey_Init(key, param, NULL, INVALID_DEVID); + if (ret != 0) { + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + } + + ret = wc_SlhDsaKey_MakeKeyWithRandom(key, + sk_seed, sk_seed_sz, sk_prf, sk_prf_sz, pk_seed, pk_seed_sz); + if (ret != 0) { + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + } + + outLen = WC_SLHDSA_MAX_PRIV_LEN; + PRIVATE_KEY_UNLOCK(); + ret = wc_SlhDsaKey_ExportPrivate(key, sk_out, &outLen); + PRIVATE_KEY_LOCK(); + if (ret != 0) { + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + } + if (outLen != expected_sk_sz) { + ERROR_OUT(WC_TEST_RET_ENC_I(outLen), out); + } + if (XMEMCMP(sk_out, expected_sk, outLen) != 0) { + ERROR_OUT(WC_TEST_RET_ENC_NC, out); + } + + outLen = WC_SLHDSA_MAX_PUB_LEN; + ret = wc_SlhDsaKey_ExportPublic(key, pk_out, &outLen); + if (ret != 0) { + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + } + if (outLen != expected_pk_sz) { + ERROR_OUT(WC_TEST_RET_ENC_I(outLen), out); + } + if (XMEMCMP(pk_out, expected_pk, outLen) != 0) { + ERROR_OUT(WC_TEST_RET_ENC_NC, out); + } + +out: +#ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC + if (key) +#endif + { + wc_SlhDsaKey_Free(key); + } + WC_FREE_VAR_EX(key, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + return ret; +} +#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ + #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY static wc_test_ret_t slhdsa_test_param(enum SlhDsaParam param) { @@ -53712,8 +54004,10 @@ static wc_test_ret_t slhdsa_test_param(enum SlhDsaParam param) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); } sigLen = WC_SLHDSA_MAX_SIG_LEN; + PRIVATE_KEY_UNLOCK(); ret = wc_SlhDsaKey_Sign(key, ctx, 0, msg, (word32)sizeof(msg), sig, &sigLen, &rng); + PRIVATE_KEY_LOCK(); if (ret != 0) { ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); } @@ -53738,14 +54032,57 @@ static wc_test_ret_t slhdsa_test_param(enum SlhDsaParam param) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); } + { +#ifdef WOLFSSL_SLHDSA_SHA2 + enum wc_HashType phType = SLHDSA_IS_SHA2(param) ? + WC_HASH_TYPE_SHA256 : WC_HASH_TYPE_SHAKE256; +#else + enum wc_HashType phType = WC_HASH_TYPE_SHAKE256; +#endif + sigLen = WC_SLHDSA_MAX_SIG_LEN; + PRIVATE_KEY_UNLOCK(); + ret = wc_SlhDsaKey_SignHash(key, ctx, 0, msg, (word32)sizeof(msg), + phType, sig, &sigLen, &rng); + PRIVATE_KEY_LOCK(); + if (ret != 0) { + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + } + ret = wc_SlhDsaKey_VerifyHash(key_vfy, ctx, 0, msg, (word32)sizeof(msg), + phType, sig, sigLen); + } + if (ret != 0) { + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + } + + /* Additional pre-hash test: SHA-384 exercises a different OID path */ +#ifdef WOLFSSL_SHA384 sigLen = WC_SLHDSA_MAX_SIG_LEN; + PRIVATE_KEY_UNLOCK(); ret = wc_SlhDsaKey_SignHash(key, ctx, 0, msg, (word32)sizeof(msg), - WC_HASH_TYPE_SHAKE256, sig, &sigLen, &rng); + WC_HASH_TYPE_SHA384, sig, &sigLen, &rng); + PRIVATE_KEY_LOCK(); if (ret != 0) { ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); } ret = wc_SlhDsaKey_VerifyHash(key_vfy, ctx, 0, msg, (word32)sizeof(msg), - WC_HASH_TYPE_SHAKE256, sig, sigLen); + WC_HASH_TYPE_SHA384, sig, sigLen); + if (ret != 0) { + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + } +#endif + + /* Internal interface: SignMsgDeterministic + VerifyMsg round-trip. + * These take M' directly (no 0x00||len(ctx)||ctx||M wrapping). */ + sigLen = WC_SLHDSA_MAX_SIG_LEN; + PRIVATE_KEY_UNLOCK(); + ret = wc_SlhDsaKey_SignMsgDeterministic(key, + msg, (word32)sizeof(msg), sig, &sigLen); + PRIVATE_KEY_LOCK(); + if (ret != 0) { + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); + } + ret = wc_SlhDsaKey_VerifyMsg(key_vfy, + msg, (word32)sizeof(msg), sig, sigLen); if (ret != 0) { ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); } @@ -54841,7 +55178,9 @@ wc_test_ret_t slhdsa_test(void) } outLen = WC_SLHDSA_MAX_PRIV_LEN; + PRIVATE_KEY_UNLOCK(); ret = wc_SlhDsaKey_ExportPrivate(key, sk, &outLen); + PRIVATE_KEY_LOCK(); if (ret != 0) { ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); } @@ -54883,8 +55222,10 @@ wc_test_ret_t slhdsa_test(void) #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY outLen = (word32)sizeof(sig_shake128s); + PRIVATE_KEY_UNLOCK(); ret = wc_SlhDsaKey_SignWithRandom(key, ctx, 0, msg, (word32)sizeof(msg), sig, &outLen, pk_seed_shake128s); + PRIVATE_KEY_LOCK(); if (ret != 0) { ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); } @@ -54899,6 +55240,601 @@ wc_test_ret_t slhdsa_test(void) #endif #endif + /* --- SHA2 KeyGen KATs (NIST CAVP cross-validation) --- + * These verify that deterministic key generation produces the exact pk/sk + * that NIST expects. Covers both SHA-256 (cat 1, n=16) and SHA-512 + * (cat 3 n=24, cat 5 n=32) code paths. */ +#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128S + { + /* NIST CAVP SLH-DSA-SHA2-128s keyGen vector (tgId=1, tcId=1). + * Same seeds as SHAKE128S; pk_root differs due to SHA-256 hash. */ + static const byte sk_seed_sha2_128s[] = { + 0x17, 0x3D, 0x04, 0xC9, 0x38, 0xC1, 0xC3, 0x6B, + 0xF2, 0x89, 0xC3, 0xC0, 0x22, 0xD0, 0x4B, 0x14 + }; + static const byte sk_prf_sha2_128s[] = { + 0x63, 0xAE, 0x23, 0xC4, 0x1A, 0xA5, 0x46, 0xDA, + 0x58, 0x97, 0x74, 0xAC, 0x20, 0xB7, 0x45, 0xC4 + }; + static const byte pk_seed_sha2_128s[] = { + 0x0D, 0x79, 0x47, 0x77, 0x91, 0x4C, 0x99, 0x76, + 0x68, 0x27, 0xF0, 0xF0, 0x9C, 0xA9, 0x72, 0xBE + }; + static const byte expected_sk_sha2_128s[] = { + 0x17, 0x3D, 0x04, 0xC9, 0x38, 0xC1, 0xC3, 0x6B, + 0xF2, 0x89, 0xC3, 0xC0, 0x22, 0xD0, 0x4B, 0x14, + 0x63, 0xAE, 0x23, 0xC4, 0x1A, 0xA5, 0x46, 0xDA, + 0x58, 0x97, 0x74, 0xAC, 0x20, 0xB7, 0x45, 0xC4, + 0x0D, 0x79, 0x47, 0x77, 0x91, 0x4C, 0x99, 0x76, + 0x68, 0x27, 0xF0, 0xF0, 0x9C, 0xA9, 0x72, 0xBE, + 0x01, 0x62, 0xC1, 0x02, 0x19, 0xD4, 0x22, 0xAD, + 0xBA, 0x13, 0x59, 0xE6, 0xAA, 0x65, 0x29, 0x9C + }; + static const byte expected_pk_sha2_128s[] = { + 0x0D, 0x79, 0x47, 0x77, 0x91, 0x4C, 0x99, 0x76, + 0x68, 0x27, 0xF0, 0xF0, 0x9C, 0xA9, 0x72, 0xBE, + 0x01, 0x62, 0xC1, 0x02, 0x19, 0xD4, 0x22, 0xAD, + 0xBA, 0x13, 0x59, 0xE6, 0xAA, 0x65, 0x29, 0x9C + }; + ret = slhdsa_keygen_kat(SLHDSA_SHA2_128S, + sk_seed_sha2_128s, (word32)sizeof(sk_seed_sha2_128s), + sk_prf_sha2_128s, (word32)sizeof(sk_prf_sha2_128s), + pk_seed_sha2_128s, (word32)sizeof(pk_seed_sha2_128s), + expected_sk_sha2_128s, (word32)sizeof(expected_sk_sha2_128s), + expected_pk_sha2_128s, (word32)sizeof(expected_pk_sha2_128s)); + if (ret != 0) { + wc_test_render_error_message("SLHDSA_SHA2_128S keyGen KAT", 0); + goto out; + } + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192S + { + /* NIST CAVP SLH-DSA-SHA2-192s keyGen vector (tgId=5, tcId=41). + * Uses SHA-512 for H and T_l operations (n=24). */ + static const byte sk_seed_sha2_192s[] = { + 0x04, 0x02, 0x66, 0x52, 0x9C, 0x18, 0x64, 0x08, + 0x89, 0x25, 0x50, 0x6C, 0x20, 0xA6, 0x24, 0xA2, + 0xB6, 0xD5, 0x0C, 0xD7, 0x7C, 0x1C, 0x6F, 0x0D + }; + static const byte sk_prf_sha2_192s[] = { + 0x28, 0x41, 0x15, 0x0A, 0xE8, 0x15, 0x75, 0x12, + 0xEF, 0x34, 0xA3, 0x43, 0xFF, 0xEA, 0x77, 0xFF, + 0x7D, 0x9E, 0x81, 0x4B, 0x45, 0xA8, 0xB4, 0x14 + }; + static const byte pk_seed_sha2_192s[] = { + 0x64, 0x46, 0x26, 0x65, 0xF4, 0x20, 0x28, 0x86, + 0x20, 0x6A, 0x8F, 0x63, 0x22, 0x67, 0x18, 0x6C, + 0xA6, 0xA1, 0xCA, 0xD0, 0x8A, 0x2B, 0x9A, 0x86 + }; + static const byte expected_sk_sha2_192s[] = { + 0x04, 0x02, 0x66, 0x52, 0x9C, 0x18, 0x64, 0x08, + 0x89, 0x25, 0x50, 0x6C, 0x20, 0xA6, 0x24, 0xA2, + 0xB6, 0xD5, 0x0C, 0xD7, 0x7C, 0x1C, 0x6F, 0x0D, + 0x28, 0x41, 0x15, 0x0A, 0xE8, 0x15, 0x75, 0x12, + 0xEF, 0x34, 0xA3, 0x43, 0xFF, 0xEA, 0x77, 0xFF, + 0x7D, 0x9E, 0x81, 0x4B, 0x45, 0xA8, 0xB4, 0x14, + 0x64, 0x46, 0x26, 0x65, 0xF4, 0x20, 0x28, 0x86, + 0x20, 0x6A, 0x8F, 0x63, 0x22, 0x67, 0x18, 0x6C, + 0xA6, 0xA1, 0xCA, 0xD0, 0x8A, 0x2B, 0x9A, 0x86, + 0x2C, 0x6A, 0x7B, 0xC4, 0xAC, 0x4A, 0xAA, 0x84, + 0xAC, 0xCE, 0xF6, 0x0D, 0x52, 0x9F, 0x03, 0x11, + 0x27, 0x4F, 0x20, 0x5E, 0x8D, 0xA6, 0x42, 0xC9 + }; + static const byte expected_pk_sha2_192s[] = { + 0x64, 0x46, 0x26, 0x65, 0xF4, 0x20, 0x28, 0x86, + 0x20, 0x6A, 0x8F, 0x63, 0x22, 0x67, 0x18, 0x6C, + 0xA6, 0xA1, 0xCA, 0xD0, 0x8A, 0x2B, 0x9A, 0x86, + 0x2C, 0x6A, 0x7B, 0xC4, 0xAC, 0x4A, 0xAA, 0x84, + 0xAC, 0xCE, 0xF6, 0x0D, 0x52, 0x9F, 0x03, 0x11, + 0x27, 0x4F, 0x20, 0x5E, 0x8D, 0xA6, 0x42, 0xC9 + }; + ret = slhdsa_keygen_kat(SLHDSA_SHA2_192S, + sk_seed_sha2_192s, (word32)sizeof(sk_seed_sha2_192s), + sk_prf_sha2_192s, (word32)sizeof(sk_prf_sha2_192s), + pk_seed_sha2_192s, (word32)sizeof(pk_seed_sha2_192s), + expected_sk_sha2_192s, (word32)sizeof(expected_sk_sha2_192s), + expected_pk_sha2_192s, (word32)sizeof(expected_pk_sha2_192s)); + if (ret != 0) { + wc_test_render_error_message("SLHDSA_SHA2_192S keyGen KAT", 0); + goto out; + } + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256S + { + /* NIST CAVP SLH-DSA-SHA2-256s keyGen vector (tgId=9, tcId=81). + * Uses SHA-512 for H and T_l operations (n=32). */ + static const byte sk_seed_sha2_256s[] = { + 0xFC, 0xBF, 0x36, 0xA9, 0x80, 0x7B, 0x30, 0x69, + 0x7B, 0xE0, 0x63, 0xA5, 0x10, 0x5E, 0x09, 0x1B, + 0x41, 0x2A, 0x39, 0x1D, 0xD3, 0x9E, 0x13, 0x26, + 0xEB, 0xA2, 0x3C, 0xBD, 0x40, 0x96, 0xCA, 0x77 + }; + static const byte sk_prf_sha2_256s[] = { + 0xEF, 0x41, 0x21, 0xC0, 0x8D, 0xD7, 0x1B, 0xE9, + 0x13, 0x57, 0x2F, 0x1F, 0x91, 0xE5, 0x7D, 0x0A, + 0xCB, 0xCD, 0x5C, 0xEC, 0x28, 0x53, 0x9A, 0xC2, + 0x75, 0x83, 0x2B, 0xBA, 0xA6, 0xC1, 0x10, 0x81 + }; + static const byte pk_seed_sha2_256s[] = { + 0xA0, 0xB4, 0xF5, 0x54, 0x9E, 0xBC, 0xAD, 0xB9, + 0x51, 0xDC, 0x2E, 0x51, 0x2C, 0x76, 0xB0, 0x62, + 0x0D, 0x8F, 0xB8, 0x10, 0x0B, 0x4E, 0xE8, 0x86, + 0xEF, 0x87, 0x84, 0x78, 0x0D, 0x52, 0xA2, 0x54 + }; + static const byte expected_sk_sha2_256s[] = { + 0xFC, 0xBF, 0x36, 0xA9, 0x80, 0x7B, 0x30, 0x69, + 0x7B, 0xE0, 0x63, 0xA5, 0x10, 0x5E, 0x09, 0x1B, + 0x41, 0x2A, 0x39, 0x1D, 0xD3, 0x9E, 0x13, 0x26, + 0xEB, 0xA2, 0x3C, 0xBD, 0x40, 0x96, 0xCA, 0x77, + 0xEF, 0x41, 0x21, 0xC0, 0x8D, 0xD7, 0x1B, 0xE9, + 0x13, 0x57, 0x2F, 0x1F, 0x91, 0xE5, 0x7D, 0x0A, + 0xCB, 0xCD, 0x5C, 0xEC, 0x28, 0x53, 0x9A, 0xC2, + 0x75, 0x83, 0x2B, 0xBA, 0xA6, 0xC1, 0x10, 0x81, + 0xA0, 0xB4, 0xF5, 0x54, 0x9E, 0xBC, 0xAD, 0xB9, + 0x51, 0xDC, 0x2E, 0x51, 0x2C, 0x76, 0xB0, 0x62, + 0x0D, 0x8F, 0xB8, 0x10, 0x0B, 0x4E, 0xE8, 0x86, + 0xEF, 0x87, 0x84, 0x78, 0x0D, 0x52, 0xA2, 0x54, + 0x3E, 0x57, 0xAB, 0x49, 0x4D, 0x47, 0x06, 0x8F, + 0xFE, 0xE4, 0xB8, 0x24, 0x4A, 0xAD, 0x6F, 0x19, + 0xCD, 0xF9, 0x4A, 0x21, 0x72, 0xBD, 0x13, 0x4A, + 0x15, 0xA6, 0xB5, 0xF2, 0x98, 0xD5, 0xA8, 0x0E + }; + static const byte expected_pk_sha2_256s[] = { + 0xA0, 0xB4, 0xF5, 0x54, 0x9E, 0xBC, 0xAD, 0xB9, + 0x51, 0xDC, 0x2E, 0x51, 0x2C, 0x76, 0xB0, 0x62, + 0x0D, 0x8F, 0xB8, 0x10, 0x0B, 0x4E, 0xE8, 0x86, + 0xEF, 0x87, 0x84, 0x78, 0x0D, 0x52, 0xA2, 0x54, + 0x3E, 0x57, 0xAB, 0x49, 0x4D, 0x47, 0x06, 0x8F, + 0xFE, 0xE4, 0xB8, 0x24, 0x4A, 0xAD, 0x6F, 0x19, + 0xCD, 0xF9, 0x4A, 0x21, 0x72, 0xBD, 0x13, 0x4A, + 0x15, 0xA6, 0xB5, 0xF2, 0x98, 0xD5, 0xA8, 0x0E + }; + ret = slhdsa_keygen_kat(SLHDSA_SHA2_256S, + sk_seed_sha2_256s, (word32)sizeof(sk_seed_sha2_256s), + sk_prf_sha2_256s, (word32)sizeof(sk_prf_sha2_256s), + pk_seed_sha2_256s, (word32)sizeof(pk_seed_sha2_256s), + expected_sk_sha2_256s, (word32)sizeof(expected_sk_sha2_256s), + expected_pk_sha2_256s, (word32)sizeof(expected_pk_sha2_256s)); + if (ret != 0) { + wc_test_render_error_message("SLHDSA_SHA2_256S keyGen KAT", 0); + goto out; + } + } +#endif + + /* --- SHAKE KeyGen KATs (128f, 192s/f, 256s/f) --- */ +#ifdef WOLFSSL_SLHDSA_PARAM_128F + { + /* NIST CAVP SLH-DSA-SHAKE-128f keyGen vector (tgId=4, tcId=31) */ + static const byte sk_seed_shake_128f[] = { + 0x39, 0x56, 0xAB, 0x39, 0x1B, 0x4D, 0x22, 0xFC, + 0x90, 0x7A, 0xF0, 0x74, 0x03, 0x26, 0xD0, 0x61 + }; + static const byte sk_prf_shake_128f[] = { + 0xAB, 0x0E, 0xB2, 0x06, 0x43, 0x6F, 0x2B, 0x86, + 0xEB, 0xE0, 0x86, 0xD7, 0x77, 0x39, 0xB3, 0xE4 + }; + static const byte pk_seed_shake_128f[] = { + 0x56, 0x50, 0x5C, 0x22, 0x9F, 0x4E, 0x7F, 0xA6, + 0xB2, 0x01, 0x71, 0x4C, 0x7D, 0xCC, 0x9D, 0xA3 + }; + static const byte expected_sk_shake_128f[] = { + 0x39, 0x56, 0xAB, 0x39, 0x1B, 0x4D, 0x22, 0xFC, + 0x90, 0x7A, 0xF0, 0x74, 0x03, 0x26, 0xD0, 0x61, + 0xAB, 0x0E, 0xB2, 0x06, 0x43, 0x6F, 0x2B, 0x86, + 0xEB, 0xE0, 0x86, 0xD7, 0x77, 0x39, 0xB3, 0xE4, + 0x56, 0x50, 0x5C, 0x22, 0x9F, 0x4E, 0x7F, 0xA6, + 0xB2, 0x01, 0x71, 0x4C, 0x7D, 0xCC, 0x9D, 0xA3, + 0x66, 0x57, 0x8F, 0x1F, 0x24, 0xC3, 0xFE, 0x37, + 0x1C, 0x97, 0xC1, 0x4C, 0xE0, 0xE7, 0x9C, 0xDC + }; + static const byte expected_pk_shake_128f[] = { + 0x56, 0x50, 0x5C, 0x22, 0x9F, 0x4E, 0x7F, 0xA6, + 0xB2, 0x01, 0x71, 0x4C, 0x7D, 0xCC, 0x9D, 0xA3, + 0x66, 0x57, 0x8F, 0x1F, 0x24, 0xC3, 0xFE, 0x37, + 0x1C, 0x97, 0xC1, 0x4C, 0xE0, 0xE7, 0x9C, 0xDC + }; + ret = slhdsa_keygen_kat(SLHDSA_SHAKE128F, + sk_seed_shake_128f, (word32)sizeof(sk_seed_shake_128f), + sk_prf_shake_128f, (word32)sizeof(sk_prf_shake_128f), + pk_seed_shake_128f, (word32)sizeof(pk_seed_shake_128f), + expected_sk_shake_128f, (word32)sizeof(expected_sk_shake_128f), + expected_pk_shake_128f, (word32)sizeof(expected_pk_shake_128f)); + if (ret != 0) { + wc_test_render_error_message("SLHDSA_SHAKE128F keyGen KAT", 0); + goto out; + } + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_192S + { + /* NIST CAVP SLH-DSA-SHAKE-192s keyGen vector (tgId=6, tcId=51) */ + static const byte sk_seed_shake_192s[] = { + 0x87, 0x32, 0x62, 0x18, 0x60, 0xE9, 0xA6, 0xE1, + 0x88, 0x7B, 0xE5, 0x5F, 0x7A, 0xF6, 0x92, 0xB9, + 0x8E, 0xB4, 0xC1, 0x0B, 0x25, 0x99, 0xF9, 0x4A + }; + static const byte sk_prf_shake_192s[] = { + 0xD5, 0xCC, 0x9D, 0x64, 0x70, 0xD8, 0xB2, 0x11, + 0x36, 0x15, 0x8E, 0x8B, 0x17, 0x10, 0xF1, 0xFB, + 0xE0, 0x3E, 0xCE, 0xD3, 0x7E, 0xD4, 0xAC, 0x68 + }; + static const byte pk_seed_shake_192s[] = { + 0x53, 0xFC, 0x64, 0xD4, 0x6D, 0x7E, 0x16, 0x53, + 0xEB, 0xBB, 0x36, 0xED, 0x5F, 0xBC, 0x12, 0xC6, + 0xE7, 0xCE, 0xF3, 0xCB, 0x75, 0x64, 0x82, 0xC8 + }; + static const byte expected_sk_shake_192s[] = { + 0x87, 0x32, 0x62, 0x18, 0x60, 0xE9, 0xA6, 0xE1, + 0x88, 0x7B, 0xE5, 0x5F, 0x7A, 0xF6, 0x92, 0xB9, + 0x8E, 0xB4, 0xC1, 0x0B, 0x25, 0x99, 0xF9, 0x4A, + 0xD5, 0xCC, 0x9D, 0x64, 0x70, 0xD8, 0xB2, 0x11, + 0x36, 0x15, 0x8E, 0x8B, 0x17, 0x10, 0xF1, 0xFB, + 0xE0, 0x3E, 0xCE, 0xD3, 0x7E, 0xD4, 0xAC, 0x68, + 0x53, 0xFC, 0x64, 0xD4, 0x6D, 0x7E, 0x16, 0x53, + 0xEB, 0xBB, 0x36, 0xED, 0x5F, 0xBC, 0x12, 0xC6, + 0xE7, 0xCE, 0xF3, 0xCB, 0x75, 0x64, 0x82, 0xC8, + 0xC6, 0x20, 0x45, 0x2E, 0x86, 0x4E, 0x84, 0x97, + 0xE1, 0xB3, 0x8A, 0x7B, 0x04, 0x44, 0x92, 0x19, + 0xAC, 0xD9, 0xE4, 0x39, 0x3F, 0x9C, 0x88, 0xEF + }; + static const byte expected_pk_shake_192s[] = { + 0x53, 0xFC, 0x64, 0xD4, 0x6D, 0x7E, 0x16, 0x53, + 0xEB, 0xBB, 0x36, 0xED, 0x5F, 0xBC, 0x12, 0xC6, + 0xE7, 0xCE, 0xF3, 0xCB, 0x75, 0x64, 0x82, 0xC8, + 0xC6, 0x20, 0x45, 0x2E, 0x86, 0x4E, 0x84, 0x97, + 0xE1, 0xB3, 0x8A, 0x7B, 0x04, 0x44, 0x92, 0x19, + 0xAC, 0xD9, 0xE4, 0x39, 0x3F, 0x9C, 0x88, 0xEF + }; + ret = slhdsa_keygen_kat(SLHDSA_SHAKE192S, + sk_seed_shake_192s, (word32)sizeof(sk_seed_shake_192s), + sk_prf_shake_192s, (word32)sizeof(sk_prf_shake_192s), + pk_seed_shake_192s, (word32)sizeof(pk_seed_shake_192s), + expected_sk_shake_192s, (word32)sizeof(expected_sk_shake_192s), + expected_pk_shake_192s, (word32)sizeof(expected_pk_shake_192s)); + if (ret != 0) { + wc_test_render_error_message("SLHDSA_SHAKE192S keyGen KAT", 0); + goto out; + } + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_192F + { + /* NIST CAVP SLH-DSA-SHAKE-192f keyGen vector (tgId=8, tcId=71) */ + static const byte sk_seed_shake_192f[] = { + 0xFB, 0x7A, 0x2C, 0x2C, 0x75, 0xCE, 0x6C, 0x96, + 0xB5, 0xF4, 0x32, 0x8E, 0x0A, 0xB3, 0x00, 0x47, + 0x6F, 0xC6, 0xF8, 0x64, 0xCB, 0x5B, 0x0B, 0x99 + }; + static const byte sk_prf_shake_192f[] = { + 0x99, 0x0E, 0xCB, 0x72, 0x6C, 0xA8, 0x22, 0xA4, + 0xE3, 0x65, 0x2D, 0xD9, 0x2E, 0xC0, 0xAA, 0xB7, + 0x63, 0x7E, 0xA4, 0x1C, 0x04, 0x82, 0xAE, 0x28 + }; + static const byte pk_seed_shake_192f[] = { + 0x68, 0xDC, 0xC6, 0x71, 0xE3, 0x53, 0x4F, 0x81, + 0xA3, 0x52, 0xC2, 0x75, 0xB6, 0xA2, 0x5F, 0x90, + 0x6D, 0x2E, 0xD0, 0xFF, 0x62, 0xB8, 0xB4, 0xE3 + }; + static const byte expected_sk_shake_192f[] = { + 0xFB, 0x7A, 0x2C, 0x2C, 0x75, 0xCE, 0x6C, 0x96, + 0xB5, 0xF4, 0x32, 0x8E, 0x0A, 0xB3, 0x00, 0x47, + 0x6F, 0xC6, 0xF8, 0x64, 0xCB, 0x5B, 0x0B, 0x99, + 0x99, 0x0E, 0xCB, 0x72, 0x6C, 0xA8, 0x22, 0xA4, + 0xE3, 0x65, 0x2D, 0xD9, 0x2E, 0xC0, 0xAA, 0xB7, + 0x63, 0x7E, 0xA4, 0x1C, 0x04, 0x82, 0xAE, 0x28, + 0x68, 0xDC, 0xC6, 0x71, 0xE3, 0x53, 0x4F, 0x81, + 0xA3, 0x52, 0xC2, 0x75, 0xB6, 0xA2, 0x5F, 0x90, + 0x6D, 0x2E, 0xD0, 0xFF, 0x62, 0xB8, 0xB4, 0xE3, + 0x98, 0xF1, 0xA9, 0x87, 0x6C, 0xB0, 0x82, 0xA4, + 0x8E, 0x9A, 0xE2, 0xC8, 0x62, 0xB2, 0x89, 0x48, + 0x6A, 0x39, 0x25, 0xCE, 0xFC, 0x6F, 0xF4, 0xBE + }; + static const byte expected_pk_shake_192f[] = { + 0x68, 0xDC, 0xC6, 0x71, 0xE3, 0x53, 0x4F, 0x81, + 0xA3, 0x52, 0xC2, 0x75, 0xB6, 0xA2, 0x5F, 0x90, + 0x6D, 0x2E, 0xD0, 0xFF, 0x62, 0xB8, 0xB4, 0xE3, + 0x98, 0xF1, 0xA9, 0x87, 0x6C, 0xB0, 0x82, 0xA4, + 0x8E, 0x9A, 0xE2, 0xC8, 0x62, 0xB2, 0x89, 0x48, + 0x6A, 0x39, 0x25, 0xCE, 0xFC, 0x6F, 0xF4, 0xBE + }; + ret = slhdsa_keygen_kat(SLHDSA_SHAKE192F, + sk_seed_shake_192f, (word32)sizeof(sk_seed_shake_192f), + sk_prf_shake_192f, (word32)sizeof(sk_prf_shake_192f), + pk_seed_shake_192f, (word32)sizeof(pk_seed_shake_192f), + expected_sk_shake_192f, (word32)sizeof(expected_sk_shake_192f), + expected_pk_shake_192f, (word32)sizeof(expected_pk_shake_192f)); + if (ret != 0) { + wc_test_render_error_message("SLHDSA_SHAKE192F keyGen KAT", 0); + goto out; + } + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_256S + { + /* NIST CAVP SLH-DSA-SHAKE-256s keyGen vector (tgId=10, tcId=91) */ + static const byte sk_seed_shake_256s[] = { + 0xE4, 0x40, 0xE3, 0x96, 0x44, 0xA1, 0x1A, 0x6A, + 0x58, 0xE8, 0x50, 0xC0, 0x9C, 0x8F, 0x03, 0xC2, + 0x73, 0xE4, 0x65, 0x23, 0x7F, 0x3B, 0xEF, 0x7C, + 0x58, 0xDE, 0x62, 0x28, 0x1E, 0x67, 0x6C, 0xEA + }; + static const byte sk_prf_shake_256s[] = { + 0x99, 0xC1, 0x99, 0xC0, 0x0D, 0xB3, 0x0F, 0x84, + 0x99, 0xA6, 0x1B, 0x5B, 0x9D, 0xC8, 0xA3, 0x61, + 0x72, 0x5F, 0x6A, 0xE8, 0x0E, 0x97, 0x03, 0x71, + 0x76, 0xF4, 0x08, 0xC3, 0x0B, 0x38, 0x84, 0x4D + }; + static const byte pk_seed_shake_256s[] = { + 0xD7, 0xB5, 0xE7, 0x55, 0xB4, 0x87, 0x9F, 0xDE, + 0x32, 0x88, 0xA2, 0x1A, 0xF3, 0xE3, 0x2F, 0xBB, + 0x00, 0x6F, 0xD9, 0xB8, 0xBC, 0x2B, 0x18, 0x0E, + 0xB9, 0xB0, 0xD8, 0x2C, 0x9F, 0x31, 0x57, 0xAF + }; + static const byte expected_sk_shake_256s[] = { + 0xE4, 0x40, 0xE3, 0x96, 0x44, 0xA1, 0x1A, 0x6A, + 0x58, 0xE8, 0x50, 0xC0, 0x9C, 0x8F, 0x03, 0xC2, + 0x73, 0xE4, 0x65, 0x23, 0x7F, 0x3B, 0xEF, 0x7C, + 0x58, 0xDE, 0x62, 0x28, 0x1E, 0x67, 0x6C, 0xEA, + 0x99, 0xC1, 0x99, 0xC0, 0x0D, 0xB3, 0x0F, 0x84, + 0x99, 0xA6, 0x1B, 0x5B, 0x9D, 0xC8, 0xA3, 0x61, + 0x72, 0x5F, 0x6A, 0xE8, 0x0E, 0x97, 0x03, 0x71, + 0x76, 0xF4, 0x08, 0xC3, 0x0B, 0x38, 0x84, 0x4D, + 0xD7, 0xB5, 0xE7, 0x55, 0xB4, 0x87, 0x9F, 0xDE, + 0x32, 0x88, 0xA2, 0x1A, 0xF3, 0xE3, 0x2F, 0xBB, + 0x00, 0x6F, 0xD9, 0xB8, 0xBC, 0x2B, 0x18, 0x0E, + 0xB9, 0xB0, 0xD8, 0x2C, 0x9F, 0x31, 0x57, 0xAF, + 0x02, 0xAC, 0xD6, 0xB3, 0x19, 0x8E, 0xE1, 0xC9, + 0xFE, 0x9A, 0xFE, 0x61, 0xFD, 0x86, 0xD1, 0xE0, + 0x87, 0x7A, 0xD9, 0x06, 0x19, 0x80, 0xB5, 0x7B, + 0x17, 0x8C, 0xE2, 0x71, 0x91, 0xD8, 0xEB, 0x1B + }; + static const byte expected_pk_shake_256s[] = { + 0xD7, 0xB5, 0xE7, 0x55, 0xB4, 0x87, 0x9F, 0xDE, + 0x32, 0x88, 0xA2, 0x1A, 0xF3, 0xE3, 0x2F, 0xBB, + 0x00, 0x6F, 0xD9, 0xB8, 0xBC, 0x2B, 0x18, 0x0E, + 0xB9, 0xB0, 0xD8, 0x2C, 0x9F, 0x31, 0x57, 0xAF, + 0x02, 0xAC, 0xD6, 0xB3, 0x19, 0x8E, 0xE1, 0xC9, + 0xFE, 0x9A, 0xFE, 0x61, 0xFD, 0x86, 0xD1, 0xE0, + 0x87, 0x7A, 0xD9, 0x06, 0x19, 0x80, 0xB5, 0x7B, + 0x17, 0x8C, 0xE2, 0x71, 0x91, 0xD8, 0xEB, 0x1B + }; + ret = slhdsa_keygen_kat(SLHDSA_SHAKE256S, + sk_seed_shake_256s, (word32)sizeof(sk_seed_shake_256s), + sk_prf_shake_256s, (word32)sizeof(sk_prf_shake_256s), + pk_seed_shake_256s, (word32)sizeof(pk_seed_shake_256s), + expected_sk_shake_256s, (word32)sizeof(expected_sk_shake_256s), + expected_pk_shake_256s, (word32)sizeof(expected_pk_shake_256s)); + if (ret != 0) { + wc_test_render_error_message("SLHDSA_SHAKE256S keyGen KAT", 0); + goto out; + } + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_256F + { + /* NIST CAVP SLH-DSA-SHAKE-256f keyGen vector (tgId=12, tcId=111) */ + static const byte sk_seed_shake_256f[] = { + 0x2A, 0xC9, 0x40, 0x38, 0x58, 0xD1, 0x86, 0xB1, + 0x72, 0xED, 0xD8, 0xDF, 0x9C, 0x78, 0xA1, 0x14, + 0x49, 0x89, 0x36, 0x81, 0x48, 0x7D, 0x3A, 0xF0, + 0xDA, 0xD0, 0xEC, 0x34, 0x1E, 0x8A, 0xCA, 0x48 + }; + static const byte sk_prf_shake_256f[] = { + 0xAF, 0xA2, 0x77, 0x1B, 0xAE, 0x6C, 0x17, 0xDD, + 0x6F, 0x77, 0xB4, 0xE3, 0x80, 0x8B, 0x05, 0xF5, + 0x6F, 0x31, 0xB8, 0xF4, 0x12, 0x8D, 0xF2, 0xCC, + 0xB6, 0x77, 0xF0, 0x28, 0x3C, 0xFB, 0x18, 0xDA + }; + static const byte pk_seed_shake_256f[] = { + 0x55, 0x9B, 0xC8, 0x83, 0x10, 0x5E, 0x8B, 0xA0, + 0x26, 0x46, 0x48, 0xB5, 0x32, 0x62, 0x61, 0x55, + 0xF8, 0x7E, 0xDB, 0x4B, 0xED, 0xCF, 0xC1, 0x2A, + 0x24, 0x20, 0x4D, 0x3B, 0x69, 0x6D, 0x53, 0x70 + }; + static const byte expected_sk_shake_256f[] = { + 0x2A, 0xC9, 0x40, 0x38, 0x58, 0xD1, 0x86, 0xB1, + 0x72, 0xED, 0xD8, 0xDF, 0x9C, 0x78, 0xA1, 0x14, + 0x49, 0x89, 0x36, 0x81, 0x48, 0x7D, 0x3A, 0xF0, + 0xDA, 0xD0, 0xEC, 0x34, 0x1E, 0x8A, 0xCA, 0x48, + 0xAF, 0xA2, 0x77, 0x1B, 0xAE, 0x6C, 0x17, 0xDD, + 0x6F, 0x77, 0xB4, 0xE3, 0x80, 0x8B, 0x05, 0xF5, + 0x6F, 0x31, 0xB8, 0xF4, 0x12, 0x8D, 0xF2, 0xCC, + 0xB6, 0x77, 0xF0, 0x28, 0x3C, 0xFB, 0x18, 0xDA, + 0x55, 0x9B, 0xC8, 0x83, 0x10, 0x5E, 0x8B, 0xA0, + 0x26, 0x46, 0x48, 0xB5, 0x32, 0x62, 0x61, 0x55, + 0xF8, 0x7E, 0xDB, 0x4B, 0xED, 0xCF, 0xC1, 0x2A, + 0x24, 0x20, 0x4D, 0x3B, 0x69, 0x6D, 0x53, 0x70, + 0x7A, 0x15, 0x8F, 0xF5, 0xD3, 0x0E, 0x34, 0x28, + 0x18, 0x3A, 0x3B, 0x3A, 0x96, 0xA0, 0xE4, 0xA3, + 0x41, 0xA2, 0xA1, 0x6E, 0x5A, 0x62, 0x26, 0xAF, + 0x37, 0x4D, 0x1E, 0xFB, 0x39, 0xA3, 0x5D, 0xF6 + }; + static const byte expected_pk_shake_256f[] = { + 0x55, 0x9B, 0xC8, 0x83, 0x10, 0x5E, 0x8B, 0xA0, + 0x26, 0x46, 0x48, 0xB5, 0x32, 0x62, 0x61, 0x55, + 0xF8, 0x7E, 0xDB, 0x4B, 0xED, 0xCF, 0xC1, 0x2A, + 0x24, 0x20, 0x4D, 0x3B, 0x69, 0x6D, 0x53, 0x70, + 0x7A, 0x15, 0x8F, 0xF5, 0xD3, 0x0E, 0x34, 0x28, + 0x18, 0x3A, 0x3B, 0x3A, 0x96, 0xA0, 0xE4, 0xA3, + 0x41, 0xA2, 0xA1, 0x6E, 0x5A, 0x62, 0x26, 0xAF, + 0x37, 0x4D, 0x1E, 0xFB, 0x39, 0xA3, 0x5D, 0xF6 + }; + ret = slhdsa_keygen_kat(SLHDSA_SHAKE256F, + sk_seed_shake_256f, (word32)sizeof(sk_seed_shake_256f), + sk_prf_shake_256f, (word32)sizeof(sk_prf_shake_256f), + pk_seed_shake_256f, (word32)sizeof(pk_seed_shake_256f), + expected_sk_shake_256f, (word32)sizeof(expected_sk_shake_256f), + expected_pk_shake_256f, (word32)sizeof(expected_pk_shake_256f)); + if (ret != 0) { + wc_test_render_error_message("SLHDSA_SHAKE256F keyGen KAT", 0); + goto out; + } + } +#endif + + /* --- SHA2 fast variant KeyGen KATs --- */ +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128F + { + /* NIST CAVP SLH-DSA-SHA2-128f keyGen vector (tgId=3, tcId=21) */ + static const byte sk_seed_sha2_128f[] = { + 0xC4, 0x2B, 0xCB, 0x3B, 0x5A, 0x6F, 0x33, 0x1F, + 0x5C, 0xCE, 0x89, 0x92, 0x53, 0xC6, 0xD9, 0xE2 + }; + static const byte sk_prf_sha2_128f[] = { + 0x9F, 0xF2, 0xB7, 0xEA, 0xD7, 0xA0, 0x4B, 0xAB, + 0x17, 0x94, 0xDB, 0x8C, 0xC6, 0x59, 0xC3, 0xB4 + }; + static const byte pk_seed_sha2_128f[] = { + 0xA8, 0x68, 0xF1, 0xBD, 0x5D, 0xEB, 0xC1, 0x2D, + 0x4C, 0x9F, 0xAD, 0x66, 0xAA, 0xBD, 0x0A, 0x94 + }; + static const byte expected_sk_sha2_128f[] = { + 0xC4, 0x2B, 0xCB, 0x3B, 0x5A, 0x6F, 0x33, 0x1F, + 0x5C, 0xCE, 0x89, 0x92, 0x53, 0xC6, 0xD9, 0xE2, + 0x9F, 0xF2, 0xB7, 0xEA, 0xD7, 0xA0, 0x4B, 0xAB, + 0x17, 0x94, 0xDB, 0x8C, 0xC6, 0x59, 0xC3, 0xB4, + 0xA8, 0x68, 0xF1, 0xBD, 0x5D, 0xEB, 0xC1, 0x2D, + 0x4C, 0x9F, 0xAD, 0x66, 0xAA, 0xBD, 0x0A, 0x94, + 0xB5, 0x46, 0xDF, 0x24, 0x7B, 0xE4, 0xC4, 0x57, + 0xF3, 0xD4, 0x67, 0xCD, 0xFC, 0xFA, 0xBD, 0x39 + }; + static const byte expected_pk_sha2_128f[] = { + 0xA8, 0x68, 0xF1, 0xBD, 0x5D, 0xEB, 0xC1, 0x2D, + 0x4C, 0x9F, 0xAD, 0x66, 0xAA, 0xBD, 0x0A, 0x94, + 0xB5, 0x46, 0xDF, 0x24, 0x7B, 0xE4, 0xC4, 0x57, + 0xF3, 0xD4, 0x67, 0xCD, 0xFC, 0xFA, 0xBD, 0x39 + }; + ret = slhdsa_keygen_kat(SLHDSA_SHA2_128F, + sk_seed_sha2_128f, (word32)sizeof(sk_seed_sha2_128f), + sk_prf_sha2_128f, (word32)sizeof(sk_prf_sha2_128f), + pk_seed_sha2_128f, (word32)sizeof(pk_seed_sha2_128f), + expected_sk_sha2_128f, (word32)sizeof(expected_sk_sha2_128f), + expected_pk_sha2_128f, (word32)sizeof(expected_pk_sha2_128f)); + if (ret != 0) { + wc_test_render_error_message("SLHDSA_SHA2_128F keyGen KAT", 0); + goto out; + } + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192F + { + /* NIST CAVP SLH-DSA-SHA2-192f keyGen vector (tgId=7, tcId=61) */ + static const byte sk_seed_sha2_192f[] = { + 0xA0, 0x21, 0xB4, 0xB9, 0xD6, 0xDE, 0xE1, 0x68, + 0x72, 0x2B, 0xC1, 0x02, 0x25, 0xE5, 0x0A, 0x94, + 0x66, 0x42, 0xAF, 0x63, 0x0C, 0x3C, 0x7C, 0x7D + }; + static const byte sk_prf_sha2_192f[] = { + 0x69, 0xE3, 0xA4, 0x0B, 0xA0, 0x9D, 0xF2, 0xAC, + 0x16, 0x5B, 0x79, 0x2A, 0x07, 0xF0, 0x64, 0xAC, + 0x5F, 0xC2, 0x8D, 0x8C, 0x99, 0xA5, 0x80, 0xF4 + }; + static const byte pk_seed_sha2_192f[] = { + 0xEE, 0x48, 0x23, 0xD0, 0x9E, 0x79, 0x85, 0x47, + 0x06, 0xDA, 0xA8, 0x0A, 0xE3, 0x17, 0x9B, 0x5B, + 0xC8, 0xC2, 0xE9, 0x40, 0x9D, 0x63, 0x28, 0xA3 + }; + static const byte expected_sk_sha2_192f[] = { + 0xA0, 0x21, 0xB4, 0xB9, 0xD6, 0xDE, 0xE1, 0x68, + 0x72, 0x2B, 0xC1, 0x02, 0x25, 0xE5, 0x0A, 0x94, + 0x66, 0x42, 0xAF, 0x63, 0x0C, 0x3C, 0x7C, 0x7D, + 0x69, 0xE3, 0xA4, 0x0B, 0xA0, 0x9D, 0xF2, 0xAC, + 0x16, 0x5B, 0x79, 0x2A, 0x07, 0xF0, 0x64, 0xAC, + 0x5F, 0xC2, 0x8D, 0x8C, 0x99, 0xA5, 0x80, 0xF4, + 0xEE, 0x48, 0x23, 0xD0, 0x9E, 0x79, 0x85, 0x47, + 0x06, 0xDA, 0xA8, 0x0A, 0xE3, 0x17, 0x9B, 0x5B, + 0xC8, 0xC2, 0xE9, 0x40, 0x9D, 0x63, 0x28, 0xA3, + 0x35, 0x77, 0xFD, 0x58, 0x4B, 0xC0, 0x78, 0x4C, + 0x55, 0x9C, 0xDB, 0x24, 0x37, 0xA4, 0x6F, 0x7F, + 0x75, 0x3C, 0x33, 0x63, 0x69, 0x41, 0x9A, 0xCF + }; + static const byte expected_pk_sha2_192f[] = { + 0xEE, 0x48, 0x23, 0xD0, 0x9E, 0x79, 0x85, 0x47, + 0x06, 0xDA, 0xA8, 0x0A, 0xE3, 0x17, 0x9B, 0x5B, + 0xC8, 0xC2, 0xE9, 0x40, 0x9D, 0x63, 0x28, 0xA3, + 0x35, 0x77, 0xFD, 0x58, 0x4B, 0xC0, 0x78, 0x4C, + 0x55, 0x9C, 0xDB, 0x24, 0x37, 0xA4, 0x6F, 0x7F, + 0x75, 0x3C, 0x33, 0x63, 0x69, 0x41, 0x9A, 0xCF + }; + ret = slhdsa_keygen_kat(SLHDSA_SHA2_192F, + sk_seed_sha2_192f, (word32)sizeof(sk_seed_sha2_192f), + sk_prf_sha2_192f, (word32)sizeof(sk_prf_sha2_192f), + pk_seed_sha2_192f, (word32)sizeof(pk_seed_sha2_192f), + expected_sk_sha2_192f, (word32)sizeof(expected_sk_sha2_192f), + expected_pk_sha2_192f, (word32)sizeof(expected_pk_sha2_192f)); + if (ret != 0) { + wc_test_render_error_message("SLHDSA_SHA2_192F keyGen KAT", 0); + goto out; + } + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256F + { + /* NIST CAVP SLH-DSA-SHA2-256f keyGen vector (tgId=11, tcId=101) */ + static const byte sk_seed_sha2_256f[] = { + 0x18, 0x52, 0x37, 0x02, 0xA0, 0xFE, 0x2C, 0x9E, + 0x48, 0x89, 0x48, 0xB1, 0x27, 0x18, 0x5B, 0xAB, + 0x93, 0xD3, 0xF0, 0x2C, 0x3D, 0x7C, 0x23, 0xA1, + 0xB3, 0x79, 0xF7, 0x62, 0xDE, 0x05, 0x09, 0xE5 + }; + static const byte sk_prf_sha2_256f[] = { + 0x6A, 0xB0, 0xD9, 0xF9, 0x35, 0x40, 0xBD, 0x80, + 0x9D, 0x1D, 0x2E, 0x8A, 0x05, 0x04, 0x40, 0xAA, + 0x81, 0xE8, 0x53, 0x75, 0x04, 0x70, 0xE2, 0xB0, + 0x0C, 0x95, 0x9D, 0xBD, 0x3B, 0xE4, 0x0E, 0x2B + }; + static const byte pk_seed_sha2_256f[] = { + 0xD7, 0x12, 0x5F, 0x5D, 0x00, 0xBA, 0x47, 0xF1, + 0xFC, 0x8D, 0x4C, 0x32, 0xC2, 0xF5, 0x7C, 0x44, + 0x4B, 0xD3, 0x84, 0xD7, 0xCE, 0x77, 0x0B, 0xC5, + 0x0D, 0xD5, 0x98, 0x0C, 0x1D, 0x12, 0x64, 0xD0 + }; + static const byte expected_sk_sha2_256f[] = { + 0x18, 0x52, 0x37, 0x02, 0xA0, 0xFE, 0x2C, 0x9E, + 0x48, 0x89, 0x48, 0xB1, 0x27, 0x18, 0x5B, 0xAB, + 0x93, 0xD3, 0xF0, 0x2C, 0x3D, 0x7C, 0x23, 0xA1, + 0xB3, 0x79, 0xF7, 0x62, 0xDE, 0x05, 0x09, 0xE5, + 0x6A, 0xB0, 0xD9, 0xF9, 0x35, 0x40, 0xBD, 0x80, + 0x9D, 0x1D, 0x2E, 0x8A, 0x05, 0x04, 0x40, 0xAA, + 0x81, 0xE8, 0x53, 0x75, 0x04, 0x70, 0xE2, 0xB0, + 0x0C, 0x95, 0x9D, 0xBD, 0x3B, 0xE4, 0x0E, 0x2B, + 0xD7, 0x12, 0x5F, 0x5D, 0x00, 0xBA, 0x47, 0xF1, + 0xFC, 0x8D, 0x4C, 0x32, 0xC2, 0xF5, 0x7C, 0x44, + 0x4B, 0xD3, 0x84, 0xD7, 0xCE, 0x77, 0x0B, 0xC5, + 0x0D, 0xD5, 0x98, 0x0C, 0x1D, 0x12, 0x64, 0xD0, + 0x0A, 0xD5, 0x19, 0x7F, 0xFC, 0xBA, 0xAF, 0xE1, + 0x1B, 0x1E, 0x41, 0x3F, 0x26, 0xAD, 0xB1, 0x50, + 0x4C, 0xE1, 0xC3, 0xF5, 0xC4, 0x0C, 0x1D, 0xCD, + 0xA1, 0x4E, 0x99, 0xFD, 0x12, 0x6D, 0x5B, 0x81 + }; + static const byte expected_pk_sha2_256f[] = { + 0xD7, 0x12, 0x5F, 0x5D, 0x00, 0xBA, 0x47, 0xF1, + 0xFC, 0x8D, 0x4C, 0x32, 0xC2, 0xF5, 0x7C, 0x44, + 0x4B, 0xD3, 0x84, 0xD7, 0xCE, 0x77, 0x0B, 0xC5, + 0x0D, 0xD5, 0x98, 0x0C, 0x1D, 0x12, 0x64, 0xD0, + 0x0A, 0xD5, 0x19, 0x7F, 0xFC, 0xBA, 0xAF, 0xE1, + 0x1B, 0x1E, 0x41, 0x3F, 0x26, 0xAD, 0xB1, 0x50, + 0x4C, 0xE1, 0xC3, 0xF5, 0xC4, 0x0C, 0x1D, 0xCD, + 0xA1, 0x4E, 0x99, 0xFD, 0x12, 0x6D, 0x5B, 0x81 + }; + ret = slhdsa_keygen_kat(SLHDSA_SHA2_256F, + sk_seed_sha2_256f, (word32)sizeof(sk_seed_sha2_256f), + sk_prf_sha2_256f, (word32)sizeof(sk_prf_sha2_256f), + pk_seed_sha2_256f, (word32)sizeof(pk_seed_sha2_256f), + expected_sk_sha2_256f, (word32)sizeof(expected_sk_sha2_256f), + expected_pk_sha2_256f, (word32)sizeof(expected_pk_sha2_256f)); + if (ret != 0) { + wc_test_render_error_message("SLHDSA_SHA2_256F keyGen KAT", 0); + goto out; + } + } +#endif +#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ + #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY #ifdef WOLFSSL_SLHDSA_PARAM_128S ret = slhdsa_test_param(SLHDSA_SHAKE128S); @@ -54942,6 +55878,48 @@ wc_test_ret_t slhdsa_test(void) goto out; } #endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128S + ret = slhdsa_test_param(SLHDSA_SHA2_128S); + if (ret != 0) { + wc_test_render_error_message("SLHDSA_SHA2_128S", 0); + goto out; + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128F + ret = slhdsa_test_param(SLHDSA_SHA2_128F); + if (ret != 0) { + wc_test_render_error_message("SLHDSA_SHA2_128F", 0); + goto out; + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192S + ret = slhdsa_test_param(SLHDSA_SHA2_192S); + if (ret != 0) { + wc_test_render_error_message("SLHDSA_SHA2_192S", 0); + goto out; + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192F + ret = slhdsa_test_param(SLHDSA_SHA2_192F); + if (ret != 0) { + wc_test_render_error_message("SLHDSA_SHA2_192F", 0); + goto out; + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256S + ret = slhdsa_test_param(SLHDSA_SHA2_256S); + if (ret != 0) { + wc_test_render_error_message("SLHDSA_SHA2_256S", 0); + goto out; + } +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256F + ret = slhdsa_test_param(SLHDSA_SHA2_256F); + if (ret != 0) { + wc_test_render_error_message("SLHDSA_SHA2_256F", 0); + goto out; + } +#endif #endif out: @@ -67022,7 +68000,7 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx) len = (word32)sizeof(seed); if (info->seed.sz < len) len = info->seed.sz; - XMEMCPY(info->seed.seed, seed, sizeof(seed)); + XMEMCPY(info->seed.seed, seed, len); info->seed.seed += len; info->seed.sz -= len; (*seedWord32)++; @@ -69544,7 +70522,10 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aes_siv_test(void) #else printf("Test Profile: Default (Aggressive multi-threaded)\n"); #endif - printf("Expected statistical false positive rate: ~%.2f failures\n", + printf("Current expected statistical false positive rate with ADP/RCT" + ": NONE\n"); + printf("Historical expected statistical false positive rate with " + "continuous test: ~%.2f failures\n", (double)total_iterations * 32.0 / 4294967296.0); for (i = 0; i < NUM_THREADS; i++) { diff --git a/wolfssl/wolfcrypt/aes.h b/wolfssl/wolfcrypt/aes.h index c64f8b658e..b01aa3b473 100644 --- a/wolfssl/wolfcrypt/aes.h +++ b/wolfssl/wolfcrypt/aes.h @@ -189,6 +189,12 @@ enum { #include #endif +/* Undefine the settings.h compat macro so it doesn't collide with the enum + * member below (settings.h may pre-define WC_AES_BLOCK_SIZE for old FIPS). */ +#ifdef WC_AES_BLOCK_SIZE + #undef WC_AES_BLOCK_SIZE +#endif + enum { AES_ENC_TYPE = WC_CIPHER_AES, /* cipher unique type */ AES_ENCRYPTION = 0, @@ -777,6 +783,7 @@ WOLFSSL_API int wc_AesInit_Label(Aes* aes, const char* label, void* heap, #endif WOLFSSL_API void wc_AesFree(Aes* aes); #ifndef WC_NO_CONSTRUCTORS +#define WC_AES_NEW_API_AVAILABLE WOLFSSL_API Aes* wc_AesNew(void* heap, int devId, int *result_code); #ifdef WOLF_PRIVATE_KEY_ID WOLFSSL_API Aes* wc_AesNew_Id(unsigned char* id, int len, void* heap, diff --git a/wolfssl/wolfcrypt/dilithium.h b/wolfssl/wolfcrypt/dilithium.h index 07eee8c6a4..71ae96ce68 100644 --- a/wolfssl/wolfcrypt/dilithium.h +++ b/wolfssl/wolfcrypt/dilithium.h @@ -856,6 +856,9 @@ WOLFSSL_API int wc_dilithium_sign_ctx_hash_with_seed(const byte* ctx, byte ctxLen, int hashAlg, const byte* hash, word32 hashLen, byte* sig, word32 *sigLen, dilithium_key* key, const byte* seed); +WOLFSSL_API +int wc_dilithium_sign_mu_with_seed(const byte* mu, word32 muLen, + byte* sig, word32 *sigLen, dilithium_key* key, const byte* seed); #endif /* !WOLFSSL_DILITHIUM_VERIFY_ONLY */ /* Legacy verify API without context parameter (pre-FIPS 204). * Only available when WOLFSSL_DILITHIUM_NO_CTX is defined. @@ -874,6 +877,9 @@ WOLFSSL_API int wc_dilithium_verify_ctx_hash(const byte* sig, word32 sigLen, const byte* ctx, byte ctxLen, int hashAlg, const byte* hash, word32 hashLen, int* res, dilithium_key* key); +WOLFSSL_API +int wc_dilithium_verify_mu(const byte* sig, word32 sigLen, const byte* mu, + word32 muLen, int* res, dilithium_key* key); #ifndef WC_NO_CONSTRUCTORS WOLFSSL_API diff --git a/wolfssl/wolfcrypt/error-crypt.h b/wolfssl/wolfcrypt/error-crypt.h index d17cfafd9f..8d49ffc18e 100644 --- a/wolfssl/wolfcrypt/error-crypt.h +++ b/wolfssl/wolfcrypt/error-crypt.h @@ -89,7 +89,7 @@ enum wolfCrypt_ErrorCodes { AES_EAX_AUTH_E = -122, /* AES-EAX Authentication check failure */ KEY_EXHAUSTED_E = -123, /* No longer usable for operation. */ - /* -124 unused. */ + ML_KEM_KAT_FIPS_E = -124, /* ML-KEM KAT failure */ MEMORY_E = -125, /* out of memory error */ VAR_STATE_CHANGE_E = -126, /* var state modified by different thread */ @@ -137,7 +137,9 @@ enum wolfCrypt_ErrorCodes { ED448_KAT_FIPS_E = -164, /* Ed448 Known answer test failure */ PBKDF2_KAT_FIPS_E = -165, /* PBKDF2 Known answer test failure */ WC_KEY_MISMATCH_E = -166, /* Error for private/public key mismatch */ - /* -167..-169 unused. */ + ML_DSA_KAT_FIPS_E = -167, /* ML-DSA KAT failure */ + LMS_KAT_FIPS_E = -168, /* LMS KAT failure */ + XMSS_KAT_FIPS_E = -169, /* XMSS KAT failure */ ECC_BAD_ARG_E = -170, /* ECC input argument of wrong type */ ASN_ECC_KEY_E = -171, /* ASN ECC bad input */ @@ -312,7 +314,6 @@ enum wolfCrypt_ErrorCodes { * not match stored hash*/ BUSY_E = -1006, /* Object is busy */ ALREADY_E = -1007, /* Operation was redundant or preempted */ - SEQ_OVERFLOW_E = -1008, /* Sequence counter would overflow */ PUF_INIT_E = -1009, /* PUF initialization failed (reserved) */ @@ -322,8 +323,13 @@ enum wolfCrypt_ErrorCodes { PUF_DERIVE_KEY_E = -1013, /* PUF key derivation failed */ PUF_IDENTITY_E = -1014, /* PUF identity retrieval failed */ - WC_SPAN2_LAST_E = -1014, /* Update to indicate last used error code */ - WC_LAST_E = -1014, /* the last code used either here or in + ML_KEM_PCT_E = -1015, /* ML-KEM Pairwise Consistency Test failure */ + ML_DSA_PCT_E = -1016, /* ML-DSA Pairwise Consistency Test failure */ + DRBG_SHA512_KAT_FIPS_E = -1017, /* SHA-512 DRBG KAT failure */ + SLH_DSA_KAT_FIPS_E = -1018, /* SLH-DSA CAST KAT failure */ + + WC_SPAN2_LAST_E = -1018, /* Update to indicate last used error code */ + WC_LAST_E = -1018, /* the last code used either here or in * error-ssl.h */ WC_SPAN2_MIN_CODE_E = -1999, /* Last usable code in span 2 */ diff --git a/wolfssl/wolfcrypt/fips_test.h b/wolfssl/wolfcrypt/fips_test.h index e4e8bf84d2..de2b506df2 100644 --- a/wolfssl/wolfcrypt/fips_test.h +++ b/wolfssl/wolfcrypt/fips_test.h @@ -74,7 +74,13 @@ enum FipsCastId { FIPS_CAST_PBKDF2 = 18, /* v7.0.0 + */ FIPS_CAST_AES_ECB = 19, - FIPS_CAST_COUNT = 20 + FIPS_CAST_ML_KEM = 20, + FIPS_CAST_ML_DSA = 21, + FIPS_CAST_LMS = 22, + FIPS_CAST_XMSS = 23, + FIPS_CAST_DRBG_SHA512 = 24, + FIPS_CAST_SLH_DSA = 25, + FIPS_CAST_COUNT = 26 }; enum FipsCastStateId { diff --git a/wolfssl/wolfcrypt/lms.h b/wolfssl/wolfcrypt/lms.h index 8ba69d98a3..19a7a0543c 100644 --- a/wolfssl/wolfcrypt/lms.h +++ b/wolfssl/wolfcrypt/lms.h @@ -118,6 +118,15 @@ enum wc_LmsParm { WC_LMS_PARM_L4_H5_W8 = 33, WC_LMS_PARM_L4_H10_W4 = 34, WC_LMS_PARM_L4_H10_W8 = 35, + /* H25 parameter sets for SHA-256/256 */ + WC_LMS_PARM_L1_H25_W1 = 56, + WC_LMS_PARM_L1_H25_W2 = 57, + WC_LMS_PARM_L1_H25_W4 = 58, + WC_LMS_PARM_L1_H25_W8 = 59, + /* W1 for non-H5 heights */ + WC_LMS_PARM_L1_H10_W1 = 60, + WC_LMS_PARM_L1_H15_W1 = 61, + WC_LMS_PARM_L1_H20_W1 = 62, #endif #ifdef WOLFSSL_LMS_SHA256_192 @@ -141,6 +150,61 @@ enum wc_LmsParm { WC_LMS_PARM_SHA256_192_L3_H5_W8 = 50, WC_LMS_PARM_SHA256_192_L3_H10_W4 = 51, WC_LMS_PARM_SHA256_192_L4_H5_W8 = 52, + /* H25 for SHA-256/192 */ + WC_LMS_PARM_SHA256_192_L1_H25_W1 = 63, + WC_LMS_PARM_SHA256_192_L1_H25_W2 = 64, + WC_LMS_PARM_SHA256_192_L1_H25_W4 = 65, + WC_LMS_PARM_SHA256_192_L1_H25_W8 = 66, + /* W1 for non-H5 heights (SHA-256/192) */ + WC_LMS_PARM_SHA256_192_L1_H10_W1 = 67, + WC_LMS_PARM_SHA256_192_L1_H15_W1 = 68, + WC_LMS_PARM_SHA256_192_L1_H20_W1 = 69, + WC_LMS_PARM_SHA256_192_L1_H15_W8 = 70, +#endif + +#ifdef WOLFSSL_LMS_SHAKE256 + /* SHAKE256/256, 32-byte output */ + WC_LMS_PARM_SHAKE_L1_H5_W1 = 100, + WC_LMS_PARM_SHAKE_L1_H5_W2 = 101, + WC_LMS_PARM_SHAKE_L1_H5_W4 = 102, + WC_LMS_PARM_SHAKE_L1_H5_W8 = 103, + WC_LMS_PARM_SHAKE_L1_H10_W1 = 104, + WC_LMS_PARM_SHAKE_L1_H10_W2 = 105, + WC_LMS_PARM_SHAKE_L1_H10_W4 = 106, + WC_LMS_PARM_SHAKE_L1_H10_W8 = 107, + WC_LMS_PARM_SHAKE_L1_H15_W1 = 108, + WC_LMS_PARM_SHAKE_L1_H15_W2 = 109, + WC_LMS_PARM_SHAKE_L1_H15_W4 = 110, + WC_LMS_PARM_SHAKE_L1_H15_W8 = 111, + WC_LMS_PARM_SHAKE_L1_H20_W1 = 112, + WC_LMS_PARM_SHAKE_L1_H20_W2 = 113, + WC_LMS_PARM_SHAKE_L1_H20_W4 = 114, + WC_LMS_PARM_SHAKE_L1_H20_W8 = 115, + WC_LMS_PARM_SHAKE_L1_H25_W1 = 116, + WC_LMS_PARM_SHAKE_L1_H25_W2 = 117, + WC_LMS_PARM_SHAKE_L1_H25_W4 = 118, + WC_LMS_PARM_SHAKE_L1_H25_W8 = 119, + /* SHAKE256/192, 24-byte output */ + WC_LMS_PARM_SHAKE192_L1_H5_W1 = 120, + WC_LMS_PARM_SHAKE192_L1_H5_W2 = 121, + WC_LMS_PARM_SHAKE192_L1_H5_W4 = 122, + WC_LMS_PARM_SHAKE192_L1_H5_W8 = 123, + WC_LMS_PARM_SHAKE192_L1_H10_W1 = 124, + WC_LMS_PARM_SHAKE192_L1_H10_W2 = 125, + WC_LMS_PARM_SHAKE192_L1_H10_W4 = 126, + WC_LMS_PARM_SHAKE192_L1_H10_W8 = 127, + WC_LMS_PARM_SHAKE192_L1_H15_W1 = 128, + WC_LMS_PARM_SHAKE192_L1_H15_W2 = 129, + WC_LMS_PARM_SHAKE192_L1_H15_W4 = 130, + WC_LMS_PARM_SHAKE192_L1_H15_W8 = 131, + WC_LMS_PARM_SHAKE192_L1_H20_W1 = 132, + WC_LMS_PARM_SHAKE192_L1_H20_W2 = 133, + WC_LMS_PARM_SHAKE192_L1_H20_W4 = 134, + WC_LMS_PARM_SHAKE192_L1_H20_W8 = 135, + WC_LMS_PARM_SHAKE192_L1_H25_W1 = 136, + WC_LMS_PARM_SHAKE192_L1_H25_W2 = 137, + WC_LMS_PARM_SHAKE192_L1_H25_W4 = 138, + WC_LMS_PARM_SHAKE192_L1_H25_W8 = 139, #endif }; diff --git a/wolfssl/wolfcrypt/random.h b/wolfssl/wolfcrypt/random.h index db7d58a97e..afc5994191 100644 --- a/wolfssl/wolfcrypt/random.h +++ b/wolfssl/wolfcrypt/random.h @@ -52,11 +52,15 @@ #endif #endif -/* Size of the BRBG seed */ +/* Size of the DRBG seed (SHA-256) */ #ifndef DRBG_SEED_LEN #define DRBG_SEED_LEN (440/8) #endif +#ifdef WOLFSSL_DRBG_SHA512 + #define DRBG_SHA512_SEED_LEN (888/8) /* 111 bytes per SP 800-90A Table 2 */ +#endif + #if !defined(CUSTOM_RAND_TYPE) /* To maintain compatibility the default is byte */ @@ -104,9 +108,16 @@ #endif #elif defined(HAVE_HASHDRBG) #ifdef NO_SHA256 - #error "Hash DRBG requires SHA-256." + #ifndef WOLFSSL_DRBG_SHA512 + #error "Hash DRBG requires SHA-256 or SHA-512." + #endif #endif /* NO_SHA256 */ - #include + #ifndef NO_SHA256 + #include + #endif + #ifdef WOLFSSL_DRBG_SHA512 + #include + #endif #elif defined(HAVE_WNR) /* allow whitewood as direct RNG source using wc_GenerateSeed directly */ #elif defined(HAVE_INTEL_RDRAND) @@ -141,8 +152,11 @@ #endif #endif -#ifndef WC_RNG_TYPE_DEFINED /* guard on redeclaration */ +#ifndef WC_OS_SEED_TYPE_DEFINED typedef struct OS_Seed OS_Seed; + #define WC_OS_SEED_TYPE_DEFINED +#endif +#ifndef WC_RNG_TYPE_DEFINED /* guard on redeclaration */ typedef struct WC_RNG WC_RNG; #ifdef WC_RNG_SEED_CB typedef int (*wc_RngSeed_Cb)(OS_Seed* os, byte* seed, word32 sz); @@ -239,7 +253,33 @@ struct OS_Seed { #define WC_DRBG_SEED_BLOCK_SZ SEED_BLOCK_SZ -#define WC_DRBG_SEED_SZ (RNG_SECURITY_STRENGTH*ENTROPY_SCALE_FACTOR/8) +/* WC_DRBG_SEED_SZ is the number of bytes of raw entropy gathered from the + * NDRNG at instantiation and reseed. We deliberately "overseed" beyond the + * NIST minimum (security_strength bits) to account for entropy sources that + * may deliver fewer than 1 bit of real entropy per bit of output. With the + * default FIPS ENTROPY_SCALE_FACTOR of 4 this yields 256*4/8 = 128 bytes = + * 1024 bits of raw seed material, guaranteeing at least 256 bits of real + * entropy even if the source provides only 1 good bit per 4. + * + * Hash_df then compresses this seed material into the internal V and C state + * vectors (seedlen = 440 bits for SHA-256, 888 bits for SHA-512 per + * SP 800-90A Table 2). + * + * In FIPS mode (ENTROPY_SCALE_FACTOR >= 4) the base is already >= 128 bytes + * which exceeds DRBG_SHA512_SEED_LEN (111), so both DRBGs use the same + * seed size. In non-FIPS mode we use the base for both DRBGs so that + * enabling SHA-512 DRBG does not inflate the per-init entropy cost. + * SP 800-90A requires only security_strength bits (256 = 32 bytes) of + * entropy regardless of hash size; hash_df compresses the seed material + * into the internal V/C state vectors. */ +#define WC_DRBG_SEED_SZ_BASE (RNG_SECURITY_STRENGTH*ENTROPY_SCALE_FACTOR/8) + +#if defined(HAVE_FIPS) && defined(WOLFSSL_DRBG_SHA512) && \ + (WC_DRBG_SEED_SZ_BASE < DRBG_SHA512_SEED_LEN) + #define WC_DRBG_SEED_SZ DRBG_SHA512_SEED_LEN +#else + #define WC_DRBG_SEED_SZ WC_DRBG_SEED_SZ_BASE +#endif /* The maximum seed size will be the seed size plus a seed block for the * test, and an additional half of the seed size. This additional half @@ -248,8 +288,14 @@ struct OS_Seed { #define WC_DRBG_MAX_SEED_SZ (WC_DRBG_SEED_SZ + WC_DRBG_SEED_SZ/2 + \ SEED_BLOCK_SZ) -#define RNG_HEALTH_TEST_CHECK_SIZE (WC_SHA256_DIGEST_SIZE * 4) +#ifndef NO_SHA256 + #define RNG_HEALTH_TEST_CHECK_SIZE (WC_SHA256_DIGEST_SIZE * 4) +#endif +#ifdef WOLFSSL_DRBG_SHA512 + #define RNG_HEALTH_TEST_CHECK_SIZE_SHA512 (WC_SHA512_DIGEST_SIZE * 4) +#endif +#ifndef NO_SHA256 struct DRBG_internal { #ifdef WORD64_AVAILABLE word64 reseedCtr; @@ -268,8 +314,34 @@ struct DRBG_internal { byte digest_scratch[WC_SHA256_DIGEST_SIZE]; #endif }; +#endif /* !NO_SHA256 */ + +#ifdef WOLFSSL_DRBG_SHA512 +struct DRBG_SHA512_internal { + word64 reseedCtr; + byte V[DRBG_SHA512_SEED_LEN]; + byte C[DRBG_SHA512_SEED_LEN]; + void* heap; +#if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB) + int devId; +#endif +#ifdef WOLFSSL_SMALL_STACK_CACHE + wc_Sha512 sha512; + byte seed_scratch[DRBG_SHA512_SEED_LEN]; + byte digest_scratch[WC_SHA512_DIGEST_SIZE]; +#endif +}; +#endif /* WOLFSSL_DRBG_SHA512 */ #endif /* HAVE_HASHDRBG */ +/* DRBG type enum */ +#ifdef HAVE_HASHDRBG +enum wc_DrbgType { + WC_DRBG_SHA256 = 0, + WC_DRBG_SHA512 = 1, +}; +#endif + /* RNG health states */ #define WC_DRBG_NOT_INIT 0 #define WC_DRBG_OK 1 @@ -301,17 +373,35 @@ struct WC_RNG { #ifdef HAVE_ANONYMOUS_INLINE_AGGREGATES struct { #endif - /* Hash-based Deterministic Random Bit Generator */ + #ifndef NO_SHA256 + /* SHA-256 Hash-based Deterministic Random Bit Generator */ struct DRBG* drbg; #if defined(WOLFSSL_NO_MALLOC) && !defined(WOLFSSL_STATIC_MEMORY) struct DRBG_internal drbg_data; #endif #ifdef WOLFSSL_SMALL_STACK_CACHE - /* Scratch buffers -- all preallocated by _InitRng(). */ + /* SHA-256 scratch buffers -- preallocated by _InitRng(). */ struct DRBG_internal *drbg_scratch; byte *health_check_scratch; + #endif + #endif /* !NO_SHA256 */ + #ifdef WOLFSSL_SMALL_STACK_CACHE + /* Seed buffer for PollAndReSeed -- shared by both DRBG types */ byte *newSeed_buf; #endif + #ifdef WOLFSSL_DRBG_SHA512 + /* SHA-512 Hash-based Deterministic Random Bit Generator */ + struct DRBG_SHA512* drbg512; + #if defined(WOLFSSL_NO_MALLOC) && !defined(WOLFSSL_STATIC_MEMORY) + struct DRBG_SHA512_internal drbg512_data; + #endif + #ifdef WOLFSSL_SMALL_STACK_CACHE + /* SHA-512 scratch buffers -- preallocated by _InitRng(). */ + struct DRBG_SHA512_internal *drbg512_scratch; + byte *health_check_scratch_512; + #endif + #endif /* WOLFSSL_DRBG_SHA512 */ + byte drbgType; /* WC_DRBG_SHA256 or WC_DRBG_SHA512 */ #ifdef HAVE_ANONYMOUS_INLINE_AGGREGATES }; #endif @@ -397,6 +487,10 @@ WOLFSSL_API int wc_FreeRng(WC_RNG* rng); WOLFSSL_API int wc_RNG_DRBG_Reseed(WC_RNG* rng, const byte* seed, word32 seedSz); WOLFSSL_API int wc_RNG_TestSeed(const byte* seed, word32 seedSz); +#ifndef NO_SHA256 + /* SHA-256 Hash_DRBG health test entry points. SHA-512-only builds + * (NO_SHA256 + WOLFSSL_DRBG_SHA512) use wc_RNG_HealthTest_SHA512_ex + * declared below. */ WOLFSSL_API int wc_RNG_HealthTest(int reseed, const byte* seedA, word32 seedASz, const byte* seedB, word32 seedBSz, @@ -407,6 +501,98 @@ WOLFSSL_API int wc_FreeRng(WC_RNG* rng); const byte* seedB, word32 seedBSz, byte* output, word32 outputSz, void* heap, int devId); +#endif /* !NO_SHA256 */ +#if !defined(NO_SHA256) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + /* Extended SHA-256 Hash_DRBG health test per SP 800-90A. + * Flexible output size, prediction resistance, personalization + * strings, and additional input support. */ + WOLFSSL_API int wc_RNG_HealthTest_SHA256_ex( + int predResistance, + const byte* nonce, word32 nonceSz, + const byte* persoString, + word32 persoStringSz, + const byte* entropyA, + word32 entropyASz, + const byte* entropyB, + word32 entropyBSz, + const byte* entropyC, + word32 entropyCsz, + const byte* additionalA, + word32 additionalASz, + const byte* additionalB, + word32 additionalBSz, + const byte* additionalReseed, + word32 additionalReseedSz, + byte* output, word32 outputSz, + void* heap, int devId); +#endif /* !NO_SHA256 && !HAVE_SELFTEST && FIPS v7+ */ +#if defined(WOLFSSL_DRBG_SHA512) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + WOLFSSL_API int wc_RNG_HealthTest_SHA512(int reseed, + const byte* seedA, word32 seedASz, + const byte* seedB, word32 seedBSz, + byte* output, word32 outputSz); + WOLFSSL_API int wc_RNG_HealthTest_SHA512_ex(int reseed, + const byte* nonce, word32 nonceSz, + const byte* persoString, + word32 persoStringSz, + const byte* seedA, word32 seedASz, + const byte* seedB, word32 seedBSz, + const byte* additionalA, + word32 additionalASz, + const byte* additionalB, + word32 additionalBSz, + byte* output, word32 outputSz, + void* heap, int devId); + /* Extended SHA-512 Hash_DRBG health test per SP 800-90A. + * Flexible output size, prediction resistance support. + * predResistance=1: additionalA/B go to Reseed per SP 800-90A 9.3.1, + * Generate gets NULL additional input. + * predResistance=0: additionalReseed goes to Reseed, additionalA/B go + * to Generate calls 1 and 2 respectively. */ + WOLFSSL_API int wc_RNG_HealthTest_SHA512_ex2( + int predResistance, + const byte* nonce, word32 nonceSz, + const byte* persoString, + word32 persoStringSz, + const byte* entropyA, + word32 entropyASz, + const byte* entropyB, + word32 entropyBSz, + const byte* entropyC, + word32 entropyCsz, + const byte* additionalA, + word32 additionalASz, + const byte* additionalB, + word32 additionalBSz, + const byte* additionalReseed, + word32 additionalReseedSz, + byte* output, word32 outputSz, + void* heap, int devId); +#endif /* WOLFSSL_DRBG_SHA512 && !HAVE_SELFTEST && FIPS v7+ */ + + /* Runtime DRBG disable/enable API */ +#if !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + WOLFSSL_API int wc_Sha256Drbg_Disable(void); + WOLFSSL_API int wc_Sha256Drbg_Enable(void); + WOLFSSL_API int wc_Sha256Drbg_IsDisabled(void); +#ifdef WOLFSSL_DRBG_SHA512 + WOLFSSL_API int wc_Sha512Drbg_Disable(void); + WOLFSSL_API int wc_Sha512Drbg_Enable(void); + WOLFSSL_API int wc_Sha512Drbg_IsDisabled(void); +#endif +#endif /* !HAVE_SELFTEST && (!HAVE_FIPS || FIPS v7+) */ + + /* DRBG state mutex init/free, called from wolfCrypt_Init/Cleanup. + * Only in v7+ or non-FIPS/non-selftest; older modules lack these. */ +#if !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) + WOLFSSL_LOCAL int wc_DrbgState_MutexInit(void); + WOLFSSL_LOCAL int wc_DrbgState_MutexFree(void); +#endif + #endif /* HAVE_HASHDRBG */ #ifdef __cplusplus diff --git a/wolfssl/wolfcrypt/rsa.h b/wolfssl/wolfcrypt/rsa.h index 09084091dd..8c48fe9e8d 100644 --- a/wolfssl/wolfcrypt/rsa.h +++ b/wolfssl/wolfcrypt/rsa.h @@ -299,6 +299,7 @@ WOLFSSL_API int wc_InitRsaKey(RsaKey* key, void* heap); WOLFSSL_API int wc_InitRsaKey_ex(RsaKey* key, void* heap, int devId); WOLFSSL_API int wc_FreeRsaKey(RsaKey* key); #ifndef WC_NO_CONSTRUCTORS +#define WC_RSA_NEW_API_AVAILABLE WOLFSSL_API RsaKey* wc_NewRsaKey(void* heap, int devId, int *result_code); #ifdef WOLF_PRIVATE_KEY_ID WOLFSSL_API RsaKey* wc_NewRsaKey_Id(unsigned char* id, int len, void* heap, @@ -432,6 +433,14 @@ WOLFSSL_API int wc_RsaPublicKeyDecodeRaw(const byte* n, word32 nSz, #define WC_MGF1SHA512 3 #define WC_MGF1SHA512_224 5 #define WC_MGF1SHA512_256 6 +#define WC_MGF1SHA3_224 7 +#define WC_MGF1SHA3_256 8 +#define WC_MGF1SHA3_384 9 +#define WC_MGF1SHA3_512 10 +#define WC_MGF1SHAKE128 11 +#define WC_MGF1SHAKE256 12 +#define WC_MGFSHAKE128 13 +#define WC_MGFSHAKE256 14 /* Padding types */ #define WC_RSA_PKCSV15_PAD 0 diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 63b66d92cd..2eb3f52f06 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -513,7 +513,7 @@ /* old FIPS has only AES_BLOCK_SIZE. */ #if !defined(NO_AES) && (defined(HAVE_SELFTEST) || \ (defined(HAVE_FIPS) && FIPS_VERSION3_LT(6,0,0))) - #define WC_AES_BLOCK_SIZE AES_BLOCK_SIZE + #define WC_AES_BLOCK_SIZE 16 #endif /* !NO_AES && (HAVE_SELFTEST || FIPS_VERSION3_LT(6,0,0)) */ #ifdef WOLFSSL_HARDEN_TLS diff --git a/wolfssl/wolfcrypt/wc_lms.h b/wolfssl/wolfcrypt/wc_lms.h index 914ffa1371..34f77279a0 100644 --- a/wolfssl/wolfcrypt/wc_lms.h +++ b/wolfssl/wolfcrypt/wc_lms.h @@ -94,6 +94,9 @@ #include #include +#ifdef WOLFSSL_LMS_SHAKE256 +#include +#endif /* When raw hash access APIs are disabled or unavailable (WOLFSSL_NO_HASH_RAW), * fall back to using the full hash API calls. */ @@ -122,10 +125,10 @@ #define LMS_MAX_HEIGHT WOLFSSL_LMS_MAX_HEIGHT #else /* Maximum height of a tree supported by implementation. */ - #define LMS_MAX_HEIGHT 20 + #define LMS_MAX_HEIGHT 25 #endif -#if (LMS_MAX_HEIGHT < 5) || (LMS_MAX_HEIGHT > 20) - #error "LMS parameters only support heights 5-20." +#if (LMS_MAX_HEIGHT < 5) || (LMS_MAX_HEIGHT > 25) + #error "LMS parameters only support heights 5-25." #endif /* Length of I in bytes. */ @@ -312,10 +315,16 @@ #define LMS_SHA256 0x0000 /* Indicates using SHA-256/192 for hashing. */ #define LMS_SHA256_192 0x1000 +/* Indicates using SHAKE256/256 for hashing. */ +#define LMS_SHAKE256 0x2000 +/* Indicates using SHAKE256/192 for hashing. */ +#define LMS_SHAKE256_192 0x3000 /* Mask to get hashing algorithm from type. */ #define LMS_HASH_MASK 0xf000 /* Mask to get height or Winternitz width from type. */ #define LMS_H_W_MASK 0x0fff +/* Bit test: non-zero if type uses SHAKE256. */ +#define LMS_IS_SHAKE(type) (((type) & 0x2000) != 0) /* LMS Parameters. */ /* SHA-256 hash, 32-bytes of hash used, tree height of 5. */ @@ -349,15 +358,55 @@ /* SHA-256 hash, 32-bytes of hash used, tree height of 25. */ #define LMS_SHA256_M24_H25 (0x0e | LMS_SHA256_192) -/* SHA-256 hash, 32-bytes of hash used, Winternitz width of 1 bit. */ +/* SHA-256 hash, 24-bytes of hash used, Winternitz width of 1 bit. */ #define LMOTS_SHA256_N24_W1 (0x05 | LMS_SHA256_192) -/* SHA-256 hash, 32-bytes of hash used, Winternitz width of 2 bits. */ +/* SHA-256 hash, 24-bytes of hash used, Winternitz width of 2 bits. */ #define LMOTS_SHA256_N24_W2 (0x06 | LMS_SHA256_192) -/* SHA-256 hash, 32-bytes of hash used, Winternitz width of 4 bits. */ +/* SHA-256 hash, 24-bytes of hash used, Winternitz width of 4 bits. */ #define LMOTS_SHA256_N24_W4 (0x07 | LMS_SHA256_192) -/* SHA-256 hash, 32-bytes of hash used, Winternitz width of 8 bits. */ +/* SHA-256 hash, 24-bytes of hash used, Winternitz width of 8 bits. */ #define LMOTS_SHA256_N24_W8 (0x08 | LMS_SHA256_192) +/* SHAKE256 hash, 32-bytes of hash used, tree height of 5. */ +#define LMS_SHAKE_M32_H5 (0x0f | LMS_SHAKE256) +/* SHAKE256 hash, 32-bytes of hash used, tree height of 10. */ +#define LMS_SHAKE_M32_H10 (0x10 | LMS_SHAKE256) +/* SHAKE256 hash, 32-bytes of hash used, tree height of 15. */ +#define LMS_SHAKE_M32_H15 (0x11 | LMS_SHAKE256) +/* SHAKE256 hash, 32-bytes of hash used, tree height of 20. */ +#define LMS_SHAKE_M32_H20 (0x12 | LMS_SHAKE256) +/* SHAKE256 hash, 32-bytes of hash used, tree height of 25. */ +#define LMS_SHAKE_M32_H25 (0x13 | LMS_SHAKE256) + +/* SHAKE256 hash, 32-bytes of hash used, Winternitz width of 1 bit. */ +#define LMOTS_SHAKE_N32_W1 (0x09 | LMS_SHAKE256) +/* SHAKE256 hash, 32-bytes of hash used, Winternitz width of 2 bits. */ +#define LMOTS_SHAKE_N32_W2 (0x0a | LMS_SHAKE256) +/* SHAKE256 hash, 32-bytes of hash used, Winternitz width of 4 bits. */ +#define LMOTS_SHAKE_N32_W4 (0x0b | LMS_SHAKE256) +/* SHAKE256 hash, 32-bytes of hash used, Winternitz width of 8 bits. */ +#define LMOTS_SHAKE_N32_W8 (0x0c | LMS_SHAKE256) + +/* SHAKE256 hash, 24-bytes of hash used, tree height of 5. */ +#define LMS_SHAKE_M24_H5 (0x14 | LMS_SHAKE256_192) +/* SHAKE256 hash, 24-bytes of hash used, tree height of 10. */ +#define LMS_SHAKE_M24_H10 (0x15 | LMS_SHAKE256_192) +/* SHAKE256 hash, 24-bytes of hash used, tree height of 15. */ +#define LMS_SHAKE_M24_H15 (0x16 | LMS_SHAKE256_192) +/* SHAKE256 hash, 24-bytes of hash used, tree height of 20. */ +#define LMS_SHAKE_M24_H20 (0x17 | LMS_SHAKE256_192) +/* SHAKE256 hash, 24-bytes of hash used, tree height of 25. */ +#define LMS_SHAKE_M24_H25 (0x18 | LMS_SHAKE256_192) + +/* SHAKE256 hash, 24-bytes of hash used, Winternitz width of 1 bit. */ +#define LMOTS_SHAKE_N24_W1 (0x0d | LMS_SHAKE256_192) +/* SHAKE256 hash, 24-bytes of hash used, Winternitz width of 2 bits. */ +#define LMOTS_SHAKE_N24_W2 (0x0e | LMS_SHAKE256_192) +/* SHAKE256 hash, 24-bytes of hash used, Winternitz width of 4 bits. */ +#define LMOTS_SHAKE_N24_W4 (0x0f | LMS_SHAKE256_192) +/* SHAKE256 hash, 24-bytes of hash used, Winternitz width of 8 bits. */ +#define LMOTS_SHAKE_N24_W8 (0x10 | LMS_SHAKE256_192) + typedef struct LmsParams { /* Number of tree levels. */ word8 levels; @@ -408,12 +457,43 @@ typedef struct LmsState { #endif /* LMS parameters. */ const LmsParams* params; - /* Hash algorithm. */ +#ifdef WOLFSSL_LMS_SHAKE256 + /* The LMS instance uses exactly one hash family at a time, selected at + * init time by params->lmOtsType (see wc_lms.c LMS_IS_SHAKE dispatch). + * The two contexts are unionized to shrink LmsState; access via the + * LMS_STATE_HASH / LMS_STATE_SHAKE macros below. Anonymous unions + * would avoid the macros but require C11 (HAVE_ANONYMOUS_INLINE_AGGREGATES) + * gating that ends up uglier than the named form here. */ + union { + wc_Sha256 sha256; + wc_Shake shake; + } hash; + union { + wc_Sha256 sha256; + wc_Shake shake; + } hash_k; +#else + /* Hash algorithm (SHA-256). */ wc_Sha256 hash; - /* Hash algorithm for calculating K. */ + /* Hash algorithm for calculating K (SHA-256). */ wc_Sha256 hash_k; +#endif } LmsState; +/* Access macros for the LmsState hash contexts. All call sites use the + * address-of form, so the macros yield pointers directly. In the + * SHAKE-disabled build the SHAKE macros are intentionally undefined -- + * the only callers are themselves under #ifdef WOLFSSL_LMS_SHAKE256. */ +#ifdef WOLFSSL_LMS_SHAKE256 + #define LMS_STATE_HASH(state) (&(state)->hash.sha256) + #define LMS_STATE_HASH_K(state) (&(state)->hash_k.sha256) + #define LMS_STATE_SHAKE(state) (&(state)->hash.shake) + #define LMS_STATE_SHAKE_K(state) (&(state)->hash_k.shake) +#else + #define LMS_STATE_HASH(state) (&(state)->hash) + #define LMS_STATE_HASH_K(state) (&(state)->hash_k) +#endif + #ifndef WOLFSSL_WC_LMS_SMALL /* Stack of interior node hashes. */ typedef struct LmsStack { @@ -504,8 +584,9 @@ int wc_hss_reload_key(LmsState* state, const byte* priv_raw, int wc_hss_sign(LmsState* state, byte* priv_raw, HssPrivKey* priv_key, byte* priv_data, const byte* msg, word32 msgSz, byte* sig); int wc_hss_sigsleft(const LmsParams* params, const byte* priv_raw); +WOLFSSL_API int wc_hss_verify(LmsState* state, const byte* pub, const byte* msg, - word32 msgSz, const byte* sig); + word32 msgSz, const byte* sig, word32 sigSz); #endif /* WOLFSSL_HAVE_LMS && WOLFSSL_WC_LMS */ diff --git a/wolfssl/wolfcrypt/wc_slhdsa.h b/wolfssl/wolfcrypt/wc_slhdsa.h index 19ee86fbb2..7153143d27 100644 --- a/wolfssl/wolfcrypt/wc_slhdsa.h +++ b/wolfssl/wolfcrypt/wc_slhdsa.h @@ -26,8 +26,20 @@ #include #include +#ifdef WOLFSSL_SLHDSA_SHA2 + #include + #include + #include +#endif + +#if FIPS_VERSION3_GE(7,0,0) + #include +#endif + #ifdef WOLFSSL_HAVE_SLHDSA +/* ======== SHAKE parameter guards ======== */ + /* When a bits/opt is defined then ensure 'NO' defines are off. */ #ifdef WOLFSSL_SLHDSA_PARAM_128S #undef WOLFSSL_SLHDSA_PARAM_NO_128S @@ -155,12 +167,159 @@ #define WOLFSSL_SLHDSA_PARAM_NO_256 #endif +/* ======== SHA2 parameter guards ======== */ +#ifdef WOLFSSL_SLHDSA_SHA2 + +/* When a SHA2 param is defined, ensure 'NO' defines are off. */ +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128S + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_128S + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_128 + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128F + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_128F + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_128 + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192S + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_192S + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_192 + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192F + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_192F + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_192 + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256S + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_256S + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_256 + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256F + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_256F + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_256 + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST +#endif + +/* Derive aggregate 'NO' defines for SHA2. */ +#if defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128S) && \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128F) + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_128 + #define WOLFSSL_SLHDSA_PARAM_NO_SHA2_128 +#endif +#if defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192S) && \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192F) + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_192 + #define WOLFSSL_SLHDSA_PARAM_NO_SHA2_192 +#endif +#if defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256S) && \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256F) + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_256 + #define WOLFSSL_SLHDSA_PARAM_NO_SHA2_256 +#endif +#if defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128S) && \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192S) && \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256S) + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL + #define WOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL +#endif +#if defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128F) && \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192F) && \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256F) + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST + #define WOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST +#endif + +/* Turn on SHA2 parameter set based on 'NO' defines. */ +#if !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128S) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL) + #undef WOLFSSL_SLHDSA_PARAM_SHA2_128S + #define WOLFSSL_SLHDSA_PARAM_SHA2_128S +#endif +#if !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128F) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST) + #undef WOLFSSL_SLHDSA_PARAM_SHA2_128F + #define WOLFSSL_SLHDSA_PARAM_SHA2_128F +#endif +#if !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192S) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL) + #undef WOLFSSL_SLHDSA_PARAM_SHA2_192S + #define WOLFSSL_SLHDSA_PARAM_SHA2_192S +#endif +#if !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192F) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST) + #undef WOLFSSL_SLHDSA_PARAM_SHA2_192F + #define WOLFSSL_SLHDSA_PARAM_SHA2_192F +#endif +#if !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256S) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL) + #undef WOLFSSL_SLHDSA_PARAM_SHA2_256S + #define WOLFSSL_SLHDSA_PARAM_SHA2_256S +#endif +#if !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256F) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST) + #undef WOLFSSL_SLHDSA_PARAM_SHA2_256F + #define WOLFSSL_SLHDSA_PARAM_SHA2_256F +#endif + +/* Re-derive aggregate NOs for SHA2. */ +#if defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128S) && \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192S) && \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256S) + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL + #define WOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL +#endif +#if defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128F) && \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192F) && \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256F) + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST + #define WOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST +#endif +#if defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128S) && \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128F) + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_128 + #define WOLFSSL_SLHDSA_PARAM_NO_SHA2_128 +#endif +#if defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192S) && \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192F) + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_192 + #define WOLFSSL_SLHDSA_PARAM_NO_SHA2_192 +#endif +#if defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256S) && \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256F) + #undef WOLFSSL_SLHDSA_PARAM_NO_SHA2_256 + #define WOLFSSL_SLHDSA_PARAM_NO_SHA2_256 +#endif + +#endif /* WOLFSSL_SLHDSA_SHA2 */ + +/* ======== Security parameter (n) per FIPS 205 Table 2 ======== */ + +/* Security parameter n, in bytes. SLH-DSA seed length, public key half, + * and other primitive sizes are derived from n. The SHA2 hash dispatch + * also keys off n: n = 128 uses SHA-256, n = 192/256 use SHA-512. */ +/* Category 1, 128-bit classical security. */ +#define WC_SLHDSA_N_128 16 +/* Category 3, 192-bit classical security. */ +#define WC_SLHDSA_N_192 24 +/* Category 5, 256-bit classical security. */ +#define WC_SLHDSA_N_256 32 + +/* ======== SHAKE size defines ======== */ + /* Seed length for SLH-DSA SHAKE-128s/f. */ -#define WC_SLHDSA_SHAKE128_SEED_LEN 16 +#define WC_SLHDSA_SHAKE128_SEED_LEN WC_SLHDSA_N_128 /* Seed length for SLH-DSA SHAKE-192s/f. */ -#define WC_SLHDSA_SHAKE192_SEED_LEN 24 +#define WC_SLHDSA_SHAKE192_SEED_LEN WC_SLHDSA_N_192 /* Seed length for SLH-DSA SHAKE-256s/f. */ -#define WC_SLHDSA_SHAKE256_SEED_LEN 32 +#define WC_SLHDSA_SHAKE256_SEED_LEN WC_SLHDSA_N_256 /* Private key length for SLH-DSA SHAKE-128s. */ #define WC_SLHDSA_SHAKE128S_PRIV_LEN (4 * 16) @@ -216,8 +375,76 @@ /* Seed length for SLH-DSA SHAKE-256f. */ #define WC_SLHDSA_SHAKE256F_SEED_LEN WC_SLHDSA_SHAKE256_SEED_LEN -/* Determine maximum private and public key lengths based on maximum SHAKE-256 - * output length. */ +/* ======== SHA2 size defines ======== */ +#ifdef WOLFSSL_SLHDSA_SHA2 + +/* Seed length for SLH-DSA SHA2-128s/f. */ +#define WC_SLHDSA_SHA2_128_SEED_LEN WC_SLHDSA_N_128 +/* Seed length for SLH-DSA SHA2-192s/f. */ +#define WC_SLHDSA_SHA2_192_SEED_LEN WC_SLHDSA_N_192 +/* Seed length for SLH-DSA SHA2-256s/f. */ +#define WC_SLHDSA_SHA2_256_SEED_LEN WC_SLHDSA_N_256 + +/* Private key length for SLH-DSA SHA2-128s. */ +#define WC_SLHDSA_SHA2_128S_PRIV_LEN (4 * 16) +/* Public key length for SLH-DSA SHA2-128s. */ +#define WC_SLHDSA_SHA2_128S_PUB_LEN (2 * 16) +/* Signature length for SLH-DSA SHA2-128s. */ +#define WC_SLHDSA_SHA2_128S_SIG_LEN 7856 +/* Seed length for SLH-DSA SHA2-128s. */ +#define WC_SLHDSA_SHA2_128S_SEED_LEN WC_SLHDSA_SHA2_128_SEED_LEN + +/* Private key length for SLH-DSA SHA2-128f. */ +#define WC_SLHDSA_SHA2_128F_PRIV_LEN (4 * 16) +/* Public key length for SLH-DSA SHA2-128f. */ +#define WC_SLHDSA_SHA2_128F_PUB_LEN (2 * 16) +/* Signature length for SLH-DSA SHA2-128f. */ +#define WC_SLHDSA_SHA2_128F_SIG_LEN 17088 +/* Seed length for SLH-DSA SHA2-128f. */ +#define WC_SLHDSA_SHA2_128F_SEED_LEN WC_SLHDSA_SHA2_128_SEED_LEN + +/* Private key length for SLH-DSA SHA2-192s. */ +#define WC_SLHDSA_SHA2_192S_PRIV_LEN (4 * 24) +/* Public key length for SLH-DSA SHA2-192s. */ +#define WC_SLHDSA_SHA2_192S_PUB_LEN (2 * 24) +/* Signature length for SLH-DSA SHA2-192s. */ +#define WC_SLHDSA_SHA2_192S_SIG_LEN 16224 +/* Seed length for SLH-DSA SHA2-192s. */ +#define WC_SLHDSA_SHA2_192S_SEED_LEN WC_SLHDSA_SHA2_192_SEED_LEN + +/* Private key length for SLH-DSA SHA2-192f. */ +#define WC_SLHDSA_SHA2_192F_PRIV_LEN (4 * 24) +/* Public key length for SLH-DSA SHA2-192f. */ +#define WC_SLHDSA_SHA2_192F_PUB_LEN (2 * 24) +/* Signature length for SLH-DSA SHA2-192f. */ +#define WC_SLHDSA_SHA2_192F_SIG_LEN 35664 +/* Seed length for SLH-DSA SHA2-192f. */ +#define WC_SLHDSA_SHA2_192F_SEED_LEN WC_SLHDSA_SHA2_192_SEED_LEN + +/* Private key length for SLH-DSA SHA2-256s. */ +#define WC_SLHDSA_SHA2_256S_PRIV_LEN (4 * 32) +/* Public key length for SLH-DSA SHA2-256s. */ +#define WC_SLHDSA_SHA2_256S_PUB_LEN (2 * 32) +/* Signature length for SLH-DSA SHA2-256s. */ +#define WC_SLHDSA_SHA2_256S_SIG_LEN 29792 +/* Seed length for SLH-DSA SHA2-256s. */ +#define WC_SLHDSA_SHA2_256S_SEED_LEN WC_SLHDSA_SHA2_256_SEED_LEN + +/* Private key length for SLH-DSA SHA2-256f. */ +#define WC_SLHDSA_SHA2_256F_PRIV_LEN (4 * 32) +/* Public key length for SLH-DSA SHA2-256f. */ +#define WC_SLHDSA_SHA2_256F_PUB_LEN (2 * 32) +/* Signature length for SLH-DSA SHA2-256f. */ +#define WC_SLHDSA_SHA2_256F_SIG_LEN 49856 +/* Seed length for SLH-DSA SHA2-256f. */ +#define WC_SLHDSA_SHA2_256F_SEED_LEN WC_SLHDSA_SHA2_256_SEED_LEN + +#endif /* WOLFSSL_SLHDSA_SHA2 */ + +/* ======== Maximum size defines ======== */ + +/* Determine maximum private and public key lengths based on maximum 256-bit + * output length. SHA2 variants have identical sizes to SHAKE counterparts. */ #ifndef WOLFSSL_SLHDSA_PARAM_NO_256 /* Maximum private key length. */ #define WC_SLHDSA_MAX_PRIV_LEN WC_SLHDSA_SHAKE256F_PRIV_LEN @@ -279,8 +506,23 @@ enum SlhDsaParam { SLHDSA_SHAKE192F = 3, /* SLH-DSA SHAKE192f */ SLHDSA_SHAKE256S = 4, /* SLH-DSA SHAKE256s */ SLHDSA_SHAKE256F = 5, /* SLH-DSA SHAKE256f */ +#ifdef WOLFSSL_SLHDSA_SHA2 + SLHDSA_SHA2_128S = 6, /* SLH-DSA SHA2-128s */ + SLHDSA_SHA2_128F = 7, /* SLH-DSA SHA2-128f */ + SLHDSA_SHA2_192S = 8, /* SLH-DSA SHA2-192s */ + SLHDSA_SHA2_192F = 9, /* SLH-DSA SHA2-192f */ + SLHDSA_SHA2_256S = 10, /* SLH-DSA SHA2-256s */ + SLHDSA_SHA2_256F = 11, /* SLH-DSA SHA2-256f */ +#endif }; +/* Helper macro to detect SHA2 parameter sets. */ +#ifdef WOLFSSL_SLHDSA_SHA2 + #define SLHDSA_IS_SHA2(p) ((p) >= SLHDSA_SHA2_128S) +#else + #define SLHDSA_IS_SHA2(p) (0) +#endif + /* Pre-defined parameter values. */ typedef struct SlhDsaParameters { enum SlhDsaParam param; /* Parameter set id. */ @@ -317,10 +559,31 @@ typedef struct SlhDsaKey { /* sk_seed | sk_prf | pk_seed, pk_root */ byte sk[32 * 4]; - /* First SHAKE-256 object. */ - wc_Shake shake; - /* Second SHAKE-256 object. */ - wc_Shake shake2; + /* Hash objects for SHAKE or SHA2. */ + union { + struct { + /* Primary SHAKE-256 object. */ + wc_Shake shake; + /* Secondary SHAKE-256 object (T_l streaming). */ + wc_Shake shake2; + } shk; +#ifdef WOLFSSL_SLHDSA_SHA2 + struct { + /* F, PRF (all cats) + H, T_l (cat 1). */ + wc_Sha256 sha256; + /* T_l streaming (cat 1), H_msg scratch. */ + wc_Sha256 sha256_2; + /* H, T_l (cats 3, 5). */ + wc_Sha512 sha512; + /* H_msg streaming (cats 3, 5). */ + wc_Sha512 sha512_2; + /* Pre-computed midstate: PK.seed || pad(64 - n). */ + wc_Sha256 sha256_mid; + /* Pre-computed midstate: PK.seed || pad(128 - n). */ + wc_Sha512 sha512_mid; + } sha2; +#endif + } hash; } SlhDsaKey; WOLFSSL_API int wc_SlhDsaKey_Init(SlhDsaKey* key, enum SlhDsaParam param, @@ -344,6 +607,15 @@ WOLFSSL_API int wc_SlhDsaKey_Sign(SlhDsaKey* key, const byte* ctx, WOLFSSL_API int wc_SlhDsaKey_Verify(SlhDsaKey* key, const byte* ctx, byte ctxSz, const byte* msg, word32 msgSz, const byte* sig, word32 sigSz); +/* Internal interface: M' provided directly (no M' construction). */ +WOLFSSL_API int wc_SlhDsaKey_SignMsgDeterministic(SlhDsaKey* key, + const byte* mprime, word32 mprimeSz, byte* sig, word32* sigSz); +WOLFSSL_API int wc_SlhDsaKey_SignMsgWithRandom(SlhDsaKey* key, + const byte* mprime, word32 mprimeSz, byte* sig, word32* sigSz, + const byte* addRnd); +WOLFSSL_API int wc_SlhDsaKey_VerifyMsg(SlhDsaKey* key, const byte* mprime, + word32 mprimeSz, const byte* sig, word32 sigSz); + WOLFSSL_API int wc_SlhDsaKey_SignHashDeterministic(SlhDsaKey* key, const byte* ctx, byte ctxSz, const byte* msg, word32 msgSz, enum wc_HashType hashType, byte* sig, word32* sigSz); From 6f2d48cd4c322347214e8d25e0de4e8d85c394c7 Mon Sep 17 00:00:00 2001 From: Eric Blankenhorn Date: Fri, 24 Apr 2026 07:54:52 -0500 Subject: [PATCH 119/167] Fix from review --- src/tls.c | 65 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 15 deletions(-) diff --git a/src/tls.c b/src/tls.c index 996edafbbc..4cae2e0aa1 100644 --- a/src/tls.c +++ b/src/tls.c @@ -15125,11 +15125,20 @@ static int TLSX_Write(TLSX* list, byte* output, byte* semaphore, { int ret = 0; TLSX* extension; - word16 offset = 0; - word16 length_offset = 0; + /* Use word32 to symmetrize with TLSX_GetSize -- a single extension can + * contribute up to 0x10003 bytes (4-byte type/length header + 0xFFFF + * payload), which would word16-overflow undetectably (e.g. wrap to a + * value still above prevOffset). Per-iteration and aggregate bounds are + * checked below before truncating back into the word16 wire fields. + * Callees that take a word16* offset use the cbShim pattern (init to 0, + * then add the returned delta to the word32 accumulator). */ + word32 offset = 0; + word32 length_offset = 0; word32 prevOffset; + word16 cbShim = 0; byte isRequest = (msgType == client_hello || msgType == certificate_request); + (void)cbShim; while ((extension = list)) { list = extension->next; @@ -15249,7 +15258,9 @@ static int TLSX_Write(TLSX* list, byte* output, byte* semaphore, #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) case TLSX_ENCRYPT_THEN_MAC: WOLFSSL_MSG("Encrypt-Then-Mac extension to write"); - ret = ETM_WRITE(extension->data, output, msgType, &offset); + cbShim = 0; + ret = ETM_WRITE(extension->data, output, msgType, &cbShim); + offset += cbShim; break; #endif /* HAVE_ENCRYPT_THEN_MAC */ @@ -15257,20 +15268,26 @@ static int TLSX_Write(TLSX* list, byte* output, byte* semaphore, #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) case TLSX_PRE_SHARED_KEY: WOLFSSL_MSG("Pre-Shared Key extension to write"); + cbShim = 0; ret = PSK_WRITE((PreSharedKey*)extension->data, output + offset, - msgType, &offset); + msgType, &cbShim); + offset += cbShim; break; #ifdef WOLFSSL_TLS13 case TLSX_PSK_KEY_EXCHANGE_MODES: WOLFSSL_MSG("PSK Key Exchange Modes extension to write"); + cbShim = 0; ret = PKM_WRITE((byte)extension->val, output + offset, msgType, - &offset); + &cbShim); + offset += cbShim; break; #ifdef WOLFSSL_CERT_WITH_EXTERN_PSK case TLSX_CERT_WITH_EXTERN_PSK: WOLFSSL_MSG("Cert with external PSK extension to write"); - ret = PSK_WITH_CERT_WRITE(output + offset, msgType, &offset); + cbShim = 0; + ret = PSK_WITH_CERT_WRITE(output + offset, msgType, &cbShim); + offset += cbShim; break; #endif #endif @@ -15284,28 +15301,36 @@ static int TLSX_Write(TLSX* list, byte* output, byte* semaphore, #ifdef WOLFSSL_TLS13 case TLSX_SUPPORTED_VERSIONS: WOLFSSL_MSG("Supported Versions extension to write"); + cbShim = 0; ret = SV_WRITE(extension->data, output + offset, msgType, - &offset); + &cbShim); + offset += cbShim; break; case TLSX_COOKIE: WOLFSSL_MSG("Cookie extension to write"); + cbShim = 0; ret = CKE_WRITE((Cookie*)extension->data, output + offset, - msgType, &offset); + msgType, &cbShim); + offset += cbShim; break; #ifdef WOLFSSL_EARLY_DATA case TLSX_EARLY_DATA: WOLFSSL_MSG("Early Data extension to write"); + cbShim = 0; ret = EDI_WRITE(extension->val, output + offset, msgType, - &offset); + &cbShim); + offset += cbShim; break; #endif #ifdef WOLFSSL_POST_HANDSHAKE_AUTH case TLSX_POST_HANDSHAKE_AUTH: WOLFSSL_MSG("Post-Handshake Authentication extension to write"); - ret = PHA_WRITE(output + offset, msgType, &offset); + cbShim = 0; + ret = PHA_WRITE(output + offset, msgType, &cbShim); + offset += cbShim; break; #endif @@ -15361,16 +15386,26 @@ static int TLSX_Write(TLSX* list, byte* output, byte* semaphore, #if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) case TLSX_ECH: WOLFSSL_MSG("ECH extension to write"); + cbShim = 0; ret = ECH_WRITE((WOLFSSL_ECH*)extension->data, msgType, - output + offset, &offset); + output + offset, &cbShim); + offset += cbShim; break; #endif default: break; } + /* Per-extension data length is a 2-byte wire field; reject any + * single extension whose payload exceeds that before truncating. */ + if (offset - length_offset > WOLFSSL_MAX_16BIT) { + WOLFSSL_MSG("TLSX_Write single extension length exceeds word16"); + return BUFFER_E; + } + /* writes extension data length. */ - c16toa(offset - length_offset, output + length_offset - OPAQUE16_LEN); + c16toa((word16)(offset - length_offset), + output + length_offset - OPAQUE16_LEN); /* marks the extension as processed so ctx level */ /* extensions don't overlap with ssl level ones. */ @@ -15381,7 +15416,7 @@ static int TLSX_Write(TLSX* list, byte* output, byte* semaphore, break; if (offset <= prevOffset) { - WOLFSSL_MSG("TLSX_Write extension length exceeds word16"); + WOLFSSL_MSG("TLSX_Write extension made no progress"); return BUFFER_E; } } @@ -15391,11 +15426,11 @@ static int TLSX_Write(TLSX* list, byte* output, byte* semaphore, * unchanged and return the original failure reason so callers * see the real error instead of a masking BUFFER_E. */ if (ret == 0) { - if ((word32)*pOffset + (word32)offset > WOLFSSL_MAX_16BIT) { + if ((word32)*pOffset + offset > WOLFSSL_MAX_16BIT) { WOLFSSL_MSG("TLSX_Write total extensions length exceeds word16"); return BUFFER_E; } - *pOffset += offset; + *pOffset += (word16)offset; } return ret; From 008ca51cb514b9b67c2dcf93076884dee8f6dbd9 Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Fri, 24 Apr 2026 06:09:25 -0700 Subject: [PATCH 120/167] Add additional macros to known macro list --- .wolfssl_known_macro_extras | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 9dfce8514c..c84b3f7203 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -157,6 +157,7 @@ CONFIG_WOLFSSL CONFIG_WOLFSSL_ALLOW_TLS13 CONFIG_WOLFSSL_ALPN CONFIG_WOLFSSL_ALT_CERT_CHAINS +CONFIG_WOLFSSL_ALWAYS_VERIFY_CB CONFIG_WOLFSSL_APPLE_HOMEKIT CONFIG_WOLFSSL_ASN_ALLOW_0_SERIAL CONFIG_WOLFSSL_CERTIFICATE_BUNDLE @@ -174,11 +175,13 @@ CONFIG_WOLFSSL_EXAMPLE_NAME_WOLFMQTT_TEMPLATE CONFIG_WOLFSSL_EXAMPLE_NAME_WOLFSSH_ECHOSERVER CONFIG_WOLFSSL_EXAMPLE_NAME_WOLFSSH_TEMPLATE CONFIG_WOLFSSL_HKDF +CONFIG_WOLFSSL_KEEP_PEER_CERT CONFIG_WOLFSSL_MAX_FRAGMENT_LEN CONFIG_WOLFSSL_MLKEM CONFIG_WOLFSSL_NO_ASN_STRICT CONFIG_WOLFSSL_PSK CONFIG_WOLFSSL_RSA_PSS +CONFIG_WOLFSSL_SESSION_EXPORT CONFIG_WOLFSSL_TARGET_HOST CONFIG_WOLFSSL_TARGET_PORT CONFIG_WOLFSSL_TLS13_ENABLED From 5dad65c04c7c0f3dfe377b346ec9fb6877f306e2 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Fri, 24 Apr 2026 17:07:37 +0200 Subject: [PATCH 121/167] Remove ap_wpa2_eap_sim_sql --- .../configs/07c9f183ea744ac04585fb6dd10220c75a5e2e74/tests | 2 -- .../configs/b607d2723e927a3446d89aed813f1aa6068186bb/tests | 1 - .github/workflows/hostap-files/configs/hostap_2_10/tests | 1 - 3 files changed, 4 deletions(-) diff --git a/.github/workflows/hostap-files/configs/07c9f183ea744ac04585fb6dd10220c75a5e2e74/tests b/.github/workflows/hostap-files/configs/07c9f183ea744ac04585fb6dd10220c75a5e2e74/tests index 2ece8719ef..425007f3ab 100644 --- a/.github/workflows/hostap-files/configs/07c9f183ea744ac04585fb6dd10220c75a5e2e74/tests +++ b/.github/workflows/hostap-files/configs/07c9f183ea744ac04585fb6dd10220c75a5e2e74/tests @@ -238,8 +238,6 @@ ap_wpa2_eap_sim_imsi_privacy_attr ap_wpa2_eap_sim_imsi_privacy_key ap_wpa2_eap_sim_no_change_set ap_wpa2_eap_sim_oom -ap_wpa2_eap_sim_sql -ap_wpa2_eap_sim_sql_fallback_to_pseudonym ap_wpa2_eap_sim_zero_db_timeout ap_wpa2_eap_tls_13_ec ap_wpa2_eap_tls_13_missing_prot_success diff --git a/.github/workflows/hostap-files/configs/b607d2723e927a3446d89aed813f1aa6068186bb/tests b/.github/workflows/hostap-files/configs/b607d2723e927a3446d89aed813f1aa6068186bb/tests index 3caefd947a..08c5d170dd 100644 --- a/.github/workflows/hostap-files/configs/b607d2723e927a3446d89aed813f1aa6068186bb/tests +++ b/.github/workflows/hostap-files/configs/b607d2723e927a3446d89aed813f1aa6068186bb/tests @@ -219,7 +219,6 @@ ap_wpa2_eap_sim ap_wpa2_eap_sim_imsi_identity ap_wpa2_eap_sim_imsi_privacy_key ap_wpa2_eap_sim_imsi_privacy_attr -ap_wpa2_eap_sim_sql ap_wpa2_eap_sim_config ap_wpa2_eap_sim_id_0 ap_wpa2_eap_sim_id_1 diff --git a/.github/workflows/hostap-files/configs/hostap_2_10/tests b/.github/workflows/hostap-files/configs/hostap_2_10/tests index 5679cbda93..489c62f6f7 100644 --- a/.github/workflows/hostap-files/configs/hostap_2_10/tests +++ b/.github/workflows/hostap-files/configs/hostap_2_10/tests @@ -176,7 +176,6 @@ ap_wpa2_psk_ext_key_id_ptk_rekey_sta0 ap_wpa2_psk_ext_key_id_ptk_rekey_sta1 ap_wpa2_psk_ext_key_id_ptk_rekey_sta2 ap_wpa2_eap_sim -ap_wpa2_eap_sim_sql ap_wpa2_eap_sim_config ap_wpa2_eap_sim_id_0 ap_wpa2_eap_sim_id_1 From 186ab8b0c3315b35c2210706717503bbc492b86f Mon Sep 17 00:00:00 2001 From: JacobBarthelmeh Date: Fri, 24 Apr 2026 16:55:51 -0600 Subject: [PATCH 122/167] remove openvpn master from CI test --- .github/workflows/openvpn.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/openvpn.yml b/.github/workflows/openvpn.yml index 2f4974bb7a..0b793f19ef 100644 --- a/.github/workflows/openvpn.yml +++ b/.github/workflows/openvpn.yml @@ -42,7 +42,7 @@ jobs: strategy: fail-fast: false matrix: - ref: [ master, release/2.6, v2.6.19 ] + ref: [ release/2.6, v2.6.19 ] name: ${{ matrix.ref }} if: github.repository_owner == 'wolfssl' runs-on: ubuntu-24.04 From 6c9e0ea5a7663d9ebdfbcaadf61eaa3c9767caa4 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Fri, 24 Apr 2026 11:54:36 -0500 Subject: [PATCH 123/167] linuxkm/lkcapi_ecdsa_glue.c: in km_ecdsa_verify(), add checks on hash_len following pattern of #10131, before calling wc_ecc_verify_hash(), for defense-in-depth. --- linuxkm/lkcapi_ecdsa_glue.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/linuxkm/lkcapi_ecdsa_glue.c b/linuxkm/lkcapi_ecdsa_glue.c index 15113e6b1b..46469131e5 100644 --- a/linuxkm/lkcapi_ecdsa_glue.c +++ b/linuxkm/lkcapi_ecdsa_glue.c @@ -401,7 +401,9 @@ static int km_ecdsa_verify(struct akcipher_request *req) sig_len = req->src_len; hash_len = req->dst_len; - if (hash_len <= 0) { + if ((hash_len > WC_MAX_DIGEST_SIZE) || + (hash_len < WC_MIN_DIGEST_SIZE)) + { err = -EINVAL; goto ecdsa_verify_end; } From 1f1b5725485f118471268841bf62fa0df715774d Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Fri, 24 Apr 2026 11:56:57 -0500 Subject: [PATCH 124/167] tests/api.c: fix -Wnull-dereferences in wolfSSL_UseSecureRenegotiation(). --- tests/api.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/api.c b/tests/api.c index ee283df1cf..618398f3c3 100644 --- a/tests/api.c +++ b/tests/api.c @@ -10296,11 +10296,15 @@ static int test_wolfSSL_clear_secure_renegotiation(void) ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_UseSecureRenegotiation(ssl)); ExpectNotNull(ssl->secure_renegotiation); - if (ssl->secure_renegotiation != NULL) - ssl->secure_renegotiation->enabled = 1; + if (EXPECT_SUCCESS()) { + if (ssl->secure_renegotiation != NULL) + ssl->secure_renegotiation->enabled = 1; + } ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_clear(ssl)); - support = wolfSSL_SSL_get_secure_renegotiation_support(ssl); + if (EXPECT_SUCCESS()) { + support = wolfSSL_SSL_get_secure_renegotiation_support(ssl); + } ExpectNull(ssl->secure_renegotiation); ExpectIntEQ(WOLFSSL_FAILURE, support); From 91f66fb9c0487e77601a73ca843448ebaa67b03e Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Fri, 24 Apr 2026 12:22:14 -0500 Subject: [PATCH 125/167] tests/api/test_pkcs7.c: in test_wc_PKCS7_BER(), in expected-failure wc_PKCS7_DecodeEnvelopedData() in WOLFSSL_SP_MATH build, allow failure with either WC_KEY_SIZE_E or BUFFER_E, to accommodate blinding added by #10128 / 589feabc0c. --- tests/api/test_pkcs7.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/api/test_pkcs7.c b/tests/api/test_pkcs7.c index 69b4631605..6d033b15d0 100644 --- a/tests/api/test_pkcs7.c +++ b/tests/api/test_pkcs7.c @@ -4577,8 +4577,12 @@ int test_wc_PKCS7_BER(void) } #ifndef NO_RSA #ifdef WOLFSSL_SP_MATH - ExpectIntEQ(wc_PKCS7_DecodeEnvelopedData(pkcs7, berContent, - sizeof(berContent), decoded, sizeof(decoded)), WC_NO_ERR_TRACE(WC_KEY_SIZE_E)); + if (EXPECT_SUCCESS()) { + ret = wc_PKCS7_DecodeEnvelopedData( + pkcs7, berContent, sizeof(berContent), decoded, sizeof(decoded)); + ExpectTrue((ret == WC_NO_ERR_TRACE(WC_KEY_SIZE_E)) || + (ret == WC_NO_ERR_TRACE(BUFFER_E))); + } #else ExpectIntGT(wc_PKCS7_DecodeEnvelopedData(pkcs7, berContent, sizeof(berContent), decoded, sizeof(decoded)), 0); From 91c7c8f9fb1ee9735f9ab9489b02e68ef88a8daa Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Fri, 24 Apr 2026 13:05:13 -0500 Subject: [PATCH 126/167] wolfcrypt/test/test.c and wolfcrypt/test/test.h: fix gating for dsa_test() and srp_test() prototypes to avoid -Wunused-function in --enable-sp-math builds. --- wolfcrypt/test/test.c | 4 ++++ wolfcrypt/test/test.h | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index ef8809b3a2..c2eb3a807e 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -900,8 +900,12 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t rsa_no_pad_test(void); #endif WOLFSSL_TEST_SUBROUTINE wc_test_ret_t rsa_test(void); WOLFSSL_TEST_SUBROUTINE wc_test_ret_t dh_test(void); +#ifndef NO_DSA WOLFSSL_TEST_SUBROUTINE wc_test_ret_t dsa_test(void); +#endif +#ifdef WOLFCRYPT_HAVE_SRP WOLFSSL_TEST_SUBROUTINE wc_test_ret_t srp_test(void); +#endif #ifndef WC_NO_RNG WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_test(void); #ifdef WC_RNG_BANK_SUPPORT diff --git a/wolfcrypt/test/test.h b/wolfcrypt/test/test.h index 72b9ff586d..75ea16234a 100644 --- a/wolfcrypt/test/test.h +++ b/wolfcrypt/test/test.h @@ -237,8 +237,12 @@ extern WOLFSSL_TEST_SUBROUTINE wc_test_ret_t rsa_no_pad_test(void); #endif extern WOLFSSL_TEST_SUBROUTINE wc_test_ret_t rsa_test(void); extern WOLFSSL_TEST_SUBROUTINE wc_test_ret_t dh_test(void); +#ifndef NO_DSA extern WOLFSSL_TEST_SUBROUTINE wc_test_ret_t dsa_test(void); +#endif +#ifdef WOLFCRYPT_HAVE_SRP extern WOLFSSL_TEST_SUBROUTINE wc_test_ret_t srp_test(void); +#endif #ifndef WC_NO_RNG extern WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_test(void); #ifdef WC_RNG_BANK_SUPPORT From d14b8f8e79466a90fc8e4d87092d8c374a41ba99 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Fri, 24 Apr 2026 13:06:13 -0500 Subject: [PATCH 127/167] .github/workflows/: * add "-Wnull-dereference" to all existing "-pedantic -Wdeclaration-after-statement" configs; * add an --enable-sp-math config to .github/workflows/pq-all.yml and .github/workflows/multi-arch.yml. --- .github/workflows/async.yml | 10 +++++----- .github/workflows/multi-arch.yml | 23 ++++++++++++++++++----- .github/workflows/multi-compiler.yml | 2 +- .github/workflows/no-malloc.yml | 6 +++--- .github/workflows/no-tls.yml | 2 +- .github/workflows/opensslcoexist.yml | 2 +- .github/workflows/pq-all.yml | 27 ++++++++++++++------------- 7 files changed, 43 insertions(+), 29 deletions(-) diff --git a/.github/workflows/async.yml b/.github/workflows/async.yml index 0fa50bc049..c6956458de 100644 --- a/.github/workflows/async.yml +++ b/.github/workflows/async.yml @@ -18,11 +18,11 @@ jobs: matrix: config: [ # Add new configs here - '--enable-asynccrypt --enable-all --enable-dtls13 --disable-mlkem CFLAGS="-pedantic -Wdeclaration-after-statement -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE -DWOLFCRYPT_TEST_LINT"', - '--enable-asynccrypt-sw --enable-ocspstapling --enable-ocspstapling2 --disable-mlkem CFLAGS="-pedantic -Wdeclaration-after-statement -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', - '--enable-asynccrypt --enable-all --enable-dtls13 CFLAGS="-pedantic -Wdeclaration-after-statement -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE -DWOLFCRYPT_TEST_LINT"', - '--enable-asynccrypt-sw --enable-ocspstapling --enable-ocspstapling2 CFLAGS="-pedantic -Wdeclaration-after-statement -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', - '--enable-ocsp CFLAGS="-DTEST_NONBLOCK_CERTS -pedantic -Wdeclaration-after-statement -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', + '--enable-asynccrypt --enable-all --enable-dtls13 --disable-mlkem CFLAGS="-pedantic -Wdeclaration-after-statement -Wnull-dereference -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE -DWOLFCRYPT_TEST_LINT"', + '--enable-asynccrypt-sw --enable-ocspstapling --enable-ocspstapling2 --disable-mlkem CFLAGS="-pedantic -Wdeclaration-after-statement -Wnull-dereference -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', + '--enable-asynccrypt --enable-all --enable-dtls13 CFLAGS="-pedantic -Wdeclaration-after-statement -Wnull-dereference -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE -DWOLFCRYPT_TEST_LINT"', + '--enable-asynccrypt-sw --enable-ocspstapling --enable-ocspstapling2 CFLAGS="-pedantic -Wdeclaration-after-statement -Wnull-dereference -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', + '--enable-ocsp CFLAGS="-DTEST_NONBLOCK_CERTS -pedantic -Wdeclaration-after-statement -Wnull-dereference -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', ] name: make check if: github.repository_owner == 'wolfssl' diff --git a/.github/workflows/multi-arch.yml b/.github/workflows/multi-arch.yml index 7a9a741174..1ee3c0baf5 100644 --- a/.github/workflows/multi-arch.yml +++ b/.github/workflows/multi-arch.yml @@ -14,7 +14,7 @@ concurrency: jobs: my_matrix: - name: Multi-arch test + name: Multi-arch test (${{ matrix.ARCH }}, ${{ matrix.opts.name }}) strategy: fail-fast: false matrix: @@ -37,7 +37,20 @@ jobs: CFLAGS: -marm -DWOLFSSL_SP_ARM_ARCH=6 ARCH: armel EXTRA_OPTS: --enable-sp-asm - opts: [ '-O2', '-O3', '-O1 -UFP_ECC', '-O0', '-Os', '-Ofast' ] + opts: + - name: '-O2' + OPT_CFLAGS: '-O2' + - name: '-O2 sp-math' + OPT_CFLAGS: '-O2' + OPT_EXTRA_OPTS: '--enable-sp-math' + - name: '-O1 -UFP_ECC' + OPT_CFLAGS: '-O1 -UFP_ECC' + - name: '-O0' + OPT_CFLAGS: '-O0' + - name: '-Os' + OPT_CFLAGS: '-Os' + - name: '-Ofast' + OPT_CFLAGS: '-Ofast' if: github.repository_owner == 'wolfssl' runs-on: ubuntu-22.04 # This should be a safe limit for the tests to run. @@ -48,12 +61,12 @@ jobs: sudo apt update sudo apt install -y crossbuild-essential-${{ matrix.ARCH }} qemu-user - uses: actions/checkout@v4 - - name: Build for ${{ matrix.ARCH }} with Opt Level ${{ matrix.opts }} + - name: Build for ${{ matrix.ARCH }} with ${{ matrix.opts.name }} env: CC: ${{ matrix.CC }} - CFLAGS: ${{ matrix.CFLAGS }} ${{ matrix.opts }} + CFLAGS: ${{ matrix.CFLAGS }} ${{ matrix.opts.OPT_CFLAGS }} QEMU_LD_PREFIX: /usr/${{ matrix.HOST }} - run: ./autogen.sh && ./configure --host=${{ matrix.HOST }} --enable-all --disable-examples CPPFLAGS="-pedantic -Wdeclaration-after-statement -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE -DWOLFCRYPT_TEST_LINT" ${{ matrix.EXTRA_OPTS }} && make + run: ./autogen.sh && ./configure --host=${{ matrix.HOST }} --enable-all --disable-examples CPPFLAGS="-pedantic -Wdeclaration-after-statement -Wnull-dereference -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE -DWOLFCRYPT_TEST_LINT" ${{ matrix.EXTRA_OPTS }} ${{ matrix.opts.OPT_EXTRA_OPTS }} && make - name: Print errors if: ${{ failure() }} run: | diff --git a/.github/workflows/multi-compiler.yml b/.github/workflows/multi-compiler.yml index 273ea71453..b52bd6432c 100644 --- a/.github/workflows/multi-compiler.yml +++ b/.github/workflows/multi-compiler.yml @@ -51,7 +51,7 @@ jobs: env: CC: ${{ matrix.CC }} CXX: ${{ matrix.CXX }} - run: ./autogen.sh && ./configure CFLAGS="-pedantic -Wdeclaration-after-statement" && make && make dist + run: ./autogen.sh && ./configure CFLAGS="-pedantic -Wdeclaration-after-statement -Wnull-dereference" && make && make dist - name: Show log on errors if: ${{ failure() }} run: | diff --git a/.github/workflows/no-malloc.yml b/.github/workflows/no-malloc.yml index 33a40fb88a..4268d47da4 100644 --- a/.github/workflows/no-malloc.yml +++ b/.github/workflows/no-malloc.yml @@ -18,9 +18,9 @@ jobs: matrix: config: [ # Add new configs here - '--enable-rsa --enable-keygen --disable-dh CFLAGS="-DWOLFSSL_NO_MALLOC -DRSA_MIN_SIZE=1024 -pedantic -Wdeclaration-after-statement -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', - '--enable-ecc --enable-rsa --enable-keygen --enable-ed25519 --enable-curve25519 --enable-ed448 --enable-curve448 --enable-mlkem CFLAGS="-DWOLFSSL_NO_MALLOC -pedantic -Wdeclaration-after-statement -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', - '--enable-ecc --enable-rsa --enable-keygen --enable-ed25519 --enable-curve25519 --enable-ed448 --enable-curve448 --enable-mlkem --enable-staticmemory CFLAGS="-DWOLFSSL_NO_MALLOC -pedantic -Wdeclaration-after-statement -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', + '--enable-rsa --enable-keygen --disable-dh CFLAGS="-DWOLFSSL_NO_MALLOC -DRSA_MIN_SIZE=1024 -pedantic -Wdeclaration-after-statement -Wnull-dereference -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', + '--enable-ecc --enable-rsa --enable-keygen --enable-ed25519 --enable-curve25519 --enable-ed448 --enable-curve448 --enable-mlkem CFLAGS="-DWOLFSSL_NO_MALLOC -pedantic -Wdeclaration-after-statement -Wnull-dereference -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', + '--enable-ecc --enable-rsa --enable-keygen --enable-ed25519 --enable-curve25519 --enable-ed448 --enable-curve448 --enable-mlkem --enable-staticmemory CFLAGS="-DWOLFSSL_NO_MALLOC -pedantic -Wdeclaration-after-statement -Wnull-dereference -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', ] name: make check if: github.repository_owner == 'wolfssl' diff --git a/.github/workflows/no-tls.yml b/.github/workflows/no-tls.yml index fb6ff9cadc..13cf7c8f05 100644 --- a/.github/workflows/no-tls.yml +++ b/.github/workflows/no-tls.yml @@ -18,7 +18,7 @@ jobs: matrix: config: [ # Add new configs here - '--disable-tls --enable-all CFLAGS="-pedantic -Wdeclaration-after-statement -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', + '--disable-tls --enable-all CFLAGS="-pedantic -Wdeclaration-after-statement -Wnull-dereference -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', ] name: make check if: github.repository_owner == 'wolfssl' diff --git a/.github/workflows/opensslcoexist.yml b/.github/workflows/opensslcoexist.yml index 1b26ed947c..7bc006d05b 100644 --- a/.github/workflows/opensslcoexist.yml +++ b/.github/workflows/opensslcoexist.yml @@ -18,7 +18,7 @@ jobs: matrix: config: [ # Add new configs here - '--verbose --enable-all --disable-all-osp --disable-opensslall --enable-opensslcoexist CPPFLAGS="-DNO_WOLFSSL_CIPHER_SUITE_TEST -pedantic -Wdeclaration-after-statement -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', + '--verbose --enable-all --disable-all-osp --disable-opensslall --enable-opensslcoexist CPPFLAGS="-DNO_WOLFSSL_CIPHER_SUITE_TEST -pedantic -Wdeclaration-after-statement -Wnull-dereference -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', '--verbose --enable-all --disable-all-osp --disable-opensslall --enable-opensslcoexist CPPFLAGS="-DNO_WOLFSSL_CIPHER_SUITE_TEST -pedantic -DTEST_OPENSSL_COEXIST -Wdeclaration-after-statement -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"' ] name: make check diff --git a/.github/workflows/pq-all.yml b/.github/workflows/pq-all.yml index 305faa5403..7e2e132e72 100644 --- a/.github/workflows/pq-all.yml +++ b/.github/workflows/pq-all.yml @@ -20,20 +20,21 @@ jobs: # Add new configs here '--disable-shared --enable-dilithium --enable-mlkem CFLAGS="-fsanitize=undefined -fno-sanitize-recover=undefined -fno-omit-frame-pointer" LDFLAGS="-fsanitize=undefined" CPPFLAGS="-DWOLFSSL_DILITHIUM_ALIGNMENT=4"', '--enable-intelasm --enable-sp-asm --enable-mlkem=yes,kyber,ml-kem CPPFLAGS="-DWOLFSSL_ML_KEM_USE_OLD_IDS"', - '--enable-intelasm --enable-sp-asm --enable-all --enable-testcert --enable-acert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-quic --with-sys-crypto-policy --enable-experimental --enable-mlkem=yes,kyber,ml-kem --enable-tls-mlkem-standalone --enable-extra-pqc-hybrids --enable-lms --enable-xmss --enable-slhdsa --enable-dilithium --enable-dual-alg-certs --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE -DWOLFSSL_BLIND_PRIVATE_KEY -DWOLFSSL_TLSX_PQC_MLKEM_STORE_OBJ"', - '--enable-smallstack --enable-smallstackcache --enable-intelasm --enable-sp-asm --enable-all --enable-testcert --enable-acert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-quic --with-sys-crypto-policy --enable-experimental --enable-mlkem=yes,kyber,ml-kem --enable-lms --enable-xmss --enable-slhdsa --enable-dilithium --enable-dual-alg-certs --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', + '--enable-intelasm --enable-sp-asm --enable-all --enable-testcert --enable-acert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-quic --with-sys-crypto-policy --enable-experimental --enable-mlkem=yes,kyber,ml-kem --enable-tls-mlkem-standalone --enable-extra-pqc-hybrids --enable-lms --enable-xmss --enable-slhdsa --enable-dilithium --enable-dual-alg-certs --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -Wnull-dereference -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE -DWOLFSSL_BLIND_PRIVATE_KEY -DWOLFSSL_TLSX_PQC_MLKEM_STORE_OBJ"', + '--enable-intelasm --enable-sp-math --enable-sp-asm --enable-all --enable-testcert --enable-acert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-quic --with-sys-crypto-policy --enable-experimental --enable-mlkem=yes,kyber,ml-kem --enable-tls-mlkem-standalone --enable-extra-pqc-hybrids --enable-lms --enable-xmss --enable-slhdsa --enable-dilithium --enable-dual-alg-certs --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -Wnull-dereference -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE -DWOLFSSL_BLIND_PRIVATE_KEY -DWOLFSSL_TLSX_PQC_MLKEM_STORE_OBJ"', + '--enable-smallstack --enable-smallstackcache --enable-intelasm --enable-sp-asm --enable-all --enable-testcert --enable-acert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-quic --with-sys-crypto-policy --enable-experimental --enable-mlkem=yes,kyber,ml-kem --enable-lms --enable-xmss --enable-slhdsa --enable-dilithium --enable-dual-alg-certs --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -Wnull-dereference -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', '--enable-intelasm --enable-sp-asm --enable-all --enable-testcert --enable-acert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-quic --with-sys-crypto-policy --enable-experimental --enable-mlkem=yes,kyber,ml-kem --enable-lms --enable-xmss --enable-slhdsa --enable-dilithium --enable-dual-alg-certs --disable-qt CPPFLAGS="-Wdeclaration-after-statement -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE" CC=c++', - '--disable-intelasm --enable-all --enable-testcert --enable-acert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-quic --with-sys-crypto-policy --enable-experimental --enable-mlkem=yes,kyber,ml-kem,small --enable-lms=yes,small --enable-xmss=yes,small --enable-slhdsa=yes,small --enable-dilithium=yes,small --enable-dual-alg-certs --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE -DWOLFSSL_MLKEM_MAKEKEY_SMALL_MEM -DWOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM -DWOLFSSL_MLKEM_NO_LARGE_CODE -DWOLFSSL_DILITHIUM_SIGN_SMALL_MEM -DWOLFSSL_DILITHIUM_VERIFY_SMALL_MEM -DWOLFSSL_DILITHIUM_MAKE_KEY_SMALL_MEM -DWOLFSSL_DILITHIUM_NO_LARGE_CODE"', - '--disable-intelasm --enable-smallstack --enable-smallstackcache --enable-all --enable-testcert --enable-acert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-quic --with-sys-crypto-policy --enable-experimental --enable-mlkem=yes,kyber,ml-kem,small --enable-lms=yes,small --enable-xmss=yes,small --enable-slhdsa=yes,small --enable-dilithium=yes,small --enable-dual-alg-certs --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE -DWOLFSSL_MLKEM_MAKEKEY_SMALL_MEM -DWOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM -DWOLFSSL_MLKEM_NO_LARGE_CODE -DWOLFSSL_DILITHIUM_SIGN_SMALL_MEM -DWOLFSSL_DILITHIUM_VERIFY_SMALL_MEM -DWOLFSSL_DILITHIUM_MAKE_KEY_SMALL_MEM -DWOLFSSL_DILITHIUM_NO_LARGE_CODE"', - '--disable-intelasm --enable-all --disable-mlkem --enable-lms=yes,small,verify-only --enable-xmss=yes,small,verify-only --enable-slhdsa=yes,small,verify-only --enable-dilithium=yes,small,verify-only --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE -DWOLFSSL_DILITHIUM_VERIFY_SMALL_MEM -DWOLFSSL_DILITHIUM_NO_LARGE_CODE"', - '--enable-intelasm --enable-sp-asm --enable-all --enable-testcert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-mlkem=make,enc,dec,512 --enable-tls-mlkem-standalone --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', - '--enable-intelasm --enable-sp-asm --enable-all --enable-testcert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-mlkem=make,enc,dec,768 --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', - '--enable-intelasm --enable-sp-asm --enable-all --enable-testcert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-mlkem=make,enc,dec,768 --enable-tls-mlkem-standalone --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', - '--enable-intelasm --enable-sp-asm --enable-all --enable-testcert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-mlkem=make,enc,dec,768 --enable-tls-mlkem-standalone --disable-pqc-hybrids --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', - '--enable-intelasm --enable-sp-asm --enable-all --enable-testcert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-mlkem=make,enc,dec,1024 --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', - '--enable-intelasm --enable-sp-asm --enable-all --enable-testcert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-mlkem=make,enc,dec,1024 --enable-tls-mlkem-standalone --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', - '--enable-intelasm --enable-sp-asm --enable-all --enable-testcert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-mlkem=make,enc,dec,1024 --enable-tls-mlkem-standalone --disable-pqc-hybrids --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', - '--enable-intelasm --enable-sp-asm --enable-all --enable-testcert --enable-acert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-quic --with-sys-crypto-policy --enable-experimental --enable-mlkem=yes,kyber,ml-kem --enable-lms --enable-xmss --enable-slhdsa --enable-dilithium=yes,no-ctx --enable-dual-alg-certs --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', + '--disable-intelasm --enable-all --enable-testcert --enable-acert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-quic --with-sys-crypto-policy --enable-experimental --enable-mlkem=yes,kyber,ml-kem,small --enable-lms=yes,small --enable-xmss=yes,small --enable-slhdsa=yes,small --enable-dilithium=yes,small --enable-dual-alg-certs --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -Wnull-dereference -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE -DWOLFSSL_MLKEM_MAKEKEY_SMALL_MEM -DWOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM -DWOLFSSL_MLKEM_NO_LARGE_CODE -DWOLFSSL_DILITHIUM_SIGN_SMALL_MEM -DWOLFSSL_DILITHIUM_VERIFY_SMALL_MEM -DWOLFSSL_DILITHIUM_MAKE_KEY_SMALL_MEM -DWOLFSSL_DILITHIUM_NO_LARGE_CODE"', + '--disable-intelasm --enable-smallstack --enable-smallstackcache --enable-all --enable-testcert --enable-acert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-quic --with-sys-crypto-policy --enable-experimental --enable-mlkem=yes,kyber,ml-kem,small --enable-lms=yes,small --enable-xmss=yes,small --enable-slhdsa=yes,small --enable-dilithium=yes,small --enable-dual-alg-certs --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -Wnull-dereference -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE -DWOLFSSL_MLKEM_MAKEKEY_SMALL_MEM -DWOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM -DWOLFSSL_MLKEM_NO_LARGE_CODE -DWOLFSSL_DILITHIUM_SIGN_SMALL_MEM -DWOLFSSL_DILITHIUM_VERIFY_SMALL_MEM -DWOLFSSL_DILITHIUM_MAKE_KEY_SMALL_MEM -DWOLFSSL_DILITHIUM_NO_LARGE_CODE"', + '--disable-intelasm --enable-all --disable-mlkem --enable-lms=yes,small,verify-only --enable-xmss=yes,small,verify-only --enable-slhdsa=yes,small,verify-only --enable-dilithium=yes,small,verify-only --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -Wnull-dereference -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE -DWOLFSSL_DILITHIUM_VERIFY_SMALL_MEM -DWOLFSSL_DILITHIUM_NO_LARGE_CODE"', + '--enable-intelasm --enable-sp-asm --enable-all --enable-testcert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-mlkem=make,enc,dec,512 --enable-tls-mlkem-standalone --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -Wnull-dereference -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', + '--enable-intelasm --enable-sp-asm --enable-all --enable-testcert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-mlkem=make,enc,dec,768 --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -Wnull-dereference -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', + '--enable-intelasm --enable-sp-asm --enable-all --enable-testcert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-mlkem=make,enc,dec,768 --enable-tls-mlkem-standalone --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -Wnull-dereference -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', + '--enable-intelasm --enable-sp-asm --enable-all --enable-testcert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-mlkem=make,enc,dec,768 --enable-tls-mlkem-standalone --disable-pqc-hybrids --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -Wnull-dereference -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', + '--enable-intelasm --enable-sp-asm --enable-all --enable-testcert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-mlkem=make,enc,dec,1024 --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -Wnull-dereference -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', + '--enable-intelasm --enable-sp-asm --enable-all --enable-testcert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-mlkem=make,enc,dec,1024 --enable-tls-mlkem-standalone --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -Wnull-dereference -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', + '--enable-intelasm --enable-sp-asm --enable-all --enable-testcert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-mlkem=make,enc,dec,1024 --enable-tls-mlkem-standalone --disable-pqc-hybrids --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -Wnull-dereference -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', + '--enable-intelasm --enable-sp-asm --enable-all --enable-testcert --enable-acert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-quic --with-sys-crypto-policy --enable-experimental --enable-mlkem=yes,kyber,ml-kem --enable-lms --enable-xmss --enable-slhdsa --enable-dilithium=yes,no-ctx --enable-dual-alg-certs --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -Wnull-dereference -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', '--enable-intelasm --enable-sp-asm --enable-mlkem=yes,kyber,ml-kem,cache-a CPPFLAGS="-DWOLFSSL_MLKEM_DYNAMIC_KEYS"', '--enable-intelasm --enable-sp-asm --enable-dilithium=yes CPPFLAGS="-DWOLFSSL_DILITHIUM_DYNAMIC_KEYS"', '--disable-intelasm --enable-dilithium=yes,small CPPFLAGS="-DWOLFSSL_DILITHIUM_DYNAMIC_KEYS"', From b79221acd3f7f3c300cf9b5c664729c07af133c1 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Fri, 24 Apr 2026 14:42:57 -0500 Subject: [PATCH 128/167] wolfcrypt/test/test.c: in random_bank_test(), accommodate WOLFSSL_DRBG_SHA512 in the WC_RNG_BANK_FLAG_NO_VECTOR_OPS test; linuxkm/lkcapi_sha_glue.c: in wc_mix_pool_bytes(), accommodate WOLFSSL_DRBG_SHA512. --- linuxkm/lkcapi_sha_glue.c | 20 ++++++++++++++++---- wolfcrypt/test/test.c | 13 +++++++++++-- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/linuxkm/lkcapi_sha_glue.c b/linuxkm/lkcapi_sha_glue.c index 4edf50a06f..6a75afc95f 100644 --- a/linuxkm/lkcapi_sha_glue.c +++ b/linuxkm/lkcapi_sha_glue.c @@ -1510,10 +1510,22 @@ static int wc_mix_pool_bytes(const void *buf, size_t len) { if (wc_rng_bank_checkout(ctx, &drbg, n, 0, WC_RNG_BANK_FLAG_NONE) != 0) continue; - for (i = 0, V_offset = 0; i < len; ++i) { - ((struct DRBG_internal *)WC_RNG_BANK_INST_TO_RNG(drbg)->drbg)->V[V_offset++] += ((byte *)buf)[i]; - if (V_offset == (int)sizeof ((struct DRBG_internal *)WC_RNG_BANK_INST_TO_RNG(drbg)->drbg)->V) - V_offset = 0; +#ifdef WOLFSSL_DRBG_SHA512 + if (WC_RNG_BANK_INST_TO_RNG(drbg)->drbgType == WC_DRBG_SHA512) { + for (i = 0, V_offset = 0; i < len; ++i) { + ((struct DRBG_SHA512_internal *)WC_RNG_BANK_INST_TO_RNG(drbg)->drbg512)->V[V_offset++] += ((byte *)buf)[i]; + if (V_offset == (int)sizeof ((struct DRBG_SHA512_internal *)WC_RNG_BANK_INST_TO_RNG(drbg)->drbg512)->V) + V_offset = 0; + } + } + else +#endif /* WOLFSSL_DRBG_SHA512 */ + { + for (i = 0, V_offset = 0; i < len; ++i) { + ((struct DRBG_internal *)WC_RNG_BANK_INST_TO_RNG(drbg)->drbg)->V[V_offset++] += ((byte *)buf)[i]; + if (V_offset == (int)sizeof ((struct DRBG_internal *)WC_RNG_BANK_INST_TO_RNG(drbg)->drbg)->V) + V_offset = 0; + } } wc_rng_bank_checkin(ctx, &drbg); diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index c2eb3a807e..7e00b45459 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -21991,8 +21991,17 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_bank_test(void) defined(WC_C_DYNAMIC_FALLBACK) && \ defined(HAVE_HASHDRBG) && \ defined(WC_NO_INTERNAL_FUNCTION_POINTERS) - if (((struct DRBG_internal *)rng_inst->rng.drbg)->sha256.sha_method != 7 /* SHA256_C */) - ERROR_OUT(WC_TEST_RET_ENC_I(((struct DRBG_internal *)rng_inst->rng.drbg)->sha256.sha_method), out); +#ifdef WOLFSSL_DRBG_SHA512 + if (rng_inst->rng.drbgType == WC_DRBG_SHA512) { + if (((struct DRBG_SHA512_internal *)rng_inst->rng.drbg512)->sha512.sha_method != 5 /* SHA512_C */) + ERROR_OUT(WC_TEST_RET_ENC_I(((struct DRBG_SHA512_internal *)rng_inst->rng.drbg512)->sha512.sha_method), out); + } + else +#endif /* WOLFSSL_DRBG_SHA512 */ + { + if (((struct DRBG_internal *)rng_inst->rng.drbg)->sha256.sha_method != 7 /* SHA256_C */) + ERROR_OUT(WC_TEST_RET_ENC_I(((struct DRBG_internal *)rng_inst->rng.drbg)->sha256.sha_method), out); + } #endif ret = wc_RNG_GenerateBlock(WC_RNG_BANK_INST_TO_RNG(rng_inst), outbuf1, sizeof(outbuf1)); From 72a39bfa57a691195a9d8aa30abc8be2799fcab2 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Fri, 24 Apr 2026 15:16:23 -0500 Subject: [PATCH 129/167] wolfssl/wolfcrypt/random.h: fix "comma at end of enumerator list [-Werror=pedantic]" in enum wc_DrbgType. --- wolfssl/wolfcrypt/random.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wolfssl/wolfcrypt/random.h b/wolfssl/wolfcrypt/random.h index afc5994191..102f05d6b5 100644 --- a/wolfssl/wolfcrypt/random.h +++ b/wolfssl/wolfcrypt/random.h @@ -338,7 +338,7 @@ struct DRBG_SHA512_internal { #ifdef HAVE_HASHDRBG enum wc_DrbgType { WC_DRBG_SHA256 = 0, - WC_DRBG_SHA512 = 1, + WC_DRBG_SHA512 = 1 }; #endif From 363bb0e2163e9522039c3ab6cd4b26d0913b0bae Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Fri, 24 Apr 2026 15:16:57 -0500 Subject: [PATCH 130/167] configure.ac: * allow for fips-dev in v7|ready|dev ENABLED_SHA256_DRBG and ENABLED_SHA512_DRBG setup and change from AC_MSG_WARN to AC_MSG_ERROR if user tries to disable outside fips-dev; * set ENABLED_SHA512_DRBG=no in lean-aesgcm setup; wolfcrypt/test/test.c: suppress concurrency-mt-unsafe in myFipsCb(); .wolfssl_known_macro_extras: fix lexical order. --- .wolfssl_known_macro_extras | 2 +- configure.ac | 17 +++++++++-------- wolfcrypt/test/test.c | 2 +- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index ea10e62ee0..7f8cc3f886 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -842,6 +842,7 @@ WOLFSSL_NO_KCAPI_HMAC_SHA384 WOLFSSL_NO_KCAPI_HMAC_SHA512 WOLFSSL_NO_KCAPI_SHA224 WOLFSSL_NO_KTRI_ORACLE_WARNING +WOLFSSL_NO_LMS_SHAKE256_256 WOLFSSL_NO_OCSP_DATE_CHECK WOLFSSL_NO_OCSP_ISSUER_CHAIN_CHECK WOLFSSL_NO_OCSP_OPTIONAL_CERTS @@ -1145,4 +1146,3 @@ ssize_t sun versal wc_Tls13_HKDF_Expand_Label -WOLFSSL_NO_LMS_SHAKE256_256 diff --git a/configure.ac b/configure.ac index 849e5aedd9..6e68f47f9b 100644 --- a/configure.ac +++ b/configure.ac @@ -6350,14 +6350,14 @@ AS_CASE([$FIPS_VERSION], SLHDSA_PARAM_SHA2_256F="yes"]) # SHA-256 DRBG -- cannot be disabled at build time in FIPS mode - AS_IF([test "$enable_sha256_drbg" = "no"], - [AC_MSG_WARN([Can not disable SHA256-DRBG at build time in FIPS mode, disable at run-time with wc_Sha256Drbg_Disable() or wc_Sha256Drbg_Disable_fips()])]) - ENABLED_SHA256_DRBG="yes" + AS_IF([test "$ENABLED_SHA256_DRBG" != "yes" && + test "$FIPS_VERSION" != "dev"], + [AC_MSG_ERROR([Can not disable SHA256-DRBG at build time in FIPS mode. Disable at run-time with wc_Sha256Drbg_Disable() or wc_Sha256Drbg_Disable_fips()])]) # SHA-512 DRBG -- cannot be disabled at build time in FIPS mode - AS_IF([test "$enable_sha512_drbg" = "no"], - [AC_MSG_WARN([Can not disable SHA512-DRBG at build time in FIPS mode, disable it at run-time with wc_Sha512Drbg_Disable() or wc_Sha512Drbg_Disable_fips()])]) - ENABLED_SHA512_DRBG="yes" + AS_IF([test "$ENABLED_SHA512_DRBG" != "yes" && + test "$FIPS_VERSION" != "dev"], + [AC_MSG_ERROR([Can not disable SHA512-DRBG at build time in FIPS mode. Disable it at run-time with wc_Sha512Drbg_Disable() or wc_Sha512Drbg_Disable_fips()])]) # Old TLS requires MD5 + HMAC, which is not allowed under FIPS 140-3 AS_IF([test "$ENABLED_OLD_TLS" != "no"], @@ -6683,7 +6683,7 @@ AS_CASE([$FIPS_VERSION], AS_IF([test "$ENABLED_SHA512" != "no" && (test "$FIPS_VERSION" != "lean-aesgcm-dev" || test "$enable_sha512" != "yes")], - [enable_sha512="no"; ENABLED_SHA512="no"; AM_CFLAGS="$AM_CFLAGS -UWOLFSSL_SHA512 -UWOLFSSL_SHA384"]) + [enable_sha512="no"; ENABLED_SHA512="no"; ENABLED_SHA512_DRBG="no"; AM_CFLAGS="$AM_CFLAGS -UWOLFSSL_SHA512 -UWOLFSSL_SHA384"]) # SHA512-224 and SHA512-256 are SHA-2 algorithms not in our FIPS algorithm list AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NOSHA512_224 -DWOLFSSL_NOSHA512_256" @@ -7813,7 +7813,8 @@ then fi # FIPS override: Hash DRBG is mandatory -if test "x$ENABLED_HASHDRBG" != "xyes" && test "x$ENABLED_FIPS" = "xyes" && test "x$ENABLED_KCAPI" = "xno" +if test "$ENABLED_HASHDRBG" != "yes" && test "$ENABLED_FIPS" = "yes" && + test "$FIPS_VERSION" != "dev" && test "$ENABLED_KCAPI" = "no" then if test "$enable_hashdrbg" = "no" then diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 7e00b45459..5e51093edd 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -1272,7 +1272,7 @@ static void myFipsCb(int ok, int err, const char* hash) * fail, fire this callback, and produce millions of lines of * redundant output. Exit now -- the hash has been printed for * fips-hash.sh to extract, and no test can possibly pass. */ - exit(IN_CORE_FIPS_E); + exit(IN_CORE_FIPS_E); /* NOLINT(concurrency-mt-unsafe) */ #endif } #ifdef REALLY_LONG_DRBG_CONTINUOUS_TEST From df486d8cd5fa02efbffb61b9eae7e402809437bc Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Fri, 24 Apr 2026 16:15:49 -0500 Subject: [PATCH 131/167] src/ssl_load.c: fix -Wnull-dereference in wolfssl_ctx_set_tmp_dh() (detected by armel build); .github/workflows/pq-all.yml: for the --enable-sp-math scenario, --disable-quic (QUIC unit tests fail on that combo); wolfcrypt/test/test.c: add WC_MAYBE_UNUSED to ecdsa_test_deterministic_k_rs(), to fix armel sp-math build. --- .github/workflows/pq-all.yml | 2 +- src/ssl_load.c | 9 +++++++-- wolfcrypt/test/test.c | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/pq-all.yml b/.github/workflows/pq-all.yml index 7e2e132e72..237a1fa5ee 100644 --- a/.github/workflows/pq-all.yml +++ b/.github/workflows/pq-all.yml @@ -21,7 +21,7 @@ jobs: '--disable-shared --enable-dilithium --enable-mlkem CFLAGS="-fsanitize=undefined -fno-sanitize-recover=undefined -fno-omit-frame-pointer" LDFLAGS="-fsanitize=undefined" CPPFLAGS="-DWOLFSSL_DILITHIUM_ALIGNMENT=4"', '--enable-intelasm --enable-sp-asm --enable-mlkem=yes,kyber,ml-kem CPPFLAGS="-DWOLFSSL_ML_KEM_USE_OLD_IDS"', '--enable-intelasm --enable-sp-asm --enable-all --enable-testcert --enable-acert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-quic --with-sys-crypto-policy --enable-experimental --enable-mlkem=yes,kyber,ml-kem --enable-tls-mlkem-standalone --enable-extra-pqc-hybrids --enable-lms --enable-xmss --enable-slhdsa --enable-dilithium --enable-dual-alg-certs --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -Wnull-dereference -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE -DWOLFSSL_BLIND_PRIVATE_KEY -DWOLFSSL_TLSX_PQC_MLKEM_STORE_OBJ"', - '--enable-intelasm --enable-sp-math --enable-sp-asm --enable-all --enable-testcert --enable-acert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-quic --with-sys-crypto-policy --enable-experimental --enable-mlkem=yes,kyber,ml-kem --enable-tls-mlkem-standalone --enable-extra-pqc-hybrids --enable-lms --enable-xmss --enable-slhdsa --enable-dilithium --enable-dual-alg-certs --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -Wnull-dereference -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE -DWOLFSSL_BLIND_PRIVATE_KEY -DWOLFSSL_TLSX_PQC_MLKEM_STORE_OBJ"', + '--enable-intelasm --enable-sp-math --enable-sp-asm --enable-all --enable-testcert --enable-acert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --disable-quic --with-sys-crypto-policy --enable-experimental --enable-mlkem=yes,kyber,ml-kem --enable-tls-mlkem-standalone --enable-extra-pqc-hybrids --enable-lms --enable-xmss --enable-slhdsa --enable-dilithium --enable-dual-alg-certs --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -Wnull-dereference -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE -DWOLFSSL_BLIND_PRIVATE_KEY -DWOLFSSL_TLSX_PQC_MLKEM_STORE_OBJ"', '--enable-smallstack --enable-smallstackcache --enable-intelasm --enable-sp-asm --enable-all --enable-testcert --enable-acert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-quic --with-sys-crypto-policy --enable-experimental --enable-mlkem=yes,kyber,ml-kem --enable-lms --enable-xmss --enable-slhdsa --enable-dilithium --enable-dual-alg-certs --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -Wnull-dereference -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', '--enable-intelasm --enable-sp-asm --enable-all --enable-testcert --enable-acert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-quic --with-sys-crypto-policy --enable-experimental --enable-mlkem=yes,kyber,ml-kem --enable-lms --enable-xmss --enable-slhdsa --enable-dilithium --enable-dual-alg-certs --disable-qt CPPFLAGS="-Wdeclaration-after-statement -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE" CC=c++', '--disable-intelasm --enable-all --enable-testcert --enable-acert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-quic --with-sys-crypto-policy --enable-experimental --enable-mlkem=yes,kyber,ml-kem,small --enable-lms=yes,small --enable-xmss=yes,small --enable-slhdsa=yes,small --enable-dilithium=yes,small --enable-dual-alg-certs --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -Wnull-dereference -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE -DWOLFSSL_MLKEM_MAKEKEY_SMALL_MEM -DWOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM -DWOLFSSL_MLKEM_NO_LARGE_CODE -DWOLFSSL_DILITHIUM_SIGN_SMALL_MEM -DWOLFSSL_DILITHIUM_VERIFY_SMALL_MEM -DWOLFSSL_DILITHIUM_MAKE_KEY_SMALL_MEM -DWOLFSSL_DILITHIUM_NO_LARGE_CODE"', diff --git a/src/ssl_load.c b/src/ssl_load.c index fe6f052865..2d38dba6d6 100644 --- a/src/ssl_load.c +++ b/src/ssl_load.c @@ -5685,9 +5685,14 @@ static int wolfssl_ctx_set_tmp_dh(WOLFSSL_CTX* ctx, unsigned char* p, int pSz, WOLFSSL_ENTER("wolfSSL_CTX_SetTmpDH"); + if ((ctx == NULL) || (p == NULL) || (g == NULL)) + ret = BAD_FUNC_ARG; + /* Check the size of the prime meets the requirements of the SSL context. */ - if (((word16)pSz < ctx->minDhKeySz) || ((word16)pSz > ctx->maxDhKeySz)) { - ret = DH_KEY_SIZE_E; + if (ret == 1) { + if (((word16)pSz < ctx->minDhKeySz) || ((word16)pSz > ctx->maxDhKeySz)) { + ret = DH_KEY_SIZE_E; + } } #if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 5e51093edd..914f9ab22b 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -35421,7 +35421,7 @@ done: #ifdef WOLFSSL_PUBLIC_MP -static wc_test_ret_t ecdsa_test_deterministic_k_rs(ecc_key *key, +static WC_MAYBE_UNUSED wc_test_ret_t ecdsa_test_deterministic_k_rs(ecc_key *key, enum wc_HashType hashType, const char* msg, WC_RNG* rng, mp_int* r, mp_int* s, mp_int* expR, mp_int* expS) From aab90d7a252da330d6148e5f5c545da062c5d694 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Fri, 24 Apr 2026 16:24:44 -0500 Subject: [PATCH 132/167] tests/api.c: fix false-positive -Wmaybe-uninitialized in test_wolfSSL_clear_secure_renegotiation() with --enable-all CFLAGS=-Og. --- tests/api.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/api.c b/tests/api.c index 618398f3c3..05a7688d7f 100644 --- a/tests/api.c +++ b/tests/api.c @@ -10304,9 +10304,9 @@ static int test_wolfSSL_clear_secure_renegotiation(void) ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_clear(ssl)); if (EXPECT_SUCCESS()) { support = wolfSSL_SSL_get_secure_renegotiation_support(ssl); + ExpectNull(ssl->secure_renegotiation); + ExpectIntEQ(WOLFSSL_FAILURE, support); } - ExpectNull(ssl->secure_renegotiation); - ExpectIntEQ(WOLFSSL_FAILURE, support); wolfSSL_free(ssl); wolfSSL_CTX_free(ctx); From caffc458affae96f8f9d28f7aabb0c528c1d4a94 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Fri, 24 Apr 2026 16:30:17 -0500 Subject: [PATCH 133/167] .github/workflows/: add -Wnull-dereferences to a few -pedantic scenarios missed in the first pass. --- .github/workflows/opensslcoexist.yml | 2 +- .github/workflows/os-check.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/opensslcoexist.yml b/.github/workflows/opensslcoexist.yml index 7bc006d05b..e6ff993bdb 100644 --- a/.github/workflows/opensslcoexist.yml +++ b/.github/workflows/opensslcoexist.yml @@ -19,7 +19,7 @@ jobs: config: [ # Add new configs here '--verbose --enable-all --disable-all-osp --disable-opensslall --enable-opensslcoexist CPPFLAGS="-DNO_WOLFSSL_CIPHER_SUITE_TEST -pedantic -Wdeclaration-after-statement -Wnull-dereference -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"', - '--verbose --enable-all --disable-all-osp --disable-opensslall --enable-opensslcoexist CPPFLAGS="-DNO_WOLFSSL_CIPHER_SUITE_TEST -pedantic -DTEST_OPENSSL_COEXIST -Wdeclaration-after-statement -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"' + '--verbose --enable-all --disable-all-osp --disable-opensslall --enable-opensslcoexist CPPFLAGS="-DNO_WOLFSSL_CIPHER_SUITE_TEST -pedantic -Wdeclaration-after-statement -Wnull-dereference -DTEST_OPENSSL_COEXIST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"' ] name: make check if: github.repository_owner == 'wolfssl' diff --git a/.github/workflows/os-check.yml b/.github/workflows/os-check.yml index 871d239a3b..b7c7264b25 100644 --- a/.github/workflows/os-check.yml +++ b/.github/workflows/os-check.yml @@ -99,7 +99,7 @@ jobs: - name: Build and test wolfSSL uses: wolfSSL/actions-build-autotools-project@v1 with: - configure: CFLAGS="-pedantic -Wno-overlength-strings -Wdeclaration-after-statement -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE" ${{ matrix.config }} + configure: CFLAGS="-pedantic -Wdeclaration-after-statement -Wnull-dereference -Wno-overlength-strings -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE" ${{ matrix.config }} check: true # Platform-agnostic configs: pure crypto algorithms, preprocessor guards, @@ -139,7 +139,7 @@ jobs: - name: Build and test wolfSSL uses: wolfSSL/actions-build-autotools-project@v1 with: - configure: CFLAGS="-pedantic -Wno-overlength-strings -Wdeclaration-after-statement -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE" ${{ matrix.config }} + configure: CFLAGS="-pedantic -Wdeclaration-after-statement -Wnull-dereference -Wno-overlength-strings -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE" ${{ matrix.config }} check: true make_user_settings: From 0bfa206b74cc0f7a206cf39c54c7a05417764d1f Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Sat, 25 Apr 2026 12:21:26 -0500 Subject: [PATCH 134/167] configure.ac: for FIPS v6 setup, explicitly set WOLFSSL_NOSHA512_224 and WOLFSSL_NOSHA512_256; wolfssl/wolfcrypt/hash.h: when WOLFSSL_NOSHA512_{224,256}, gate out prototypes for wc_Sha512_{224,256}Hash[_ex](), to shift build failures from link-time to compile-time. --- configure.ac | 3 ++- wolfssl/wolfcrypt/hash.h | 16 ++++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/configure.ac b/configure.ac index 6e68f47f9b..bda54372a0 100644 --- a/configure.ac +++ b/configure.ac @@ -6480,7 +6480,8 @@ AS_CASE([$FIPS_VERSION], (test "$FIPS_VERSION" != "dev" || test "$enable_sha512" != "no")], [ENABLED_SHA512="yes"; AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SHA512 -DWOLFSSL_SHA384"]) - # SHA512-224 and SHA512-256 are needed for HashML-DSA (FIPS 204) + # SHA512-224 and SHA512-256 are not in-boundary in FIPS v6. + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NOSHA512_224 -DWOLFSSL_NOSHA512_256" # Shake128 because we're testing SHAKE256 AS_IF([test "x$ENABLED_SHAKE128" = "xno" && diff --git a/wolfssl/wolfcrypt/hash.h b/wolfssl/wolfcrypt/hash.h index 781909b931..cd0ec0b9c9 100644 --- a/wolfssl/wolfcrypt/hash.h +++ b/wolfssl/wolfcrypt/hash.h @@ -310,14 +310,18 @@ WOLFSSL_API int wc_Sha384Hash_ex(const byte* data, word32 len, byte* hash, #ifdef WOLFSSL_SHA512 #include WOLFSSL_API int wc_Sha512Hash(const byte* data, word32 len, byte* hash); -WOLFSSL_API int wc_Sha512_224Hash(const byte* data, word32 len, byte* hash); -WOLFSSL_API int wc_Sha512_256Hash(const byte* data, word32 len, byte* hash); WOLFSSL_API int wc_Sha512Hash_ex(const byte* data, word32 len, byte* hash, void* heap, int devId); -WOLFSSL_API int wc_Sha512_224Hash_ex(const byte* data, word32 len, byte* hash, - void* heap, int devId); -WOLFSSL_API int wc_Sha512_256Hash_ex(const byte* data, word32 len, byte* hash, - void* heap, int devId); +#ifndef WOLFSSL_NOSHA512_224 + WOLFSSL_API int wc_Sha512_224Hash(const byte* data, word32 len, byte* hash); + WOLFSSL_API int wc_Sha512_224Hash_ex(const byte* data, word32 len, + byte* hash, void* heap, int devId); +#endif +#ifndef WOLFSSL_NOSHA512_256 + WOLFSSL_API int wc_Sha512_256Hash(const byte* data, word32 len, byte* hash); + WOLFSSL_API int wc_Sha512_256Hash_ex(const byte* data, word32 len, + byte* hash, void* heap, int devId); +#endif #endif /* WOLFSSL_SHA512 */ #ifdef WOLFSSL_SHA3 From 6040cd79151223c5625e01f3c497241736384eed Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Sat, 25 Apr 2026 12:34:25 -0500 Subject: [PATCH 135/167] configure.ac: fix to allow SHAKE force-off FIPS lean-aesgcm setup. --- configure.ac | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index bda54372a0..21ba1304a7 100644 --- a/configure.ac +++ b/configure.ac @@ -4509,7 +4509,6 @@ then then AC_MSG_NOTICE([MLKEM enabled (not explicitly disabled); overriding --disable-shake128 to enable SHAKE128]) ENABLED_SHAKE128=yes - enable_shake128=yes fi fi @@ -4527,7 +4526,6 @@ then then AC_MSG_NOTICE([MLKEM enabled (not explicitly disabled); overriding --disable-shake256 to enable SHAKE256]) ENABLED_SHAKE256=yes - enable_shake256=yes fi fi @@ -6674,6 +6672,14 @@ AS_CASE([$FIPS_VERSION], (test "$FIPS_VERSION" != "lean-aesgcm-dev" || test "$enable_sha3" != "yes")], [enable_sha3="no"; ENABLED_SHA3="no"; AM_CFLAGS="$AM_CFLAGS -UWOLFSSL_SHA3"]) + AS_IF([test "$ENABLED_SHAKE128" != "no" && + (test "$FIPS_VERSION" != "lean-aesgcm-dev" || test "$enable_shake128" != "yes")], + [enable_shake128="no"; ENABLED_SHAKE128="no"]) + + AS_IF([test "$ENABLED_SHAKE256" != "no" && + (test "$FIPS_VERSION" != "lean-aesgcm-dev" || test "$enable_shake256" != "yes")], + [enable_shake256="no"; ENABLED_SHAKE256="no"]) + AS_IF([test "$ENABLED_SHA224" != "no" && (test "$FIPS_VERSION" != "lean-aesgcm-dev" || test "$enable_sha224" != "yes")], [enable_sha224="no"; ENABLED_SHA224="no"; AM_CFLAGS="$AM_CFLAGS -UWOLFSSL_SHA224"]) @@ -7046,14 +7052,12 @@ then then AC_MSG_WARN([MLKEM enabled (not explicitly disabled); overriding --disable-shake128 to enable SHAKE128]) ENABLED_SHAKE128=yes - enable_shake128=yes fi if test "$ENABLED_SHAKE256" = "no" then AC_MSG_WARN([MLKEM enabled (not explicitly disabled); overriding --disable-shake256 to enable SHAKE256]) ENABLED_SHAKE256=yes - enable_shake256=yes fi fi From 7035fcf72b48b001f2fdb46a416db64e8a859502 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Mon, 27 Apr 2026 11:36:15 -0500 Subject: [PATCH 136/167] wolfcrypt/src/wc_slhdsa.c: * fix smallstackcache memory leaks in sha256 and sha512 contexts -- don't init or copy over a context that's been inited but not freed, and make sure to explicitly free any context that's been inited or copied over. * fix uninited-var warnings in slhdsakey_wots_sign(), slhdsakey_xmss_sign(), and slhdsakey_fors_sign() (the uninited-var scenario depends on corrupt arg(s) resulting in zero iterations). --- .wolfssl_known_macro_extras | 2 + wolfcrypt/src/wc_slhdsa.c | 129 +++++++++++++++++++++++++++++++++--- 2 files changed, 122 insertions(+), 9 deletions(-) diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 7f8cc3f886..277703dd14 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -670,6 +670,7 @@ WC_RSA_NONBLOCK_TIME WC_RSA_NO_FERMAT_CHECK WC_RWLOCK_OPS_INLINE WC_SKIP_INCLUDED_C_FILES +WC_SLHDSA_VERBOSE_DEBUG WC_SSIZE_TYPE WC_STRICT_SIG WC_USE_PIE_FENCEPOSTS_FOR_FIPS @@ -1018,6 +1019,7 @@ __ATOMIC_CONSUME __ATOMIC_RELAXED __AVR_ARCH__ __AVR__ +__AVX512F__ __BCPLUSPLUS__ __BIG_ENDIAN__ __BORLANDC__ diff --git a/wolfcrypt/src/wc_slhdsa.c b/wolfcrypt/src/wc_slhdsa.c index 402b484746..3252dbbe3a 100644 --- a/wolfcrypt/src/wc_slhdsa.c +++ b/wolfcrypt/src/wc_slhdsa.c @@ -726,6 +726,7 @@ static int slhdsakey_hash_f_sha2(SlhDsaKey* key, const byte* pk_seed, int ret; byte address[SLHDSA_HAC_SZ]; byte digest[WC_SHA256_DIGEST_SIZE]; + int copy_succeeded = 0; (void)pk_seed; @@ -733,8 +734,10 @@ static int slhdsakey_hash_f_sha2(SlhDsaKey* key, const byte* pk_seed, HA_Encode_Compressed(adrs, address); /* Restore SHA-256 midstate. */ + ret = wc_Sha256Copy(&key->hash.sha2.sha256_mid, &key->hash.sha2.sha256); if (ret == 0) { + copy_succeeded = 1; /* Update with compressed ADRS and message. */ ret = wc_Sha256Update(&key->hash.sha2.sha256, address, SLHDSA_HAC_SZ); } @@ -748,6 +751,9 @@ static int slhdsakey_hash_f_sha2(SlhDsaKey* key, const byte* pk_seed, /* Truncate to n bytes. */ XMEMCPY(hash, digest, n); } + if (copy_succeeded) { + wc_Sha256Free(&key->hash.sha2.sha256); + } return ret; } @@ -780,10 +786,12 @@ static int slhdsakey_hash_h_sha2(SlhDsaKey* key, const byte* pk_seed, if (n == WC_SLHDSA_N_128) { /* Category 1: use SHA-256. */ byte digest[WC_SHA256_DIGEST_SIZE]; + int copy_succeeded = 0; ret = wc_Sha256Copy(&key->hash.sha2.sha256_mid, &key->hash.sha2.sha256); if (ret == 0) { + copy_succeeded = 1; ret = wc_Sha256Update(&key->hash.sha2.sha256, address, SLHDSA_HAC_SZ); } @@ -796,14 +804,19 @@ static int slhdsakey_hash_h_sha2(SlhDsaKey* key, const byte* pk_seed, if (ret == 0) { XMEMCPY(hash, digest, n); } + if (copy_succeeded) { + wc_Sha256Free(&key->hash.sha2.sha256); + } } else { /* Categories 3, 5: use SHA-512. */ byte digest[WC_SHA512_DIGEST_SIZE]; + int copy_succeeded = 0; ret = wc_Sha512Copy(&key->hash.sha2.sha512_mid, &key->hash.sha2.sha512); if (ret == 0) { + copy_succeeded = 1; ret = wc_Sha512Update(&key->hash.sha2.sha512, address, SLHDSA_HAC_SZ); } @@ -816,6 +829,9 @@ static int slhdsakey_hash_h_sha2(SlhDsaKey* key, const byte* pk_seed, if (ret == 0) { XMEMCPY(hash, digest, n); } + if (copy_succeeded) { + wc_Sha512Free(&key->hash.sha2.sha512); + } } return ret; @@ -848,10 +864,12 @@ static int slhdsakey_hash_h_2_sha2(SlhDsaKey* key, const byte* pk_seed, if (n == WC_SLHDSA_N_128) { /* Category 1: use SHA-256. */ byte digest[WC_SHA256_DIGEST_SIZE]; + int copy_succeeded = 0; ret = wc_Sha256Copy(&key->hash.sha2.sha256_mid, &key->hash.sha2.sha256); if (ret == 0) { + copy_succeeded = 1; ret = wc_Sha256Update(&key->hash.sha2.sha256, address, SLHDSA_HAC_SZ); } @@ -867,14 +885,19 @@ static int slhdsakey_hash_h_2_sha2(SlhDsaKey* key, const byte* pk_seed, if (ret == 0) { XMEMCPY(hash, digest, n); } + if (copy_succeeded) { + wc_Sha256Free(&key->hash.sha2.sha256); + } } else { /* Categories 3, 5: use SHA-512. */ byte digest[WC_SHA512_DIGEST_SIZE]; + int copy_succeeded = 0; ret = wc_Sha512Copy(&key->hash.sha2.sha512_mid, &key->hash.sha2.sha512); if (ret == 0) { + copy_succeeded = 1; ret = wc_Sha512Update(&key->hash.sha2.sha512, address, SLHDSA_HAC_SZ); } @@ -890,6 +913,9 @@ static int slhdsakey_hash_h_2_sha2(SlhDsaKey* key, const byte* pk_seed, if (ret == 0) { XMEMCPY(hash, digest, n); } + if (copy_succeeded) { + wc_Sha512Free(&key->hash.sha2.sha512); + } } return ret; @@ -915,6 +941,7 @@ static int slhdsakey_hash_prf_sha2(SlhDsaKey* key, const byte* pk_seed, int ret; byte address[SLHDSA_HAC_SZ]; byte digest[WC_SHA256_DIGEST_SIZE]; + int copy_succeeded = 0; (void)pk_seed; @@ -924,6 +951,7 @@ static int slhdsakey_hash_prf_sha2(SlhDsaKey* key, const byte* pk_seed, /* Restore SHA-256 midstate. */ ret = wc_Sha256Copy(&key->hash.sha2.sha256_mid, &key->hash.sha2.sha256); if (ret == 0) { + copy_succeeded = 1; ret = wc_Sha256Update(&key->hash.sha2.sha256, address, SLHDSA_HAC_SZ); } if (ret == 0) { @@ -935,6 +963,9 @@ static int slhdsakey_hash_prf_sha2(SlhDsaKey* key, const byte* pk_seed, if (ret == 0) { XMEMCPY(hash, digest, n); } + if (copy_succeeded) { + wc_Sha256Free(&key->hash.sha2.sha256); + } return ret; } @@ -1031,6 +1062,24 @@ static int slhdsakey_hash_final_sha2(SlhDsaKey* key, byte* hash, word32 len) return ret; } +/* SHA2 T_l streaming: free internal allocations. + * + * @param [in] key SLH-DSA key. + */ +static void slhdsakey_hash_free_sha2(SlhDsaKey* key) +{ + byte n = key->params->n; + + if (n == WC_SLHDSA_N_128) { + wc_Sha256Free(&key->hash.sha2.sha256_2); + } + else { + wc_Sha512Free(&key->hash.sha2.sha512_2); + } + + return; +} + /* Local MGF1 implementation for H_msg. * * FIPS 205. Section 11.2. @@ -1063,9 +1112,11 @@ static int slhdsakey_mgf1_sha2(SlhDsaKey* key, const byte* seed, byte digest[WC_SHA256_DIGEST_SIZE]; word32 cpLen = (left < WC_SHA256_DIGEST_SIZE) ? left : WC_SHA256_DIGEST_SIZE; + int hash_inited = 0; ret = wc_InitSha256(&key->hash.sha2.sha256_2); if (ret == 0) { + hash_inited = 1; ret = wc_Sha256Update(&key->hash.sha2.sha256_2, seed, seedLen); } if (ret == 0) { @@ -1074,6 +1125,9 @@ static int slhdsakey_mgf1_sha2(SlhDsaKey* key, const byte* seed, if (ret == 0) { ret = wc_Sha256Final(&key->hash.sha2.sha256_2, digest); } + if (hash_inited) { + wc_Sha256Free(&key->hash.sha2.sha256_2); + } if (ret == 0) { XMEMCPY(out + done, digest, cpLen); done += cpLen; @@ -1084,9 +1138,11 @@ static int slhdsakey_mgf1_sha2(SlhDsaKey* key, const byte* seed, byte digest[WC_SHA512_DIGEST_SIZE]; word32 cpLen = (left < WC_SHA512_DIGEST_SIZE) ? left : WC_SHA512_DIGEST_SIZE; + int hash_inited = 0; ret = wc_InitSha512(&key->hash.sha2.sha512_2); if (ret == 0) { + hash_inited = 1; ret = wc_Sha512Update(&key->hash.sha2.sha512_2, seed, seedLen); } if (ret == 0) { @@ -1095,6 +1151,9 @@ static int slhdsakey_mgf1_sha2(SlhDsaKey* key, const byte* seed, if (ret == 0) { ret = wc_Sha512Final(&key->hash.sha2.sha512_2, digest); } + if (hash_inited) { + wc_Sha512Free(&key->hash.sha2.sha512_2); + } if (ret == 0) { XMEMCPY(out + done, digest, cpLen); done += cpLen; @@ -1199,10 +1258,12 @@ static int slhdsakey_h_msg_sha2(SlhDsaKey* key, const byte* r, byte innerHash[WC_SHA256_DIGEST_SIZE]; /* Seed for MGF1: R || PK.seed || innerHash. */ byte mgfSeed[32 + 16 + WC_SHA256_DIGEST_SIZE]; + int sha_inited = 0; /* Step 1: innerHash = SHA-256(R || PK.seed || PK.root || M). */ ret = wc_InitSha256(&key->hash.sha2.sha256_2); if (ret == 0) { + sha_inited = 1; ret = wc_Sha256Update(&key->hash.sha2.sha256_2, r, n); } if (ret == 0) { @@ -1223,6 +1284,9 @@ static int slhdsakey_h_msg_sha2(SlhDsaKey* key, const byte* r, if (ret == 0) { ret = wc_Sha256Final(&key->hash.sha2.sha256_2, innerHash); } + if (sha_inited) { + wc_Sha256Free(&key->hash.sha2.sha256_2); + } /* Step 2: MGF1-SHA-256(R || PK.seed || innerHash, mdLen). */ if (ret == 0) { @@ -1238,10 +1302,12 @@ static int slhdsakey_h_msg_sha2(SlhDsaKey* key, const byte* r, byte innerHash[WC_SHA512_DIGEST_SIZE]; /* Seed for MGF1: R || PK.seed || innerHash. */ byte mgfSeed[32 + 32 + WC_SHA512_DIGEST_SIZE]; + int sha_inited = 0; /* Step 1: innerHash = SHA-512(R || PK.seed || PK.root || M). */ ret = wc_InitSha512(&key->hash.sha2.sha512_2); if (ret == 0) { + sha_inited = 1; ret = wc_Sha512Update(&key->hash.sha2.sha512_2, r, n); } if (ret == 0) { @@ -1262,6 +1328,9 @@ static int slhdsakey_h_msg_sha2(SlhDsaKey* key, const byte* r, if (ret == 0) { ret = wc_Sha512Final(&key->hash.sha2.sha512_2, innerHash); } + if (sha_inited) { + wc_Sha512Free(&key->hash.sha2.sha512_2); + } /* Step 2: MGF1-SHA-512(R || PK.seed || innerHash, mdLen). */ if (ret == 0) { @@ -1424,6 +1493,11 @@ static int slhdsakey_hash_prf_shake(SlhDsaKey* key, const byte* pk_seed, slhdsakey_hash_final_sha2(k, o, l) : \ slhdsakey_hash_final(&(k)->hash.shk.shake2, o, l)) +#define HASH_T_FREE(k) \ + (SLHDSA_IS_SHA2((k)->params->param) ? \ + slhdsakey_hash_free_sha2(k) : \ + slhdsakey_hash_free(&(k)->hash.shk.shake2)) + #else #define HASH_T_START_ADDR(k, pk_seed, adrs, n) \ @@ -1435,6 +1509,9 @@ static int slhdsakey_hash_prf_shake(SlhDsaKey* key, const byte* pk_seed, #define HASH_T_FINAL(k, o, l) \ slhdsakey_hash_final(&(k)->hash.shk.shake2, o, l) +#define HASH_T_FREE(k) \ + slhdsakey_hash_free(&(k)->hash.shk.shake2) + #endif /* WOLFSSL_SLHDSA_SHA2 */ /* Start hashing with SHAKE-256. @@ -1534,6 +1611,15 @@ static int slhdsakey_hash_final(wc_Shake* shake, byte* hash, word32 len) return wc_Shake256_Final(shake, hash, len); } +/* Free internal resources. + * + * @param [in] shake SHAKE-256 object. + */ +static void slhdsakey_hash_free(wc_Shake* shake) +{ + wc_Shake256_Free(shake); +} + /****************************************************************************** * Conversion functions ******************************************************************************/ @@ -3173,6 +3259,7 @@ static int slhdsakey_wots_pkgen(SlhDsaKey* key, const byte* sk_seed, { int ret; byte n = key->params->n; + int hash_t_started = 0; { HashAddress wotspk_adrs; @@ -3186,6 +3273,8 @@ static int slhdsakey_wots_pkgen(SlhDsaKey* key, const byte* sk_seed, if (ret == 0) { HashAddress sk_adrs; + hash_t_started = 1; + /* Steps 1-2. Copy address and set to WOTS PRF. */ HA_Copy(sk_adrs, adrs); HA_SetTypeAndClearNotKPA(sk_adrs, HA_WOTS_PRF); @@ -3210,6 +3299,10 @@ static int slhdsakey_wots_pkgen(SlhDsaKey* key, const byte* sk_seed, ret = HASH_T_FINAL(key, node, n); } + if (hash_t_started) { + HASH_T_FREE(key); + } + return ret; } @@ -3565,7 +3658,7 @@ static int slhdsakey_wots_sign_chain_x4(SlhDsaKey* key, const byte* msg, static int slhdsakey_wots_sign(SlhDsaKey* key, const byte* m, const byte* sk_seed, const byte* pk_seed, word32* adrs, byte* sig) { - int ret; + int ret = WC_NO_ERR_TRACE(BAD_FUNC_ARG); word16 csum; HashAddress sk_adrs; byte n = key->params->n; @@ -3894,6 +3987,7 @@ static int slhdsakey_wots_pk_from_sig_x4(SlhDsaKey* key, const byte* sig, byte n = key->params->n; byte len = key->params->len; WC_DECLARE_VAR(nodes, byte, SLHDSA_MAX_MSG_SZ * SLHDSA_MAX_N, key->heap); + int hash_t_started = 0; WC_ALLOC_VAR_EX(nodes, byte, SLHDSA_MAX_MSG_SZ * SLHDSA_MAX_N, key->heap, DYNAMIC_TYPE_SLHDSA, ret = MEMORY_E); @@ -3987,12 +4081,16 @@ static int slhdsakey_wots_pk_from_sig_x4(SlhDsaKey* key, const byte* sig, ret = HASH_T_START_ADDR(key, pk_seed, wotspk_adrs, n); } if (ret == 0) { + hash_t_started = 1; ret = HASH_T_UPDATE(key, nodes, len * n); sig += len * n; } if (ret == 0) { ret = HASH_T_FINAL(key, pk_sig, n); } + if (hash_t_started) { + HASH_T_FREE(key); + } WC_FREE_VAR_EX(nodes, key->heap, DYNAMIC_TYPE_SLHDSA); return ret; @@ -4034,6 +4132,7 @@ static int slhdsakey_wots_pk_from_sig_c(SlhDsaKey* key, const byte* sig, byte len = key->params->len; HashAddress wotspk_adrs; WC_DECLARE_VAR(nodes, byte, SLHDSA_MAX_MSG_SZ * SLHDSA_MAX_N, key->heap); + int hash_t_started = 0; WC_ALLOC_VAR_EX(nodes, byte, SLHDSA_MAX_MSG_SZ * SLHDSA_MAX_N, key->heap, DYNAMIC_TYPE_SLHDSA, ret = MEMORY_E); @@ -4060,6 +4159,7 @@ static int slhdsakey_wots_pk_from_sig_c(SlhDsaKey* key, const byte* sig, ret = HASH_T_START_ADDR(key, pk_seed, wotspk_adrs, n); } if (ret == 0) { + hash_t_started = 1; /* Step 15: Update with the nodes ... */ ret = HASH_T_UPDATE(key, nodes, len * n); } @@ -4067,6 +4167,9 @@ static int slhdsakey_wots_pk_from_sig_c(SlhDsaKey* key, const byte* sig, /* Step 15: Generate root node - public key signature. */ ret = HASH_T_FINAL(key, pk_sig, n); } + if (hash_t_started) { + HASH_T_FREE(key); + } WC_FREE_VAR_EX(nodes, key->heap, DYNAMIC_TYPE_SLHDSA); return ret; @@ -4106,6 +4209,7 @@ static int slhdsakey_wots_pk_from_sig_c(SlhDsaKey* key, const byte* sig, byte len = key->params->len; HashAddress wotspk_adrs; byte* node = pk_sig; + int hash_t_started = 0; /* Step 12-14: Copy the address for WOTS PK. */ HA_Copy(wotspk_adrs, adrs); @@ -4113,6 +4217,7 @@ static int slhdsakey_wots_pk_from_sig_c(SlhDsaKey* key, const byte* sig, /* Step 15: Hash the public key seed and WOTS PK address ... */ ret = HASH_T_START_ADDR(key, pk_seed, wotspk_adrs, n); if (ret == 0) { + hash_t_started = 1; /* Step 8: For each value in msg. */ for (i = 0; i < len; i++) { /* Step 9: Set chain address for WOTS HASH. */ @@ -4136,6 +4241,9 @@ static int slhdsakey_wots_pk_from_sig_c(SlhDsaKey* key, const byte* sig, /* Step 15: Generate root node - public key signature. */ ret = HASH_T_FINAL(key, pk_sig, n); } + if (hash_t_started) { + HASH_T_FREE(key); + } return ret; } @@ -4422,7 +4530,7 @@ static int slhdsakey_xmss_sign(SlhDsaKey* key, const byte* m, const byte* sk_seed, word32 idx, const byte* pk_seed, word32* adrs, byte* sig_xmss) { - int ret; + int ret = WC_NO_ERR_TRACE(BAD_FUNC_ARG); byte n = key->params->n; byte len = key->params->len; byte h_m = key->params->h_m; @@ -5610,7 +5718,7 @@ static int slhdsakey_fors_node_c(SlhDsaKey* key, const byte* sk_seed, word32 i, static int slhdsakey_fors_sign(SlhDsaKey* key, const byte* md, const byte* sk_seed, const byte* pk_seed, word32* adrs, byte* sig_fors) { - int ret; + int ret = WC_NO_ERR_TRACE(BAD_FUNC_ARG); word16 indices[SLHDSA_MAX_INDICES_SZ]; int i; int j; @@ -6293,6 +6401,7 @@ static int slhdsakey_fors_pk_from_sig(SlhDsaKey* key, const byte* sig_fors, byte n = key->params->n; byte a = key->params->a; byte k = key->params->k; + int hash_t_started = 0; /* Step 1: Get indices from byte array. */ slhdsakey_base_2b(md, a, k, indices); @@ -6304,6 +6413,10 @@ static int slhdsakey_fors_pk_from_sig(SlhDsaKey* key, const byte* sig_fors, /* Step 24: Add public key seed and FORS roots address to hash ... */ ret = HASH_T_START_ADDR(key, pk_seed, forspk_adrs, n); + if (ret == 0) { + hash_t_started = 1; + } + /* Steps 2-20: Compute roots and add to hash. */ #if defined(USE_INTEL_SPEEDUP) && !defined(WOLFSSL_WC_SLHDSA_SMALL) if ((ret == 0) && !SLHDSA_IS_SHA2(key->params->param) && @@ -6325,6 +6438,10 @@ static int slhdsakey_fors_pk_from_sig(SlhDsaKey* key, const byte* sig_fors, ret = HASH_T_FINAL(key, pk_fors, n); } + if (hash_t_started) { + HASH_T_FREE(key); + } + return ret; } @@ -6385,14 +6502,8 @@ int wc_SlhDsaKey_Init(SlhDsaKey* key, enum SlhDsaParam param, void* heap, if (SLHDSA_IS_SHA2(param)) { /* Initialize SHA2 hash objects. */ ret = wc_InitSha256(&key->hash.sha2.sha256); - if (ret == 0) { - ret = wc_InitSha256(&key->hash.sha2.sha256_2); - } if ((ret == 0) && (key->params->n > 16)) { ret = wc_InitSha512(&key->hash.sha2.sha512); - if (ret == 0) { - ret = wc_InitSha512(&key->hash.sha2.sha512_2); - } } } else From beae56fba7ed7d680b9e816339d8661552fc08bb Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Mon, 27 Apr 2026 11:36:34 -0500 Subject: [PATCH 137/167] wolfcrypt/test/test.c: * fix aes_eax_test() for NO_MALLOC (use WC_*_VAR() to allocate eax context). * in slhdsa_test(), gate the profusely verbose TestDumpData() clauses on WC_SLHDSA_VERBOSE_DEBUG. --- wolfcrypt/test/test.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 914f9ab22b..b016204f7a 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -19601,11 +19601,12 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aes_eax_test(void) * one-shot API above is a separate code path. Heap-allocate the * AesEax context to keep stack usage within Linux kernel limits. */ { - AesEax *eax = (AesEax *)XMALLOC(sizeof(*eax), HEAP_HINT, - DYNAMIC_TYPE_TMP_BUFFER); - if (eax == NULL) { - return WC_TEST_RET_ENC_NC; - } + WC_DECLARE_VAR(eax, AesEax, 1, HEAP_HINT); + + WC_ALLOC_VAR(eax, AesEax, 1, HEAP_HINT); + if (!WC_VAR_OK(eax)) + return WC_TEST_RET_ENC_EC(MEMORY_E); + XMEMSET(eax, 0, sizeof(*eax)); ret = wc_AesEaxInit(eax, vectors[0].key, (word32)vectors[0].key_length, @@ -19613,14 +19614,14 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aes_eax_test(void) vectors[0].aad, (word32)vectors[0].aad_length); if (ret != 0) { - XFREE(eax, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + WC_FREE_VAR(eax, HEAP_HINT); return WC_TEST_RET_ENC_EC(ret); } ret = wc_AesEaxDecryptFinal(eax, zero_tag, 0); if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) { wc_AesEaxFree(eax); - XFREE(eax, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + WC_FREE_VAR(eax, HEAP_HINT); return WC_TEST_RET_ENC_EC(ret); } @@ -19629,7 +19630,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aes_eax_test(void) WOLFSSL_MIN_AUTH_TAG_SZ - 1); if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) { wc_AesEaxFree(eax); - XFREE(eax, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + WC_FREE_VAR(eax, HEAP_HINT); return WC_TEST_RET_ENC_EC(ret); } #endif @@ -19638,12 +19639,12 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t aes_eax_test(void) ret = wc_AesEaxDecryptFinal(eax, zero_tag, WC_AES_BLOCK_SIZE + 1); if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) { wc_AesEaxFree(eax); - XFREE(eax, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + WC_FREE_VAR(eax, HEAP_HINT); return WC_TEST_RET_ENC_EC(ret); } wc_AesEaxFree(eax); - XFREE(eax, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + WC_FREE_VAR(eax, HEAP_HINT); } } #endif /* WOLFSSL_MIN_AUTH_TAG_SZ > 0 */ @@ -55354,8 +55355,10 @@ wc_test_ret_t slhdsa_test(void) ERROR_OUT(WC_TEST_RET_ENC_I(outLen), out); } if (XMEMCMP(sig, sig_shake128s, outLen) != 0) { +#ifdef WC_SLHDSA_VERBOSE_DEBUG TestDumpData("SIG", sig, outLen); TestDumpData("EXP", sig_shake128s, outLen); +#endif ERROR_OUT(WC_TEST_RET_ENC_NC, out); } #endif From 1d8028865f0b0f87735657e0c4175bd559a9066f Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Mon, 27 Apr 2026 11:36:48 -0500 Subject: [PATCH 138/167] wolfcrypt/benchmark/benchmark.c: add missing WOLFSSL_USE_SAVE_VECTOR_REGISTERS handling in bench_stats_ops_finish(). --- wolfcrypt/benchmark/benchmark.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/wolfcrypt/benchmark/benchmark.c b/wolfcrypt/benchmark/benchmark.c index e8ab96cf87..6b77af42e5 100644 --- a/wolfcrypt/benchmark/benchmark.c +++ b/wolfcrypt/benchmark/benchmark.c @@ -3339,6 +3339,12 @@ static void bench_stats_ops_finish(const char* algo, int strength, (void)ret; +#if defined(WOLFSSL_USE_SAVE_VECTOR_REGISTERS) + RESTORE_VECTOR_REGISTERS(); +#elif defined(WOLFSSL_LINUXKM) + kernel_fpu_end(); +#endif + bench_stats_prepare(); TEST_SLEEP(); } /* bench_stats_ops_finish */ From ac11279c60acee6df8e1d18bcc48d1194fb5c526 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Mon, 27 Apr 2026 11:37:15 -0500 Subject: [PATCH 139/167] wolfcrypt/src/random.c: * add workaround in Hash512_df() for gcc compiler bug around AVX512 and object alignment. * add missing WC_VERBOSE_RNG clause. --- wolfcrypt/src/random.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/wolfcrypt/src/random.c b/wolfcrypt/src/random.c index 33ff460006..efc9eaf59a 100644 --- a/wolfcrypt/src/random.c +++ b/wolfcrypt/src/random.c @@ -1058,8 +1058,16 @@ static int Hash512_df(DRBG_SHA512_internal* drbg, byte* out, word32 outSz, byte* digest = drbg->digest_scratch; #elif defined(WOLFSSL_SMALL_STACK) byte* digest; +#else +#if defined(__GNUC__) && !defined(__clang__) && defined(__AVX512F__) + /* Use a jumbo alignment to work around a gcc compiler/optimizer bug that + * assumes AVX512 alignment in an object sized correctly for AVX512 passed + * to builtin memcpy(), which promptly crashes if not thus aligned. + */ + byte digest[WC_SHA512_DIGEST_SIZE] WOLFSSL_ALIGN(WC_SHA512_DIGEST_SIZE); #else byte digest[WC_SHA512_DIGEST_SIZE]; +#endif #endif if (drbg == NULL) { @@ -1135,6 +1143,12 @@ static int Hash512_df(DRBG_SHA512_internal* drbg, byte* out, word32 outSz, XFREE(digest, drbg->heap, DYNAMIC_TYPE_DIGEST); #endif +#ifdef WC_VERBOSE_RNG + if (ret != 0) + WOLFSSL_DEBUG_PRINTF("ERROR: %s failed with err = %d", __FUNCTION__, + ret); +#endif + return (ret == 0) ? DRBG_SUCCESS : DRBG_FAILURE; } From 3279b367d7d7c1d0600bd9e1462eec0725e7a68e Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Mon, 27 Apr 2026 11:37:29 -0500 Subject: [PATCH 140/167] wolfcrypt/src/wc_lms.c: remove redundant gating on WOLFSSL_LMS_SHAKE256 in wc_LmsParamsMap wc_lms_map[]. --- wolfcrypt/src/wc_lms.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/wolfcrypt/src/wc_lms.c b/wolfcrypt/src/wc_lms.c index 6192dcdba7..01286cdc2b 100644 --- a/wolfcrypt/src/wc_lms.c +++ b/wolfcrypt/src/wc_lms.c @@ -521,7 +521,6 @@ static const wc_LmsParamsMap wc_lms_map[] = { #endif #endif /* !WOLFSSL_NO_LMS_SHAKE256_256 */ -#ifdef WOLFSSL_LMS_SHAKE256 /* SHAKE256/192 L1 H5 */ { WC_LMS_PARM_SHAKE192_L1_H5_W1 , "LMS/HSS_SHAKE256/192_L1_H5_W1", LMS_PARAMS(1, 5, 1, 2, LMS_SHAKE_M24_H5 , LMOTS_SHAKE_N24_W1, @@ -595,7 +594,6 @@ static const wc_LmsParamsMap wc_lms_map[] = { LMS_PARAMS(1, 25, 8, 4, LMS_SHAKE_M24_H25, LMOTS_SHAKE_N24_W8, WC_SHA256_192_DIGEST_SIZE) }, #endif -#endif /* WOLFSSL_LMS_SHAKE256 (M24 entries) */ #endif /* WOLFSSL_LMS_SHAKE256 */ }; /* Number of parameter sets supported. */ From 66ea4daa09bc687ede514331f291302f795b7014 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Mon, 27 Apr 2026 11:40:04 -0500 Subject: [PATCH 141/167] wolfcrypt/src/wc_port.c: in wc_socket_cloexec(), add necessary but undocumented __USE_GNU gating on call to accept4() (pre-includes can bring in socket.h before the override setting of _GNU_SOURCE at the top). Also enable accept4() for FreeBSD. --- .wolfssl_known_macro_extras | 1 + wolfcrypt/src/wc_port.c | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 277703dd14..c676c15524 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -1023,6 +1023,7 @@ __AVX512F__ __BCPLUSPLUS__ __BIG_ENDIAN__ __BORLANDC__ +__BSD_VISIBLE __CCRX__ __CC_ARM __COMPILER_VER__ diff --git a/wolfcrypt/src/wc_port.c b/wolfcrypt/src/wc_port.c index 3ffb962de0..e84c385744 100644 --- a/wolfcrypt/src/wc_port.c +++ b/wolfcrypt/src/wc_port.c @@ -23,6 +23,9 @@ !defined(WOLFSSL_LINUXKM) && !defined(WOLFSSL_ZEPHYR) && \ !defined(_GNU_SOURCE) #define _GNU_SOURCE 1 +#elif defined(__FreeBSD__) + /* for __FreeBSD_version */ + #include #endif /* @@ -5210,7 +5213,9 @@ int wc_socket_cloexec(int domain, int type, int protocol) int wc_accept_cloexec(int sockfd, void* addr, void* addrlen) { int fd; -#if defined(__linux__) || defined(__ANDROID__) +#if (defined(__USE_GNU) && (defined(__linux__) || defined(__ANDROID__))) || \ + (defined(__FreeBSD__) && defined(__BSD_VISIBLE) && __BSD_VISIBLE && \ + (__FreeBSD_version >= 1000000)) fd = accept4(sockfd, (struct sockaddr*)addr, (socklen_t*)addrlen, SOCK_CLOEXEC); if (fd >= 0) From e31e15822536f6250af8d51ff0607e2367f1487c Mon Sep 17 00:00:00 2001 From: David Garske Date: Fri, 24 Apr 2026 17:14:13 -0700 Subject: [PATCH 142/167] Fix for using STM32 AES hardware crypto with WOLFSSL_ARMASM set (ZD 21262) --- wolfcrypt/src/aes.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/wolfcrypt/src/aes.c b/wolfcrypt/src/aes.c index 0e5304c2ea..c2c982203f 100644 --- a/wolfcrypt/src/aes.c +++ b/wolfcrypt/src/aes.c @@ -7707,7 +7707,13 @@ int wc_AesGcmSetKey(Aes* aes, const byte* key, word32 len) return ret; #endif /* WOLFSSL_RENESAS_RSIP && WOLFSSL_RENESAS_FSPSM_CRYPTONLY*/ -#if defined(WOLFSSL_ARMASM) +/* GCM setup needs one AES block encrypt of the all-zero IV to generate + * the hash subkey H. STM32_CRYPTO stores only the raw key (no expanded + * key schedule), so the ARMASM AES_ECB_encrypt helpers used here cannot + * be used. Excluding STM32_CRYPTO from this block falls back to the + * non-ARMASM wc_AesEncrypt implementation, which on STM32 routes to + * CRYP. */ +#if defined(WOLFSSL_ARMASM) && !defined(STM32_CRYPTO) if (ret == 0) { #ifndef WOLFSSL_ARMASM_NO_HW_CRYPTO #if !defined(__aarch64__) From 1f260ccb0a6b9101455b8196c9a498f115b32e03 Mon Sep 17 00:00:00 2001 From: Lealem Amedie Date: Mon, 27 Apr 2026 17:15:06 -0600 Subject: [PATCH 143/167] Add TLS-ALPN-01 challenge cert support (RFC 8737 acmeId extension) --- tests/api.c | 85 ++++++++++++++++++++++++++ wolfcrypt/src/asn.c | 108 +++++++++++++++++++++++++++++++++ wolfssl/wolfcrypt/asn.h | 8 ++- wolfssl/wolfcrypt/asn_public.h | 27 +++++++++ wolfssl/wolfcrypt/oid_sum.h | 12 +++- 5 files changed, 237 insertions(+), 3 deletions(-) diff --git a/tests/api.c b/tests/api.c index 05a7688d7f..840562d32b 100644 --- a/tests/api.c +++ b/tests/api.c @@ -11626,6 +11626,90 @@ static int test_wolfSSL_mcast(void) | Wolfcrypt *----------------------------------------------------------------------------*/ +/* + * Testing wc_SetAcmeIdentifierExt() round-trip — the RFC 8737 + * id-pe-acmeIdentifier (1.3.6.1.5.5.7.1.31) extension used by + * TLS-ALPN-01 ACME challenge certs. + */ +static int test_wc_SetAcmeIdentifierExt(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_ACME_OID) && defined(WOLFSSL_CERT_GEN) && \ + defined(HAVE_ECC) && !defined(NO_SHA256) && !defined(NO_ASN_TIME) && \ + !defined(WC_NO_RNG) && !defined(NO_RSA) + Cert cert; + DecodedCert decoded; + WC_RNG rng; + ecc_key key; + byte der[TWOK_BUF]; + int derSz = 0; + int rngInited = 0, keyInited = 0; + const char* keyAuth = "evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA" + ".kZdq0qaDcXNVxKBkP_uiKvw2Yg5sRJ8KBfQa9Ru13nE"; + word32 keyAuthSz = (word32)XSTRLEN(keyAuth); + byte expected[WC_SHA256_DIGEST_SIZE]; + + XMEMSET(&cert, 0, sizeof(cert)); + XMEMSET(&decoded, 0, sizeof(decoded)); + XMEMSET(&rng, 0, sizeof(rng)); + XMEMSET(&key, 0, sizeof(key)); + XMEMSET(der, 0, sizeof(der)); + + /* Compute the expected digest */ + ExpectIntEQ(wc_Sha256Hash((const byte*)keyAuth, keyAuthSz, expected), 0); + + /* Input validation. */ + ExpectIntEQ(wc_SetAcmeIdentifierExt(NULL, (const byte*)keyAuth, keyAuthSz), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_SetAcmeIdentifierExt(&cert, NULL, keyAuthSz), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_SetAcmeIdentifierExt(&cert, (const byte*)keyAuth, 0), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* Build a P-256 keypair to sign the cert. */ + ExpectIntEQ(wc_InitRng(&rng), 0); + rngInited = 1; + ExpectIntEQ(wc_ecc_init(&key), 0); + keyInited = 1; + ExpectIntEQ(wc_ecc_make_key_ex(&rng, KEY32, &key, ECC_SECP256R1), 0); + + /* Build a minimal self-signed cert template carrying the extension. */ + ExpectIntEQ(wc_InitCert(&cert), 0); + cert.sigType = CTC_SHA256wECDSA; + cert.daysValid = 1; + cert.isCA = 0; + XSTRNCPY(cert.subject.commonName, "acme-test.example", CTC_NAME_SIZE); + + ExpectIntEQ(wc_SetAcmeIdentifierExt(&cert, (const byte*)keyAuth, + keyAuthSz), 0); + ExpectIntEQ(cert.acmeIdentifierSz, WC_SHA256_DIGEST_SIZE); + ExpectIntEQ(XMEMCMP(cert.acmeIdentifier, expected, + WC_SHA256_DIGEST_SIZE), 0); + + /* MakeCert + SignCert. ECC_TYPE selects the ECDSA signing path. */ + ExpectIntGT(derSz = wc_MakeCert_ex(&cert, der, sizeof(der), + ECC_TYPE, &key, &rng), 0); + ExpectIntGT(derSz = wc_SignCert_ex(cert.bodySz, cert.sigType, + der, sizeof(der), + ECC_TYPE, &key, &rng), 0); + + /* Parse the cert back and verify the extension survives the + * round-trip via DecodeAcmeId. */ + wc_InitDecodedCert(&decoded, der, derSz, NULL); + ExpectIntEQ(wc_ParseCert(&decoded, CERT_TYPE, NO_VERIFY, NULL), 0); + ExpectIntEQ(decoded.extAcmeIdentifierSet, 1); + ExpectIntEQ(decoded.extAcmeIdentifierCrit, 1); + ExpectIntEQ(decoded.acmeIdentifierSz, WC_SHA256_DIGEST_SIZE); + ExpectIntEQ(XMEMCMP(decoded.acmeIdentifier, expected, + WC_SHA256_DIGEST_SIZE), 0); + + wc_FreeDecodedCert(&decoded); + if (keyInited) wc_ecc_free(&key); + if (rngInited) wc_FreeRng(&rng); +#endif + return EXPECT_RESULT(); +} /* END test_wc_SetAcmeIdentifierExt */ + /* * Testing wc_SetKeyUsage() */ @@ -37017,6 +37101,7 @@ TEST_CASE testCases[] = { #ifdef WOLFSSL_CERT_SIGN_CB TEST_DECL(test_wc_SignCert_cb), #endif + TEST_DECL(test_wc_SetAcmeIdentifierExt), TEST_DECL(test_wc_SetKeyUsage), TEST_DECL(test_wc_SetAuthKeyIdFromPublicKey_ex), TEST_DECL(test_wc_SetSubjectBuffer), diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 9a3be56616..6ecf6a05d5 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -19014,6 +19014,39 @@ static int DecodeKeyUsageInternal(const byte* input, word32 sz, return DecodeKeyUsage(input, sz, &cert->extKeyUsage); } +#ifdef WOLFSSL_ACME_OID +/* Decodes the RFC 8737 id-pe-acmeIdentifier (1.3.6.1.5.5.7.1.31) + * extension value into cert->acmeIdentifier. + * + * The extnValue is an OCTET STRING wrapping a SHA-256 digest of the + * ACME keyAuth, per RFC 8737 3. Length is verified against + * WC_SHA256_DIGEST_SIZE. + * + * @param [in] input ASN.1 DER-encoded extension value. + * @param [in] sz Length of input in bytes. + * @param [in, out] cert DecodedCert to populate (acmeIdentifier and + * acmeIdentifierSz fields). + * + * @return 0 on success. + * @return ASN_PARSE_E when the inner OCTET STRING is missing or not + * exactly WC_SHA256_DIGEST_SIZE bytes. + */ +static int DecodeAcmeId(const byte* input, word32 sz, DecodedCert* cert) +{ + word32 hashIdx = 0; + int hashLen = 0; + + if (GetOctetString(input, &hashIdx, &hashLen, sz) < 0) + return ASN_PARSE_E; + if (hashLen != WC_SHA256_DIGEST_SIZE) + return ASN_PARSE_E; + + XMEMCPY(cert->acmeIdentifier, &input[hashIdx], WC_SHA256_DIGEST_SIZE); + cert->acmeIdentifierSz = WC_SHA256_DIGEST_SIZE; + return 0; +} +#endif /* WOLFSSL_ACME_OID */ + #ifdef WOLFSSL_ASN_TEMPLATE /* ASN.1 template for KeyPurposeId. * X.509: RFC 5280, 4.2.1.12 - Extended Key Usage. @@ -20236,6 +20269,14 @@ int DecodeExtensionType(const byte* input, word32 length, word32 oid, return ASN_PARSE_E; break; #endif /* WOLFSSL_DUAL_ALG_CERTS */ + #ifdef WOLFSSL_ACME_OID + case ACME_IDENTIFIER_OID: + VERIFY_AND_SET_OID(cert->extAcmeIdentifierSet); + cert->extAcmeIdentifierCrit = critical ? 1 : 0; + if (DecodeAcmeId(&input[idx], length, cert) < 0) + return ASN_PARSE_E; + break; + #endif default: if (isUnknownExt != NULL) *isUnknownExt = 1; @@ -26510,6 +26551,12 @@ static const ASNItem static_certExtsASN[] = { /* CRLINFO_SEQ */ { 0, ASN_SEQUENCE, 1, 1, 0 }, /* CRLINFO_OID */ { 1, ASN_OBJECT_ID, 0, 0, 0 }, /* CRLINFO_STR */ { 1, ASN_OCTET_STRING, 0, 0, 0 }, + /* RFC 8737 id-pe-acmeIdentifier */ +/* ACMEID_SEQ */ { 0, ASN_SEQUENCE, 1, 1, 0 }, +/* ACMEID_OID */ { 1, ASN_OBJECT_ID, 0, 0, 0 }, +/* ACMEID_CRIT */ { 1, ASN_BOOLEAN, 0, 0, 0 }, +/* ACMEID_STR */ { 1, ASN_OCTET_STRING, 0, 1, 0 }, +/* ACMEID_HASH */ { 2, ASN_OCTET_STRING, 0, 0, 0 }, #ifdef WOLFSSL_DUAL_ALG_CERTS /* SAPKI_SEQ */ { 0, ASN_SEQUENCE, 1, 1, 0 }, /* SAPKI_OID */ { 1, ASN_OBJECT_ID, 0, 0, 0 }, @@ -26568,6 +26615,11 @@ enum { CERTEXTSASN_IDX_CRLINFO_SEQ, CERTEXTSASN_IDX_CRLINFO_OID, CERTEXTSASN_IDX_CRLINFO_STR, + CERTEXTSASN_IDX_ACMEID_SEQ, + CERTEXTSASN_IDX_ACMEID_OID, + CERTEXTSASN_IDX_ACMEID_CRIT, + CERTEXTSASN_IDX_ACMEID_STR, + CERTEXTSASN_IDX_ACMEID_HASH, #ifdef WOLFSSL_DUAL_ALG_CERTS CERTEXTSASN_IDX_SAPKI_SEQ, CERTEXTSASN_IDX_SAPKI_OID, @@ -26623,6 +26675,10 @@ static int EncodeExtensions(Cert* cert, byte* output, word32 maxSz, static const byte nsCertOID[] = { 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x42, 0x01, 0x01 }; static const byte crlInfoOID[] = { 0x55, 0x1D, 0x1F }; +#ifdef WOLFSSL_ACME_OID + static const byte acmeIdOID[] = { 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x01, 0x1F }; +#endif #ifdef WOLFSSL_DUAL_ALG_CERTS static const byte sapkiOID[] = { 0x55, 0x1d, 0x48 }; static const byte altSigAlgOID[] = { 0x55, 0x1d, 0x49 }; @@ -26878,6 +26934,24 @@ static int EncodeExtensions(Cert* cert, byte* output, word32 maxSz, CERTEXTSASN_IDX_CRLINFO_STR); } + #ifdef WOLFSSL_ACME_OID + /* id-pe-acmeIdentifier (TLS-ALPN-01 challenge cert). + * Always critical=TRUE. */ + if (cert->acmeIdentifierSz == WC_SHA256_DIGEST_SIZE) { + SetASN_Buffer(&dataASN[CERTEXTSASN_IDX_ACMEID_OID], + acmeIdOID, sizeof(acmeIdOID)); + SetASN_Boolean(&dataASN[CERTEXTSASN_IDX_ACMEID_CRIT], 1); + SetASN_Buffer(&dataASN[CERTEXTSASN_IDX_ACMEID_HASH], + cert->acmeIdentifier, (word32)cert->acmeIdentifierSz); + } + else + #endif /* WOLFSSL_ACME_OID */ + { + /* Don't write out the ACME identifier extension. */ + SetASNItem_NoOut(dataASN, CERTEXTSASN_IDX_ACMEID_SEQ, + CERTEXTSASN_IDX_ACMEID_HASH); + } + #ifdef WOLFSSL_DUAL_ALG_CERTS if (cert->sapkiDer != NULL) { /* Set subject alternative public key info OID, criticality and @@ -29313,6 +29387,40 @@ int wc_SetExtKeyUsage(Cert *cert, const char *value) return ret; } +#ifdef WOLFSSL_ACME_OID +/* Set the id-pe-acmeIdentifier extension value from the ACME + * keyAuth string. Computes SHA-256 over keyAuth and stores the digest + * as the extension value. RFC 8737 3 requires critical=TRUE; that's + * applied at encode time in EncodeExtensions. + * + * keyAuth is the raw bytes of the key authorization string per + * RFC 8555 8.1: token "." JWK_thumbprint. + */ +int wc_SetAcmeIdentifierExt(Cert *cert, const byte *keyAuth, word32 keyAuthSz) +{ + int ret; + byte digest[WC_SHA256_DIGEST_SIZE]; + wc_Sha256 sha; + + if (cert == NULL || keyAuth == NULL || keyAuthSz == 0) + return BAD_FUNC_ARG; + + ret = wc_InitSha256(&sha); + if (ret != 0) + return ret; + ret = wc_Sha256Update(&sha, keyAuth, keyAuthSz); + if (ret == 0) + ret = wc_Sha256Final(&sha, digest); + wc_Sha256Free(&sha); + if (ret != 0) + return ret; + + XMEMCPY(cert->acmeIdentifier, digest, WC_SHA256_DIGEST_SIZE); + cert->acmeIdentifierSz = WC_SHA256_DIGEST_SIZE; + return 0; +} +#endif /* WOLFSSL_ACME_OID */ + #ifdef WOLFSSL_EKU_OID /* * cert structure to set EKU oid in diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index b3028c9c99..d4ede74abd 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -2107,7 +2107,13 @@ struct DecodedCert { WC_BITFIELD extAltSigAlgCrit:1; WC_BITFIELD extAltSigValCrit:1; #endif /* WOLFSSL_DUAL_ALG_CERTS */ - +#ifdef WOLFSSL_ACME_OID + /* id-pe-acmeIdentifier (TLS-ALPN-01 challenge cert) */ + byte acmeIdentifier[WC_SHA256_DIGEST_SIZE]; + int acmeIdentifierSz; + WC_BITFIELD extAcmeIdentifierSet:1; + WC_BITFIELD extAcmeIdentifierCrit:1; +#endif /* WOLFSSL_ACME_OID */ WOLFSSL_AIA_ENTRY extAuthInfoList[WOLFSSL_MAX_AIA_ENTRIES]; WC_BITFIELD extAuthInfoListSz:7; WC_BITFIELD extAuthInfoListOverflow:1; diff --git a/wolfssl/wolfcrypt/asn_public.h b/wolfssl/wolfcrypt/asn_public.h index 3d4a78b598..c32bac563a 100644 --- a/wolfssl/wolfcrypt/asn_public.h +++ b/wolfssl/wolfcrypt/asn_public.h @@ -36,6 +36,9 @@ This library defines the interface APIs for X509 certificates. #include #endif #include +#ifdef WOLFSSL_ACME_OID + #include +#endif #ifdef __cplusplus extern "C" { @@ -469,6 +472,10 @@ typedef struct Cert { word16 certPoliciesNb; /* Number of Cert Policy */ byte crlInfo[CTC_MAX_CRLINFO_SZ]; /* CRL Distribution points */ int crlInfoSz; +#ifdef WOLFSSL_ACME_OID + byte acmeIdentifier[WC_SHA256_DIGEST_SIZE]; /* SHA256 of ACME keyAuth */ + int acmeIdentifierSz; +#endif #endif #if defined(WOLFSSL_CERT_EXT) || defined(OPENSSL_EXTRA) || \ defined(WOLFSSL_CERT_REQ) @@ -622,6 +629,26 @@ WOLFSSL_API int wc_SetKeyUsage(Cert *cert, const char *value); */ WOLFSSL_API int wc_SetExtKeyUsage(Cert *cert, const char *value); +#ifdef WOLFSSL_ACME_OID +/* Set the RFC 8737 id-pe-acmeIdentifier (1.3.6.1.5.5.7.1.31) extension on + * the certificate. Used to construct TLS-ALPN-01 ACME challenge response + * certificates. + * + * keyAuth is the ACME key authorization string (token "." JWK_thumbprint + * per RFC 8555 8.1), as raw bytes — keyAuthSz is its byte length. + * wc_SetAcmeIdentifierExt computes SHA-256 over keyAuth internally and + * stores the digest as the extension value, emitted critical=TRUE per + * RFC 8737 3. + * + * Returns 0 on success. + * Returns BAD_FUNC_ARG when cert is NULL, keyAuth is NULL, or + * keyAuthSz is 0. + * May return a SHA-256 error code if hashing fails. */ +WOLFSSL_API int wc_SetAcmeIdentifierExt(Cert *cert, + const byte *keyAuth, + word32 keyAuthSz); +#endif /* WOLFSSL_ACME_OID */ + #ifdef WOLFSSL_EKU_OID /* Set ExtendedKeyUsage with unique OID diff --git a/wolfssl/wolfcrypt/oid_sum.h b/wolfssl/wolfcrypt/oid_sum.h index e1fbee5f44..5e83664f7d 100644 --- a/wolfssl/wolfcrypt/oid_sum.h +++ b/wolfssl/wolfcrypt/oid_sum.h @@ -431,7 +431,11 @@ enum Extensions_Sum { /* 0x55,0x1d,0x49 */ ALT_SIG_ALG_OID = 187, /* 2.5.29.73 */ /* 0x55,0x1d,0x4a */ - ALT_SIG_VAL_OID = 188 /* 2.5.29.74 */ + ALT_SIG_VAL_OID = 188, /* 2.5.29.74 */ +#ifdef WOLFSSL_ACME_OID + /* 0x2b,0x06,0x01,0x05,0x05,0x07,0x01,0x1f */ + ACME_IDENTIFIER_OID = 99 /* 1.3.6.1.5.5.7.1.31 */ +#endif #else /* 0x55,0x1d,0x13 */ BASIC_CA_OID = 0x7fec1daa, /* 2.5.29.19 */ @@ -488,7 +492,11 @@ enum Extensions_Sum { /* 0x55,0x1d,0x49 */ ALT_SIG_ALG_OID = 0x7fb61daa, /* 2.5.29.73 */ /* 0x55,0x1d,0x4a */ - ALT_SIG_VAL_OID = 0x7fb51daa /* 2.5.29.74 */ + ALT_SIG_VAL_OID = 0x7fb51daa, /* 2.5.29.74 */ +#ifdef WOLFSSL_ACME_OID + /* 0x2b,0x06,0x01,0x05,0x05,0x07,0x01,0x1f */ + ACME_IDENTIFIER_OID = 0x1a00012e /* 1.3.6.1.5.5.7.1.31 */ +#endif #endif }; From 4791d8c26d49419dd9c330415d2c3e7f4a586736 Mon Sep 17 00:00:00 2001 From: Lealem Amedie Date: Tue, 28 Apr 2026 07:05:26 -0600 Subject: [PATCH 144/167] Add --enable-tailscale to autotools --- configure.ac | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/configure.ac b/configure.ac index 21ba1304a7..186c23c457 100644 --- a/configure.ac +++ b/configure.ac @@ -1298,6 +1298,7 @@ then AC_MSG_ERROR([--enable-all-osp is incompatible with --enable-linuxkm-defaults]) fi + test "$enable_tailscale" = "" && enable_tailscale=yes test "$enable_wolfguard" = "" && enable_wolfguard=yes test "$enable_webserver" = "" && enable_webserver=yes @@ -1648,6 +1649,31 @@ then AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_ECDSA_DETERMINISTIC_K_VARIANT" fi +# Support for Tailscale port +AC_ARG_ENABLE([tailscale], + [AS_HELP_STRING([--enable-tailscale],[Enable Tailscale build dependencies (default: disabled)])], + [ ENABLED_TAILSCALE=$enableval ], + [ ENABLED_TAILSCALE=no ] + ) +if test "$ENABLED_TAILSCALE" = "yes" +then + enable_wolfguard=yes + test "x$enable_sp" = "x" && enable_sp="yes,256" + enable_compkey=yes + enable_opensslall=yes + enable_alpn=yes + enable_sni=yes + enable_certgen=yes + enable_certreq=yes + enable_certext=yes + enable_sessioncerts=yes + enable_cert_setup_cb=yes + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_PUBLIC_MP" + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_INIT_CTX_KEY" + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_ALWAYS_KEEP_SNI" + AM_CFLAGS="$AM_CFLAGS -DWC_CTC_NAME_SIZE=128 -DWOLFSSL_ACME_OID" +fi + # wolfGuard AC_ARG_ENABLE([wolfguard], [AS_HELP_STRING([--enable-wolfguard],[Enable wolfGuard dependencies (default: disabled)])], From c4400a15fb76bb5d56dc94161326d2aadffb143e Mon Sep 17 00:00:00 2001 From: Lealem Amedie Date: Tue, 28 Apr 2026 08:10:10 -0600 Subject: [PATCH 145/167] Address copilot feedback --- configure.ac | 2 +- wolfssl/wolfcrypt/oid_sum.h | 20 ++++++++++---------- wolfssl/wolfcrypt/settings.h | 5 +++++ 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/configure.ac b/configure.ac index 186c23c457..1972989f5b 100644 --- a/configure.ac +++ b/configure.ac @@ -1653,7 +1653,7 @@ fi AC_ARG_ENABLE([tailscale], [AS_HELP_STRING([--enable-tailscale],[Enable Tailscale build dependencies (default: disabled)])], [ ENABLED_TAILSCALE=$enableval ], - [ ENABLED_TAILSCALE=no ] + [ ENABLED_TAILSCALE=${enable_tailscale:-no} ] ) if test "$ENABLED_TAILSCALE" = "yes" then diff --git a/wolfssl/wolfcrypt/oid_sum.h b/wolfssl/wolfcrypt/oid_sum.h index 5e83664f7d..a85b6fb7c5 100644 --- a/wolfssl/wolfcrypt/oid_sum.h +++ b/wolfssl/wolfcrypt/oid_sum.h @@ -412,6 +412,10 @@ enum Extensions_Sum { ISSUE_ALT_NAMES_OID = 132, /* 2.5.29.18 */ /* 0x2b,0x06,0x01,0x05,0x05,0x07,0x01,0x18 */ TLS_FEATURE_OID = 92, /* 1.3.6.1.5.5.7.1.24 */ +#ifdef WOLFSSL_ACME_OID + /* 0x2b,0x06,0x01,0x05,0x05,0x07,0x01,0x1f */ + ACME_IDENTIFIER_OID = 99, /* 1.3.6.1.5.5.7.1.31 */ +#endif /* 0x2b,0x06,0x01,0x05,0x05,0x07,0x08,0x07 */ DNS_SRV_OID = 82, /* 1.3.6.1.5.5.7.8.7 */ /* 0x60,0x86,0x48,0x01,0x86,0xf8,0x42,0x01,0x01 */ @@ -431,11 +435,7 @@ enum Extensions_Sum { /* 0x55,0x1d,0x49 */ ALT_SIG_ALG_OID = 187, /* 2.5.29.73 */ /* 0x55,0x1d,0x4a */ - ALT_SIG_VAL_OID = 188, /* 2.5.29.74 */ -#ifdef WOLFSSL_ACME_OID - /* 0x2b,0x06,0x01,0x05,0x05,0x07,0x01,0x1f */ - ACME_IDENTIFIER_OID = 99 /* 1.3.6.1.5.5.7.1.31 */ -#endif + ALT_SIG_VAL_OID = 188 /* 2.5.29.74 */ #else /* 0x55,0x1d,0x13 */ BASIC_CA_OID = 0x7fec1daa, /* 2.5.29.19 */ @@ -473,6 +473,10 @@ enum Extensions_Sum { ISSUE_ALT_NAMES_OID = 0x7fed1daa, /* 2.5.29.18 */ /* 0x2b,0x06,0x01,0x05,0x05,0x07,0x01,0x18 */ TLS_FEATURE_OID = 0x1d00012e, /* 1.3.6.1.5.5.7.1.24 */ +#ifdef WOLFSSL_ACME_OID + /* 0x2b,0x06,0x01,0x05,0x05,0x07,0x01,0x1f */ + ACME_IDENTIFIER_OID = 0x1a00012e, /* 1.3.6.1.5.5.7.1.31 */ +#endif /* 0x2b,0x06,0x01,0x05,0x05,0x07,0x08,0x07 */ DNS_SRV_OID = 0x0209012e, /* 1.3.6.1.5.5.7.8.7 */ /* 0x60,0x86,0x48,0x01,0x86,0xf8,0x42,0x01,0x01 */ @@ -492,11 +496,7 @@ enum Extensions_Sum { /* 0x55,0x1d,0x49 */ ALT_SIG_ALG_OID = 0x7fb61daa, /* 2.5.29.73 */ /* 0x55,0x1d,0x4a */ - ALT_SIG_VAL_OID = 0x7fb51daa, /* 2.5.29.74 */ -#ifdef WOLFSSL_ACME_OID - /* 0x2b,0x06,0x01,0x05,0x05,0x07,0x01,0x1f */ - ACME_IDENTIFIER_OID = 0x1a00012e /* 1.3.6.1.5.5.7.1.31 */ -#endif + ALT_SIG_VAL_OID = 0x7fb51daa /* 2.5.29.74 */ #endif }; diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 1dfc05a909..952e4645f9 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -558,6 +558,11 @@ #define HAVE_OID_DECODING #endif /* WOLFSSL_DUAL_ALG_CERTS */ +/* RFC 8737 id-pe-acmeIdentifier (TLS-ALPN-01) requires SHA-256. */ +#if defined(WOLFSSL_ACME_OID) && defined(NO_SHA256) + #undef WOLFSSL_ACME_OID +#endif + #if defined(_WIN32) && !defined(_M_X64) && \ defined(HAVE_AESGCM) && defined(WOLFSSL_AESNI) From 5da71f4c98dd0f2f9e0399f1d2807c7c08b024eb Mon Sep 17 00:00:00 2001 From: Lealem Amedie Date: Tue, 28 Apr 2026 08:21:55 -0600 Subject: [PATCH 146/167] Move new wolfSSL_ED* API's to openssl/ed*.h headers --- wolfssl/openssl/ed25519.h | 14 ++++++++++++++ wolfssl/openssl/ed448.h | 14 ++++++++++++++ wolfssl/wolfcrypt/ed25519.h | 7 ------- wolfssl/wolfcrypt/ed448.h | 7 ------- 4 files changed, 28 insertions(+), 14 deletions(-) diff --git a/wolfssl/openssl/ed25519.h b/wolfssl/openssl/ed25519.h index d38248fbaf..1c95e71eec 100644 --- a/wolfssl/openssl/ed25519.h +++ b/wolfssl/openssl/ed25519.h @@ -42,6 +42,20 @@ int wolfSSL_ED25519_verify(const unsigned char *msg, unsigned int msgSz, const unsigned char *pub, unsigned int pubSz, const unsigned char *sig, unsigned int sigSz); +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) +#ifndef WC_ED25519KEY_TYPE_DEFINED + typedef struct ed25519_key ed25519_key; + #define WC_ED25519KEY_TYPE_DEFINED +#endif +/* Not OpenSSL API's, but these two constructors are leveraged within + * wolfSSL's compat layer for Ed25519 object creation/deletion simplicity */ +WOLFSSL_API +ed25519_key* wolfSSL_ED25519_new(void* heap, int devId); + +WOLFSSL_API +void wolfSSL_ED25519_free(ed25519_key* key); +#endif + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/wolfssl/openssl/ed448.h b/wolfssl/openssl/ed448.h index cc2ece4206..99a57d6a0b 100644 --- a/wolfssl/openssl/ed448.h +++ b/wolfssl/openssl/ed448.h @@ -42,6 +42,20 @@ int wolfSSL_ED448_verify(const unsigned char *msg, unsigned int msgSz, const unsigned char *pub, unsigned int pubSz, const unsigned char *sig, unsigned int sigSz); +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) +#ifndef WC_ED448KEY_TYPE_DEFINED + typedef struct ed448_key ed448_key; + #define WC_ED448KEY_TYPE_DEFINED +#endif +/* Not OpenSSL API's, but these two constructors are leveraged within + * wolfSSL's compat layer for Ed448 object creation/deletion simplicity */ +WOLFSSL_API +ed448_key* wolfSSL_ED448_new(void* heap, int devId); + +WOLFSSL_API +void wolfSSL_ED448_free(ed448_key* key); +#endif + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/wolfssl/wolfcrypt/ed25519.h b/wolfssl/wolfcrypt/ed25519.h index 02858cc227..120c210a92 100644 --- a/wolfssl/wolfcrypt/ed25519.h +++ b/wolfssl/wolfcrypt/ed25519.h @@ -188,13 +188,6 @@ WOLFSSL_API int wc_ed25519_delete(ed25519_key* key, ed25519_key** key_p); #endif -#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) -WOLFSSL_API -ed25519_key* wolfSSL_ED25519_new(void* heap, int devId); -WOLFSSL_API -void wolfSSL_ED25519_free(ed25519_key* key); -#endif - #ifdef HAVE_ED25519_KEY_IMPORT WOLFSSL_API int wc_ed25519_import_public(const byte* in, word32 inLen, ed25519_key* key); diff --git a/wolfssl/wolfcrypt/ed448.h b/wolfssl/wolfcrypt/ed448.h index 44397b70e3..0890198874 100644 --- a/wolfssl/wolfcrypt/ed448.h +++ b/wolfssl/wolfcrypt/ed448.h @@ -170,13 +170,6 @@ WOLFSSL_API int wc_ed448_delete(ed448_key* key, ed448_key** key_p); #endif -#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) -WOLFSSL_API -ed448_key* wolfSSL_ED448_new(void* heap, int devId); -WOLFSSL_API -void wolfSSL_ED448_free(ed448_key* key); -#endif - #ifdef HAVE_ED448_KEY_IMPORT WOLFSSL_API int wc_ed448_import_public(const byte* in, word32 inLen, ed448_key* key); From b59ff436f330fcb3b1f48dcfced8aa80b747fbfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Tue, 28 Apr 2026 19:34:05 +0200 Subject: [PATCH 147/167] Remove the amount of macos based tests in os-check Reduce the number of tests running on macos in os-check.yml to the minimum required number to cover all mac os specific features. All other platform-agnostic configs and setups are only tested on Linux, which is much faster in GitHub CI. --- .github/workflows/os-check.yml | 100 ++++++++++++++++++++------------- 1 file changed, 62 insertions(+), 38 deletions(-) diff --git a/.github/workflows/os-check.yml b/.github/workflows/os-check.yml index b7c7264b25..c209b6505d 100644 --- a/.github/workflows/os-check.yml +++ b/.github/workflows/os-check.yml @@ -13,14 +13,13 @@ concurrency: # END OF COMMON SECTION jobs: - # Configs that interact with platform-specific features (sys-ca-certs, - # Apple Security.framework, OpenSSL compat layer, networking). - # Run on both Ubuntu and macOS. - make_check: + # Ubuntu config matrix. macOS is covered separately by make_check_macos + # below with a curated subset; configs here either have equivalent macOS + # coverage there or exercise no Darwin-specific code. + make_check_linux: strategy: fail-fast: false matrix: - os: [ ubuntu-24.04, macos-latest ] config: [ # Add new configs here '', @@ -89,26 +88,6 @@ jobs: '--enable-ocsp --enable-ocsp-responder --enable-ocspstapling CPPFLAGS="-DWOLFSSL_NONBLOCK_OCSP" --enable-maxfragment', '--enable-all CPPFLAGS=-DWOLFSSL_HASH_KEEP', '--enable-all --enable-writedup', - ] - name: make check - if: github.repository_owner == 'wolfssl' - runs-on: ${{ matrix.os }} - # This should be a safe limit for the tests to run. - timeout-minutes: 14 - steps: - - name: Build and test wolfSSL - uses: wolfSSL/actions-build-autotools-project@v1 - with: - configure: CFLAGS="-pedantic -Wdeclaration-after-statement -Wnull-dereference -Wno-overlength-strings -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE" ${{ matrix.config }} - check: true - - # Platform-agnostic configs: pure crypto algorithms, preprocessor guards, - # or features with no macOS-specific code paths. Linux only. - make_check_linux: - strategy: - fail-fast: false - matrix: - config: [ '--enable-ascon --enable-experimental', '--enable-ascon CPPFLAGS=-DWOLFSSL_ASCON_UNROLL --enable-experimental', # PKCS#7 with RSA-PSS (CMS RSASSA-PSS signers) @@ -130,7 +109,7 @@ jobs: '--enable-curve25519=nonblock --enable-ecc=nonblock --enable-sp=yes,nonblock CPPFLAGS="-DWOLFSSL_PUBLIC_MP -DWOLFSSL_DEBUG_NONBLOCK"', '--enable-certreq --enable-certext --enable-certgen --disable-secure-renegotiation-info CPPFLAGS="-DNO_TLS"', ] - name: make check (Linux only) + name: make check linux if: github.repository_owner == 'wolfssl' runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. @@ -142,6 +121,55 @@ jobs: configure: CFLAGS="-pedantic -Wdeclaration-after-statement -Wnull-dereference -Wno-overlength-strings -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE" ${{ matrix.config }} check: true + # Curated macOS subset. Each config exists for a Darwin-specific reason; + # do not add entries that only re-test platform-agnostic crypto already + # covered by the corresponding Linux run. + make_check_macos: + strategy: + fail-fast: false + matrix: + config: [ + # Default build: --enable-sys-ca-certs is auto-on on macOS, so + # this exercises Apple keychain / system trust loading in + # src/ssl_load.c that has no Linux equivalent. + '', + # Broad key-crypto + Security.framework + opensslextra in one run + # (RSA, ECC, AES, SHA-2/3, ChaCha20-Poly1305, Curve25519/448, HMAC, + # sniffer, DTLS, OCSP, ...). Note: --enable-all does NOT enable + # cryptocb or SHE, so those have their own entries below. + '--enable-all --enable-asn=template', + # Validates the configure-time auto-enable override and that the + # build compiles out the Security.framework code path cleanly -- + # macOS is the only OS where sys-ca-certs is auto-on by default. + '--disable-sys-ca-certs', + # DTLS over BSD sockets on Darwin: connection-ID, fragmented + # ClientHello, secure renegotiation, PSK, AES-CCM, null cipher -- + # exercises recvmsg/MTU/datagram handling that differs from Linux. + '--enable-dtls --enable-dtlscid --enable-dtls13 --enable-secure-renegotiation + --enable-psk --enable-aesccm --enable-nullcipher + CPPFLAGS=-DWOLFSSL_STATIC_RSA', + # Crypto-callback dispatcher under Apple clang. Not covered by + # --enable-all; verifies the cryptocb find/setkey/keygen path + # compiles and runs on the macOS toolchain. + '--enable-cryptocb --enable-keygen --enable-cryptocbutils=setkey', + ] + name: make check macos + if: github.repository_owner == 'wolfssl' + runs-on: macos-latest + # This should be a safe limit for the tests to run. + timeout-minutes: 14 + steps: + - name: Build and test wolfSSL + uses: wolfSSL/actions-build-autotools-project@v1 + with: + configure: CFLAGS="-pedantic -Wdeclaration-after-statement -Wnull-dereference -Wno-overlength-strings -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE" ${{ matrix.config }} + check: true + + # Run on both OSes: the user_settings.h header-driven build path is + # distinct from the autotools-driven --enable-all path in + # make_check_linux / make_check_macos, and macOS-specific guard ordering + # (e.g. WOLFSSL_SYS_CA_CERTS pulling in Security.framework) needs to be + # exercised under Apple clang here. make_user_settings: strategy: fail-fast: false @@ -165,12 +193,11 @@ jobs: user-settings: ${{ matrix.user-settings }} make_user_settings_testwolfcrypt: + # testwolfcrypt runs pure crypto tests with no platform-specific + # features, so Linux-only is sufficient for these user_settings. strategy: fail-fast: false matrix: - # testwolfcrypt runs pure crypto tests with no platform-specific - # features, so Linux-only is sufficient for these user_settings. - os: [ ubuntu-24.04 ] user-settings: [ # Add new user_settings.h here (alphabetical order) 'examples/configs/user_settings_ca.h', @@ -194,7 +221,7 @@ jobs: ] name: make user_setting.h (testwolfcrypt only) if: github.repository_owner == 'wolfssl' - runs-on: ${{ matrix.os }} + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 14 steps: @@ -208,21 +235,18 @@ jobs: - name: Run wolfcrypt/test/testwolfcrypt run: ./wolfcrypt/test/testwolfcrypt - # Has to be dedicated function due to the sed call + # Has to be dedicated function due to the sed call. + # Platform-agnostic; --enable-all macOS coverage in make_check_macos and + # the macOS user_settings_all.h run in make_user_settings already cover + # the equivalent code paths on Darwin. make_user_all: - strategy: - fail-fast: false - matrix: - os: [ ubuntu-24.04, macos-latest ] name: make user_setting.h (with sed) if: github.repository_owner == 'wolfssl' - runs-on: ${{ matrix.os }} + runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. timeout-minutes: 14 steps: - uses: actions/checkout@v4 - - if: ${{ matrix.os == 'macos-latest' }} - run: brew install automake libtool - run: ./autogen.sh - name: user_settings_all.h with compatibility layer run: | From 82b15efebc7cba91ebee32ab514dfe210a8d6103 Mon Sep 17 00:00:00 2001 From: Lealem Amedie Date: Tue, 28 Apr 2026 11:51:40 -0600 Subject: [PATCH 148/167] Add acmeIdentifier to asn=original --- wolfcrypt/src/asn.c | 6 +++++ wolfcrypt/src/asn_orig.c | 52 ++++++++++++++++++++++++++++++++++++++++ wolfssl/wolfcrypt/asn.h | 4 ++++ 3 files changed, 62 insertions(+) diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 6ecf6a05d5..a83d651022 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -25291,6 +25291,9 @@ typedef struct DerCert { #endif byte certPolicies[MAX_CERTPOL_NB*MAX_CERTPOL_SZ]; /* Certificate Policies */ byte crlInfo[CTC_MAX_CRLINFO_SZ]; /* CRL Distribution Points */ +#ifdef WOLFSSL_ACME_OID + byte acmeId[MAX_ACMEID_SZ]; /* RFC 8737 id-pe-acmeIdentifier */ +#endif #endif #ifdef WOLFSSL_CERT_REQ byte attrib[MAX_ATTRIB_SZ]; /* Cert req attributes encoded */ @@ -25321,6 +25324,9 @@ typedef struct DerCert { #endif int certPoliciesSz; /* encoded CertPolicies extension length*/ int crlInfoSz; /* encoded CRL Dist Points length */ +#ifdef WOLFSSL_ACME_OID + int acmeIdSz; /* encoded acmeIdentifier length */ +#endif #endif #ifdef WOLFSSL_ALT_NAMES int altNamesSz; /* encoded AltNames extension length */ diff --git a/wolfcrypt/src/asn_orig.c b/wolfcrypt/src/asn_orig.c index d6568aa5d1..b39417c60e 100644 --- a/wolfcrypt/src/asn_orig.c +++ b/wolfcrypt/src/asn_orig.c @@ -5295,6 +5295,31 @@ static int SetAKID(byte* output, word32 outSz, byte *input, word32 length, return (int)idx + enc_valSz; } +#ifdef WOLFSSL_ACME_OID +/* encode RFC 8737 id-pe-acmeIdentifier extension, return total bytes written + * RFC8737 : critical */ +static int SetAcmeIdentifier(byte* output, word32 outSz, const byte* digest, + word32 digestSz) +{ + byte inner[1 + MAX_LENGTH_SZ + WC_SHA256_DIGEST_SIZE]; + word32 innerSz; + const byte acmeId_oid[] = { 0x06, 0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x01, 0x1F, 0x01, 0x01, 0xFF, 0x04 }; + + if (output == NULL || digest == NULL) + return BAD_FUNC_ARG; + if (digestSz != WC_SHA256_DIGEST_SIZE) + return BAD_FUNC_ARG; + + innerSz = SetOctetString(digestSz, inner); + XMEMCPY(inner + innerSz, digest, digestSz); + innerSz += digestSz; + + return SetOidValue(output, outSz, acmeId_oid, sizeof(acmeId_oid), + inner, innerSz); +} +#endif /* WOLFSSL_ACME_OID */ + /* encode Key Usage, return total bytes written * RFC5280 : critical */ static int SetKeyUsage(byte* output, word32 outSz, word16 input) @@ -6340,6 +6365,22 @@ static int EncodeCert(Cert* cert, DerCert* der, RsaKey* rsaKey, ecc_key* eccKey, der->certPoliciesSz = 0; #endif /* WOLFSSL_CERT_EXT */ +#ifdef WOLFSSL_ACME_OID + /* RFC 8737 id-pe-acmeIdentifier (TLS-ALPN-01 challenge cert). + * Always critical=TRUE. */ + if (cert->acmeIdentifierSz == WC_SHA256_DIGEST_SIZE) { + der->acmeIdSz = SetAcmeIdentifier(der->acmeId, sizeof(der->acmeId), + cert->acmeIdentifier, + (word32)cert->acmeIdentifierSz); + if (der->acmeIdSz <= 0) + return EXTENSIONS_E; + + der->extensionsSz += der->acmeIdSz; + } + else + der->acmeIdSz = 0; +#endif + /* put extensions */ if (der->extensionsSz > 0) { @@ -6436,6 +6477,17 @@ static int EncodeCert(Cert* cert, DerCert* der, RsaKey* rsaKey, ecc_key* eccKey, return EXTENSIONS_E; } #endif /* WOLFSSL_CERT_EXT */ + +#ifdef WOLFSSL_ACME_OID + /* put ACME Identifier */ + if (der->acmeIdSz) { + ret = SetExtensions(der->extensions, sizeof(der->extensions), + &der->extensionsSz, + der->acmeId, der->acmeIdSz); + if (ret <= 0) + return EXTENSIONS_E; + } +#endif } der->total = der->versionSz + der->serialSz + der->sigAlgoSz + diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index d4ede74abd..abdfa953f9 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -1310,6 +1310,10 @@ enum Misc_ASN { #endif MAX_CERTPOL_NB = CTC_MAX_CERTPOL_NB,/* Max number of Cert Policy */ MAX_CERTPOL_SZ = CTC_MAX_CERTPOL_SZ, +#endif +#ifdef WOLFSSL_ACME_OID + MAX_ACMEID_SZ = 19 + WC_SHA256_DIGEST_SIZE, /* Max encoded + acmeIdentifier size */ #endif OCSP_NONCE_EXT_SZ = 35, /* OCSP Nonce Extension size */ MAX_OCSP_EXT_SZ = 58, /* Max OCSP Extension length */ From 00b65a9e0072a9be62590dfea82c887be5e936f2 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Thu, 16 Apr 2026 18:00:45 -0500 Subject: [PATCH 149/167] linuxkm/Kbuild: define NO_PIE_FLAG to 1, not empty, to satisfy gnu make criteria for ifdef. --- linuxkm/Kbuild | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linuxkm/Kbuild b/linuxkm/Kbuild index 17c9d4f137..fe3f823942 100644 --- a/linuxkm/Kbuild +++ b/linuxkm/Kbuild @@ -118,11 +118,11 @@ ifeq "$(ENABLED_LINUXKM_PIE)" "yes" ifndef NO_PIE_FLAG ifeq ($(KERNEL_ARCH),arm) ifeq ($(intcmp $(VERSION),5,1,0,0),1) - NO_PIE_FLAG := + NO_PIE_FLAG := 1 $(info Note: disabling -fPIE to avoid R_ARM_REL32 on pre-5.11 target kernel.) else ifeq ($(intcmp $(VERSION),5,0,1,0)-$(intcmp $(PATCHLEVEL),11,1,0,0),1-1) - NO_PIE_FLAG := + NO_PIE_FLAG := 1 $(info Note: disabling -fPIE to avoid R_ARM_REL32 on pre-5.11 target kernel.) endif endif From d218d3fbdd0169b209aae9aa74659c724c57acf8 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Thu, 16 Apr 2026 18:01:07 -0500 Subject: [PATCH 150/167] wolfcrypt/src/ge_operations.c and wolfssl/wolfcrypt/ge_operations.h: when ge_tobytes_nct and ge_tobytes have identical definitions, map the former to the latter using a macro and omit the latter definition, to avoid problematic R_ARM_THM_JUMP11 tail call. --- wolfcrypt/src/ge_operations.c | 10 +++------- wolfssl/wolfcrypt/ge_operations.h | 4 +++- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/wolfcrypt/src/ge_operations.c b/wolfcrypt/src/ge_operations.c index 3758552c15..7556594f4b 100644 --- a/wolfcrypt/src/ge_operations.c +++ b/wolfcrypt/src/ge_operations.c @@ -10176,12 +10176,8 @@ void ge_tobytes(unsigned char *s,const ge_p2 *h) s[31] ^= (unsigned char)((unsigned char)fe_isnegative(x) << 7); } -#ifdef HAVE_ED25519_VERIFY -#ifndef CURVED25519_ASM_64BIT - #define fe_invert_nct fe_invert -#endif - -/* ge tobytes */ +#if defined(HAVE_ED25519_VERIFY) && defined(CURVED25519_ASM_64BIT) +/* ge tobytes_nct */ void ge_tobytes_nct(unsigned char *s,const ge_p2 *h) { ge recip; @@ -10194,7 +10190,7 @@ void ge_tobytes_nct(unsigned char *s,const ge_p2 *h) fe_tobytes(s,y); s[31] ^= (unsigned char)((unsigned char)fe_isnegative(x) << 7); } -#endif +#endif /* HAVE_ED25519_VERIFY && CURVED25519_ASM_64BIT */ #endif /* !ED25519_SMALL */ diff --git a/wolfssl/wolfcrypt/ge_operations.h b/wolfssl/wolfcrypt/ge_operations.h index 8496b959b1..0a18a7ebba 100644 --- a/wolfssl/wolfcrypt/ge_operations.h +++ b/wolfssl/wolfcrypt/ge_operations.h @@ -85,11 +85,13 @@ WOLFSSL_LOCAL void sc_reduce(byte* s); WOLFSSL_LOCAL void sc_muladd(byte* s, const byte* a, const byte* b, const byte* c); WOLFSSL_LOCAL void ge_tobytes(unsigned char *s,const ge_p2 *h); -#ifndef ED25519_SMALL +#ifdef HAVE_ED25519_VERIFY +#if !defined(ED25519_SMALL) && defined(CURVED25519_ASM_64BIT) WOLFSSL_LOCAL void ge_tobytes_nct(unsigned char *s,const ge_p2 *h); #else #define ge_tobytes_nct ge_tobytes #endif +#endif /* HAVE_ED25519_VERIFY */ #ifndef GE_P3_TOBYTES_IMPL #define ge_p3_tobytes(s, h) ge_tobytes((s), (const ge_p2 *)(h)) #else From 8b98f7f8eab20eb5ae001e55a3e4b26ff51740c4 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Thu, 16 Apr 2026 18:10:00 -0500 Subject: [PATCH 151/167] linuxkm/: refactor wc_reloc_table_segments.reloc_tab_* as wc_reloc_table_segments.text_reloc_tab.* (using the new struct wc_reloc_table_fenceposts and WC_RELOC_TABLE_FENCEPOSTS_INITIALIZER), and add wc_reloc_table_segments.rodata_reloc_tab (allocated but not yet implemented). --- linuxkm/Makefile | 4 +-- linuxkm/linuxkm-fips-hash-wrapper.sh | 8 ++--- linuxkm/linuxkm-fips-hash.c | 34 +++++++++--------- linuxkm/linuxkm_memory.c | 52 ++++++++++++++-------------- linuxkm/linuxkm_memory.h | 46 +++++++++++++++++------- linuxkm/module_hooks.c | 14 ++++---- 6 files changed, 89 insertions(+), 69 deletions(-) diff --git a/linuxkm/Makefile b/linuxkm/Makefile index b91d4c0b1b..f28f058738 100644 --- a/linuxkm/Makefile +++ b/linuxkm/Makefile @@ -163,7 +163,7 @@ GENERATE_RELOC_TAB := $(AWK) ' \ print "\#include "; \ print "\#include "; \ printf("%s\n ", \ - "WOLFSSL_LOCAL const struct wc_reloc_table_ent wc_linuxkm_pie_reloc_tab[] = { "); \ + "WOLFSSL_LOCAL const struct wc_reloc_table_ent wc_linuxkm_pie_text_reloc_tab[] = { "); \ if ("SECTION_MAP" in ENVIRON) { \ while (getline 0) \ section_map[$$1] = $$2; \ @@ -232,7 +232,7 @@ GENERATE_RELOC_TAB := $(AWK) ' \ exit(1); \ } \ print " { .offset = ~0U, .dest_offset = ~0U, .dest_addend = 0, .dest_segment = WC_R_SEG_NONE, .reloc_type = WC_R_NONE } };"; \ - print "WOLFSSL_LOCAL const unsigned int wc_linuxkm_pie_reloc_tab_length = (unsigned int)(sizeof wc_linuxkm_pie_reloc_tab / sizeof wc_linuxkm_pie_reloc_tab[0]);"; \ + print "WOLFSSL_LOCAL const unsigned int wc_linuxkm_pie_text_reloc_tab_length = (unsigned int)(sizeof wc_linuxkm_pie_text_reloc_tab / sizeof wc_linuxkm_pie_text_reloc_tab[0]);"; \ }' ifeq "$(V)" "1" diff --git a/linuxkm/linuxkm-fips-hash-wrapper.sh b/linuxkm/linuxkm-fips-hash-wrapper.sh index 57a2f02be0..9f68b82f61 100755 --- a/linuxkm/linuxkm-fips-hash-wrapper.sh +++ b/linuxkm/linuxkm-fips-hash-wrapper.sh @@ -48,15 +48,15 @@ fi # shellcheck disable=SC2016 # using $AWK instead of awk confuses shellcheck. readarray -t fenceposts < <(readelf --wide --sections --symbols "$mod_path" | "$AWK" ' BEGIN { - fips_fenceposts["wc_linuxkm_pie_reloc_tab"] = "reloc_tab_start"; - fips_fenceposts["wc_linuxkm_pie_reloc_tab_length"] = "reloc_tab_len_start"; + fips_fenceposts["wc_linuxkm_pie_text_reloc_tab"] = "text_reloc_tab.start"; + fips_fenceposts["wc_linuxkm_pie_text_reloc_tab_length"] = "text_reloc_tab.len_start"; fips_fenceposts["verifyCore"] = "verifyCore_start"; fips_fenceposts["wolfCrypt_FIPS_first"] = "fips_text_start"; fips_fenceposts["wolfCrypt_FIPS_last"] = "fips_text_end"; fips_fenceposts["wolfCrypt_FIPS_ro_start"] = "fips_rodata_start"; fips_fenceposts["wolfCrypt_FIPS_ro_end"] = "fips_rodata_end"; - singleton_ends["wc_linuxkm_pie_reloc_tab"] = "reloc_tab_end"; - singleton_ends["wc_linuxkm_pie_reloc_tab_length"] = "reloc_tab_len_end"; + singleton_ends["wc_linuxkm_pie_text_reloc_tab"] = "text_reloc_tab.end"; + singleton_ends["wc_linuxkm_pie_text_reloc_tab_length"] = "text_reloc_tab.len_end"; singleton_ends["verifyCore"] = "verifyCore_end"; } diff --git a/linuxkm/linuxkm-fips-hash.c b/linuxkm/linuxkm-fips-hash.c index fc53a1619f..59719f51ac 100644 --- a/linuxkm/linuxkm-fips-hash.c +++ b/linuxkm/linuxkm-fips-hash.c @@ -104,10 +104,10 @@ int main(int argc, char **argv) .val = FENCEPOST_OPT_FLAG | offsetof(typeof(seg_map), x) } FENCEPOST_OPT(text_start), FENCEPOST_OPT(text_end), - FENCEPOST_OPT(reloc_tab_start), - FENCEPOST_OPT(reloc_tab_end), - FENCEPOST_OPT(reloc_tab_len_start), - FENCEPOST_OPT(reloc_tab_len_end), + FENCEPOST_OPT(text_reloc_tab.start), + FENCEPOST_OPT(text_reloc_tab.end), + FENCEPOST_OPT(text_reloc_tab.len_start), + FENCEPOST_OPT(text_reloc_tab.len_end), FENCEPOST_OPT(fips_text_start), FENCEPOST_OPT(fips_text_end), FENCEPOST_OPT(rodata_start), @@ -228,10 +228,10 @@ int main(int argc, char **argv) if ((seg_map.text_start == ~0UL) || (seg_map.text_end == ~0UL) || - (seg_map.reloc_tab_start == ~0UL) || - (seg_map.reloc_tab_end == ~0UL) || - (seg_map.reloc_tab_len_start == ~0UL) || - (seg_map.reloc_tab_len_end == ~0UL) || + (seg_map.text_reloc_tab.start == ~0UL) || + (seg_map.text_reloc_tab.end == ~0UL) || + (seg_map.text_reloc_tab.len_start == ~0UL) || + (seg_map.text_reloc_tab.len_end == ~0UL) || (seg_map.fips_text_start == ~0UL) || (seg_map.fips_text_end == ~0UL) || (seg_map.rodata_start == ~0UL) || @@ -267,12 +267,12 @@ int main(int argc, char **argv) exit(1); } - if ((seg_map.reloc_tab_start >= seg_map.reloc_tab_end) || - (seg_map.reloc_tab_end >= (unsigned long)st.st_size) || - (seg_map.reloc_tab_len_start >= seg_map.reloc_tab_len_end) || - (seg_map.reloc_tab_len_end >= (unsigned long)st.st_size)) + if ((seg_map.text_reloc_tab.start >= seg_map.text_reloc_tab.end) || + (seg_map.text_reloc_tab.end >= (unsigned long)st.st_size) || + (seg_map.text_reloc_tab.len_start >= seg_map.text_reloc_tab.len_end) || + (seg_map.text_reloc_tab.len_end >= (unsigned long)st.st_size)) { - fprintf(stderr, "%s: supplied reloc_tab fencepost(s) are out of bounds " + fprintf(stderr, "%s: supplied text_reloc_tab fencepost(s) are out of bounds " "for supplied module %s with length %lu.\n", progname, mod_path, (unsigned long)st.st_size); exit(1); @@ -291,10 +291,10 @@ int main(int argc, char **argv) seg_map.start = (unsigned long)mod_map; seg_map.end = (unsigned long)mod_map + st.st_size; - seg_map.reloc_tab_start += (unsigned long)mod_map; - seg_map.reloc_tab_end += (unsigned long)mod_map; - seg_map.reloc_tab_len_start += (unsigned long)mod_map; - seg_map.reloc_tab_len_end += (unsigned long)mod_map; + seg_map.text_reloc_tab.start += (unsigned long)mod_map; + seg_map.text_reloc_tab.end += (unsigned long)mod_map; + seg_map.text_reloc_tab.len_start += (unsigned long)mod_map; + seg_map.text_reloc_tab.len_end += (unsigned long)mod_map; seg_map.verifyCore_start += (unsigned long)mod_map; seg_map.verifyCore_end += (unsigned long)mod_map; diff --git a/linuxkm/linuxkm_memory.c b/linuxkm/linuxkm_memory.c index 3448cc6de8..01f816a73b 100644 --- a/linuxkm/linuxkm_memory.c +++ b/linuxkm/linuxkm_memory.c @@ -140,8 +140,8 @@ ssize_t wc_reloc_normalize_text( size_t text_in_offset; const struct wc_reloc_table_ent *last_reloc; /* for error-checking order in reloc_tab[] */ int n_text_r = 0, n_rodata_r = 0, n_rwdata_r = 0, n_bss_r = 0, n_other_r = 0, n_oob_r = 0; - const struct wc_reloc_table_ent *reloc_tab = (const struct wc_reloc_table_ent *)seg_map->reloc_tab_start; - const word32 reloc_tab_len = *(const word32 *)seg_map->reloc_tab_len_start; + const struct wc_reloc_table_ent *reloc_tab = (const struct wc_reloc_table_ent *)seg_map->text_reloc_tab.start; + const word32 reloc_tab_len = *(const word32 *)seg_map->text_reloc_tab.len_start; if ((text_in_len == 0) || ((uintptr_t)text_in < seg_map->text_start) || @@ -553,16 +553,16 @@ int wc_fips_generate_hash( #if defined(WC_SYM_RELOC_TABLES) || defined(WC_SYM_RELOC_TABLES_SUPPORT) if (seg_map->text_is_live) { - if ((seg_map->reloc_tab_start == 0) || - (seg_map->reloc_tab_len_start == 0)) + if ((seg_map->text_reloc_tab.start == 0) || + (seg_map->text_reloc_tab.len_start == 0)) { RELOC_DEBUG_PRINTF("assert failed.\n"); return BAD_FUNC_ARG; } } else { - if ((seg_map->reloc_tab_end == 0) || - (seg_map->reloc_tab_len_end == 0)) + if ((seg_map->text_reloc_tab.end == 0) || + (seg_map->text_reloc_tab.len_end == 0)) { RELOC_DEBUG_PRINTF("assert failed.\n"); return BAD_FUNC_ARG; @@ -575,8 +575,8 @@ int wc_fips_generate_hash( (seg_map->fips_rodata_start >= seg_map->fips_rodata_end) #if defined(WC_SYM_RELOC_TABLES) || defined(WC_SYM_RELOC_TABLES_SUPPORT) || - ((seg_map->reloc_tab_end != 0) && (seg_map->reloc_tab_start >= seg_map->reloc_tab_end)) || - ((seg_map->reloc_tab_len_end != 0) && (seg_map->reloc_tab_len_start >= seg_map->reloc_tab_len_end)) || + ((seg_map->text_reloc_tab.end != 0) && (seg_map->text_reloc_tab.start >= seg_map->text_reloc_tab.end)) || + ((seg_map->text_reloc_tab.len_end != 0) && (seg_map->text_reloc_tab.len_start >= seg_map->text_reloc_tab.len_end)) || (seg_map->text_start >= seg_map->text_end) || (seg_map->rodata_start >= seg_map->rodata_end) || (seg_map->data_start >= seg_map->data_end) || @@ -594,8 +594,8 @@ int wc_fips_generate_hash( (seg_map->verifyCore_start < seg_map->start) #if defined(WC_SYM_RELOC_TABLES) || defined(WC_SYM_RELOC_TABLES_SUPPORT) || - (seg_map->reloc_tab_start < seg_map->start) || - (seg_map->reloc_tab_len_start < seg_map->start) || + (seg_map->text_reloc_tab.start < seg_map->start) || + (seg_map->text_reloc_tab.len_start < seg_map->start) || (seg_map->text_start < seg_map->start) || (seg_map->rodata_start < seg_map->start) || (seg_map->data_start < seg_map->start) || @@ -614,10 +614,10 @@ int wc_fips_generate_hash( (seg_map->verifyCore_end > seg_map->end) #if defined(WC_SYM_RELOC_TABLES) || defined(WC_SYM_RELOC_TABLES_SUPPORT) || - ((seg_map->reloc_tab_end != 0) && - (seg_map->reloc_tab_end > seg_map->end)) || - ((seg_map->reloc_tab_len_end != 0) && - (seg_map->reloc_tab_len_end > seg_map->end)) || + ((seg_map->text_reloc_tab.end != 0) && + (seg_map->text_reloc_tab.end > seg_map->end)) || + ((seg_map->text_reloc_tab.len_end != 0) && + (seg_map->text_reloc_tab.len_end > seg_map->end)) || (seg_map->text_end > seg_map->end) || (seg_map->rodata_end > seg_map->end) || (seg_map->data_end > seg_map->end) || @@ -631,15 +631,15 @@ int wc_fips_generate_hash( } #if defined(WC_SYM_RELOC_TABLES) || defined(WC_SYM_RELOC_TABLES_SUPPORT) - if ((seg_map->reloc_tab_len_end != 0) && - (seg_map->reloc_tab_len_end - seg_map->reloc_tab_len_start != sizeof(word32))) + if ((seg_map->text_reloc_tab.len_end != 0) && + (seg_map->text_reloc_tab.len_end - seg_map->text_reloc_tab.len_start != sizeof(word32))) { RELOC_DEBUG_PRINTF("assert failed.\n"); return BAD_FUNC_ARG; } - else if (seg_map->reloc_tab_len_start & (sizeof(word32) - 1)) { - /* fprintf(stderr, "%s: seg_map->reloc_tab_len_start isn't properly aligned: 0x%llx.\n", progname, ( - unsigned long long)seg_map->reloc_tab_len_start); */ + else if (seg_map->text_reloc_tab.len_start & (sizeof(word32) - 1)) { + /* fprintf(stderr, "%s: seg_map->text_reloc_tab.len_start isn't properly aligned: 0x%llx.\n", progname, ( + unsigned long long)seg_map->text_reloc_tab.len_start); */ RELOC_DEBUG_PRINTF("assert failed.\n"); return BAD_ALIGN_E; } @@ -649,8 +649,8 @@ int wc_fips_generate_hash( * a nonsense byte-swapped value, or the final reloc_tab ent has * nonsense flags. */ - word32 reloc_tab_len = *(const word32 *)seg_map->reloc_tab_len_start; - const struct wc_reloc_table_ent *reloc_tab = (const struct wc_reloc_table_ent *)seg_map->reloc_tab_start; + word32 reloc_tab_len = *(const word32 *)seg_map->text_reloc_tab.len_start; + const struct wc_reloc_table_ent *reloc_tab = (const struct wc_reloc_table_ent *)seg_map->text_reloc_tab.start; if (reloc_tab_len == 0) { RELOC_DEBUG_PRINTF("assert failed.\n"); return BAD_FUNC_ARG; @@ -667,14 +667,14 @@ int wc_fips_generate_hash( RELOC_DEBUG_PRINTF("assert failed.\n"); return BAD_FUNC_ARG; } - else if ((seg_map->reloc_tab_end != 0) && - (seg_map->reloc_tab_end - seg_map->reloc_tab_start != sizeof(struct wc_reloc_table_ent) * *(const word32 *)seg_map->reloc_tab_len_start)) + else if ((seg_map->text_reloc_tab.end != 0) && + (seg_map->text_reloc_tab.end - seg_map->text_reloc_tab.start != sizeof(struct wc_reloc_table_ent) * *(const word32 *)seg_map->text_reloc_tab.len_start)) { /* - fprintf(stderr, "%s: wc_linuxkm_pie_reloc_tab_length from module (%u) is inconsistent with actual reloc_tab size %llu.\n", + fprintf(stderr, "%s: wc_linuxkm_pie_text_reloc_tab_length from module (%u) is inconsistent with actual text_reloc_tab size %llu.\n", progname, - *(const word32 *)seg_map->reloc_tab_len_start, - (unsigned long long)(seg_map->reloc_tab_end - seg_map->reloc_tab_start)); + *(const word32 *)seg_map->text_reloc_tab.len_start, + (unsigned long long)(seg_map->text_reloc_tab.end - seg_map->text_reloc_tab.start)); */ RELOC_DEBUG_PRINTF("assert failed.\n"); return BAD_FUNC_ARG; diff --git a/linuxkm/linuxkm_memory.h b/linuxkm/linuxkm_memory.h index 695a82aafa..c60a734b8e 100644 --- a/linuxkm/linuxkm_memory.h +++ b/linuxkm/linuxkm_memory.h @@ -80,13 +80,25 @@ struct __attribute__((packed)) wc_reloc_table_ent { /* full ELF fencepost representation, to allow wc_reloc_normalize_text() */ +struct wc_reloc_table_fenceposts { + unsigned long start; + unsigned long end; + unsigned long len_start; + unsigned long len_end; +}; + +#define WC_RELOC_TABLE_FENCEPOSTS_INITIALIZER { \ + .start = ~0UL, \ + .end = ~0UL, \ + .len_start = ~0UL, \ + .len_end = ~0UL \ +} + struct wc_reloc_table_segments { unsigned long start; unsigned long end; - unsigned long reloc_tab_start; - unsigned long reloc_tab_end; - unsigned long reloc_tab_len_start; - unsigned long reloc_tab_len_end; + struct wc_reloc_table_fenceposts text_reloc_tab; + struct wc_reloc_table_fenceposts rodata_reloc_tab; unsigned long text_start; unsigned long text_end; #ifdef HAVE_FIPS @@ -113,10 +125,8 @@ struct wc_reloc_table_segments { #define WC_RELOC_TABLE_SEGMENTS_INITIALIZER { \ .start = ~0UL, \ .end = ~0UL, \ - .reloc_tab_start = ~0UL, \ - .reloc_tab_end = ~0UL, \ - .reloc_tab_len_start = ~0UL, \ - .reloc_tab_len_end = ~0UL, \ + .text_reloc_tab = WC_RELOC_TABLE_FENCEPOSTS_INITIALIZER, \ + .rodata_reloc_tab = WC_RELOC_TABLE_FENCEPOSTS_INITIALIZER, \ .text_start = ~0UL, \ .text_end = ~0UL, \ .fips_text_start = ~0UL, \ @@ -139,10 +149,8 @@ struct wc_reloc_table_segments { #define WC_RELOC_TABLE_SEGMENTS_INITIALIZER { \ .start = ~0UL, \ .end = ~0UL, \ - .reloc_tab_start = ~0UL, \ - .reloc_tab_end = ~0UL, \ - .reloc_tab_len_start = ~0UL, \ - .reloc_tab_len_end = ~0UL, \ + .text_reloc_tab = WC_RELOC_TABLE_FENCEPOSTS_INITIALIZER, \ + .rodata_reloc_tab = WC_RELOC_TABLE_FENCEPOSTS_INITIALIZER, \ .text_start = ~0UL, \ .text_end = ~0UL, \ .rodata_start = ~0UL, \ @@ -200,8 +208,12 @@ struct wc_reloc_counts { #if defined(WC_SYM_RELOC_TABLES) || defined(WC_SYM_RELOC_TABLES_SUPPORT) +#ifndef WOLFSSL_SEGMENT_CANONICALIZER_BUFSIZ + #define WOLFSSL_SEGMENT_CANONICALIZER_BUFSIZ 8192 +#endif + #ifndef WOLFSSL_TEXT_SEGMENT_CANONICALIZER_BUFSIZ - #define WOLFSSL_TEXT_SEGMENT_CANONICALIZER_BUFSIZ 8192 + #define WOLFSSL_TEXT_SEGMENT_CANONICALIZER_BUFSIZ WOLFSSL_SEGMENT_CANONICALIZER_BUFSIZ #endif WOLFSSL_API ssize_t wc_reloc_normalize_text( @@ -212,6 +224,14 @@ WOLFSSL_API ssize_t wc_reloc_normalize_text( const struct wc_reloc_table_segments *seg_map, struct wc_reloc_counts *reloc_counts); +WOLFSSL_API ssize_t wc_reloc_normalize_rodata( + const byte *rodata_in, + size_t rodata_in_len, + byte *rodata_out, + ssize_t *cur_index_p, + const struct wc_reloc_table_segments *seg_map, + struct wc_reloc_counts *reloc_counts); + #endif /* WC_SYM_RELOC_TABLES || WC_SYM_RELOC_TABLES_SUPPORT */ #ifdef HAVE_FIPS diff --git a/linuxkm/module_hooks.c b/linuxkm/module_hooks.c index 90fc3123b2..90a695aa45 100644 --- a/linuxkm/module_hooks.c +++ b/linuxkm/module_hooks.c @@ -621,7 +621,7 @@ static int wolfssl_init(void) #ifdef HAVE_FIPS /* The compiled-in verifycore must be the right length, else the module * geometry will change when the correct value is passed in, destabilizing - * wc_linuxkm_pie_reloc_tab. It also must be the right length for the + * wc_linuxkm_pie_text_reloc_tab. It also must be the right length for the * module-update-fips-hash recipe (in-place overwrite) to work, and for * updateFipsHash() (WOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE) to be safe from * overruns. @@ -1118,17 +1118,17 @@ MODULE_VERSION(LIBWOLFSSL_VERSION_STRING); #ifdef WC_SYM_RELOC_TABLES -extern const struct wc_reloc_table_ent wc_linuxkm_pie_reloc_tab[]; -extern const unsigned int wc_linuxkm_pie_reloc_tab_length; +extern const struct wc_reloc_table_ent wc_linuxkm_pie_text_reloc_tab[]; +extern const unsigned int wc_linuxkm_pie_text_reloc_tab_length; static const struct wc_reloc_table_segments seg_map = { .start = 0, .end = 0, .text_start = (size_t)(uintptr_t)__wc_text_start, .text_end = (size_t)(uintptr_t)__wc_text_end, - .reloc_tab_start = (size_t)(uintptr_t)wc_linuxkm_pie_reloc_tab, - .reloc_tab_end = 0, - .reloc_tab_len_start = (size_t)(uintptr_t)&wc_linuxkm_pie_reloc_tab_length, - .reloc_tab_len_end = 0, + .text_reloc_tab.start = (size_t)(uintptr_t)wc_linuxkm_pie_text_reloc_tab, + .text_reloc_tab.end = 0, + .text_reloc_tab.len_start = (size_t)(uintptr_t)&wc_linuxkm_pie_text_reloc_tab_length, + .text_reloc_tab.len_end = 0, #ifdef HAVE_FIPS #ifdef WC_USE_PIE_FENCEPOSTS_FOR_FIPS .fips_text_start = (size_t)(uintptr_t)__wc_text_start, From 29c5b02046fcd6f1489e4a6448dd80a4bde414ce Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 28 Apr 2026 12:57:27 -0500 Subject: [PATCH 152/167] linuxkm/: finish support for stabilization of .rodata_wolfcrypt segment in WC_SYM_RELOC_TABLES (FIPS) kernel module builds: linuxkm/Makefile: update the GENERATE_RELOC_TAB recipe to generate both wc_linuxkm_pie_text_reloc_tab[] and wc_linuxkm_pie_rodata_reloc_tab. linuxkm/linuxkm-fips-hash-wrapper.sh: add handling for wc_linuxkm_pie_rodata_reloc_tab. linuxkm/linuxkm-fips-hash.c: add handling for rodata_reloc_tab.*. linuxkm/linuxkm_memory.c: * refactor find_reloc_tab_offset() to be segment-agnostic and tolerate empty reloc tabs. * refactor wc_reloc_normalize_segment(): * to be segment-agnostic, * identify the src segment dynamically, * return BAD_FUNC_ARG where previously returning literal -1, * use seg_in_out_len arg to accommodate size skew between input and output (not currently used), and * rename working vars for better mnemonicitude. * update wc_fips_generate_hash() to * handle seg_map->rodata_reloc_tab, * use new calling convention for wc_reloc_normalize_segment(), and * add wc_reloc_normalize_segment() loop for .rodata_wolfcrypt. linuxkm/linuxkm_memory.h and linuxkm/linuxkm_wc_port.h: rename WOLFSSL_TEXT_SEGMENT_CANONICALIZER* to WOLFSSL_SEGMENT_CANONICALIZER*, with backward-compat provisions. linuxkm/module_hooks.c: * add wc_linuxkm_normalize_relocations_noresize() backward-compat wrapper. * wolfssl_init(): add .rodata_wolfcrypt relocation handling alongside existing .text_wolfcrypt handling, and update for new wc_reloc_normalize_segment() calling convention. * add seg_map.rodata_reloc_tab initialization. * update wc_linuxkm_normalize_relocations() to be segment-agnostic and use new wc_reloc_normalize_segment() calling convention. --- linuxkm/Makefile | 57 +++-- linuxkm/linuxkm-fips-hash-wrapper.sh | 4 + linuxkm/linuxkm-fips-hash.c | 24 ++ linuxkm/linuxkm_memory.c | 351 +++++++++++++++++++-------- linuxkm/linuxkm_memory.h | 18 +- linuxkm/linuxkm_wc_port.h | 31 ++- linuxkm/module_hooks.c | 77 +++++- 7 files changed, 413 insertions(+), 149 deletions(-) diff --git a/linuxkm/Makefile b/linuxkm/Makefile index f28f058738..0c1cdfaa11 100644 --- a/linuxkm/Makefile +++ b/linuxkm/Makefile @@ -157,30 +157,48 @@ GENERATE_SECTION_MAP := $(AWK) 'BEGIN { printf("") >ENVIRON["SECTION_MAP"]; } \ }' GENERATE_RELOC_TAB := $(AWK) ' \ - BEGIN { \ - n=0; \ + function open_seg(seg) { \ + seen_seg[seg] = 1; \ + printf("%s\n ", \ + "WOLFSSL_LOCAL const struct wc_reloc_table_ent wc_linuxkm_pie_" seg "_reloc_tab[] = { "); \ + cur_seg = seg; \ + } \ + function close_cur_seg() { \ + print " { .offset = ~0U, .dest_offset = ~0U, .dest_addend = 0, .dest_segment = WC_R_SEG_NONE, .reloc_type = WC_R_NONE } };"; \ + print "WOLFSSL_LOCAL const unsigned int wc_linuxkm_pie_" cur_seg "_reloc_tab_length = (unsigned int)(sizeof wc_linuxkm_pie_" cur_seg "_reloc_tab / sizeof wc_linuxkm_pie_" cur_seg "_reloc_tab[0]);"; \ + cur_seg = ""; \ + } \ + BEGIN { \ bad_relocs=0; \ print "\#include "; \ print "\#include "; \ - printf("%s\n ", \ - "WOLFSSL_LOCAL const struct wc_reloc_table_ent wc_linuxkm_pie_text_reloc_tab[] = { "); \ + print ""; \ if ("SECTION_MAP" in ENVIRON) { \ while (getline 0) \ section_map[$$1] = $$2; \ close(ENVIRON["SECTION_MAP"]); \ } \ } \ - /^Relocation section '\''\.rela?\.text_wolfcrypt'\''/ { \ - p=1; \ - next; \ - } \ + \ /^Relocation section/ { \ - p=0; \ + if (cur_seg) { \ + close_cur_seg(); \ + } \ + { \ + if (match($$0, "^Relocation section '\''\\.rela?\\.(text|rodata)_wolfcrypt'\''", a)) {\ + open_seg(a[1]); \ + next; \ + } \ + } \ + } \ + \ + { \ + if (! cur_seg) \ + next; \ } \ /^0/ { \ - if (p) { \ - if ($$3 !~ "^(R_X86_64_PLT32|R_X86_64_PC32|R_AARCH64_.*|R_ARM.*)$$") { \ - print "Unexpected relocation type:\n" $$0 >"/dev/stderr"; \ + if ($$3 !~ "^(R_X86_.*|R_AARCH64_.*|R_ARM.*)$$") { \ + print "Unexpected relocation type in " cur_seg ":\n" $$0 >"/dev/stderr"; \ ++bad_relocs; \ } \ if ($$5 in section_map) \ @@ -224,15 +242,22 @@ GENERATE_RELOC_TAB := $(AWK) ' \ strtonum("0x" $$4), \ $$6 strtonum("0x" $$7), \ section_tag, reloc_type); \ - } \ } \ END { \ + if (cur_seg) { \ + close_cur_seg(); \ + } \ + n = split("text rodata", segs, " "); \ + for (i = 1; i <= n; ++i) { \ + if (! (segs[i] in seen_seg)) { \ + open_seg(segs[i]); \ + close_cur_seg(); \ + } \ + } \ if (bad_relocs) { \ print "Found " bad_relocs " unresolvable relocations." >"/dev/stderr"; \ exit(1); \ } \ - print " { .offset = ~0U, .dest_offset = ~0U, .dest_addend = 0, .dest_segment = WC_R_SEG_NONE, .reloc_type = WC_R_NONE } };"; \ - print "WOLFSSL_LOCAL const unsigned int wc_linuxkm_pie_text_reloc_tab_length = (unsigned int)(sizeof wc_linuxkm_pie_text_reloc_tab / sizeof wc_linuxkm_pie_text_reloc_tab[0]);"; \ }' ifeq "$(V)" "1" @@ -384,7 +409,7 @@ $(MODULE_TOP)/libwolfssl-user-build/src/.libs/libwolfssl.so: $(LIBWOLFSSL_NAME). @ echo 'Using existing Makefile for libwolfssl.so.' @else @ echo -n 'Configuring user libwolfssl.so...' - @ $(FRESH_ENV) ./configure $(QFLAG) $(VFLAG) --disable-jobserver --enable-cryptonly --enable-fips="$$FIPS_FLAVOR" CFLAGS='-DWC_SYM_RELOC_TABLES_SUPPORT -DWOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE -DWOLFSSL_USER_SETTINGS -DWOLFSSL_USER_SETTINGS_ASM' $(if $(HOSTCC),CC='$(HOSTCC)') + @ $(FRESH_ENV) ./configure $(QFLAG) $(VFLAG) --disable-jobserver --enable-cryptonly --enable-fips="$$FIPS_FLAVOR" CFLAGS='-DWC_SYM_RELOC_TABLES_SUPPORT -DWOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE -DWOLFSSL_USER_SETTINGS -DWOLFSSL_USER_SETTINGS_ASM -DDEBUG_LINUXKM_PIE_SUPPORT' $(if $(HOSTCC),CC='$(HOSTCC)') @ echo ' done.' @fi @echo -n 'Building user libwolfssl.so...' diff --git a/linuxkm/linuxkm-fips-hash-wrapper.sh b/linuxkm/linuxkm-fips-hash-wrapper.sh index 9f68b82f61..1018d30c15 100755 --- a/linuxkm/linuxkm-fips-hash-wrapper.sh +++ b/linuxkm/linuxkm-fips-hash-wrapper.sh @@ -50,6 +50,8 @@ readarray -t fenceposts < <(readelf --wide --sections --symbols "$mod_path" | "$ BEGIN { fips_fenceposts["wc_linuxkm_pie_text_reloc_tab"] = "text_reloc_tab.start"; fips_fenceposts["wc_linuxkm_pie_text_reloc_tab_length"] = "text_reloc_tab.len_start"; + fips_fenceposts["wc_linuxkm_pie_rodata_reloc_tab"] = "rodata_reloc_tab.start"; + fips_fenceposts["wc_linuxkm_pie_rodata_reloc_tab_length"] = "rodata_reloc_tab.len_start"; fips_fenceposts["verifyCore"] = "verifyCore_start"; fips_fenceposts["wolfCrypt_FIPS_first"] = "fips_text_start"; fips_fenceposts["wolfCrypt_FIPS_last"] = "fips_text_end"; @@ -57,6 +59,8 @@ BEGIN { fips_fenceposts["wolfCrypt_FIPS_ro_end"] = "fips_rodata_end"; singleton_ends["wc_linuxkm_pie_text_reloc_tab"] = "text_reloc_tab.end"; singleton_ends["wc_linuxkm_pie_text_reloc_tab_length"] = "text_reloc_tab.len_end"; + singleton_ends["wc_linuxkm_pie_rodata_reloc_tab"] = "rodata_reloc_tab.end"; + singleton_ends["wc_linuxkm_pie_rodata_reloc_tab_length"] = "rodata_reloc_tab.len_end"; singleton_ends["verifyCore"] = "verifyCore_end"; } diff --git a/linuxkm/linuxkm-fips-hash.c b/linuxkm/linuxkm-fips-hash.c index 59719f51ac..ff327f0ceb 100644 --- a/linuxkm/linuxkm-fips-hash.c +++ b/linuxkm/linuxkm-fips-hash.c @@ -108,6 +108,10 @@ int main(int argc, char **argv) FENCEPOST_OPT(text_reloc_tab.end), FENCEPOST_OPT(text_reloc_tab.len_start), FENCEPOST_OPT(text_reloc_tab.len_end), + FENCEPOST_OPT(rodata_reloc_tab.start), + FENCEPOST_OPT(rodata_reloc_tab.end), + FENCEPOST_OPT(rodata_reloc_tab.len_start), + FENCEPOST_OPT(rodata_reloc_tab.len_end), FENCEPOST_OPT(fips_text_start), FENCEPOST_OPT(fips_text_end), FENCEPOST_OPT(rodata_start), @@ -232,6 +236,10 @@ int main(int argc, char **argv) (seg_map.text_reloc_tab.end == ~0UL) || (seg_map.text_reloc_tab.len_start == ~0UL) || (seg_map.text_reloc_tab.len_end == ~0UL) || + (seg_map.rodata_reloc_tab.start == ~0UL) || + (seg_map.rodata_reloc_tab.end == ~0UL) || + (seg_map.rodata_reloc_tab.len_start == ~0UL) || + (seg_map.rodata_reloc_tab.len_end == ~0UL) || (seg_map.fips_text_start == ~0UL) || (seg_map.fips_text_end == ~0UL) || (seg_map.rodata_start == ~0UL) || @@ -278,6 +286,17 @@ int main(int argc, char **argv) exit(1); } + if ((seg_map.rodata_reloc_tab.start >= seg_map.rodata_reloc_tab.end) || + (seg_map.rodata_reloc_tab.end >= (unsigned long)st.st_size) || + (seg_map.rodata_reloc_tab.len_start >= seg_map.rodata_reloc_tab.len_end) || + (seg_map.rodata_reloc_tab.len_end >= (unsigned long)st.st_size)) + { + fprintf(stderr, "%s: supplied rodata_reloc_tab fencepost(s) are out of bounds " + "for supplied module %s with length %lu.\n", + progname, mod_path, (unsigned long)st.st_size); + exit(1); + } + mod_map = (byte *)mmap(NULL, st.st_size, inplace ? PROT_READ | PROT_WRITE : PROT_READ, (inplace ? MAP_SHARED : MAP_PRIVATE) | MAP_POPULATE, @@ -296,6 +315,11 @@ int main(int argc, char **argv) seg_map.text_reloc_tab.len_start += (unsigned long)mod_map; seg_map.text_reloc_tab.len_end += (unsigned long)mod_map; + seg_map.rodata_reloc_tab.start += (unsigned long)mod_map; + seg_map.rodata_reloc_tab.end += (unsigned long)mod_map; + seg_map.rodata_reloc_tab.len_start += (unsigned long)mod_map; + seg_map.rodata_reloc_tab.len_end += (unsigned long)mod_map; + seg_map.verifyCore_start += (unsigned long)mod_map; seg_map.verifyCore_end += (unsigned long)mod_map; seg_map.fips_text_start += (unsigned long)mod_map; diff --git a/linuxkm/linuxkm_memory.c b/linuxkm/linuxkm_memory.c index 01f816a73b..9969a7fc73 100644 --- a/linuxkm/linuxkm_memory.c +++ b/linuxkm/linuxkm_memory.c @@ -74,44 +74,41 @@ static const struct reloc_layout_ent { }; static inline long find_reloc_tab_offset( - const struct wc_reloc_table_segments *seg_map, const struct wc_reloc_table_ent reloc_tab[], word32 reloc_tab_len, - size_t text_in_offset) + size_t seg_in_offset) { long ret; unsigned long hop; + + if (seg_in_offset >= (size_t)reloc_tab[reloc_tab_len - 1].offset) { + RELOC_DEBUG_PRINTF("ERROR: %s failed.\n", __FUNCTION__); + return BAD_FUNC_ARG; + } + if (reloc_tab_len <= 1) { - RELOC_DEBUG_PRINTF("ERROR: %s failed.\n", __FUNCTION__); - return -1; - } - if (text_in_offset >= (size_t)(seg_map->text_end - seg_map->text_start)) { - RELOC_DEBUG_PRINTF("ERROR: %s failed.\n", __FUNCTION__); - return -1; - } - if (text_in_offset >= (size_t)reloc_tab[reloc_tab_len - 1].offset) { - RELOC_DEBUG_PRINTF("ERROR: %s failed.\n", __FUNCTION__); - return -1; + /* empty relocation table. */ + return 0; } for (ret = 0, hop = reloc_tab_len >> 1; hop; hop >>= 1) { - if (text_in_offset == (size_t)reloc_tab[ret].offset) + if (seg_in_offset == (size_t)reloc_tab[ret].offset) break; - else if (text_in_offset > (size_t)reloc_tab[ret].offset) + else if (seg_in_offset > (size_t)reloc_tab[ret].offset) ret += hop; else if (ret) ret -= hop; } while ((ret < (long)reloc_tab_len - 1) && - ((size_t)reloc_tab[ret].offset < text_in_offset)) + ((size_t)reloc_tab[ret].offset < seg_in_offset)) ++ret; while ((ret > 0) && - ((size_t)reloc_tab[ret - 1].offset >= text_in_offset)) + ((size_t)reloc_tab[ret - 1].offset >= seg_in_offset)) --ret; #ifdef DEBUG_LINUXKM_PIE_SUPPORT @@ -128,35 +125,65 @@ static inline long find_reloc_tab_offset( #define wc_get_unaligned(v) ({ typeof(*(v)) _v_aligned; XMEMCPY((void *)&_v_aligned, (void *)(v), sizeof _v_aligned); _v_aligned; }) #define wc_put_unaligned(v, v_out) do { typeof(v) _v = (v); XMEMCPY((void *)(v_out), (void *)&_v, sizeof(typeof(*(v_out)))); } while (0) -ssize_t wc_reloc_normalize_text( - const byte *text_in, - size_t text_in_len, - byte *text_out, +ssize_t wc_reloc_normalize_segment( + const byte *seg_in, + size_t *seg_in_out_len, + byte *seg_out, ssize_t *cur_index_p, const struct wc_reloc_table_segments *seg_map, struct wc_reloc_counts *reloc_counts) { ssize_t i; - size_t text_in_offset; + size_t seg_in_offset; const struct wc_reloc_table_ent *last_reloc; /* for error-checking order in reloc_tab[] */ int n_text_r = 0, n_rodata_r = 0, n_rwdata_r = 0, n_bss_r = 0, n_other_r = 0, n_oob_r = 0; - const struct wc_reloc_table_ent *reloc_tab = (const struct wc_reloc_table_ent *)seg_map->text_reloc_tab.start; - const word32 reloc_tab_len = *(const word32 *)seg_map->text_reloc_tab.len_start; + const struct wc_reloc_table_ent *reloc_tab; + word32 reloc_tab_len; + uintptr_t src_seg_start; +#ifdef DEBUG_LINUXKM_PIE_SUPPORT + uintptr_t src_seg_end; + const char *src_seg_name; +#endif - if ((text_in_len == 0) || - ((uintptr_t)text_in < seg_map->text_start) || - ((uintptr_t)(text_in + text_in_len) > seg_map->text_end)) + if (*seg_in_out_len == 0) + return BAD_FUNC_ARG; + + if (((uintptr_t)seg_in >= seg_map->text_start) && + ((uintptr_t)(seg_in + *seg_in_out_len) <= seg_map->text_end)) { - RELOC_DEBUG_PRINTF("ERROR: %s returning -1 with span %llx-%llx versus segment %llx-%llx.\n", + reloc_tab = (const struct wc_reloc_table_ent *)seg_map->text_reloc_tab.start; + reloc_tab_len = *(const word32 *)seg_map->text_reloc_tab.len_start; + src_seg_start = seg_map->text_start; +#ifdef DEBUG_LINUXKM_PIE_SUPPORT + src_seg_end = seg_map->text_end; + src_seg_name = "text"; +#endif + } + else if (((uintptr_t)seg_in >= seg_map->rodata_start) && + ((uintptr_t)(seg_in + *seg_in_out_len) <= seg_map->rodata_end)) + { + reloc_tab = (const struct wc_reloc_table_ent *)seg_map->rodata_reloc_tab.start; + reloc_tab_len = *(const word32 *)seg_map->rodata_reloc_tab.len_start; + src_seg_start = seg_map->rodata_start; +#ifdef DEBUG_LINUXKM_PIE_SUPPORT + src_seg_end = seg_map->rodata_end; + src_seg_name = "rodata"; +#endif + } + else + { + RELOC_DEBUG_PRINTF("ERROR: %s returning BAD_FUNC_ARG with span %llx-%llx versus text %llx-%llx and rodata %llx-%llx.\n", __FUNCTION__, - (unsigned long long)(uintptr_t)text_in, - (unsigned long long)(uintptr_t)(text_in + text_in_len), + (unsigned long long)(uintptr_t)seg_in, + (unsigned long long)(uintptr_t)(seg_in + *seg_in_out_len), (unsigned long long)seg_map->text_start, - (unsigned long long)seg_map->text_end); - return -1; + (unsigned long long)seg_map->text_end, + (unsigned long long)seg_map->rodata_start, + (unsigned long long)seg_map->rodata_end); + return BAD_FUNC_ARG; } - text_in_offset = (uintptr_t)text_in - seg_map->text_start; + seg_in_offset = (uintptr_t)seg_in - src_seg_start; if (cur_index_p) i = *cur_index_p; @@ -164,25 +191,28 @@ ssize_t wc_reloc_normalize_text( i = -1; if (i == -1) - i = find_reloc_tab_offset(seg_map, reloc_tab, reloc_tab_len, text_in_offset); + i = find_reloc_tab_offset(reloc_tab, reloc_tab_len, seg_in_offset); if (i < 0) return i; WC_SANITIZE_DISABLE(); - memcpy(text_out, text_in, text_in_len); + memcpy(seg_out, seg_in, *seg_in_out_len); WC_SANITIZE_ENABLE(); + /* note, if there are no relocations in the src seg, the loop isn't entered + * at all, and we return without further ado. + */ for (last_reloc = &reloc_tab[i > 0 ? i-1 : 0]; (size_t)i < reloc_tab_len - 1; ++i) { const struct wc_reloc_table_ent *next_reloc = &reloc_tab[i]; enum wc_reloc_dest_segment dest_seg; - uintptr_t seg_beg; + uintptr_t dest_seg_start; #ifdef DEBUG_LINUXKM_PIE_SUPPORT - uintptr_t seg_end; - const char *seg_name; + uintptr_t dest_seg_end; + const char *dest_seg_name; #endif word64 reloc_buf = 0; const struct reloc_layout_ent *layout; @@ -196,7 +226,7 @@ ssize_t wc_reloc_normalize_text( if (last_reloc->offset > next_reloc->offset) { RELOC_DEBUG_PRINTF("BUG: out-of-order offset found at reloc_tab[%zd]: %u > %u\n", i, last_reloc->offset, next_reloc->offset); - return -1; + return BAD_FUNC_ARG; } last_reloc = next_reloc; @@ -204,7 +234,7 @@ ssize_t wc_reloc_normalize_text( if (next_reloc->reloc_type >= (sizeof reloc_layouts / sizeof reloc_layouts[0])) { RELOC_DEBUG_PRINTF("BUG: unknown relocation type %u found at reloc_tab[%zd]\n", next_reloc->reloc_type, i); - return -1; + return BAD_FUNC_ARG; } layout = &reloc_layouts[next_reloc->reloc_type]; @@ -217,7 +247,7 @@ ssize_t wc_reloc_normalize_text( default: RELOC_DEBUG_PRINTF("BUG: unexpected relocation width %llu found at reloc_tab[%lld], reloc type %u\n", (unsigned long long)layout->width, (long long)i, next_reloc->reloc_type); - return -1; + return BAD_FUNC_ARG; } /* provisionally assign the destination segment from the reloc record -- @@ -227,23 +257,23 @@ ssize_t wc_reloc_normalize_text( dest_seg = next_reloc->dest_segment; /* next_reloc_rel is the offset of the relocation relative to the start - * of the current text chunk (text_in). i.e., text_in + next_reloc_rel + * of the current text chunk (seg_in). i.e., seg_in + next_reloc_rel * is the start of the relocation. */ - next_reloc_rel = next_reloc->offset - text_in_offset; + next_reloc_rel = next_reloc->offset - seg_in_offset; - if (next_reloc_rel >= text_in_len) { + if (next_reloc_rel >= *seg_in_out_len) { /* no more relocations in this buffer. */ break; } - if ((text_in_len < WC_BITS_TO_BYTES(layout->width)) || - (next_reloc_rel > text_in_len - WC_BITS_TO_BYTES(layout->width))) + if ((*seg_in_out_len < WC_BITS_TO_BYTES(layout->width)) || + (next_reloc_rel > *seg_in_out_len - WC_BITS_TO_BYTES(layout->width))) { /* relocation straddles buffer at end -- caller will try again with * that relocation at the start. */ - text_in_len = next_reloc_rel; + *seg_in_out_len = next_reloc_rel; break; } @@ -257,61 +287,61 @@ ssize_t wc_reloc_normalize_text( */ switch (layout->width) { case 32: - reloc_buf = (word64)(sword64)(wc_get_unaligned((sword32 *)&text_out[next_reloc_rel]) & (sword32)layout->mask); + reloc_buf = (word64)(sword64)(wc_get_unaligned((sword32 *)&seg_out[next_reloc_rel]) & (sword32)layout->mask); break; case 64: - reloc_buf = (word64)(sword64)(wc_get_unaligned((sword64 *)&text_out[next_reloc_rel]) & (sword64)layout->mask); + reloc_buf = (word64)(sword64)(wc_get_unaligned((sword64 *)&seg_out[next_reloc_rel]) & (sword64)layout->mask); break; case 16: - reloc_buf = (word64)(sword64)(wc_get_unaligned((sword16 *)&text_out[next_reloc_rel]) & (sword16)layout->mask); + reloc_buf = (word64)(sword64)(wc_get_unaligned((sword16 *)&seg_out[next_reloc_rel]) & (sword16)layout->mask); break; } } else { switch (layout->width) { case 32: - reloc_buf = (word64)(wc_get_unaligned((word32 *)&text_out[next_reloc_rel]) & (word32)layout->mask); + reloc_buf = (word64)(wc_get_unaligned((word32 *)&seg_out[next_reloc_rel]) & (word32)layout->mask); break; case 64: - reloc_buf = (word64)(wc_get_unaligned((word64 *)&text_out[next_reloc_rel]) & layout->mask); + reloc_buf = (word64)(wc_get_unaligned((word64 *)&seg_out[next_reloc_rel]) & layout->mask); break; case 16: - reloc_buf = (word64)(wc_get_unaligned((word16 *)&text_out[next_reloc_rel]) & (word16)layout->mask); + reloc_buf = (word64)(wc_get_unaligned((word16 *)&seg_out[next_reloc_rel]) & (word16)layout->mask); break; } } switch (dest_seg) { case WC_R_SEG_TEXT: - seg_beg = seg_map->text_start; + dest_seg_start = seg_map->text_start; ++n_text_r; #ifdef DEBUG_LINUXKM_PIE_SUPPORT - seg_end = seg_map->text_end; - seg_name = "text"; + dest_seg_end = seg_map->text_end; + dest_seg_name = "text"; #endif break; case WC_R_SEG_RODATA: - seg_beg = seg_map->rodata_start; + dest_seg_start = seg_map->rodata_start; ++n_rodata_r; #ifdef DEBUG_LINUXKM_PIE_SUPPORT - seg_end = seg_map->rodata_end; - seg_name = "rodata"; + dest_seg_end = seg_map->rodata_end; + dest_seg_name = "rodata"; #endif break; case WC_R_SEG_RWDATA: - seg_beg = seg_map->data_start; + dest_seg_start = seg_map->data_start; ++n_rwdata_r; #ifdef DEBUG_LINUXKM_PIE_SUPPORT - seg_end = seg_map->data_end; - seg_name = "data"; + dest_seg_end = seg_map->data_end; + dest_seg_name = "data"; #endif break; case WC_R_SEG_BSS: - seg_beg = seg_map->bss_start; + dest_seg_start = seg_map->bss_start; ++n_bss_r; #ifdef DEBUG_LINUXKM_PIE_SUPPORT - seg_end = seg_map->bss_end; - seg_name = "bss"; + dest_seg_end = seg_map->bss_end; + dest_seg_name = "bss"; #endif break; default: @@ -319,10 +349,10 @@ ssize_t wc_reloc_normalize_text( dest_seg = WC_R_SEG_OTHER; FALL_THROUGH; case WC_R_SEG_OTHER: - seg_beg = 0; + dest_seg_start = 0; #ifdef DEBUG_LINUXKM_PIE_SUPPORT - seg_end = 0; - seg_name = "other"; + dest_seg_end = 0; + dest_seg_name = "other"; #endif break; } @@ -344,33 +374,35 @@ ssize_t wc_reloc_normalize_text( * baked into the reloc_tab for each relocation. */ if (layout->is_relative) - reloc_buf = reloc_buf + (uintptr_t)next_reloc->offset - (uintptr_t)next_reloc->dest_addend - (seg_beg - seg_map->text_start); + reloc_buf = reloc_buf + (uintptr_t)next_reloc->offset - (uintptr_t)next_reloc->dest_addend - (dest_seg_start - src_seg_start); else - reloc_buf = reloc_buf - seg_beg - (uintptr_t)next_reloc->dest_addend; + reloc_buf = reloc_buf - dest_seg_start - (uintptr_t)next_reloc->dest_addend; } else { reloc_buf = (word64)next_reloc->dest_offset; } #ifdef DEBUG_LINUXKM_PIE_SUPPORT - if (reloc_buf >= seg_end - seg_beg) { + if (reloc_buf >= dest_seg_end - dest_seg_start) { ++n_oob_r; - RELOC_DEBUG_PRINTF("WARNING: normalized value is out of bounds (%s0x%llx) at index %lld, text offset 0x%x, reloc type %s, " - "dest seg .%s_wolfcrypt, offset from text to dest segment %s0x%llx, raw dest addr %s0x%llx, " - "seg span 0x%llx - 0x%llx, seg size 0x%llx, text base 0x%llx\n", + RELOC_DEBUG_PRINTF("WARNING: normalized value is out of bounds (%s0x%llx) at index %lld, %s offset 0x%x, reloc type %s, " + "src seg .%s_wolfcrypt, dest seg .%s_wolfcrypt, offset from src to dest segment %s0x%llx, raw dest addr %s0x%llx, " + "seg span 0x%llx - 0x%llx, seg size 0x%llx, src seg 0x%llx-0x%llx\n", (long long)reloc_buf < 0 ? "-" : "", (long long)reloc_buf < 0 ? -(long long)reloc_buf : (long long)reloc_buf, (long long)i, + src_seg_name, next_reloc->offset, layout->name, - seg_name, - seg_beg < seg_map->text_start ? "-" : "+", - seg_beg < seg_map->text_start ? (unsigned long long)seg_map->text_start - seg_beg : seg_beg - (unsigned long long)seg_map->text_start, + src_seg_name, + dest_seg_name, + dest_seg_start < src_seg_start ? "-" : "+", + dest_seg_start < src_seg_start ? (unsigned long long)src_seg_start - dest_seg_start : dest_seg_start - (unsigned long long)src_seg_start, (layout->is_signed && ((long long)raw_dest_addr < 0)) ? "-" : "", (layout->is_signed && ((long long)raw_dest_addr < 0)) ? (unsigned long long)-(long long)raw_dest_addr : raw_dest_addr, - (unsigned long long)seg_beg, - (unsigned long long)seg_end, - (unsigned long long)(seg_end - seg_beg), - (unsigned long long)seg_map->text_start); + (unsigned long long)dest_seg_start, + (unsigned long long)dest_seg_end, + (unsigned long long)(dest_seg_end - dest_seg_start), + (unsigned long long)src_seg_start, (unsigned long long)src_seg_end); } #endif } @@ -414,8 +446,8 @@ ssize_t wc_reloc_normalize_text( break; default: - RELOC_DEBUG_PRINTF("BUG: unrecognized relocation type %u in reloc record %zu, text offset 0x%x\n", - (unsigned)next_reloc->reloc_type, i, reloc_tab[i].offset); + RELOC_DEBUG_PRINTF("BUG: unrecognized relocation type %u in reloc record %zu, %s offset 0x%x\n", + (unsigned)next_reloc->reloc_type, i, src_seg_name, reloc_tab[i].offset); ++n_oob_r; dest_seg = WC_R_SEG_OTHER; } @@ -427,8 +459,8 @@ ssize_t wc_reloc_normalize_text( reloc_buf = 0; ++n_other_r; - RELOC_DEBUG_PRINTF("found non-wolfcrypt relocation at index %lld, text offset 0x%x.\n", - (long long)i, reloc_tab[i].offset); + RELOC_DEBUG_PRINTF("found non-wolfcrypt relocation at index %lld, %s offset 0x%x.\n", + (long long)i, src_seg_name, reloc_tab[i].offset); } /* xor in a label identifying the dest segment and reloc type. */ @@ -438,13 +470,13 @@ ssize_t wc_reloc_normalize_text( /* write the modified reloc_buf to the destination buffer. */ switch (layout->width) { case 32: - wc_put_unaligned((word32)reloc_buf, (word32 *)&text_out[next_reloc_rel]); + wc_put_unaligned((word32)reloc_buf, (word32 *)&seg_out[next_reloc_rel]); break; case 64: - wc_put_unaligned(reloc_buf, (word64 *)&text_out[next_reloc_rel]); + wc_put_unaligned(reloc_buf, (word64 *)&seg_out[next_reloc_rel]); break; case 16: - wc_put_unaligned((word16)reloc_buf, (word16 *)&text_out[next_reloc_rel]); + wc_put_unaligned((word16)reloc_buf, (word16 *)&seg_out[next_reloc_rel]); break; } } @@ -458,15 +490,15 @@ ssize_t wc_reloc_normalize_text( } if ((n_other_r > 0) || (n_oob_r > 0)) - RELOC_DEBUG_PRINTF("text_in=%llx relocs=%d/%d/%d/%d/%d/%d ret = %llu\n", - (unsigned long long)(uintptr_t)text_in, n_text_r, n_rodata_r, + RELOC_DEBUG_PRINTF("seg_in=%llx relocs=%d/%d/%d/%d/%d/%d ret = %llu\n", + (unsigned long long)(uintptr_t)seg_in, n_text_r, n_rodata_r, n_rwdata_r, n_bss_r, n_other_r, n_oob_r, - (unsigned long long)text_in_len); + (unsigned long long)*seg_in_out_len); if (cur_index_p) *cur_index_p = i; - return (ssize_t)text_in_len; + return (ssize_t)*seg_in_out_len; } #endif /* WC_SYM_RELOC_TABLES || WC_SYM_RELOC_TABLES_SUPPORT */ @@ -559,6 +591,12 @@ int wc_fips_generate_hash( RELOC_DEBUG_PRINTF("assert failed.\n"); return BAD_FUNC_ARG; } + if ((seg_map->rodata_reloc_tab.start == 0) || + (seg_map->rodata_reloc_tab.len_start == 0)) + { + RELOC_DEBUG_PRINTF("assert failed.\n"); + return BAD_FUNC_ARG; + } } else { if ((seg_map->text_reloc_tab.end == 0) || @@ -567,6 +605,12 @@ int wc_fips_generate_hash( RELOC_DEBUG_PRINTF("assert failed.\n"); return BAD_FUNC_ARG; } + if ((seg_map->rodata_reloc_tab.end == 0) || + (seg_map->rodata_reloc_tab.len_end == 0)) + { + RELOC_DEBUG_PRINTF("assert failed.\n"); + return BAD_FUNC_ARG; + } } #endif @@ -577,6 +621,8 @@ int wc_fips_generate_hash( || ((seg_map->text_reloc_tab.end != 0) && (seg_map->text_reloc_tab.start >= seg_map->text_reloc_tab.end)) || ((seg_map->text_reloc_tab.len_end != 0) && (seg_map->text_reloc_tab.len_start >= seg_map->text_reloc_tab.len_end)) || + ((seg_map->rodata_reloc_tab.end != 0) && (seg_map->rodata_reloc_tab.start >= seg_map->rodata_reloc_tab.end)) || + ((seg_map->rodata_reloc_tab.len_end != 0) && (seg_map->rodata_reloc_tab.len_start >= seg_map->rodata_reloc_tab.len_end)) || (seg_map->text_start >= seg_map->text_end) || (seg_map->rodata_start >= seg_map->rodata_end) || (seg_map->data_start >= seg_map->data_end) || @@ -596,6 +642,8 @@ int wc_fips_generate_hash( || (seg_map->text_reloc_tab.start < seg_map->start) || (seg_map->text_reloc_tab.len_start < seg_map->start) || + (seg_map->rodata_reloc_tab.start < seg_map->start) || + (seg_map->rodata_reloc_tab.len_start < seg_map->start) || (seg_map->text_start < seg_map->start) || (seg_map->rodata_start < seg_map->start) || (seg_map->data_start < seg_map->start) || @@ -618,6 +666,10 @@ int wc_fips_generate_hash( (seg_map->text_reloc_tab.end > seg_map->end)) || ((seg_map->text_reloc_tab.len_end != 0) && (seg_map->text_reloc_tab.len_end > seg_map->end)) || + ((seg_map->rodata_reloc_tab.end != 0) && + (seg_map->rodata_reloc_tab.end > seg_map->end)) || + ((seg_map->rodata_reloc_tab.len_end != 0) && + (seg_map->rodata_reloc_tab.len_end > seg_map->end)) || (seg_map->text_end > seg_map->end) || (seg_map->rodata_end > seg_map->end) || (seg_map->data_end > seg_map->end) || @@ -680,6 +732,56 @@ int wc_fips_generate_hash( return BAD_FUNC_ARG; } } + + if ((seg_map->rodata_reloc_tab.len_end != 0) && + (seg_map->rodata_reloc_tab.len_end - seg_map->rodata_reloc_tab.len_start != sizeof(word32))) + { + RELOC_DEBUG_PRINTF("assert failed.\n"); + return BAD_FUNC_ARG; + } + else if (seg_map->rodata_reloc_tab.len_start & (sizeof(word32) - 1)) { + /* fprintf(stderr, "%s: seg_map->rodata_reloc_tab.len_start isn't properly aligned: 0x%llx.\n", progname, ( + unsigned long long)seg_map->rodata_reloc_tab.len_start); */ + RELOC_DEBUG_PRINTF("assert failed.\n"); + return BAD_ALIGN_E; + } + else { + /* Note we don't currently handle modules that are endian-conflicted + * with the build host -- that'll be caught here, when reloc_tab_len is + * a nonsense byte-swapped value, or the final reloc_tab ent has + * nonsense flags. + */ + word32 reloc_tab_len = *(const word32 *)seg_map->rodata_reloc_tab.len_start; + const struct wc_reloc_table_ent *reloc_tab = (const struct wc_reloc_table_ent *)seg_map->rodata_reloc_tab.start; + if (reloc_tab_len == 0) { + RELOC_DEBUG_PRINTF("assert failed.\n"); + return BAD_FUNC_ARG; + } + else if ((seg_map->end != 0) && + ((unsigned long)(reloc_tab + reloc_tab_len) > seg_map->end)) + { + RELOC_DEBUG_PRINTF("assert failed.\n"); + return BAD_FUNC_ARG; + } + else if ((reloc_tab[reloc_tab_len - 1].dest_segment != WC_R_SEG_NONE) || + (reloc_tab[reloc_tab_len - 1].reloc_type != WC_R_NONE)) + { + RELOC_DEBUG_PRINTF("assert failed.\n"); + return BAD_FUNC_ARG; + } + else if ((seg_map->rodata_reloc_tab.end != 0) && + (seg_map->rodata_reloc_tab.end - seg_map->rodata_reloc_tab.start != sizeof(struct wc_reloc_table_ent) * *(const word32 *)seg_map->rodata_reloc_tab.len_start)) + { + /* + fprintf(stderr, "%s: wc_linuxkm_pie_rodata_reloc_tab_length from module (%u) is inconsistent with actual rodata_reloc_tab size %llu.\n", + progname, + *(const word32 *)seg_map->rodata_reloc_tab.len_start, + (unsigned long long)(seg_map->rodata_reloc_tab.end - seg_map->rodata_reloc_tab.start)); + */ + RELOC_DEBUG_PRINTF("assert failed.\n"); + return BAD_FUNC_ARG; + } + } #endif if (out_size == NULL) { @@ -728,9 +830,10 @@ int wc_fips_generate_hash( #if defined(WC_SYM_RELOC_TABLES) || defined(WC_SYM_RELOC_TABLES_SUPPORT) { - ssize_t cur_reloc_index = -1; + ssize_t cur_reloc_index; const byte *text_p = (const byte *)seg_map->fips_text_start; - byte *buf = XMALLOC(WOLFSSL_TEXT_SEGMENT_CANONICALIZER_BUFSIZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); + const byte *rodata_p = (const byte *)seg_map->fips_rodata_start; + byte *buf = XMALLOC(WOLFSSL_SEGMENT_CANONICALIZER_BUFSIZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (! buf) { ret = MEMORY_E; @@ -738,23 +841,23 @@ int wc_fips_generate_hash( goto out; } + cur_reloc_index = -1; while (text_p < (const byte *)seg_map->fips_text_end) { - /* wc_reloc_normalize_text() does its own WC_SANITIZE_DISABLE()s, so - * we defer it here. - */ - ssize_t progress = wc_reloc_normalize_text( + size_t text_in_out_len = min(WOLFSSL_SEGMENT_CANONICALIZER_BUFSIZ, + (size_t)((const byte *)seg_map->fips_text_end - text_p)); + ssize_t progress = wc_reloc_normalize_segment( text_p, - min(WOLFSSL_TEXT_SEGMENT_CANONICALIZER_BUFSIZ, (word32)((const byte *)seg_map->fips_text_end - text_p)), + &text_in_out_len, buf, &cur_reloc_index, seg_map, reloc_counts); if (progress <= 0) { - ret = IN_CORE_FIPS_E; - RELOC_DEBUG_PRINTF("wc_reloc_normalize_text() failed.\n"); + RELOC_DEBUG_PRINTF("wc_reloc_normalize_segment() for text failed: %zd.\n", progress); + ret = progress ? (int)progress : IN_CORE_FIPS_E; break; } - ret = hmac_update(hmac_ctx, buf, (word32)progress); + ret = hmac_update(hmac_ctx, buf, (word32)text_in_out_len); if (ret) { RELOC_DEBUG_PRINTF("hmac_update() failed.\n"); break; @@ -762,15 +865,53 @@ int wc_fips_generate_hash( text_p += progress; } + cur_reloc_index = -1; + while (rodata_p < (const byte *)seg_map->fips_rodata_end) { + size_t rodata_in_out_len = min(WOLFSSL_SEGMENT_CANONICALIZER_BUFSIZ, + (size_t)((const byte *)seg_map->fips_rodata_end - rodata_p)); + /* don't hash verifyCore or changing verifyCore will change hash */ + if ((rodata_p < (const byte *)seg_map->verifyCore_end) && + (rodata_p + rodata_in_out_len >= (const byte *)seg_map->verifyCore_start)) + { + rodata_in_out_len = (size_t)((const byte *)seg_map->verifyCore_start - rodata_p); + if (rodata_in_out_len == 0) { + rodata_p = (const byte *)seg_map->verifyCore_end; + /* force recomputation of relocation offset when skipping + * a span (not processed by wc_reloc_normalize_segment()). + */ + cur_reloc_index = -1; + continue; + } + } + + ssize_t progress = wc_reloc_normalize_segment( + rodata_p, + &rodata_in_out_len, + buf, + &cur_reloc_index, + seg_map, + reloc_counts); + if (progress <= 0) { + RELOC_DEBUG_PRINTF("wc_reloc_normalize_segment() for rodata failed: %zd.\n", progress); + ret = progress ? (int)progress : IN_CORE_FIPS_E; + break; + } + ret = hmac_update(hmac_ctx, buf, (word32)rodata_in_out_len); + if (ret) { + RELOC_DEBUG_PRINTF("hmac_update() failed.\n"); + break; + } + rodata_p += progress; + } + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); } - WC_SANITIZE_DISABLE(); -#else +#else /* ! (WC_SYM_RELOC_TABLES || WC_SYM_RELOC_TABLES_SUPPORT) */ + (void)reloc_counts; WC_SANITIZE_DISABLE(); ret = hmac_update(hmac_ctx, (byte *)(wc_ptr_t)seg_map->fips_text_start, (word32)(seg_map->fips_text_end - seg_map->fips_text_start)); -#endif /* !WOLFSSL_LINUXKM_PIE_REDIRECT_TABLE */ if (ret) { RELOC_DEBUG_PRINTF("ERROR: hmac_update failed: err %d\n", ret); @@ -795,6 +936,8 @@ int wc_fips_generate_hash( WC_SANITIZE_ENABLE(); +#endif /* ! (WC_SYM_RELOC_TABLES || WC_SYM_RELOC_TABLES_SUPPORT) */ + if (ret) { RELOC_DEBUG_PRINTF("ERROR: hmac_update failed: err %d\n", ret); ret = BAD_STATE_E; diff --git a/linuxkm/linuxkm_memory.h b/linuxkm/linuxkm_memory.h index c60a734b8e..76e681da80 100644 --- a/linuxkm/linuxkm_memory.h +++ b/linuxkm/linuxkm_memory.h @@ -175,7 +175,7 @@ struct wc_reloc_counts { #elif defined(HAVE_FIPS) /* barebones FIPS fencepost representation -- no provision for - * wc_reloc_normalize_text() + * wc_reloc_normalize_segment() */ struct wc_reloc_table_segments { @@ -216,18 +216,10 @@ struct wc_reloc_counts { #define WOLFSSL_TEXT_SEGMENT_CANONICALIZER_BUFSIZ WOLFSSL_SEGMENT_CANONICALIZER_BUFSIZ #endif -WOLFSSL_API ssize_t wc_reloc_normalize_text( - const byte *text_in, - size_t text_in_len, - byte *text_out, - ssize_t *cur_index_p, - const struct wc_reloc_table_segments *seg_map, - struct wc_reloc_counts *reloc_counts); - -WOLFSSL_API ssize_t wc_reloc_normalize_rodata( - const byte *rodata_in, - size_t rodata_in_len, - byte *rodata_out, +WOLFSSL_API ssize_t wc_reloc_normalize_segment( + const byte *seg_in, + size_t *seg_in_out_len, + byte *seg_out, ssize_t *cur_index_p, const struct wc_reloc_table_segments *seg_map, struct wc_reloc_counts *reloc_counts); diff --git a/linuxkm/linuxkm_wc_port.h b/linuxkm/linuxkm_wc_port.h index 22255af456..c359277e34 100644 --- a/linuxkm/linuxkm_wc_port.h +++ b/linuxkm/linuxkm_wc_port.h @@ -876,15 +876,33 @@ __wc_bss_end[]; extern ssize_t wc_linuxkm_normalize_relocations( - const u8 *text_in, - size_t text_in_len, - u8 *text_out, + const u8 *seg_in, + size_t *seg_in_out_len, + u8 *seg_out, ssize_t *cur_index_p); + extern ssize_t wc_linuxkm_normalize_relocations_noresize( + const u8 *seg_in, + size_t seg_in_len, + u8 *seg_out, + ssize_t *cur_index_p); + + #ifndef WOLFSSL_SEGMENT_CANONICALIZER_BUFSIZ + #define WOLFSSL_SEGMENT_CANONICALIZER_BUFSIZ 8192 + #endif + + #ifndef WOLFSSL_SEGMENT_CANONICALIZER + #define WOLFSSL_SEGMENT_CANONICALIZER(seg_in, seg_in_out_len, seg_out, cur_index_p) \ + wc_linuxkm_normalize_relocations(seg_in, seg_in_out_len, seg_out, cur_index_p) + #endif + + /* backward-compatible wrappers */ #ifndef WOLFSSL_TEXT_SEGMENT_CANONICALIZER #define WOLFSSL_TEXT_SEGMENT_CANONICALIZER(text_in, text_in_len, text_out, cur_index_p) \ - wc_linuxkm_normalize_relocations(text_in, text_in_len, text_out, cur_index_p) - #define WOLFSSL_TEXT_SEGMENT_CANONICALIZER_BUFSIZ 8192 + wc_linuxkm_normalize_relocations_noresize(text_in, text_in_len, text_out, cur_index_p) + #endif + #ifndef WOLFSSL_TEXT_SEGMENT_CANONICALIZER_BUFSIZ + #define WOLFSSL_TEXT_SEGMENT_CANONICALIZER_BUFSIZ WOLFSSL_SEGMENT_CANONICALIZER_BUFSIZ #endif #ifdef CONFIG_MIPS @@ -896,6 +914,7 @@ struct wolfssl_linuxkm_pie_redirect_table { #ifdef HAVE_FIPS typeof(wc_linuxkm_normalize_relocations) *wc_linuxkm_normalize_relocations; + typeof(wc_linuxkm_normalize_relocations_noresize) *wc_linuxkm_normalize_relocations_noresize; #endif #ifndef __ARCH_MEMCMP_NO_REDIRECT @@ -1234,6 +1253,8 @@ #ifdef HAVE_FIPS #define wc_linuxkm_normalize_relocations \ WC_PIE_INDIRECT_SYM(wc_linuxkm_normalize_relocations) + #define wc_linuxkm_normalize_relocations_noresize \ + WC_PIE_INDIRECT_SYM(wc_linuxkm_normalize_relocations_noresize) #endif #ifndef __ARCH_MEMCMP_NO_REDIRECT diff --git a/linuxkm/module_hooks.c b/linuxkm/module_hooks.c index 90a695aa45..03b6e2e44e 100644 --- a/linuxkm/module_hooks.c +++ b/linuxkm/module_hooks.c @@ -711,13 +711,15 @@ static int wolfssl_init(void) { unsigned int text_hash = hash_span((const u8 *)__wc_text_start, (const u8 *)__wc_text_end, 1); unsigned int rodata_hash = hash_span((const u8 *)__wc_rodata_start, (const u8 *)__wc_rodata_end, 1); - u8 *canon_buf = malloc(WOLFSSL_TEXT_SEGMENT_CANONICALIZER_BUFSIZ); + u8 *canon_buf = malloc(WOLFSSL_SEGMENT_CANONICALIZER_BUFSIZ); ssize_t cur_reloc_index = -1; const u8 *text_p = (const u8 *)__wc_text_start; + const u8 *rodata_p = (const u8 *)__wc_rodata_start; unsigned int stabilized_text_hash = 1; + unsigned int stabilized_rodata_hash = 1; if (! canon_buf) { - pr_err("ERROR: malloc(%d) for WOLFSSL_TEXT_SEGMENT_CANONICALIZER failed: %ld.\n", WOLFSSL_TEXT_SEGMENT_CANONICALIZER_BUFSIZ, PTR_ERR(canon_buf)); + pr_err("ERROR: malloc(%d) for WOLFSSL_*_SEGMENT_CANONICALIZER failed: %ld.\n", WOLFSSL_SEGMENT_CANONICALIZER_BUFSIZ, PTR_ERR(canon_buf)); return -ECANCELED; } @@ -725,14 +727,15 @@ static int wolfssl_init(void) reloc_counts.other = 0; while (text_p < (const u8 *)__wc_text_end) { + size_t text_in_out_len = min(WOLFSSL_SEGMENT_CANONICALIZER_BUFSIZ, + (size_t)((const u8 *)__wc_text_end - text_p)); ssize_t progress = - WOLFSSL_TEXT_SEGMENT_CANONICALIZER( + WOLFSSL_SEGMENT_CANONICALIZER( text_p, - min(WOLFSSL_TEXT_SEGMENT_CANONICALIZER_BUFSIZ, - (word32)((const u8 *)__wc_text_end - text_p)), + &text_in_out_len, canon_buf, &cur_reloc_index); if (progress <= 0) { - pr_err("ERROR: progress=%ld from WOLFSSL_TEXT_SEGMENT_CANONICALIZER() at offset %x (text=%x-%x).\n", + pr_err("ERROR: progress=%ld from WOLFSSL_SEGMENT_CANONICALIZER() at offset %x (text=%x-%x).\n", (long)progress, (unsigned)(uintptr_t)text_p, (unsigned)(uintptr_t)__wc_text_start, @@ -740,10 +743,32 @@ static int wolfssl_init(void) free(canon_buf); return -ECANCELED; } - stabilized_text_hash = hash_span(canon_buf, canon_buf + progress, stabilized_text_hash); + stabilized_text_hash = hash_span(canon_buf, canon_buf + text_in_out_len, stabilized_text_hash); text_p += progress; } + /* note verifyCore is hashed along with the rest of .rodata_wolfcrypt. */ + while (rodata_p < (const u8 *)__wc_rodata_end) { + size_t rodata_in_out_len = min(WOLFSSL_SEGMENT_CANONICALIZER_BUFSIZ, + (size_t)((const u8 *)__wc_rodata_end - rodata_p)); + ssize_t progress = + WOLFSSL_SEGMENT_CANONICALIZER( + rodata_p, + &rodata_in_out_len, + canon_buf, &cur_reloc_index); + if (progress <= 0) { + pr_err("ERROR: progress=%ld from WOLFSSL_SEGMENT_CANONICALIZER() at offset %x (rodata=%x-%x).\n", + (long)progress, + (unsigned)(uintptr_t)rodata_p, + (unsigned)(uintptr_t)__wc_rodata_start, + (unsigned)(uintptr_t)__wc_rodata_end); + free(canon_buf); + return -ECANCELED; + } + stabilized_rodata_hash = hash_span(canon_buf, canon_buf + rodata_in_out_len, stabilized_rodata_hash); + rodata_p += progress; + } + free(canon_buf); canon_buf = 0; @@ -1120,6 +1145,8 @@ MODULE_VERSION(LIBWOLFSSL_VERSION_STRING); extern const struct wc_reloc_table_ent wc_linuxkm_pie_text_reloc_tab[]; extern const unsigned int wc_linuxkm_pie_text_reloc_tab_length; +extern const struct wc_reloc_table_ent wc_linuxkm_pie_rodata_reloc_tab[]; +extern const unsigned int wc_linuxkm_pie_rodata_reloc_tab_length; static const struct wc_reloc_table_segments seg_map = { .start = 0, .end = 0, @@ -1129,6 +1156,10 @@ static const struct wc_reloc_table_segments seg_map = { .text_reloc_tab.end = 0, .text_reloc_tab.len_start = (size_t)(uintptr_t)&wc_linuxkm_pie_text_reloc_tab_length, .text_reloc_tab.len_end = 0, + .rodata_reloc_tab.start = (size_t)(uintptr_t)wc_linuxkm_pie_rodata_reloc_tab, + .rodata_reloc_tab.end = 0, + .rodata_reloc_tab.len_start = (size_t)(uintptr_t)&wc_linuxkm_pie_rodata_reloc_tab_length, + .rodata_reloc_tab.len_end = 0, #ifdef HAVE_FIPS #ifdef WC_USE_PIE_FENCEPOSTS_FOR_FIPS .fips_text_start = (size_t)(uintptr_t)__wc_text_start, @@ -1161,12 +1192,12 @@ static const struct wc_reloc_table_segments seg_map = { }; ssize_t wc_linuxkm_normalize_relocations( - const u8 *text_in, - size_t text_in_len, - u8 *text_out, + const u8 *seg_in, + size_t *seg_in_out_len, + u8 *seg_out, ssize_t *cur_index_p) { - return wc_reloc_normalize_text(text_in, text_in_len, text_out, cur_index_p, &seg_map, + return wc_reloc_normalize_segment(seg_in, seg_in_out_len, seg_out, cur_index_p, &seg_map, #ifdef DEBUG_LINUXKM_PIE_SUPPORT &reloc_counts #else @@ -1175,6 +1206,28 @@ ssize_t wc_linuxkm_normalize_relocations( ); } +ssize_t wc_linuxkm_normalize_relocations_noresize( + const u8 *seg_in, + size_t seg_in_len, + u8 *seg_out, + ssize_t *cur_index_p) +{ + ssize_t ret; + ret = wc_reloc_normalize_segment(seg_in, &seg_in_len, seg_out, cur_index_p, &seg_map, +#ifdef DEBUG_LINUXKM_PIE_SUPPORT + &reloc_counts +#else + NULL +#endif + ); + if (ret < 0) + return ret; + if ((size_t)ret != seg_in_len) + return -EINVAL; + else + return seg_in_len; +} + #elif defined(HAVE_FIPS) static const struct wc_reloc_table_segments seg_map = { @@ -1227,6 +1280,8 @@ static int set_up_wolfssl_linuxkm_pie_redirect_table(void) { #ifdef HAVE_FIPS wolfssl_linuxkm_pie_redirect_table.wc_linuxkm_normalize_relocations = wc_linuxkm_normalize_relocations; + wolfssl_linuxkm_pie_redirect_table.wc_linuxkm_normalize_relocations_noresize = + wc_linuxkm_normalize_relocations_noresize; #endif #ifndef __ARCH_MEMCMP_NO_REDIRECT From 2a0a5cc6108767ba78fcba33ed0472d277345971 Mon Sep 17 00:00:00 2001 From: Lealem Amedie Date: Tue, 28 Apr 2026 13:25:14 -0600 Subject: [PATCH 153/167] Multi-test fixes --- .wolfssl_known_macro_extras | 1 - tests/api.c | 2 +- wolfssl/wolfcrypt/asn_public.h | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index c676c15524..3bb23b805f 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -833,7 +833,6 @@ WOLFSSL_NO_DH186 WOLFSSL_NO_DTLS_SIZE_CHECK WOLFSSL_NO_ETM_ALERT WOLFSSL_NO_FENCE -WOLFSSL_NO_INIT_CTX_KEY WOLFSSL_NO_ISSUERHASH_TDPEER WOLFSSL_NO_KCAPI_AES_CBC WOLFSSL_NO_KCAPI_HMAC_SHA1 diff --git a/tests/api.c b/tests/api.c index 840562d32b..2dba31d135 100644 --- a/tests/api.c +++ b/tests/api.c @@ -11627,7 +11627,7 @@ static int test_wolfSSL_mcast(void) *----------------------------------------------------------------------------*/ /* - * Testing wc_SetAcmeIdentifierExt() round-trip — the RFC 8737 + * Testing wc_SetAcmeIdentifierExt() round-trip - the RFC 8737 * id-pe-acmeIdentifier (1.3.6.1.5.5.7.1.31) extension used by * TLS-ALPN-01 ACME challenge certs. */ diff --git a/wolfssl/wolfcrypt/asn_public.h b/wolfssl/wolfcrypt/asn_public.h index c32bac563a..15359ae835 100644 --- a/wolfssl/wolfcrypt/asn_public.h +++ b/wolfssl/wolfcrypt/asn_public.h @@ -635,7 +635,7 @@ WOLFSSL_API int wc_SetExtKeyUsage(Cert *cert, const char *value); * certificates. * * keyAuth is the ACME key authorization string (token "." JWK_thumbprint - * per RFC 8555 8.1), as raw bytes — keyAuthSz is its byte length. + * per RFC 8555 8.1), as raw bytes - keyAuthSz is its byte length. * wc_SetAcmeIdentifierExt computes SHA-256 over keyAuth internally and * stores the digest as the extension value, emitted critical=TRUE per * RFC 8737 3. From b7ed41357197648b41f916b08c331d5dd0df0b5a Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 28 Apr 2026 15:05:30 -0500 Subject: [PATCH 154/167] wolfcrypt/src/wc_lms_impl.c: work around false-positive -Wmaybe-uninitialized in wc_lms_treehash_update(). --- wolfcrypt/src/wc_lms_impl.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/wolfcrypt/src/wc_lms_impl.c b/wolfcrypt/src/wc_lms_impl.c index a6fc89da7f..8681080c94 100644 --- a/wolfcrypt/src/wc_lms_impl.c +++ b/wolfcrypt/src/wc_lms_impl.c @@ -2418,10 +2418,12 @@ static int wc_lms_treehash_update(LmsState* state, LmsPrivState* privState, } } - if (!useRoot && (ret == 0)) { - /* Copy stack back. */ - XMEMCPY(stackCache->stack, stack, params->height * params->hash_len); - stackCache->offset = (word32)((size_t)sp - (size_t)stack); + if (ret == 0) { + if (!useRoot) { + /* Copy stack back. */ + XMEMCPY(stackCache->stack, stack, params->height * params->hash_len); + stackCache->offset = (word32)((size_t)sp - (size_t)stack); + } } WC_FREE_VAR_EX(stack, NULL, DYNAMIC_TYPE_TMP_BUFFER); From 559b20750639e9f3384f09a5b40fc76874c0fdc6 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 28 Apr 2026 17:38:22 -0500 Subject: [PATCH 155/167] linuxkm/lkcapi_*.c and linuxkm/module_hooks.c: add missing linefeed characters in format args to pr_*(), for proper line flushing. --- linuxkm/lkcapi_dh_glue.c | 46 ++++++++++----------- linuxkm/lkcapi_ecdh_glue.c | 28 ++++++------- linuxkm/lkcapi_glue.c | 22 +++++----- linuxkm/lkcapi_rsa_glue.c | 18 ++++---- linuxkm/lkcapi_sha_glue.c | 84 +++++++++++++++++++------------------- linuxkm/module_hooks.c | 14 +++---- 6 files changed, 106 insertions(+), 106 deletions(-) diff --git a/linuxkm/lkcapi_dh_glue.c b/linuxkm/lkcapi_dh_glue.c index 9e885ed856..6caabf06ac 100644 --- a/linuxkm/lkcapi_dh_glue.c +++ b/linuxkm/lkcapi_dh_glue.c @@ -347,7 +347,7 @@ static int km_dh_decode_secret(const u8 * buf, unsigned int len, if (secret.len != expected_len) { #ifdef WOLFKM_DEBUG_DH - pr_err("%s: km_dh_decode_secret: got %d, expected %zu", + pr_err("%s: km_dh_decode_secret: got %d, expected %zu\n", WOLFKM_DH_DRIVER, secret.len, expected_len); #endif /* WOLFKM_DEBUG_DH */ return -EINVAL; @@ -413,7 +413,7 @@ static int km_dh_alloc_keys(struct km_dh_ctx * ctx) alloc_keys_end: if (err) { #ifdef WOLFKM_DEBUG_DH - pr_err("%s: km_dh_alloc_keys failed: %d", + pr_err("%s: km_dh_alloc_keys failed: %d\n", WOLFKM_DH_DRIVER, err); #endif km_dh_clear_keys(ctx); @@ -478,7 +478,7 @@ static int km_dh_set_secret(struct crypto_kpp *tfm, const void *buf, if (km_dh_decode_secret(buf, len, ¶ms) < 0) { #ifdef WOLFKM_DEBUG_DH - pr_err("%s: dh_set_secret: decode secret failed: %d", + pr_err("%s: dh_set_secret: decode secret failed: %d\n", WOLFKM_DH_DRIVER, params.key_size); #endif /* WOLFKM_DEBUG_DH */ err = -EINVAL; @@ -488,7 +488,7 @@ static int km_dh_set_secret(struct crypto_kpp *tfm, const void *buf, /* the key, p, and g, must all be provided for normal dh. */ if (!params.key || !params.key_size || !params.p_size || !params.g_size) { #ifdef WOLFKM_DEBUG_DH - pr_err("%s: dh_set_secret: empty params", WOLFKM_DH_DRIVER); + pr_err("%s: dh_set_secret: empty params\n", WOLFKM_DH_DRIVER); #endif err = -EINVAL; goto dh_secret_end; @@ -496,7 +496,7 @@ static int km_dh_set_secret(struct crypto_kpp *tfm, const void *buf, if (params.key_size > params.p_size || params.g_size > params.p_size) { #ifdef WOLFKM_DEBUG_DH - pr_err("%s: dh_set_secret: invalid params", WOLFKM_DH_DRIVER); + pr_err("%s: dh_set_secret: invalid params\n", WOLFKM_DH_DRIVER); #endif err = -EINVAL; goto dh_secret_end; @@ -518,7 +518,7 @@ static int km_dh_set_secret(struct crypto_kpp *tfm, const void *buf, if (err) { #ifdef WOLFKM_DEBUG_DH - pr_err("%s: wc_DhSetKey failed: %d", WOLFKM_DH_DRIVER, err); + pr_err("%s: wc_DhSetKey failed: %d\n", WOLFKM_DH_DRIVER, err); #endif err = -EINVAL; goto dh_secret_end; @@ -530,7 +530,7 @@ static int km_dh_set_secret(struct crypto_kpp *tfm, const void *buf, if (err) { #ifdef WOLFKM_DEBUG_DH - pr_err("%s: wc_DhImportKeyPair failed: %d", WOLFKM_DH_DRIVER, err); + pr_err("%s: wc_DhImportKeyPair failed: %d\n", WOLFKM_DH_DRIVER, err); #endif err = -EINVAL; goto dh_secret_end; @@ -585,7 +585,7 @@ static int km_ffdhe_set_secret(struct crypto_kpp *tfm, const void *buf, if (err) { #ifdef WOLFKM_DEBUG_DH - pr_err("%s: ffdhe_set_secret: decode secret failed: %d", + pr_err("%s: ffdhe_set_secret: decode secret failed: %d\n", WOLFKM_DH_DRIVER, params.key_size); #endif /* WOLFKM_DEBUG_DH */ err = -EINVAL; @@ -595,7 +595,7 @@ static int km_ffdhe_set_secret(struct crypto_kpp *tfm, const void *buf, /* p_size and g_size should be 0 for ffdhe. */ if (params.p_size || params.g_size) { #ifdef WOLFKM_DEBUG_DH - pr_err("%s: ffdhe_set_secret: unexpected p, g params: %d, %d", + pr_err("%s: ffdhe_set_secret: unexpected p, g params: %d, %d\n", WOLFKM_DH_DRIVER, params.p_size, params.g_size); #endif /* WOLFKM_DEBUG_DH */ err = -EINVAL; @@ -616,7 +616,7 @@ static int km_ffdhe_set_secret(struct crypto_kpp *tfm, const void *buf, if (!params.key_size) { /* generate the ffdhe key pair*/ #ifdef WOLFKM_DEBUG_DH - pr_info("ffdhe gen key pair"); + pr_info("ffdhe gen key pair\n"); #endif PRIVATE_KEY_UNLOCK(); err = wc_DhGenerateKeyPair(ctx->key, &ctx->rng, @@ -626,7 +626,7 @@ static int km_ffdhe_set_secret(struct crypto_kpp *tfm, const void *buf, if (err) { #ifdef WOLFKM_DEBUG_DH - pr_err("%s: wc_DhGenerateKeyPair failed: %d", + pr_err("%s: wc_DhGenerateKeyPair failed: %d\n", WOLFKM_DH_DRIVER, err); #endif err = -EINVAL; @@ -641,7 +641,7 @@ static int km_ffdhe_set_secret(struct crypto_kpp *tfm, const void *buf, if (ctx->pub_len < (ctx->nbits / WOLFSSL_BIT_SIZE)) { word32 pad_len = ctx->nbits / WOLFSSL_BIT_SIZE - ctx->pub_len; #ifdef WOLFKM_DEBUG_DH - pr_info("info: km_ffdhe_set_secret: pub key padding %d", pad_len); + pr_info("info: km_ffdhe_set_secret: pub key padding %d\n", pad_len); #endif memmove(ctx->pub_key + pad_len, ctx->pub_key, ctx->pub_len); @@ -660,7 +660,7 @@ static int km_ffdhe_set_secret(struct crypto_kpp *tfm, const void *buf, if (err) { #ifdef WOLFKM_DEBUG_DH - pr_err("%s: wc_DhImportKeyPair failed: %d", + pr_err("%s: wc_DhImportKeyPair failed: %d\n", WOLFKM_DH_DRIVER, err); #endif err = -EINVAL; @@ -783,7 +783,7 @@ static int km_ffdhe_init(struct crypto_kpp *tfm, int name, word32 nbits) } #ifdef WOLFKM_DEBUG_DH - pr_info("info: exiting km_dh_init: name %d, nbits %d", + pr_info("info: exiting km_dh_init: name %d, nbits %d\n", ctx->name, ctx->nbits); #endif /* WOLFKM_DEBUG_DH */ return 0; @@ -874,7 +874,7 @@ static int km_dh_gen_pub(struct kpp_request *req) if (ctx->pub_len > req->dst_len) { #ifdef WOLFKM_DEBUG_DH - pr_err("error: dst_len too small: %d", req->dst_len); + pr_err("error: dst_len too small: %d\n", req->dst_len); #endif /* WOLFKM_DEBUG_DH */ req->dst_len = ctx->pub_len; return -EOVERFLOW; @@ -885,7 +885,7 @@ static int km_dh_gen_pub(struct kpp_request *req) err = 0; #ifdef WOLFKM_DEBUG_DH - pr_info("info: exiting km_dh_gen_pub: %d", ctx->pub_len); + pr_info("info: exiting km_dh_gen_pub: %d\n", ctx->pub_len); #endif /* WOLFKM_DEBUG_DH */ return err; } @@ -921,7 +921,7 @@ static int km_dh_compute_shared_secret(struct kpp_request *req) if (req->src_len <= 0 || req->src_len > (ctx->nbits / WOLFSSL_BIT_SIZE)) { #ifdef WOLFKM_DEBUG_DH - pr_err("error: got src_len %d, expected %d", req->src_len, + pr_err("error: got src_len %d, expected %d\n", req->src_len, (ctx->nbits / WOLFSSL_BIT_SIZE)); #endif /* WOLFKM_DEBUG_DH */ err = -EINVAL; @@ -2903,7 +2903,7 @@ static int linuxkm_test_kpp_driver(const char * driver, dst_buf = malloc(dst_len); if (dst_buf == NULL) { - pr_err("error: allocating out buf failed"); + pr_err("error: allocating out buf failed\n"); test_rc = MEMORY_E; goto test_kpp_end; } @@ -2917,20 +2917,20 @@ static int linuxkm_test_kpp_driver(const char * driver, err = crypto_kpp_generate_public_key(req); if (err) { - pr_err("error: crypto_kpp_generate_public_key returned: %d", err); + pr_err("error: crypto_kpp_generate_public_key returned: %d\n", err); test_rc = BAD_FUNC_ARG; goto test_kpp_end; } if (memcmp(expected_a_pub, sg_virt(req->dst), pub_len)) { - pr_err("error: crypto_kpp_generate_public_key: wrong output"); + pr_err("error: crypto_kpp_generate_public_key: wrong output\n"); test_rc = WC_KEY_MISMATCH_E; goto test_kpp_end; } src_buf = malloc(src_len); if (src_buf == NULL) { - pr_err("error: allocating in buf failed"); + pr_err("error: allocating in buf failed\n"); test_rc = MEMORY_E; goto test_kpp_end; } @@ -2945,13 +2945,13 @@ static int linuxkm_test_kpp_driver(const char * driver, err = crypto_kpp_compute_shared_secret(req); if (err) { - pr_err("error: crypto_kpp_compute_shared_secret returned: %d", err); + pr_err("error: crypto_kpp_compute_shared_secret returned: %d\n", err); test_rc = BAD_FUNC_ARG; goto test_kpp_end; } if (memcmp(shared_secret, sg_virt(req->dst), shared_s_len)) { - pr_err("error: shared secret does not match"); + pr_err("error: shared secret does not match\n"); test_rc = BAD_FUNC_ARG; goto test_kpp_end; } diff --git a/linuxkm/lkcapi_ecdh_glue.c b/linuxkm/lkcapi_ecdh_glue.c index 86cef12ee3..2f88bd2037 100644 --- a/linuxkm/lkcapi_ecdh_glue.c +++ b/linuxkm/lkcapi_ecdh_glue.c @@ -199,7 +199,7 @@ static int km_ecdh_decode_secret(const u8 * buf, unsigned int len, if (secret.len != expected_len) { #ifdef WOLFKM_DEBUG_ECDH - pr_err("%s: km_ecdh_decode_secret: got %d, expected %zu", + pr_err("%s: km_ecdh_decode_secret: got %d, expected %zu\n", WOLFKM_ECDH_DRIVER, secret.len, expected_len); #endif /* WOLFKM_DEBUG_ECDH */ return -EINVAL; @@ -249,7 +249,7 @@ static int km_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf, if (km_ecdh_decode_secret(buf, len, ¶ms) < 0) { #ifdef WOLFKM_DEBUG_ECDH - pr_err("%s: ecdh_set_secret: decode secret failed: %d", + pr_err("%s: ecdh_set_secret: decode secret failed: %d\n", WOLFKM_ECDH_DRIVER, params.key_size); #endif /* WOLFKM_DEBUG_ECDH */ return -EINVAL; @@ -417,7 +417,7 @@ static int km_ecdh_init(struct crypto_kpp *tfm, int curve_id) #endif /* ECC_TIMING_RESISTANT */ #ifdef WOLFKM_DEBUG_ECDH - pr_info("info: exiting km_ecdh_init: curve_id %d, curve_len %d", + pr_info("info: exiting km_ecdh_init: curve_id %d, curve_len %d\n", ctx->curve_id, ctx->curve_len); #endif /* WOLFKM_DEBUG_ECDH */ return 0; @@ -484,7 +484,7 @@ static int km_ecdh_gen_pub(struct kpp_request *req) if (raw_pub_len > req->dst_len) { #ifdef WOLFKM_DEBUG_ECDH - pr_err("error: dst_len too small: %d", req->dst_len); + pr_err("error: dst_len too small: %d\n", req->dst_len); #endif /* WOLFKM_DEBUG_ECDH */ err = -EOVERFLOW; goto ecdh_gen_pub_end; @@ -504,7 +504,7 @@ static int km_ecdh_gen_pub(struct kpp_request *req) err = wc_ecc_make_pub(ctx->key, NULL); if (err) { #ifdef WOLFKM_DEBUG_ECDH - pr_err("error: ecc_make_pub returned: %d", err); + pr_err("error: ecc_make_pub returned: %d\n", err); #endif /* WOLFKM_DEBUG_ECDH */ goto ecdh_gen_pub_end; } @@ -522,7 +522,7 @@ static int km_ecdh_gen_pub(struct kpp_request *req) if (err || pub_x_len != ctx->curve_len || pub_y_len != ctx->curve_len) { #ifdef WOLFKM_DEBUG_ECDH - pr_err("error: ecc export pub returned: err=%d, x=%d, y=%d", err, + pr_err("error: ecc export pub returned: err=%d, x=%d, y=%d\n", err, pub_x_len, pub_y_len); #endif /* WOLFKM_DEBUG_ECDH */ err = -EINVAL; @@ -537,7 +537,7 @@ ecdh_gen_pub_end: if (pub) { free(pub); pub = NULL; } #ifdef WOLFKM_DEBUG_ECDH - pr_info("info: exiting km_ecdh_gen_pub: %d", err); + pr_info("info: exiting km_ecdh_gen_pub: %d\n", err); #endif /* WOLFKM_DEBUG_ECDH */ return err; } @@ -584,7 +584,7 @@ static int km_ecdh_compute_shared_secret(struct kpp_request *req) if (req->src_len != raw_pub_len) { #ifdef WOLFKM_DEBUG_ECDH - pr_err("error: got src_len %d, expected %d", req->src_len, raw_pub_len); + pr_err("error: got src_len %d, expected %d\n", req->src_len, raw_pub_len); #endif /* WOLFKM_DEBUG_ECDH */ err = -EINVAL; goto ecdh_shared_secret_end; @@ -928,7 +928,7 @@ static int linuxkm_test_ecdh_nist_driver(const char * driver, dst_buf = malloc(dst_len); if (dst_buf == NULL) { - pr_err("error: allocating out buf failed"); + pr_err("error: allocating out buf failed\n"); test_rc = BAD_FUNC_ARG; goto test_ecdh_nist_end; } @@ -942,20 +942,20 @@ static int linuxkm_test_ecdh_nist_driver(const char * driver, err = crypto_kpp_generate_public_key(req); if (err) { - pr_err("error: crypto_kpp_generate_public_key returned: %d", err); + pr_err("error: crypto_kpp_generate_public_key returned: %d\n", err); test_rc = BAD_FUNC_ARG; goto test_ecdh_nist_end; } if (memcmp(expected_a_pub, sg_virt(req->dst), pub_len)) { - pr_err("error: crypto_kpp_generate_public_key: wrong output"); + pr_err("error: crypto_kpp_generate_public_key: wrong output\n"); test_rc = BAD_FUNC_ARG; goto test_ecdh_nist_end; } src_buf = malloc(src_len); if (src_buf == NULL) { - pr_err("error: allocating in buf failed"); + pr_err("error: allocating in buf failed\n"); test_rc = MEMORY_E; goto test_ecdh_nist_end; } @@ -970,13 +970,13 @@ static int linuxkm_test_ecdh_nist_driver(const char * driver, err = crypto_kpp_compute_shared_secret(req); if (err) { - pr_err("error: crypto_kpp_compute_shared_secret returned: %d", err); + pr_err("error: crypto_kpp_compute_shared_secret returned: %d\n", err); test_rc = BAD_FUNC_ARG; goto test_ecdh_nist_end; } if (memcmp(shared_secret, sg_virt(req->dst), shared_s_len)) { - pr_err("error: shared secret does not match"); + pr_err("error: shared secret does not match\n"); test_rc = BAD_FUNC_ARG; goto test_ecdh_nist_end; } diff --git a/linuxkm/lkcapi_glue.c b/linuxkm/lkcapi_glue.c index f88da9e2bb..4bb25a7298 100644 --- a/linuxkm/lkcapi_glue.c +++ b/linuxkm/lkcapi_glue.c @@ -244,7 +244,7 @@ static ssize_t install_algs_handler(struct kobject *kobj, struct kobj_attribute if (kstrtoint(buf, 10, &arg) || arg != 1) return -EINVAL; - pr_info("wolfCrypt: Installing algorithms"); + pr_info("wolfCrypt: Installing algorithms\n"); ret = linuxkm_lkcapi_register(); if (ret != 0) @@ -265,7 +265,7 @@ static ssize_t deinstall_algs_handler(struct kobject *kobj, struct kobj_attribut if (kstrtoint(buf, 10, &arg) || arg != 1) return -EINVAL; - pr_info("wolfCrypt: Deinstalling algorithms"); + pr_info("wolfCrypt: Deinstalling algorithms\n"); ret = linuxkm_lkcapi_unregister(); if (ret != 0) @@ -274,7 +274,7 @@ static ssize_t deinstall_algs_handler(struct kobject *kobj, struct kobj_attribut #if defined(HAVE_FIPS) && defined(CONFIG_CRYPTO_MANAGER) && \ !defined(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS) if (enabled_fips) { - pr_info("wolfCrypt: restoring fips_enabled to off."); + pr_info("wolfCrypt: restoring fips_enabled to off.\n"); enabled_fips = fips_enabled = 0; } #endif @@ -358,7 +358,7 @@ static int linuxkm_lkcapi_register(void) /* assert system-wide FIPS status, to disable FIPS-forbidden * test vectors and fuzzing from the CRYPTO_MANAGER. */ - pr_info("wolfCrypt: changing fips_enabled from 0 to 1 for FIPS module."); + pr_info("wolfCrypt: changing fips_enabled from 0 to 1 for FIPS module.\n"); enabled_fips = fips_enabled = 1; } #endif @@ -382,7 +382,7 @@ static int linuxkm_lkcapi_register(void) if (! ((alg).base.cra_flags & CRYPTO_ALG_DEAD)) { \ pr_err("ERROR: alg %s not _DEAD " \ "after crypto_unregister_%s -- " \ - "marking as loaded despite test failure.", \ + "marking as loaded despite test failure.\n", \ (alg).base.cra_driver_name, \ #alg_class); \ alg ## _loaded = 1; \ @@ -434,7 +434,7 @@ static int linuxkm_lkcapi_register(void) if (! ((alg).base.cra_flags & CRYPTO_ALG_DEAD)) { \ pr_err("ERROR: alg %s not _DEAD " \ "after crypto_unregister_%s -- " \ - "marking as loaded despite test failure.", \ + "marking as loaded despite test failure.\n", \ (alg).base.cra_driver_name, \ #alg_class); \ alg ## _loaded = 1; \ @@ -729,7 +729,7 @@ static int linuxkm_lkcapi_register(void) disable_setkey_warnings = 0; #endif - pr_info("wolfCrypt: %d algorithm%s registered.", linuxkm_lkcapi_n_registered, + pr_info("wolfCrypt: %d algorithm%s registered.\n", linuxkm_lkcapi_n_registered, linuxkm_lkcapi_n_registered == 1 ? "" : "s"); if (ret == -1) { @@ -794,7 +794,7 @@ static int linuxkm_lkcapi_unregister(void) do { \ if (alg ## _loaded) { \ if ((alg).base.cra_flags & CRYPTO_ALG_DEAD) { \ - pr_err("alg %s already CRYPTO_ALG_DEAD.", \ + pr_err("alg %s already CRYPTO_ALG_DEAD.\n", \ (alg).base.cra_driver_name); \ alg ## _loaded = 0; \ ++n_deregistered; \ @@ -807,7 +807,7 @@ static int linuxkm_lkcapi_unregister(void) if (! ((alg).base.cra_flags & CRYPTO_ALG_DEAD)) { \ pr_err("ERROR: alg %s not _DEAD after " \ "crypto_unregister_%s -- " \ - "leaving marked as loaded.", \ + "leaving marked as loaded.\n", \ (alg).base.cra_driver_name, \ #alg_class); \ seen_err = -EBUSY; \ @@ -817,7 +817,7 @@ static int linuxkm_lkcapi_unregister(void) } \ } \ else { \ - pr_err("alg %s cannot be uninstalled (refcnt = %d)", \ + pr_err("alg %s cannot be uninstalled (refcnt = %d)\n", \ (alg).base.cra_driver_name, cur_refcnt); \ if (cur_refcnt > 0) { seen_err = -EBUSY; } \ } \ @@ -1025,7 +1025,7 @@ static int linuxkm_lkcapi_unregister(void) #undef UNREGISTER_ALG linuxkm_lkcapi_n_registered -= n_deregistered; - pr_info("wolfCrypt: %d algorithm%s deregistered, %d remain%s registered.", + pr_info("wolfCrypt: %d algorithm%s deregistered, %d remain%s registered.\n", n_deregistered, n_deregistered == 1 ? "" : "s", linuxkm_lkcapi_n_registered, linuxkm_lkcapi_n_registered == 1 ? "s" : ""); diff --git a/linuxkm/lkcapi_rsa_glue.c b/linuxkm/lkcapi_rsa_glue.c index 056a0d589d..e38dfaf28c 100644 --- a/linuxkm/lkcapi_rsa_glue.c +++ b/linuxkm/lkcapi_rsa_glue.c @@ -1172,7 +1172,7 @@ pkcs1pad_sign_out: #ifdef WOLFKM_DEBUG_RSA pr_info("info: exiting km_pkcs1pad_sign msg_len %d, enc_msg_len %d," - " sig_len %d, err %d", req->src_len, enc_len, sig_len, err); + " sig_len %d, err %d\n", req->src_len, enc_len, sig_len, err); #endif /* WOLFKM_DEBUG_RSA */ return err; } @@ -1223,7 +1223,7 @@ static int km_pkcs1pad_verify(struct akcipher_request *req) hash_enc_len = get_hash_enc_len(ctx->hash_oid); if (hash_enc_len <= 0) { #ifdef WOLFKM_DEBUG_RSA - pr_err("error: %s: bad hash enc len %d", + pr_err("error: %s: bad hash enc len %d\n", WOLFKM_RSA_DRIVER, hash_enc_len); #endif /* WOLFKM_DEBUG_RSA */ err = -EINVAL; @@ -1233,7 +1233,7 @@ static int km_pkcs1pad_verify(struct akcipher_request *req) if (msg_len != ctx->digest_len || sig_len != ctx->key_len) { /* invalid src or dst args */ #ifdef WOLFKM_DEBUG_RSA - pr_err("error: %s: got msg_len %d, expected %d", + pr_err("error: %s: got msg_len %d, expected %d\n", WOLFKM_RSA_DRIVER, msg_len, ctx->digest_len); #endif /* WOLFKM_DEBUG_RSA */ err = -EINVAL; @@ -1287,7 +1287,7 @@ pkcs1pad_verify_out: #ifdef WOLFKM_DEBUG_RSA pr_info("info: exiting km_pkcs1pad_verify msg_len %d, enc_msg_len %d," - " sig_len %d, err %d", msg_len, enc_msg_len, sig_len, err); + " sig_len %d, err %d\n", msg_len, enc_msg_len, sig_len, err); #endif /* WOLFKM_DEBUG_RSA */ return err; } @@ -1420,7 +1420,7 @@ pkcs1_sign_out: #ifdef WOLFKM_DEBUG_RSA pr_info("info: exiting km_pkcs1_sign msg_len %d, enc_msg_len %d," - " sig_len %d, err %d", slen, enc_msg_len, sig_len, err); + " sig_len %d, err %d\n", slen, enc_msg_len, sig_len, err); #endif /* WOLFKM_DEBUG_RSA */ return err; } @@ -1474,7 +1474,7 @@ static int km_pkcs1_verify(struct crypto_sig *tfm, hash_enc_len = get_hash_enc_len(ctx->hash_oid); if (hash_enc_len <= 0) { #ifdef WOLFKM_DEBUG_RSA - pr_err("error: %s: bad hash enc len %d", + pr_err("error: %s: bad hash enc len %d\n", WOLFKM_RSA_DRIVER, hash_enc_len); #endif /* WOLFKM_DEBUG_RSA */ err = -EINVAL; @@ -1484,7 +1484,7 @@ static int km_pkcs1_verify(struct crypto_sig *tfm, if (msg_len != ctx->digest_len || sig_len != ctx->key_len) { /* invalid src or dst args */ #ifdef WOLFKM_DEBUG_RSA - pr_err("error: %s: got msg_len %d, expected %d", + pr_err("error: %s: got msg_len %d, expected %d\n", WOLFKM_RSA_DRIVER, msg_len, ctx->digest_len); #endif /* WOLFKM_DEBUG_RSA */ err = -EINVAL; @@ -1538,7 +1538,7 @@ pkcs1_verify_out: #ifdef WOLFKM_DEBUG_RSA pr_info("info: exiting km_pkcs1_verify msg_len %d, enc_msg_len %d," - " sig_len %d, err %d", msg_len, enc_msg_len, sig_len, err); + " sig_len %d, err %d\n", msg_len, enc_msg_len, sig_len, err); #endif /* WOLFKM_DEBUG_RSA */ return err; } @@ -1817,7 +1817,7 @@ pkcs1_dec_out: if (dec != NULL) { free(dec); dec = NULL; } #ifdef WOLFKM_DEBUG_RSA - pr_info("info: exiting km_pkcs1pad_dec %d", err); + pr_info("info: exiting km_pkcs1pad_dec %d\n", err); #endif /* WOLFKM_DEBUG_RSA */ return err; } diff --git a/linuxkm/lkcapi_sha_glue.c b/linuxkm/lkcapi_sha_glue.c index 6a75afc95f..39754a6424 100644 --- a/linuxkm/lkcapi_sha_glue.c +++ b/linuxkm/lkcapi_sha_glue.c @@ -1188,7 +1188,7 @@ static int wc_linuxkm_drbg_generate(struct wc_rng_bank *ctx, struct wc_rng_bank_inst *drbg = linuxkm_get_drbg(ctx); if (! drbg) { - pr_err_once("BUG: linuxkm_get_drbg() failed."); + pr_err_once("BUG: linuxkm_get_drbg() failed.\n"); return -EFAULT; } @@ -1235,11 +1235,11 @@ static int wc_linuxkm_drbg_generate(struct wc_rng_bank *ctx, WC_RNG_BANK_FLAG_CAN_WAIT); if (ret == 0) { - pr_warn("WARNING: reinitialized DRBG #%d after RNG_FAILURE_E from wc_RNG_GenerateBlock().", raw_smp_processor_id()); + pr_warn("WARNING: reinitialized DRBG #%d after RNG_FAILURE_E from wc_RNG_GenerateBlock().\n", raw_smp_processor_id()); continue; } else { - pr_warn_once("ERROR: reinitialization of DRBG #%d after RNG_FAILURE_E failed with ret %d.", raw_smp_processor_id(), ret); + pr_warn_once("ERROR: reinitialization of DRBG #%d after RNG_FAILURE_E failed with ret %d.\n", raw_smp_processor_id(), ret); ret = -EINVAL; break; } @@ -1264,7 +1264,7 @@ static int wc_linuxkm_drbg_generate_tfm(struct crypto_rng *tfm, { if (tfm->base.__crt_alg->cra_init != wc_linuxkm_drbg_init_tfm) { - pr_err_once("BUG: mismatched tfm."); + pr_err_once("BUG: mismatched tfm.\n"); return -EFAULT; } @@ -1294,7 +1294,7 @@ static int wc_linuxkm_drbg_seed_tfm(struct crypto_rng *tfm, { if (tfm->base.__crt_alg->cra_init != wc_linuxkm_drbg_init_tfm) { - pr_err_once("BUG: mismatched tfm."); + pr_err_once("BUG: mismatched tfm.\n"); return -EFAULT; } @@ -1354,7 +1354,7 @@ static int wc__get_random_bytes(void *buf, size_t len) NULL, 0, buf, len); (void)wc_rng_bank_default_checkin(¤t_default_wc_rng_bank); if (ret) { - pr_warn("BUG: wc__get_random_bytes falling through to native get_random_bytes with wc_linuxkm_drbg_default_instance_registered, ret=%d.", ret); + pr_warn("BUG: wc__get_random_bytes falling through to native get_random_bytes with wc_linuxkm_drbg_default_instance_registered, ret=%d.\n", ret); } return ret; } @@ -1383,7 +1383,7 @@ static ssize_t wc_get_random_bytes_user(struct iov_iter *iter) { ret = wc_linuxkm_drbg_generate(current_default_wc_rng_bank, NULL, 0, block, sizeof block); if (unlikely(ret != 0)) { - pr_err("ERROR: wc_get_random_bytes_user() wc_linuxkm_drbg_generate() returned %d.", ret); + pr_err("ERROR: wc_get_random_bytes_user() wc_linuxkm_drbg_generate() returned %d.\n", ret); break; } @@ -1445,7 +1445,7 @@ static ssize_t wc_extract_crng_user(void __user *buf, size_t nbytes) { ret = wc_linuxkm_drbg_generate(current_default_wc_rng_bank, NULL, 0, block, sizeof block); if (unlikely(ret != 0)) { - pr_err("ERROR: wc_extract_crng_user() wc_linuxkm_drbg_generate() returned %d.", ret); + pr_err("ERROR: wc_extract_crng_user() wc_linuxkm_drbg_generate() returned %d.\n", ret); break; } @@ -1610,10 +1610,10 @@ static int wc_get_random_bytes_by_kprobe(struct kprobe *p, struct pt_regs *regs) regs->ip = (unsigned long)p->addr + p->ainsn.size; return 1; /* Handled. */ } - pr_warn("BUG: wc_get_random_bytes_by_kprobe falling through to native get_random_bytes with wc_linuxkm_drbg_default_instance_registered, ret=%d.", ret); + pr_warn("BUG: wc_get_random_bytes_by_kprobe falling through to native get_random_bytes with wc_linuxkm_drbg_default_instance_registered, ret=%d.\n", ret); } else - pr_warn("BUG: wc_get_random_bytes_by_kprobe called without wc_linuxkm_drbg_default_instance_registered."); + pr_warn("BUG: wc_get_random_bytes_by_kprobe called without wc_linuxkm_drbg_default_instance_registered.\n"); /* Not handled. Fall through to native implementation, given * that the alternative is an immediate kernel panic. @@ -1668,7 +1668,7 @@ static int wc_get_random_bytes_user_kretprobe_enter(struct kretprobe_instance *p byte block[WC_SHA256_BLOCK_SIZE]; if (unlikely(!wc_linuxkm_drbg_default_instance_registered)) { - pr_warn("BUG: wc_get_random_bytes_user_kretprobe_enter() without wc_linuxkm_drbg_default_instance_registered."); + pr_warn("BUG: wc_get_random_bytes_user_kretprobe_enter() without wc_linuxkm_drbg_default_instance_registered.\n"); ret = -ENOENT; goto out; } @@ -1681,7 +1681,7 @@ static int wc_get_random_bytes_user_kretprobe_enter(struct kretprobe_instance *p for (;;) { ret = crypto_rng_get_bytes(crypto_default_rng, block, sizeof block); if (ret != 0) { - pr_err("ERROR: wc_get_random_bytes_user_kretprobe_enter() crypto_rng_get_bytes() returned %d.", ret); + pr_err("ERROR: wc_get_random_bytes_user_kretprobe_enter() crypto_rng_get_bytes() returned %d.\n", ret); break; } @@ -1714,7 +1714,7 @@ out: if ((ret != 0) && (this_copied == (size_t)(-1L))) { /* crypto_rng_get_bytes() failed on the first call, before any update to the iov_iter. */ - pr_warn("WARNING: wc_get_random_bytes_user_kretprobe_enter() falling through to native get_random_bytes_user()."); + pr_warn("WARNING: wc_get_random_bytes_user_kretprobe_enter() falling through to native get_random_bytes_user().\n"); return -EFAULT; } @@ -1741,7 +1741,7 @@ static int wc_get_random_bytes_user_kretprobe_exit(struct kretprobe_instance *p, struct wc_get_random_bytes_user_kretprobe_ctx *ctx = (struct wc_get_random_bytes_user_kretprobe_ctx *)p->data; if (unlikely(!wc_linuxkm_drbg_default_instance_registered)) { - pr_warn("BUG: wc_get_random_bytes_user_kretprobe_exit without wc_linuxkm_drbg_default_instance_registered."); + pr_warn("BUG: wc_get_random_bytes_user_kretprobe_exit without wc_linuxkm_drbg_default_instance_registered.\n"); return -EFAULT; } @@ -1777,7 +1777,7 @@ static int wc_linuxkm_drbg_startup(void) int ret; if (wc_linuxkm_drbg_loaded) { - pr_err("ERROR: wc_linuxkm_drbg_set_default called with wc_linuxkm_drbg_loaded."); + pr_err("ERROR: wc_linuxkm_drbg_set_default called with wc_linuxkm_drbg_loaded.\n"); return -EBUSY; } @@ -1791,7 +1791,7 @@ static int wc_linuxkm_drbg_startup(void) ret = crypto_register_rng(&wc_linuxkm_drbg); if (ret != 0) { - pr_err("ERROR: crypto_register_rng: %d", ret); + pr_err("ERROR: crypto_register_rng: %d\n", ret); return ret; } @@ -1860,7 +1860,7 @@ static int wc_linuxkm_drbg_startup(void) } if (ret) - pr_err("ERROR: wc_linuxkm_drbg_startup: PRNG quality test failed, block length %d, iters %d, ret %d", + pr_err("ERROR: wc_linuxkm_drbg_startup: PRNG quality test failed, block length %d, iters %d, ret %d\n", i, j, ret); } } @@ -1890,7 +1890,7 @@ static int wc_linuxkm_drbg_startup(void) ret = crypto_del_default_rng(); if (ret) { wc_linuxkm_rng_initing_default_bank_flag = 0; - pr_err("ERROR: crypto_del_default_rng returned %d", ret); + pr_err("ERROR: crypto_del_default_rng returned %d\n", ret); return ret; } @@ -1899,27 +1899,27 @@ static int wc_linuxkm_drbg_startup(void) wc_linuxkm_rng_initing_default_bank_flag = 0; if (ret) { - pr_err("ERROR: crypto_get_default_rng returned %d", ret); + pr_err("ERROR: crypto_get_default_rng returned %d\n", ret); return ret; } { int cur_refcnt = WC_LKM_REFCOUNT_TO_INT(wc_linuxkm_drbg.base.cra_refcnt); if (cur_refcnt < 2) { - pr_err("ERROR: wc_linuxkm_drbg refcnt = %d after crypto_get_default_rng()", cur_refcnt); + pr_err("ERROR: wc_linuxkm_drbg refcnt = %d after crypto_get_default_rng()\n", cur_refcnt); crypto_put_default_rng(); return -EINVAL; } } if (! crypto_default_rng) { - pr_err("ERROR: crypto_default_rng is null"); + pr_err("ERROR: crypto_default_rng is null\n"); crypto_put_default_rng(); return -EINVAL; } if (crypto_default_rng->base.__crt_alg->cra_init != wc_linuxkm_drbg_init_tfm) { - pr_err("ERROR: %s NOT registered as systemwide default stdrng -- found \"%s\".", wc_linuxkm_drbg.base.cra_driver_name, crypto_tfm_alg_driver_name(&crypto_default_rng->base)); + pr_err("ERROR: %s NOT registered as systemwide default stdrng -- found \"%s\".\n", wc_linuxkm_drbg.base.cra_driver_name, crypto_tfm_alg_driver_name(&crypto_default_rng->base)); crypto_put_default_rng(); return -EINVAL; } @@ -1935,7 +1935,7 @@ static int wc_linuxkm_drbg_startup(void) ret = crypto_del_default_rng(); if (ret) { wc_linuxkm_rng_initing_default_bank_flag = 0; - pr_err("ERROR: crypto_del_default_rng returned %d", ret); + pr_err("ERROR: crypto_del_default_rng returned %d\n", ret); return ret; } @@ -1944,7 +1944,7 @@ static int wc_linuxkm_drbg_startup(void) wc_linuxkm_rng_initing_default_bank_flag = 0; if (ret) { - pr_err("ERROR: __crypto_stdrng_get_bytes returned %d", ret); + pr_err("ERROR: __crypto_stdrng_get_bytes returned %d\n", ret); return ret; } } @@ -1954,7 +1954,7 @@ static int wc_linuxkm_drbg_startup(void) ret = wc_linuxkm_rng_bank_init(&default_bank); wc_linuxkm_rng_initing_default_bank_flag = 0; if (ret) { - pr_err("ERROR: wc_linuxkm_rng_bank_init returned %d", ret); + pr_err("ERROR: wc_linuxkm_rng_bank_init returned %d\n", ret); return ret; } default_bank_inited = 1; @@ -1966,11 +1966,11 @@ static int wc_linuxkm_drbg_startup(void) struct wc_rng_bank *current_default_wc_rng_bank; ret = wc_rng_bank_default_checkout(¤t_default_wc_rng_bank); if (ret) - pr_err("ERROR: wc_rng_bank_default_checkout() after default stdrng registration returned %d", ret); + pr_err("ERROR: wc_rng_bank_default_checkout() after default stdrng registration returned %d\n", ret); else { ret = wc_rng_bank_default_checkin(¤t_default_wc_rng_bank); if (ret) - pr_err("ERROR: wc_rng_bank_default_checkin() after wc_rng_bank_default_checkout() returned %d", ret); + pr_err("ERROR: wc_rng_bank_default_checkin() after wc_rng_bank_default_checkout() returned %d\n", ret); } if (ret != 0) { #if defined(LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT) && \ @@ -1986,8 +1986,8 @@ static int wc_linuxkm_drbg_startup(void) } wc_linuxkm_drbg_default_instance_registered = 1; - pr_info("%s registered as systemwide default stdrng.", wc_linuxkm_drbg.base.cra_driver_name); - pr_info("libwolfssl: to unload module, first echo 1 > /sys/module/libwolfssl/deinstall_algs"); + pr_info("%s registered as systemwide default stdrng.\n", wc_linuxkm_drbg.base.cra_driver_name); + pr_info("libwolfssl: to unload module, first echo 1 > /sys/module/libwolfssl/deinstall_algs\n"); #ifdef LINUXKM_DRBG_GET_RANDOM_BYTES @@ -1999,7 +1999,7 @@ static int wc_linuxkm_drbg_startup(void) if (ret == 0) { wc_get_random_bytes_callbacks_installed = 1; - pr_info("libwolfssl: kernel global random_bytes handlers installed."); + pr_info("libwolfssl: kernel global random_bytes handlers installed.\n"); } else { pr_err("ERROR: wolfssl_linuxkm_register_random_bytes_handlers() failed: %d\n", ret); @@ -2039,22 +2039,22 @@ static int wc_linuxkm_drbg_startup(void) byte scratch[4]; ret = wc__get_random_bytes(scratch, sizeof(scratch)); if (ret != 0) { - pr_err("ERROR: wc__get_random_bytes() returned %d", ret); + pr_err("ERROR: wc__get_random_bytes() returned %d\n", ret); return -EINVAL; } ret = wc_mix_pool_bytes(scratch, sizeof(scratch)); if (ret != 0) { - pr_err("ERROR: wc_mix_pool_bytes() returned %d", ret); + pr_err("ERROR: wc_mix_pool_bytes() returned %d\n", ret); return -EINVAL; } ret = wc_crng_reseed(); if (ret != 0) { - pr_err("ERROR: wc_crng_reseed() returned %d", ret); + pr_err("ERROR: wc_crng_reseed() returned %d\n", ret); return -EINVAL; } ret = wc__get_random_bytes(scratch, sizeof(scratch)); if (ret != 0) { - pr_err("ERROR: wc__get_random_bytes() returned %d", ret); + pr_err("ERROR: wc__get_random_bytes() returned %d\n", ret); return -EINVAL; } } @@ -2071,7 +2071,7 @@ static int wc_linuxkm_drbg_cleanup(void) { int cur_refcnt; if (! wc_linuxkm_drbg_loaded) { - pr_err("ERROR: wc_linuxkm_drbg_cleanup called with ! wc_linuxkm_drbg_loaded"); + pr_err("ERROR: wc_linuxkm_drbg_cleanup called with ! wc_linuxkm_drbg_loaded\n"); return -EINVAL; } @@ -2094,7 +2094,7 @@ static int wc_linuxkm_drbg_cleanup(void) { if (wc_get_random_bytes_callbacks_installed) { ret = wolfssl_linuxkm_unregister_random_bytes_handlers(); if (ret != 0) { - pr_err("ERROR: wolfssl_linuxkm_unregister_random_bytes_handlers returned %d", ret); + pr_err("ERROR: wolfssl_linuxkm_unregister_random_bytes_handlers returned %d\n", ret); return ret; } pr_info("libwolfssl: kernel global random_bytes handlers uninstalled\n"); @@ -2127,7 +2127,7 @@ static int wc_linuxkm_drbg_cleanup(void) { #if LINUX_VERSION_CODE < KERNEL_VERSION(7, 1, 0) ret = crypto_del_default_rng(); if (ret) { - pr_err("ERROR: crypto_del_default_rng failed: %d", ret); + pr_err("ERROR: crypto_del_default_rng failed: %d\n", ret); return ret; } #else /* >= 7.1.0 */ @@ -2136,7 +2136,7 @@ static int wc_linuxkm_drbg_cleanup(void) { if (fips_enabled) { ret = crypto_del_default_rng(); if (ret) { - pr_err("ERROR: crypto_del_default_rng failed: %d", ret); + pr_err("ERROR: crypto_del_default_rng failed: %d\n", ret); return ret; } } @@ -2145,11 +2145,11 @@ static int wc_linuxkm_drbg_cleanup(void) { if (default_bank_inited) { ret = wc_rng_bank_default_clear(&default_bank); if (ret) - pr_err("ERROR: wc_rng_bank_default_clear in wc_linuxkm_drbg_cleanup failed: %d", ret); + pr_err("ERROR: wc_rng_bank_default_clear in wc_linuxkm_drbg_cleanup failed: %d\n", ret); else { ret = wc_rng_bank_fini(&default_bank); if (ret) - pr_err("ERROR: wc_rng_bank_fini in wc_linuxkm_drbg_cleanup failed: %d", ret); + pr_err("ERROR: wc_rng_bank_fini in wc_linuxkm_drbg_cleanup failed: %d\n", ret); } default_bank_inited = 0; } @@ -2162,14 +2162,14 @@ static int wc_linuxkm_drbg_cleanup(void) { cur_refcnt = WC_LKM_REFCOUNT_TO_INT(wc_linuxkm_drbg.base.cra_refcnt); if (cur_refcnt != 1) { - pr_err("ERROR: wc_linuxkm_drbg_cleanup called with refcnt = %d", cur_refcnt); + pr_err("ERROR: wc_linuxkm_drbg_cleanup called with refcnt = %d\n", cur_refcnt); return -EBUSY; } crypto_unregister_rng(&wc_linuxkm_drbg); if (! (wc_linuxkm_drbg.base.cra_flags & CRYPTO_ALG_DEAD)) { - pr_warn("WARNING: wc_linuxkm_drbg_cleanup: after crypto_unregister_rng, wc_linuxkm_drbg isn't dead."); + pr_warn("WARNING: wc_linuxkm_drbg_cleanup: after crypto_unregister_rng, wc_linuxkm_drbg isn't dead.\n"); return -EBUSY; } diff --git a/linuxkm/module_hooks.c b/linuxkm/module_hooks.c index 03b6e2e44e..cb41051a03 100644 --- a/linuxkm/module_hooks.c +++ b/linuxkm/module_hooks.c @@ -1115,7 +1115,7 @@ static void wolfssl_exit(void) pr_err("ERROR: wc_RunAllCast_fips() failed at shutdown with return value %d\n", ret); } else - pr_info("wolfCrypt FIPS re-self-test succeeded at unload: all algorithms re-verified."); + pr_info("wolfCrypt FIPS re-self-test succeeded at unload: all algorithms re-verified.\n"); #endif (void)libwolfssl_cleanup(); @@ -1772,7 +1772,7 @@ static int updateFipsHash(void) size_t desc_size = crypto_shash_descsize(tfm) + sizeof *desc; desc = XMALLOC(desc_size, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (desc == NULL) { - pr_err("ERROR: failed allocating desc."); + pr_err("ERROR: failed allocating desc.\n"); ret = MEMORY_E; goto out; } @@ -1845,13 +1845,13 @@ static WC_MAYBE_UNUSED void *my_kallsyms_lookup_name(const char *name) { int ret; kallsyms_lookup_name_kp.addr = NULL; if ((ret = register_kprobe(&kallsyms_lookup_name_kp)) != 0) { - pr_err_once("ERROR: register_kprobe(&kallsyms_lookup_name_kp) failed: %d", ret); + pr_err_once("ERROR: register_kprobe(&kallsyms_lookup_name_kp) failed: %d\n", ret); return 0; } kallsyms_lookup_name_ptr = (typeof(kallsyms_lookup_name_ptr))kallsyms_lookup_name_kp.addr; unregister_kprobe(&kallsyms_lookup_name_kp); if (! kallsyms_lookup_name_ptr) { - pr_err_once("ERROR: kallsyms_lookup_name_kp.addr is null."); + pr_err_once("ERROR: kallsyms_lookup_name_kp.addr is null.\n"); return 0; } } @@ -1880,7 +1880,7 @@ static ssize_t FIPS_rerun_self_test_handler(struct kobject *kobj, struct kobj_at return -EINVAL; } - pr_info("wolfCrypt: rerunning FIPS self-test on command."); + pr_info("wolfCrypt: rerunning FIPS self-test on command.\n"); if (WC_SIG_IGNORE_BEGIN() >= 0) { ret = wolfCrypt_IntegrityTest_fips(); @@ -1891,7 +1891,7 @@ static ssize_t FIPS_rerun_self_test_handler(struct kobject *kobj, struct kobj_at ret = -1; } if (ret != 0) { - pr_err("ERROR: wolfCrypt_IntegrityTest_fips: error %d", ret); + pr_err("ERROR: wolfCrypt_IntegrityTest_fips: error %d\n", ret); return -EINVAL; } @@ -1910,7 +1910,7 @@ static ssize_t FIPS_rerun_self_test_handler(struct kobject *kobj, struct kobj_at return -EINVAL; } - pr_info("wolfCrypt FIPS re-self-test succeeded: all algorithms verified and available."); + pr_info("wolfCrypt FIPS re-self-test succeeded: all algorithms verified and available.\n"); return count; } From f81f8479d5a3e1a4056a0e5d27cbaa03646d5956 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 28 Apr 2026 18:06:00 -0500 Subject: [PATCH 156/167] fixes for SLH-DSA verifyonly: wolfssl/wolfcrypt/wc_slhdsa.h: implement WOLFSSL_SLHDSA_NO_SHAKE and WOLFSSL_SLHDSA_NO_SHA2, and fix WC_SLHDSA_MAX_SIG_LEN setup to reflect SHA2 variants; wolfssl/wolfcrypt/settings.h: if WOLFSSL_KERNEL_MODE, set WOLFSSL_SLHDSA_VERIFY_ONLY unless WOLFSSL_SLHDSA_NO_VERIFY_ONLY; wolfcrypt/src/wc_slhdsa.c: fix WOLFSSL_SLHDSA_VERIFY_ONLY to work with --enable-slhdsa=sha2,verifyonly; fix -Wunused-variables in slhdsakey_wots_pk_from_sig_x4(); wolfcrypt/test/test.c: in slhdsa_test(), fix gating for compatibility with --enable-slhdsa=sha2,verifyonly; tests/api/test_slhdsa.c: fix gating in test_wc_slhdsa() and test_wc_slhdsa_sizes(). --- .wolfssl_known_macro_extras | 1 + tests/api/test_slhdsa.c | 8 ++--- wolfcrypt/src/wc_slhdsa.c | 64 +++++++++++++++++++++++------------ wolfcrypt/test/test.c | 16 +++++---- wolfssl/wolfcrypt/settings.h | 8 +++++ wolfssl/wolfcrypt/wc_slhdsa.h | 50 +++++++++++++++++++++++++-- 6 files changed, 113 insertions(+), 34 deletions(-) diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 7f8cc3f886..54aa491c71 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -909,6 +909,7 @@ WOLFSSL_SHA512_HASHTYPE WOLFSSL_SHUTDOWNONCE WOLFSSL_SILABS_TRNG WOLFSSL_SLHDSA_FULL_HASH +WOLFSSL_SLHDSA_NO_VERIFY_ONLY WOLFSSL_SNIFFER_NO_RECOVERY WOLFSSL_SP_ARM32_UDIV WOLFSSL_SP_FAST_NCT_EXPTMOD diff --git a/tests/api/test_slhdsa.c b/tests/api/test_slhdsa.c index fc40bed9c7..4d54bb6929 100644 --- a/tests/api/test_slhdsa.c +++ b/tests/api/test_slhdsa.c @@ -42,7 +42,7 @@ int test_wc_slhdsa(void) { EXPECT_DECLS; -#ifdef WOLFSSL_HAVE_SLHDSA +#if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_NO_SHAKE) SlhDsaKey key; /* Test NULL parameter handling for init. */ @@ -84,7 +84,7 @@ int test_wc_slhdsa(void) wc_SlhDsaKey_Free(&key); #endif -#endif /* WOLFSSL_HAVE_SLHDSA */ +#endif /* WOLFSSL_HAVE_SLHDSA && !WOLFSSL_SLHDSA_NO_SHAKE */ return EXPECT_RESULT(); } @@ -94,7 +94,7 @@ int test_wc_slhdsa(void) int test_wc_slhdsa_sizes(void) { EXPECT_DECLS; -#ifdef WOLFSSL_HAVE_SLHDSA +#if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_NO_SHAKE) SlhDsaKey key; /* Test NULL parameter handling for size functions. */ @@ -226,7 +226,7 @@ int test_wc_slhdsa_sizes(void) WC_SLHDSA_SHAKE256F_SIG_LEN); #endif -#endif /* WOLFSSL_HAVE_SLHDSA */ +#endif /* WOLFSSL_HAVE_SLHDSA && !WOLFSSL_SLHDSA_NO_SHAKE */ return EXPECT_RESULT(); } diff --git a/wolfcrypt/src/wc_slhdsa.c b/wolfcrypt/src/wc_slhdsa.c index 402b484746..4adc829799 100644 --- a/wolfcrypt/src/wc_slhdsa.c +++ b/wolfcrypt/src/wc_slhdsa.c @@ -752,6 +752,7 @@ static int slhdsakey_hash_f_sha2(SlhDsaKey* key, const byte* pk_seed, return ret; } +#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY /* SHA2 H function. * * FIPS 205. Section 11.2. @@ -820,6 +821,7 @@ static int slhdsakey_hash_h_sha2(SlhDsaKey* key, const byte* pk_seed, return ret; } +#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ /* SHA2 H function with two separate n-byte halves. * @@ -895,6 +897,7 @@ static int slhdsakey_hash_h_2_sha2(SlhDsaKey* key, const byte* pk_seed, return ret; } +#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY /* SHA2 PRF function. * * FIPS 205. Section 11.2. @@ -938,6 +941,7 @@ static int slhdsakey_hash_prf_sha2(SlhDsaKey* key, const byte* pk_seed, return ret; } +#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ /* SHA2 T_l streaming: start with address. * @@ -1106,6 +1110,7 @@ static int slhdsakey_mgf1_sha2(SlhDsaKey* key, const byte* seed, return ret; } +#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY /* SHA2 PRF_msg function. * * FIPS 205. Section 11.2. @@ -1167,6 +1172,7 @@ static int slhdsakey_prf_msg_sha2(SlhDsaKey* key, const byte* sk_prf, return ret; } +#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ /* SHA2 H_msg function. * @@ -1301,6 +1307,7 @@ static int slhdsakey_hash_f_shake(SlhDsaKey* key, const byte* pk_seed, #endif } +#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY static int slhdsakey_hash_h_shake(SlhDsaKey* key, const byte* pk_seed, const word32* adrs, const byte* node, byte n, byte* hash) { @@ -1312,6 +1319,7 @@ static int slhdsakey_hash_h_shake(SlhDsaKey* key, const byte* pk_seed, 2 * n, NULL, 0, hash, n); #endif } +#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ static int slhdsakey_hash_h_2_shake(SlhDsaKey* key, const byte* pk_seed, const word32* adrs, const byte* m1, const byte* m2, byte n, byte* hash) @@ -1320,6 +1328,7 @@ static int slhdsakey_hash_h_2_shake(SlhDsaKey* key, const byte* pk_seed, n, m2, n, hash, n); } +#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY static int slhdsakey_hash_prf_shake(SlhDsaKey* key, const byte* pk_seed, const byte* sk_seed, const word32* adrs, byte n, byte* hash) { @@ -1331,6 +1340,7 @@ static int slhdsakey_hash_prf_shake(SlhDsaKey* key, const byte* pk_seed, sk_seed, n, NULL, 0, hash, n); #endif } +#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ #define HASH_PRF(k, pk_seed, sk_seed, adrs, n, o) \ (SLHDSA_IS_SHA2((k)->params->param) ? \ @@ -1928,7 +1938,7 @@ static int slhdsakey_shake256_set_seed_ha_hash_x4(word64* state, return ret; } -#endif +#endif /* WOLFSSL_SLHDSA_VERIFY_ONLY */ /* Get the four SHAKE-256 n-byte hash results. * @@ -1963,7 +1973,7 @@ do { \ ((word8*)((state) + (o) - 2))[3] = (a) + 2; \ ((word8*)((state) + (o) - 1))[3] = (a) + 3; \ } while (0) -#endif +#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ /* Set the chain address indices into the SHAKE-256 x4 state. * @@ -2007,7 +2017,7 @@ do { \ c32toa((ti) + 2, (byte*)&((word32*)((state) + (o) - 2))[1]); \ c32toa((ti) + 3, (byte*)&((word32*)((state) + (o) - 1))[1]); \ } while (0) -#endif +#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ /* Set the tree indices into the SHAKE-256 x4 state. * @@ -2349,7 +2359,7 @@ static int slhdsakey_chain_x4_16(byte* sk, const byte* pk_seed, byte* addr, WC_FREE_VAR_EX(fixed, heap, DYNAMIC_TYPE_SLHDSA); return ret; } -#endif +#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ #if !defined(WOLFSSL_SLHDSA_PARAM_NO_192) /* Iterate the hash function 15 times with 4 hashes when n=24. @@ -3886,10 +3896,6 @@ static int slhdsakey_wots_pk_from_sig_x4(SlhDsaKey* key, const byte* sig, const byte* msg, const byte* pk_seed, word32* adrs, byte* pk_sig) { int ret = 0; - byte idx[4] = {0}; - int i; - byte ii; - sword8 j; HashAddress wotspk_adrs; byte n = key->params->n; byte len = key->params->len; @@ -3899,7 +3905,10 @@ static int slhdsakey_wots_pk_from_sig_x4(SlhDsaKey* key, const byte* sig, DYNAMIC_TYPE_SLHDSA, ret = MEMORY_E); #if !defined(WOLFSSL_SLHDSA_PARAM_NO_128) if ((ret == 0) && (n == WC_SLHDSA_N_128)) { - ii = 0; + int i; + sword8 j; + byte ii = 0; + byte idx[4] = {0}; for (j = 0; j <= SLHDSA_WM1; j++) { for (i = 0; i < len; i++) { if ((sword8)msg[i] == j) { @@ -3926,7 +3935,10 @@ static int slhdsakey_wots_pk_from_sig_x4(SlhDsaKey* key, const byte* sig, #endif #if !defined(WOLFSSL_SLHDSA_PARAM_NO_192) if ((ret == 0) && (n == 24)) { - ii = 0; + int i; + sword8 j; + byte ii = 0; + byte idx[4] = {0}; for (j = 0; j <= SLHDSA_WM1; j++) { for (i = 0; i < len; i++) { if ((sword8)msg[i] == j) { @@ -3953,7 +3965,10 @@ static int slhdsakey_wots_pk_from_sig_x4(SlhDsaKey* key, const byte* sig, #endif #if !defined(WOLFSSL_SLHDSA_PARAM_NO_256) if ((ret == 0) && (n == 32)) { - ii = 0; + int i; + sword8 j; + byte ii = 0; + byte idx[4] = {0}; for (j = 0; j <= SLHDSA_WM1; j++) { for (i = 0; i < len; i++) { if ((sword8)msg[i] == j) { @@ -3978,9 +3993,14 @@ static int slhdsakey_wots_pk_from_sig_x4(SlhDsaKey* key, const byte* sig, } else #endif - if (ret == 0) { - ret = NOT_COMPILED_IN; + { + (void)msg; + (void)key; + if (ret == 0) { + ret = NOT_COMPILED_IN; + } } + if (ret == 0) { HA_Copy(wotspk_adrs, adrs); HA_SetTypeAndClearNotKPA(wotspk_adrs, HA_WOTS_PK); @@ -4457,7 +4477,7 @@ static int slhdsakey_xmss_sign(SlhDsaKey* key, const byte* m, return ret; } -#endif +#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ /* Compute XMSS public key from XMSS signature. * @@ -4651,7 +4671,7 @@ static int slhdsakey_ht_sign(SlhDsaKey* key, const byte* pk_fors, return ret; } -#endif +#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ /* Verify hypertree signature. * @@ -5680,7 +5700,7 @@ static int slhdsakey_fors_sign(SlhDsaKey* key, const byte* md, return ret; } -#endif +#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ #if defined(USE_INTEL_SPEEDUP) && !defined(WOLFSSL_WC_SLHDSA_SMALL) /* F hash 4 simultaneously. @@ -7112,7 +7132,7 @@ int wc_SlhDsaKey_SignMsgWithRandom(SlhDsaKey* key, const byte* mprime, addRnd); } -#endif +#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ /* Verify SLH-DSA signature. * @@ -7857,7 +7877,7 @@ int wc_SlhDsaKey_SignHash(SlhDsaKey* key, const byte* ctx, byte ctxSz, return ret; } -#endif +#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ /* Verify SLH-DSA signature. * @@ -8044,7 +8064,7 @@ int wc_SlhDsaKey_ImportPrivate(SlhDsaKey* key, const byte* priv, word32 privLen) return ret; } -#endif +#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ /* Import public key from data. * @@ -8157,7 +8177,7 @@ int wc_SlhDsaKey_ExportPrivate(SlhDsaKey* key, byte* priv, word32* privLen) return ret; } -#endif +#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ /* Export the public key. * @@ -8215,7 +8235,7 @@ int wc_SlhDsaKey_PrivateSize(SlhDsaKey* key) return ret; } -#endif +#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ /* Return the size of the public key for the parameters. * @@ -8318,7 +8338,7 @@ int wc_SlhDsaKey_PrivateSizeFromParam(enum SlhDsaParam param) return ret; } -#endif +#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ /* Return the size of the public key for the parameters. * diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 914f9ab22b..57d224d92e 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -54233,9 +54233,7 @@ out: wc_test_ret_t slhdsa_test(void) { -#if !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) || defined(WOLFSSL_SLHDSA_PARAM_128S) - int ret; -#endif + int ret = 0; #ifdef WOLFSSL_SLHDSA_PARAM_128S WC_DECLARE_VAR(key_vfy, SlhDsaKey, 1, HEAP_HINT); #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY @@ -55954,9 +55952,7 @@ wc_test_ret_t slhdsa_test(void) } } #endif -#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ -#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY #ifdef WOLFSSL_SLHDSA_PARAM_128S ret = slhdsa_test_param(SLHDSA_SHAKE128S); if (ret != 0) { @@ -56041,10 +56037,17 @@ wc_test_ret_t slhdsa_test(void) goto out; } #endif -#endif + +#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ + +#if defined(WOLFSSL_SLHDSA_VERIFY_ONLY) || \ + defined(WOLFSSL_SLHDSA_PARAM_128S) out: +#endif + +#ifdef WOLFSSL_SLHDSA_PARAM_128S #ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC if (key_vfy) #endif @@ -56052,6 +56055,7 @@ out: wc_SlhDsaKey_Free(key_vfy); } WC_FREE_VAR_EX(key_vfy, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); +#endif #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY #ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC if (key) diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 1dfc05a909..b56fc5e190 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -4042,6 +4042,14 @@ extern void uITRON4_free(void *p) ; #undef WOLFSSL_GENERAL_ALIGNMENT #define WOLFSSL_GENERAL_ALIGNMENT SIZEOF_LONG #endif + + /* SLH-DSA signature generation is too computationally intensive to be + * appropriate in typical kernel deployments. + */ + #if !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) && \ + !defined(WOLFSSL_SLHDSA_NO_VERIFY_ONLY) + #define WOLFSSL_SLHDSA_VERIFY_ONLY + #endif #endif /* WOLFSSL_KERNEL_MODE */ #if defined(WC_SYM_RELOC_TABLES) && defined(HAVE_FIPS) && \ diff --git a/wolfssl/wolfcrypt/wc_slhdsa.h b/wolfssl/wolfcrypt/wc_slhdsa.h index 7153143d27..eb34c73bd8 100644 --- a/wolfssl/wolfcrypt/wc_slhdsa.h +++ b/wolfssl/wolfcrypt/wc_slhdsa.h @@ -39,6 +39,16 @@ #ifdef WOLFSSL_HAVE_SLHDSA /* ======== SHAKE parameter guards ======== */ +#ifdef WOLFSSL_SLHDSA_NO_SHAKE + + #define WOLFSSL_SLHDSA_PARAM_NO_128S + #define WOLFSSL_SLHDSA_PARAM_NO_128F + #define WOLFSSL_SLHDSA_PARAM_NO_192S + #define WOLFSSL_SLHDSA_PARAM_NO_192F + #define WOLFSSL_SLHDSA_PARAM_NO_256S + #define WOLFSSL_SLHDSA_PARAM_NO_256F + +#else /* !WOLFSSL_SLHDSA_NO_SHAKE */ /* When a bits/opt is defined then ensure 'NO' defines are off. */ #ifdef WOLFSSL_SLHDSA_PARAM_128S @@ -72,6 +82,8 @@ #undef WOLFSSL_SLHDSA_PARAM_NO_FAST #endif +#endif /* !WOLFSSL_SLHDSA_NO_SHAKE */ + /* When 'NO' defines are on then define no parameter set. */ #if defined(WOLFSSL_SLHDSA_PARAM_NO_128S) && \ defined(WOLFSSL_SLHDSA_PARAM_NO_128F) @@ -167,6 +179,12 @@ #define WOLFSSL_SLHDSA_PARAM_NO_256 #endif +#if defined(WOLFSSL_SLHDSA_PARAM_NO_128) && \ + defined(WOLFSSL_SLHDSA_PARAM_NO_192) && \ + defined(WOLFSSL_SLHDSA_PARAM_NO_256) + #define WOLFSSL_SLHDSA_NO_SHAKE +#endif + /* ======== SHA2 parameter guards ======== */ #ifdef WOLFSSL_SLHDSA_SHA2 @@ -298,7 +316,11 @@ #define WOLFSSL_SLHDSA_PARAM_NO_SHA2_256 #endif -#endif /* WOLFSSL_SLHDSA_SHA2 */ +#else /* !WOLFSSL_SLHDSA_SHA2 */ + + #define WOLFSSL_SLHDSA_NO_SHA2 + +#endif /* !WOLFSSL_SLHDSA_SHA2 */ /* ======== Security parameter (n) per FIPS 205 Table 2 ======== */ @@ -474,26 +496,50 @@ !defined(WOLFSSL_SLHDSA_PARAM_NO_FAST) /* Maximum signature length. */ #define WC_SLHDSA_MAX_SIG_LEN WC_SLHDSA_SHAKE256F_SIG_LEN +#elif !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST) + /* Maximum signature length. */ + #define WC_SLHDSA_MAX_SIG_LEN WC_SLHDSA_SHA2_256F_SIG_LEN #elif !defined(WOLFSSL_SLHDSA_PARAM_NO_192) && \ !defined(WOLFSSL_SLHDSA_PARAM_NO_FAST) /* Maximum signature length. */ #define WC_SLHDSA_MAX_SIG_LEN WC_SLHDSA_SHAKE192F_SIG_LEN +#elif !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST) + /* Maximum signature length. */ + #define WC_SLHDSA_MAX_SIG_LEN WC_SLHDSA_SHA2_192F_SIG_LEN #elif !defined(WOLFSSL_SLHDSA_PARAM_NO_256) && \ !defined(WOLFSSL_SLHDSA_PARAM_NO_SMALL) /* Maximum signature length. */ #define WC_SLHDSA_MAX_SIG_LEN WC_SLHDSA_SHAKE256S_SIG_LEN +#elif !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL) + /* Maximum signature length. */ + #define WC_SLHDSA_MAX_SIG_LEN WC_SLHDSA_SHA2_256S_SIG_LEN #elif !defined(WOLFSSL_SLHDSA_PARAM_NO_128) && \ !defined(WOLFSSL_SLHDSA_PARAM_NO_FAST) /* Maximum signature length. */ #define WC_SLHDSA_MAX_SIG_LEN WC_SLHDSA_SHAKE128F_SIG_LEN +#elif !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_FAST) + /* Maximum signature length. */ + #define WC_SLHDSA_MAX_SIG_LEN WC_SLHDSA_SHA2_128F_SIG_LEN #elif !defined(WOLFSSL_SLHDSA_PARAM_NO_192) && \ !defined(WOLFSSL_SLHDSA_PARAM_NO_SMALL) /* Maximum signature length. */ #define WC_SLHDSA_MAX_SIG_LEN WC_SLHDSA_SHAKE192S_SIG_LEN +#elif !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL) + /* Maximum signature length. */ + #define WC_SLHDSA_MAX_SIG_LEN WC_SLHDSA_SHA2_192S_SIG_LEN #elif !defined(WOLFSSL_SLHDSA_PARAM_NO_128) && \ !defined(WOLFSSL_SLHDSA_PARAM_NO_SMALL) /* Maximum signature length. */ #define WC_SLHDSA_MAX_SIG_LEN WC_SLHDSA_SHAKE128S_SIG_LEN +#elif !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_SMALL) + /* Maximum signature length. */ + #define WC_SLHDSA_MAX_SIG_LEN WC_SLHDSA_SHA2_128S_SIG_LEN #else #error "No parameters defined" #endif @@ -520,7 +566,7 @@ enum SlhDsaParam { #ifdef WOLFSSL_SLHDSA_SHA2 #define SLHDSA_IS_SHA2(p) ((p) >= SLHDSA_SHA2_128S) #else - #define SLHDSA_IS_SHA2(p) (0) + #define SLHDSA_IS_SHA2(p) 0 #endif /* Pre-defined parameter values. */ From 1d21858be17d215de56ff4770432b2cb653a6577 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 28 Apr 2026 18:12:25 -0500 Subject: [PATCH 157/167] linuxkm/module_hooks.c: in wolfssl_init() DEBUG_LINUXKM_PIE_SUPPORT hash_span() loops, reset cur_reloc_index before each loop (Fenrir review). --- linuxkm/module_hooks.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/linuxkm/module_hooks.c b/linuxkm/module_hooks.c index cb41051a03..fa0067acc2 100644 --- a/linuxkm/module_hooks.c +++ b/linuxkm/module_hooks.c @@ -712,7 +712,7 @@ static int wolfssl_init(void) unsigned int text_hash = hash_span((const u8 *)__wc_text_start, (const u8 *)__wc_text_end, 1); unsigned int rodata_hash = hash_span((const u8 *)__wc_rodata_start, (const u8 *)__wc_rodata_end, 1); u8 *canon_buf = malloc(WOLFSSL_SEGMENT_CANONICALIZER_BUFSIZ); - ssize_t cur_reloc_index = -1; + ssize_t cur_reloc_index; const u8 *text_p = (const u8 *)__wc_text_start; const u8 *rodata_p = (const u8 *)__wc_rodata_start; unsigned int stabilized_text_hash = 1; @@ -726,6 +726,7 @@ static int wolfssl_init(void) reloc_counts.text = reloc_counts.rodata = reloc_counts.rwdata = reloc_counts.bss = reloc_counts.other = 0; + cur_reloc_index = -1; while (text_p < (const u8 *)__wc_text_end) { size_t text_in_out_len = min(WOLFSSL_SEGMENT_CANONICALIZER_BUFSIZ, (size_t)((const u8 *)__wc_text_end - text_p)); @@ -748,6 +749,7 @@ static int wolfssl_init(void) } /* note verifyCore is hashed along with the rest of .rodata_wolfcrypt. */ + cur_reloc_index = -1; while (rodata_p < (const u8 *)__wc_rodata_end) { size_t rodata_in_out_len = min(WOLFSSL_SEGMENT_CANONICALIZER_BUFSIZ, (size_t)((const u8 *)__wc_rodata_end - rodata_p)); From 4f3f40e1fb7f75e55f90632387d7f3c02f70479e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Wed, 29 Apr 2026 09:21:14 +0200 Subject: [PATCH 158/167] Increase pq-all test timeout to 10 minutes Increase the timeout for PQC CI tests from 6 to 10 minutes. The new SLH-DSA tests take more time than the previous tests due to the slow signing. With the old timeout, some tests sometimes hit the timeout before finishing successfully. --- .github/workflows/pq-all.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pq-all.yml b/.github/workflows/pq-all.yml index 237a1fa5ee..c6d4704e99 100644 --- a/.github/workflows/pq-all.yml +++ b/.github/workflows/pq-all.yml @@ -44,7 +44,7 @@ jobs: if: github.repository_owner == 'wolfssl' runs-on: ubuntu-24.04 # This should be a safe limit for the tests to run. - timeout-minutes: 6 + timeout-minutes: 10 steps: - uses: actions/checkout@v4 name: Checkout wolfSSL From 46b47cb8ece9f0290196b97680ef649de2c18869 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Wed, 29 Apr 2026 11:35:40 +0200 Subject: [PATCH 159/167] Fix race conditions in hostap CI tests --- .github/workflows/hostap-vm.yml | 55 ++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/.github/workflows/hostap-vm.yml b/.github/workflows/hostap-vm.yml index 44a9f3328e..1e609028c9 100644 --- a/.github/workflows/hostap-vm.yml +++ b/.github/workflows/hostap-vm.yml @@ -76,12 +76,21 @@ jobs: with: path: hostap key: hostap-repo - lookup-only: true - name: Checkout hostap if: steps.cache.outputs.cache-hit != 'true' run: git clone https://w1.fi/hostap.git hostap + - name: tar hostap + run: tar -zcf hostap.tgz hostap + + - name: Upload hostap repo + uses: actions/upload-artifact@v4 + with: + name: hostap-repo + path: hostap.tgz + retention-days: 1 + build_uml_linux: name: Build UML (UserMode Linux) if: github.repository_owner == 'wolfssl' @@ -96,15 +105,16 @@ jobs: with: path: linux/linux key: hostap-linux-${{ env.LINUX_REF }} - lookup-only: true - - name: Checking if we have hostap in cache + - name: Download hostap repo if: steps.cache.outputs.cache-hit != 'true' - uses: actions/cache/restore@v4 + uses: actions/download-artifact@v4 with: - path: hostap - key: hostap-repo - fail-on-cache-miss: true + name: hostap-repo + + - name: untar hostap + if: steps.cache.outputs.cache-hit != 'true' + run: tar -xf hostap.tgz - name: Checkout linux if: steps.cache.outputs.cache-hit != 'true' @@ -122,6 +132,13 @@ jobs: cd linux yes "" | ARCH=um make -j $(nproc) + - name: Upload kernel binary + uses: actions/upload-artifact@v4 + with: + name: uml-linux-kernel + path: linux/linux + retention-days: 1 + hostap_test: strategy: fail-fast: false @@ -170,13 +187,14 @@ jobs: timeout-minutes: 45 needs: [build_wolfssl, build_uml_linux, checkout_hostap] steps: - - name: Checking if we have kernel in cache - uses: actions/cache/restore@v4 - id: cache + - name: Download kernel binary + uses: actions/download-artifact@v4 with: - path: linux/linux - key: hostap-linux-${{ env.LINUX_REF }} - fail-on-cache-miss: true + name: uml-linux-kernel + path: linux + + - name: Restore kernel binary executable bit + run: chmod +x linux/linux # No way to view the full strategy in the browser (really weird) - name: Print strategy @@ -215,12 +233,13 @@ jobs: - name: Install pip dependencies run: sudo pip install pycryptodome - - name: Checking if we have hostap in cache - uses: actions/cache/restore@v4 + - name: Download hostap repo + uses: actions/download-artifact@v4 with: - path: hostap - key: hostap-repo - fail-on-cache-miss: true + name: hostap-repo + + - name: untar hostap + run: tar -xf hostap.tgz - name: Checkout correct ref working-directory: hostap From 7f7d28372b1653db75211cb6da4e46b45d390043 Mon Sep 17 00:00:00 2001 From: Lealem Amedie Date: Wed, 29 Apr 2026 09:53:03 -0600 Subject: [PATCH 160/167] Configure.ac cleanup for demented AI logic --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 1972989f5b..186c23c457 100644 --- a/configure.ac +++ b/configure.ac @@ -1653,7 +1653,7 @@ fi AC_ARG_ENABLE([tailscale], [AS_HELP_STRING([--enable-tailscale],[Enable Tailscale build dependencies (default: disabled)])], [ ENABLED_TAILSCALE=$enableval ], - [ ENABLED_TAILSCALE=${enable_tailscale:-no} ] + [ ENABLED_TAILSCALE=no ] ) if test "$ENABLED_TAILSCALE" = "yes" then From e7297493d4a0dcc2aeffc63c9e04640d5c54fa27 Mon Sep 17 00:00:00 2001 From: Lealem Amedie Date: Wed, 29 Apr 2026 11:09:33 -0600 Subject: [PATCH 161/167] --enable-compkey allowed with v5 --- configure.ac | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/configure.ac b/configure.ac index 186c23c457..d324fb30d3 100644 --- a/configure.ac +++ b/configure.ac @@ -1659,7 +1659,6 @@ if test "$ENABLED_TAILSCALE" = "yes" then enable_wolfguard=yes test "x$enable_sp" = "x" && enable_sp="yes,256" - enable_compkey=yes enable_opensslall=yes enable_alpn=yes enable_sni=yes @@ -1687,9 +1686,9 @@ then test "$enable_aesgcm" = "" && enable_aesgcm=yes test "$enable_base64encode" = "" && enable_base64encode=yes test "$enable_base16" = "" && enable_base16=yes + test "$enable_compkey" = "" && enable_compkey=yes if test "$ENABLED_FIPS" = "no" || test "$HAVE_FIPS_VERSION" -ge 6 then - test "$enable_compkey" = "" && enable_compkey=yes test "$enable_aesgcm_stream" = "" && enable_aesgcm_stream=yes fi fi @@ -4938,8 +4937,7 @@ AC_ARG_ENABLE([compkey], [ ENABLED_COMPKEY=no ] ) -if (test "$ENABLED_WPAS" = "yes" || test "$ENABLED_OPENSSLALL" = "yes") && - (test "$HAVE_FIPS_VERSION" != "5") +if (test "$ENABLED_WPAS" = "yes" || test "$ENABLED_OPENSSLALL" = "yes") then ENABLED_COMPKEY=yes fi @@ -6836,11 +6834,6 @@ AS_CASE([$FIPS_VERSION], (test "$FIPS_VERSION" != "v5-dev" || test "$enable_keygen" != "no")], [ENABLED_KEYGEN="yes"; AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_KEY_GEN"]) - AS_IF([test "$ENABLED_COMPKEY" = "yes" && - ! (test "$FIPS_VERSION" = "v5-dev" && test "$enable_compkey" = "yes")], - [AC_MSG_WARN([Forcing off compkey for FIPS ${FIPS_VERSION}.]) - ENABLED_COMPKEY="no"]) - AS_IF([test "$ENABLED_SHA224" != "yes" && (test "$FIPS_VERSION" != "v5-dev" || test "$enable_sha224" != "no")], [ENABLED_SHA224="yes"; AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SHA224"]) From e1fefcca4f13f450b4c3ff22fd7c70e5de6f9a2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Thu, 23 Apr 2026 12:35:23 +0200 Subject: [PATCH 162/167] Remove deprecated liblms and libxmss --- CMakeLists.txt | 2 - Docker/Dockerfile | 4 - IDE/INTIME-RTOS/Makefile | 4 +- IDE/INTIME-RTOS/wolfssl-lib.vcxproj | 2 - INSTALL | 13 +- configure.ac | 151 +-- examples/configs/user_settings_pq.h | 2 - .../configs/user_settings_wolfboot_keytools.h | 2 - linuxkm/module_exports.c.template | 10 - src/include.am | 8 - tests/api.c | 12 +- wolfcrypt/benchmark/benchmark.c | 54 +- wolfcrypt/src/ext_lms.c | 1111 ----------------- wolfcrypt/src/ext_xmss.c | 1041 --------------- wolfcrypt/src/wc_lms.c | 6 +- wolfcrypt/src/wc_lms_impl.c | 4 +- wolfcrypt/src/wc_xmss.c | 2 +- wolfcrypt/test/test.c | 32 +- wolfcrypt/test/test.h | 3 +- wolfssl/wolfcrypt/ext_lms.h | 62 - wolfssl/wolfcrypt/ext_xmss.h | 53 - wolfssl/wolfcrypt/include.am | 4 - wolfssl/wolfcrypt/lms.h | 266 ---- wolfssl/wolfcrypt/settings.h | 8 +- wolfssl/wolfcrypt/wc_lms.h | 247 +++- wolfssl/wolfcrypt/wc_xmss.h | 171 ++- wolfssl/wolfcrypt/xmss.h | 203 --- 27 files changed, 445 insertions(+), 3032 deletions(-) delete mode 100644 wolfcrypt/src/ext_lms.c delete mode 100644 wolfcrypt/src/ext_xmss.c delete mode 100644 wolfssl/wolfcrypt/ext_lms.h delete mode 100644 wolfssl/wolfcrypt/ext_xmss.h delete mode 100644 wolfssl/wolfcrypt/lms.h delete mode 100644 wolfssl/wolfcrypt/xmss.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 317aa9c8e8..dd0b7d4c0a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -700,10 +700,8 @@ add_option(WOLFSSL_LMSSHA256192 if (WOLFSSL_LMS) list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_HAVE_LMS") - list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_WC_LMS") set_wolfssl_definitions("WOLFSSL_HAVE_LMS" RESULT) - set_wolfssl_definitions("WOLFSSL_WC_LMS" RESULT) if (WOLFSSL_LMSSHA256192) list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_LMS_SHA256_192") diff --git a/Docker/Dockerfile b/Docker/Dockerfile index 9ae6f1ec52..d5b4832110 100644 --- a/Docker/Dockerfile +++ b/Docker/Dockerfile @@ -34,10 +34,6 @@ RUN git clone --single-branch https://github.com/open-quantum-safe/liboqs.git && RUN mkdir /opt/sources -# install liblms -RUN cd /opt/sources && git clone --single-branch https://github.com/cisco/hash-sigs.git && cd hash-sigs && git checkout b0631b8891295bf2929e68761205337b7c031726 \ - && sed -i 's/USE_OPENSSL 1/USE_OPENSSL 0/g' sha256.h && make -j4 hss_lib_thread.a - # Install pkixssh to /opt/pkixssh for X509 interop testing with wolfSSH RUN mkdir /var/empty RUN cd /opt/sources && wget -q -O- https://roumenpetrov.info/secsh/src/pkixssh-15.1.tar.gz | tar xzf - && cd pkixssh-15.1 && ./configure --prefix=/opt/pkixssh/ --exec-prefix=/opt/pkixssh/ && make install diff --git a/IDE/INTIME-RTOS/Makefile b/IDE/INTIME-RTOS/Makefile index 3755c29205..3ec9ae7199 100644 --- a/IDE/INTIME-RTOS/Makefile +++ b/IDE/INTIME-RTOS/Makefile @@ -287,7 +287,6 @@ INCL_TARGS := wolfssl/callbacks.h \ wolfssl/wolfcrypt/integer.h \ wolfssl/wolfcrypt/kdf.h \ wolfssl/wolfcrypt/kyber.h \ - wolfssl/wolfcrypt/lms.h \ wolfssl/wolfcrypt/logging.h \ wolfssl/wolfcrypt/md2.h \ wolfssl/wolfcrypt/md4.h \ @@ -327,11 +326,12 @@ INCL_TARGS := wolfssl/callbacks.h \ wolfssl/wolfcrypt/visibility.h \ wolfssl/wolfcrypt/wc_encrypt.h \ wolfssl/wolfcrypt/wc_kyber.h \ + wolfssl/wolfcrypt/wc_lms.h \ wolfssl/wolfcrypt/wc_pkcs11.h \ wolfssl/wolfcrypt/wc_port.h \ + wolfssl/wolfcrypt/wc_xmss.h \ wolfssl/wolfcrypt/wolfevent.h \ wolfssl/wolfcrypt/wolfmath.h \ - wolfssl/wolfcrypt/xmss.h \ wolfssl/wolfcrypt/port/nrf51.h \ wolfssl/wolfcrypt/port/af_alg/afalg_hash.h \ wolfssl/wolfcrypt/port/af_alg/wc_afalg.h \ diff --git a/IDE/INTIME-RTOS/wolfssl-lib.vcxproj b/IDE/INTIME-RTOS/wolfssl-lib.vcxproj index 3c5bd1d8d5..5b4226af94 100644 --- a/IDE/INTIME-RTOS/wolfssl-lib.vcxproj +++ b/IDE/INTIME-RTOS/wolfssl-lib.vcxproj @@ -87,8 +87,6 @@ true - - diff --git a/INSTALL b/INSTALL index dc6e2908c1..3e362908b9 100644 --- a/INSTALL +++ b/INSTALL @@ -296,11 +296,7 @@ The wolfssl port in vcpkg is kept up to date by wolfSSL. We also have vcpkg ports for wolftpm, wolfmqtt and curl. -17. Building with hash-sigs lib for LMS/HSS support [EXPERIMENTAL] - - Deprecated. wolfSSL now has its own LMS/HSS implementation in wolfCrypt. - -18. Building for Debian, Ubuntu, Linux Mint, and derivatives +17. Building for Debian, Ubuntu, Linux Mint, and derivatives To generate a .deb package, configure wolfSSL with the desired configuration. Then run `make deb` to generate a Debian package @@ -309,7 +305,7 @@ We also have vcpkg ports for wolftpm, wolfmqtt and curl. resulting packages are placed in the root directory of the project. -19. Building for RHEL, Fedora, CentOS, SUSE, and openSUSE +18. Building for RHEL, Fedora, CentOS, SUSE, and openSUSE To generate a .rpm package, configure wolfSSL with the desired configuration. Then run `make rpm` to generate a .rpm package @@ -317,8 +313,3 @@ We also have vcpkg ports for wolftpm, wolfmqtt and curl. Docker container, use `make rpm-docker`. In both cases the resulting packages are placed in the root directory of the project. - -20. Building with xmss-reference lib for XMSS/XMSS^MT support [EXPERIMENTAL] - - Deprecated. wolfSSL now has its own XMMS/XMSS^MT implementation in - wolfCrypt. diff --git a/configure.ac b/configure.ac index 21ba1304a7..f8e9cc8129 100644 --- a/configure.ac +++ b/configure.ac @@ -1839,7 +1839,6 @@ do done # XMSS -ENABLED_WC_XMSS=no AC_ARG_ENABLE([xmss], [AS_HELP_STRING([--enable-xmss],[Enable stateful XMSS/XMSS^MT signatures (default: disabled)])], [ ENABLED_XMSS=$enableval ], @@ -1865,60 +1864,7 @@ do esac done -# libxmss -# Get the path to xmss-reference. -ENABLED_LIBXMSS="no" -trylibxmssdir="" -AC_ARG_WITH([libxmss], - [AS_HELP_STRING([--with-libxmss=PATH],[PATH to xmss-reference root dir. (requires --enable-experimental)!])], - [ - AS_IF([ test "$ENABLED_EXPERIMENTAL" != "yes" ],[ AC_MSG_ERROR([libxmss requires --enable-experimental.]) ]) - AC_MSG_CHECKING([for libxmss]) - - trylibxmssdir=$withval - - if test -e $trylibxmssdir; then - libxmss_linked=yes - else - AC_MSG_ERROR([libxmss isn't found. - If it's already installed, specify its path using --with-libxmss=/dir/]) - fi - if test "$XMSS_VERIFY_ONLY" = "yes"; then - if test -e $trylibxmssdir/xmss_verify_lib.a; then - CPPFLAGS="$AM_CPPFLAGS -DHAVE_LIBXMSS -I$trylibxmssdir" - LIB_STATIC_ADD="$LIB_STATIC_ADD $trylibxmssdir/xmss_verify_lib.a" - enable_shared=no - enable_static=yes - libxmss_linked=yes - else - AC_MSG_ERROR([xmss_verify_lib.a isn't found. - If it's already installed, specify its path using --with-libxmss=/dir/]) - fi - elif test -e $trylibxmssdir/xmss_lib.a; then - CPPFLAGS="$AM_CPPFLAGS -DHAVE_LIBXMSS -I$trylibxmssdir" - LIB_STATIC_ADD="$LIB_STATIC_ADD $trylibxmssdir/xmss_lib.a" - enable_shared=no - enable_static=yes - libxmss_linked=yes - else - AC_MSG_ERROR([libxmss isn't found. - If it's already installed, specify its path using --with-libxmss=/dir/]) - fi - - XMSS_ROOT=$trylibxmssdir - - AC_MSG_RESULT([yes]) - AM_CPPFLAGS="$CPPFLAGS" - - AM_CFLAGS="$AM_CFLAGS -DHAVE_LIBXMSS -I$trylibxmssdir" - ENABLED_LIBXMSS="yes" - AC_SUBST([XMSS_ROOT]) - ], - [XMSS_ROOT=""] -) - # LMS -ENABLED_WC_LMS=no AC_ARG_ENABLE([lms], [AS_HELP_STRING([--enable-lms],[Enable stateful LMS/HSS signatures (default: disabled)])], [ ENABLED_LMS=$enableval ], @@ -1953,74 +1899,6 @@ do esac done -# liblms -# Get the path to the hash-sigs LMS HSS lib. -ENABLED_LIBLMS="no" -tryliblmsdir="" -AC_ARG_WITH([liblms], - [AS_HELP_STRING([--with-liblms=PATH],[PATH to hash-sigs LMS/HSS install (default /usr/local) (requires --enable-experimental)!])], - [ - AS_IF([ test "$ENABLED_EXPERIMENTAL" != "yes" ],[ AC_MSG_ERROR([liblms requires --enable-experimental.]) ]) - AC_MSG_CHECKING([for liblms]) - - AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[ param_set_t lm_type; param_set_t lm_ots_type; hss_get_public_key_len(4, &lm_type, &lm_ots_type); ]])], [ liblms_linked=yes ],[ liblms_linked=no ]) - - if test "x$liblms_linked" = "xno" ; then - if test "x$withval" != "xno" ; then - tryliblmsdir=$withval - fi - if test "x$withval" = "xyes" ; then - tryliblmsdir="/usr/local" - fi - - # 1. If verify only build, use hss_verify.a - # 2. If normal build, by default use single-threaded hss_lib.a - # 3. If 2 not found, then use the multi-threaded hss_lib_thread.a - if test "$LMS_VERIFY_ONLY" = "yes"; then - if test -e $tryliblmsdir/hss_verify.a; then - CPPFLAGS="$AM_CPPFLAGS -DHAVE_LIBLMS -I$tryliblmsdir" - LIB_STATIC_ADD="$LIB_STATIC_ADD $tryliblmsdir/hss_verify.a" - enable_shared=no - enable_static=yes - liblms_linked=yes - else - AC_MSG_ERROR([hss_verify.a isn't found. - If it's already installed, specify its path using --with-liblms=/dir/]) - fi - elif test -e $tryliblmsdir/hss_lib.a; then - CPPFLAGS="$AM_CPPFLAGS -DHAVE_LIBLMS -I$tryliblmsdir" - LIB_STATIC_ADD="$LIB_STATIC_ADD $tryliblmsdir/hss_lib.a" - enable_shared=no - enable_static=yes - liblms_linked=yes - elif test -e $tryliblmsdir/hss_lib_thread.a; then - CPPFLAGS="$AM_CPPFLAGS -DHAVE_LIBLMS -I$tryliblmsdir" - LIB_STATIC_ADD="$LIB_STATIC_ADD $tryliblmsdir/hss_lib_thread.a" - enable_shared=no - enable_static=yes - liblms_linked=yes - else - AC_MSG_ERROR([liblms isn't found. - If it's already installed, specify its path using --with-liblms=/dir/]) - fi - - if test "x$liblms_linked" = "xno" ; then - AC_MSG_ERROR([liblms isn't found. - If it's already installed, specify its path using --with-liblms=/dir/]) - fi - - AC_MSG_RESULT([yes]) - AM_CPPFLAGS="$CPPFLAGS" - AM_LDFLAGS="$LDFLAGS" - else - AC_MSG_RESULT([yes]) - fi - - AM_CFLAGS="$AM_CFLAGS -DHAVE_LIBLMS" - ENABLED_LIBLMS="yes" - ] -) - # SLH-DSA ENABLED_SLHDSA=yes AC_ARG_ENABLE([slhdsa], @@ -7539,28 +7417,12 @@ fi if test "$ENABLED_XMSS" != "no" then AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_XMSS" - - # Use hash-sigs XMSS lib if enabled. - if test "$ENABLED_LIBXMSS" = "yes"; then - ENABLED_WC_XMSS=no - else - ENABLED_WC_XMSS=yes - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_XMSS" - fi fi # LMS CFLAG processing (after FIPS section for sandwich pattern) if test "$ENABLED_LMS" != "no" then AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_LMS" - - # Use hash-sigs LMS lib if enabled. - if test "$ENABLED_LIBLMS" = "yes"; then - ENABLED_WC_LMS=no - else - ENABLED_WC_LMS=yes - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_LMS" - fi fi # SLH-DSA CFLAG processing (after FIPS section for sandwich pattern) @@ -12186,8 +12048,8 @@ AM_CONDITIONAL([BUILD_FE448], [test "x$ENABLED_FE448" = "xyes" || test "x$ENABLE AM_CONDITIONAL([BUILD_GE448], [test "x$ENABLED_GE448" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_CURVE448],[test "x$ENABLED_CURVE448" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_CURVE448_SMALL],[test "x$ENABLED_CURVE448_SMALL" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) -AM_CONDITIONAL([BUILD_WC_LMS],[test "x$ENABLED_WC_LMS" != "xno" || test "x$ENABLED_USERSETTINGS" = "xyes"]) -AM_CONDITIONAL([BUILD_WC_XMSS],[test "x$ENABLED_WC_XMSS" != "xno" || test "x$ENABLED_USERSETTINGS" = "xyes"]) +AM_CONDITIONAL([BUILD_WC_LMS],[test "x$ENABLED_LMS" != "xno" || test "x$ENABLED_USERSETTINGS" = "xyes"]) +AM_CONDITIONAL([BUILD_WC_XMSS],[test "x$ENABLED_XMSS" != "xno" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_WC_SLHDSA],[test "x$ENABLED_SLHDSA" != "xno" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_WC_MLKEM],[test "x$ENABLED_WC_MLKEM" != "xno" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_DILITHIUM],[test "x$ENABLED_DILITHIUM" != "xno" || test "x$ENABLED_USERSETTINGS" = "xyes"]) @@ -12238,8 +12100,6 @@ AM_CONDITIONAL([BUILD_OCSP_STAPLING_MULTI],[test "x$ENABLED_CERTIFICATE_STATUS_R AM_CONDITIONAL([BUILD_OCSP_STAPLING_V2],[test "x$ENABLED_CERTIFICATE_STATUS_REQUEST_V2" = "xyes"]) AM_CONDITIONAL([BUILD_CRL],[test "x$ENABLED_CRL" != "xno" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_CRL_MONITOR],[test "x$ENABLED_CRL_MONITOR" = "xyes"]) -AM_CONDITIONAL([BUILD_LIBLMS],[test "x$ENABLED_LIBLMS" = "xyes"]) -AM_CONDITIONAL([BUILD_LIBXMSS],[test "x$ENABLED_LIBXMSS" = "xyes"]) AM_CONDITIONAL([BUILD_LIBOQS],[test "x$ENABLED_LIBOQS" = "xyes"]) AM_CONDITIONAL([BUILD_WNR],[test "x$ENABLED_WNR" = "xyes"]) AM_CONDITIONAL([BUILD_SRP],[test "x$ENABLED_SRP" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) @@ -12741,12 +12601,7 @@ echo " * CURVE448: $ENABLED_CURVE448" echo " * ED448: $ENABLED_ED448" echo " * ED448 streaming: $ENABLED_ED448_STREAM" echo " * LMS: $ENABLED_LMS" -echo " * LMS wolfSSL impl: $ENABLED_WC_LMS" echo " * XMSS: $ENABLED_XMSS" -echo " * XMSS wolfSSL impl: $ENABLED_WC_XMSS" -if test "$ENABLED_LIBXMSS" = "yes"; then -echo " * XMSS_ROOT: $XMSS_ROOT" -fi echo " * SLH-DSA $ENABLED_SLHDSA" echo " * MLKEM: $ENABLED_MLKEM" echo " * MLKEM wolfSSL impl: $ENABLED_WC_MLKEM" @@ -12807,8 +12662,6 @@ echo " * Persistent session cache: $ENABLED_SAVESESSION" echo " * Persistent cert cache: $ENABLED_SAVECERT" echo " * Atomic User Record Layer: $ENABLED_ATOMICUSER" echo " * Public Key Callbacks: $ENABLED_PKCALLBACKS" -echo " * libxmss: $ENABLED_LIBXMSS" -echo " * liblms: $ENABLED_LIBLMS" echo " * liboqs: $ENABLED_LIBOQS" echo " * Whitewood netRandom: $ENABLED_WNR" echo " * Server Name Indication: $ENABLED_SNI" diff --git a/examples/configs/user_settings_pq.h b/examples/configs/user_settings_pq.h index b207cbd95b..752f34e861 100644 --- a/examples/configs/user_settings_pq.h +++ b/examples/configs/user_settings_pq.h @@ -105,7 +105,6 @@ extern "C" { /* ------------------------------------------------- */ #if 0 /* LMS signatures */ #define WOLFSSL_HAVE_LMS - #define WOLFSSL_WC_LMS #ifndef LMS_LEVELS #define LMS_LEVELS 2 #endif @@ -122,7 +121,6 @@ extern "C" { /* ------------------------------------------------- */ #if 0 /* XMSS signatures */ #define WOLFSSL_HAVE_XMSS - #define WOLFSSL_WC_XMSS #ifndef WOLFSSL_XMSS_MAX_HEIGHT #define WOLFSSL_XMSS_MAX_HEIGHT 20 #endif diff --git a/examples/configs/user_settings_wolfboot_keytools.h b/examples/configs/user_settings_wolfboot_keytools.h index 8c44d3f0f7..be97f5d3c5 100644 --- a/examples/configs/user_settings_wolfboot_keytools.h +++ b/examples/configs/user_settings_wolfboot_keytools.h @@ -131,7 +131,6 @@ extern "C" { #if 1 /* LMS */ #define WOLFSSL_HAVE_LMS - #define WOLFSSL_WC_LMS #ifndef LMS_LEVELS #define LMS_LEVELS 1 #endif @@ -145,7 +144,6 @@ extern "C" { #if 1 /* XMSS */ #define WOLFSSL_HAVE_XMSS - #define WOLFSSL_WC_XMSS #ifndef WOLFSSL_XMSS_MAX_HEIGHT #define WOLFSSL_XMSS_MAX_HEIGHT 32 #endif diff --git a/linuxkm/module_exports.c.template b/linuxkm/module_exports.c.template index ad2f07cac9..3b9fa73cb7 100644 --- a/linuxkm/module_exports.c.template +++ b/linuxkm/module_exports.c.template @@ -158,21 +158,11 @@ #endif #endif #if defined(WOLFSSL_HAVE_XMSS) - #include -#ifdef HAVE_LIBXMSS - #include -#else #include #endif -#endif #if defined(WOLFSSL_HAVE_LMS) - #include -#ifdef HAVE_LIBLMS - #include -#else #include #endif -#endif #ifdef HAVE_DILITHIUM #include #endif diff --git a/src/include.am b/src/include.am index 0ac8d62602..118aa7e54a 100644 --- a/src/include.am +++ b/src/include.am @@ -1984,14 +1984,6 @@ src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/ext_mlkem.c src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/liboqs/liboqs.c endif -if BUILD_LIBLMS -src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/ext_lms.c -endif - -if BUILD_LIBXMSS -src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/ext_xmss.c -endif - if BUILD_LIBZ src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/compress.c endif diff --git a/tests/api.c b/tests/api.c index 05a7688d7f..ee56e80f78 100644 --- a/tests/api.c +++ b/tests/api.c @@ -35539,11 +35539,9 @@ int stopOnFail = 0; int test_wc_LmsKey_sign_verify(void); int test_wc_LmsKey_reload_cache(void); -#if defined(WOLFSSL_HAVE_LMS) && defined(WOLFSSL_WC_LMS) && \ - !defined(WOLFSSL_LMS_VERIFY_ONLY) +#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) #include -#include #define LMS_TEST_PRIV_KEY_FILE "/tmp/wolfssl_test_lms.key" @@ -35596,7 +35594,7 @@ static int test_lms_init_key(LmsKey* key, WC_RNG* rng) return 0; } -#endif /* WOLFSSL_HAVE_LMS && WOLFSSL_WC_LMS && !WOLFSSL_LMS_VERIFY_ONLY */ +#endif /* WOLFSSL_HAVE_LMS && !WOLFSSL_LMS_VERIFY_ONLY */ /* * Test basic LMS sign/verify with multiple signings. @@ -35605,8 +35603,7 @@ static int test_lms_init_key(LmsKey* key, WC_RNG* rng) int test_wc_LmsKey_sign_verify(void) { EXPECT_DECLS; -#if defined(WOLFSSL_HAVE_LMS) && defined(WOLFSSL_WC_LMS) && \ - !defined(WOLFSSL_LMS_VERIFY_ONLY) +#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) LmsKey key; WC_RNG rng; byte msg[] = "test message for LMS signing"; @@ -35655,8 +35652,7 @@ int test_wc_LmsKey_sign_verify(void) int test_wc_LmsKey_reload_cache(void) { EXPECT_DECLS; -#if defined(WOLFSSL_HAVE_LMS) && defined(WOLFSSL_WC_LMS) && \ - !defined(WOLFSSL_LMS_VERIFY_ONLY) +#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) LmsKey key; LmsKey vkey; WC_RNG rng; diff --git a/wolfcrypt/benchmark/benchmark.c b/wolfcrypt/benchmark/benchmark.c index 6b77af42e5..9cd4a73c77 100644 --- a/wolfcrypt/benchmark/benchmark.c +++ b/wolfcrypt/benchmark/benchmark.c @@ -178,20 +178,10 @@ #endif #endif #if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) - #include - #ifdef HAVE_LIBLMS - #include - #else - #include - #endif + #include #endif #if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) - #include - #ifdef HAVE_LIBXMSS - #include - #else - #include - #endif + #include #endif #if defined(WOLFSSL_HAVE_SLHDSA) #include @@ -11894,10 +11884,8 @@ static void bench_lms_sign_verify(enum wc_LmsParm parm, byte* pub) #ifndef WOLFSSL_WC_LMS_SMALL do { - #ifdef WOLFSSL_WC_LMS key.priv.inited = 0; key.state = WC_LMS_STATE_PARMSET; - #endif ret = wc_LmsKey_Reload(&key); if (ret) { printf("wc_LmsKey_Reload failed: %d\n", ret); @@ -11918,9 +11906,6 @@ static void bench_lms_sign_verify(enum wc_LmsParm parm, byte* pub) printf("wc_LmsKey_GetPrivLen failed: %d\n", ret); goto exit_lms_sign_verify; } - #ifdef HAVE_LIBLMS - break; - #endif } while (bench_stats_check(start) #ifdef MULTI_VALUE_STATISTICS || runs < minimum_runs @@ -12039,7 +12024,7 @@ void bench_lms(void) #ifndef WOLFSSL_NO_LMS_SHA256_256 #ifdef BENCH_LMS_SLOW_KEYGEN -#if !defined(WOLFSSL_WC_LMS) || (LMS_MAX_HEIGHT >= 15) +#if (LMS_MAX_HEIGHT >= 15) bench_lms_keygen(WC_LMS_PARM_L1_H15_W2, pub); bench_lms_sign_verify(WC_LMS_PARM_L1_H15_W2, pub); bench_lms_keygen(WC_LMS_PARM_L1_H15_W4, pub); @@ -12048,8 +12033,7 @@ void bench_lms(void) #define LMS_PARAMS_BENCHED #endif #endif -#if !defined(WOLFSSL_WC_LMS) || ((LMS_MAX_LEVELS >= 2) && \ - (LMS_MAX_HEIGHT >= 10)) +#if (LMS_MAX_LEVELS >= 2) && (LMS_MAX_HEIGHT >= 10) bench_lms_keygen(WC_LMS_PARM_L2_H10_W2, pub); bench_lms_sign_verify(WC_LMS_PARM_L2_H10_W2, pub); bench_lms_keygen(WC_LMS_PARM_L2_H10_W4, pub); @@ -12061,7 +12045,7 @@ void bench_lms(void) bench_lms_sign_verify(WC_LMS_PARM_L2_H10_W8, pub); #endif #endif -#if !defined(WOLFSSL_WC_LMS) || (LMS_MAX_LEVELS >= 3) +#if (LMS_MAX_LEVELS >= 3) bench_lms_keygen(WC_LMS_PARM_L3_H5_W4, pub); bench_lms_sign_verify(WC_LMS_PARM_L3_H5_W4, pub); bench_lms_keygen(WC_LMS_PARM_L3_H5_W8, pub); @@ -12069,17 +12053,16 @@ void bench_lms(void) #undef LMS_PARAMS_BENCHED #define LMS_PARAMS_BENCHED #endif -#if !defined(WOLFSSL_WC_LMS) || ((LMS_MAX_LEVELS >= 3) && \ - (LMS_MAX_HEIGHT >= 10)) +#if (LMS_MAX_LEVELS >= 3) && (LMS_MAX_HEIGHT >= 10) bench_lms_keygen(WC_LMS_PARM_L3_H10_W4, pub); bench_lms_sign_verify(WC_LMS_PARM_L3_H10_W4, pub); #endif -#if !defined(WOLFSSL_WC_LMS) || (LMS_MAX_LEVELS >= 4) +#if (LMS_MAX_LEVELS >= 4) bench_lms_keygen(WC_LMS_PARM_L4_H5_W8, pub); bench_lms_sign_verify(WC_LMS_PARM_L4_H5_W8, pub); #endif -#if defined(WOLFSSL_WC_LMS) && !defined(LMS_PARAMS_BENCHED) +#ifndef LMS_PARAMS_BENCHED bench_lms_keygen(WC_LMS_PARM_L1_H5_W1, pub); bench_lms_sign_verify(WC_LMS_PARM_L1_H5_W1, pub); #endif @@ -12087,7 +12070,7 @@ void bench_lms(void) #ifdef WOLFSSL_LMS_SHA256_192 #ifdef BENCH_LMS_SLOW_KEYGEN -#if !defined(WOLFSSL_WC_LMS) || (LMS_MAX_HEIGHT >= 15) +#if (LMS_MAX_HEIGHT >= 15) bench_lms_keygen(WC_LMS_PARM_SHA256_192_L1_H15_W2, pub); bench_lms_sign_verify(WC_LMS_PARM_SHA256_192_L1_H15_W2, pub); bench_lms_keygen(WC_LMS_PARM_SHA256_192_L1_H15_W4, pub); @@ -12096,8 +12079,7 @@ void bench_lms(void) #define LMS_PARAMS_BENCHED #endif #endif -#if !defined(WOLFSSL_WC_LMS) || ((LMS_MAX_LEVELS >= 2) && \ - (LMS_MAX_HEIGHT >= 10)) +#if (LMS_MAX_LEVELS >= 2) && (LMS_MAX_HEIGHT >= 10) bench_lms_keygen(WC_LMS_PARM_SHA256_192_L2_H10_W2, pub); bench_lms_sign_verify(WC_LMS_PARM_SHA256_192_L2_H10_W2, pub); bench_lms_keygen(WC_LMS_PARM_SHA256_192_L2_H10_W4, pub); @@ -12109,7 +12091,7 @@ void bench_lms(void) bench_lms_sign_verify(WC_LMS_PARM_SHA256_192_L2_H10_W8, pub); #endif #endif -#if !defined(WOLFSSL_WC_LMS) || (LMS_MAX_LEVELS >= 3) +#if (LMS_MAX_LEVELS >= 3) bench_lms_keygen(WC_LMS_PARM_SHA256_192_L3_H5_W4, pub); bench_lms_sign_verify(WC_LMS_PARM_SHA256_192_L3_H5_W4, pub); bench_lms_keygen(WC_LMS_PARM_SHA256_192_L3_H5_W8, pub); @@ -12117,17 +12099,16 @@ void bench_lms(void) #undef LMS_PARAMS_BENCHED #define LMS_PARAMS_BENCHED #endif -#if !defined(WOLFSSL_WC_LMS) || ((LMS_MAX_LEVELS >= 3) && \ - (LMS_MAX_HEIGHT >= 10)) +#if (LMS_MAX_LEVELS >= 3) && (LMS_MAX_HEIGHT >= 10) bench_lms_keygen(WC_LMS_PARM_SHA256_192_L3_H10_W4, pub); bench_lms_sign_verify(WC_LMS_PARM_SHA256_192_L3_H10_W4, pub); #endif -#if !defined(WOLFSSL_WC_LMS) || (LMS_MAX_LEVELS >= 4) +#if (LMS_MAX_LEVELS >= 4) bench_lms_keygen(WC_LMS_PARM_SHA256_192_L4_H5_W8, pub); bench_lms_sign_verify(WC_LMS_PARM_SHA256_192_L4_H5_W8, pub); #endif -#if defined(WOLFSSL_WC_LMS) && !defined(LMS_PARAMS_BENCHED) +#ifndef LMS_PARAMS_BENCHED bench_lms_keygen(WC_LMS_PARM_SHA256_192_L1_H5_W1, pub); bench_lms_sign_verify(WC_LMS_PARM_SHA256_192_L1_H5_W1, pub); #endif @@ -12208,13 +12189,6 @@ static void bench_xmss_sign_verify(const char * params) printf("wc_XmssKey_GetPubLen failed: %d\n", ret); goto exit_xmss_sign_verify; } -#ifndef WOLFSSL_WC_XMSS - if (pkSz != XMSS_SHA256_PUBLEN) { - printf("error: xmss pub len: got %u, expected %d\n", pkSz, - XMSS_SHA256_PUBLEN); - goto exit_xmss_sign_verify; - } -#endif ret = wc_XmssKey_GetPrivLen(&key, &skSz); if (ret != 0 || skSz <= 0) { diff --git a/wolfcrypt/src/ext_lms.c b/wolfcrypt/src/ext_lms.c deleted file mode 100644 index a36fc6579f..0000000000 --- a/wolfcrypt/src/ext_lms.c +++ /dev/null @@ -1,1111 +0,0 @@ -/* ext_lms.c - * - * Copyright (C) 2006-2026 wolfSSL Inc. - * - * This file is part of wolfSSL. - * - * wolfSSL is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * wolfSSL is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA - */ - -#include - -#if defined(WOLFSSL_HAVE_LMS) && defined(HAVE_LIBLMS) - -#include - -#ifdef NO_INLINE - #include -#else - #define WOLFSSL_MISC_INCLUDED - #include -#endif - -#ifndef WOLFSSL_LMS_VERIFY_ONLY -/* If built against hss_lib_thread.a, the hash-sigs lib will spawn - * worker threads to parallelize cpu intensive tasks. This will mainly - * speedup key generation and signing, and to a lesser extent - * verifying for larger levels values. - * - * Their default max is 16 worker threads, but can be capped with - * hss_extra_info_set_threads(). To be safe we are capping at 4 here. - * */ -#define EXT_LMS_MAX_THREADS (4) - -/* The hash-sigs hss_generate_private_key API requires a generate_random - * callback that only has output and length args. The RNG struct must be global - * to the function. Maybe there should be a wc_LmsKey_SetRngCb. */ -static THREAD_LS_T WC_RNG * LmsRng = NULL; - -static bool LmsGenerateRand(void * output, size_t length) -{ - int ret = 0; - - if (output == NULL || LmsRng == NULL) { - return false; - } - - if (length == 0) { - return true; - } - - ret = wc_RNG_GenerateBlock(LmsRng, output, (word32) length); - - if (ret) { - WOLFSSL_MSG("error: LmsGenerateRand failed"); - return false; - } - - return true; -} - -/* Write callback passed into hash-sigs hss lib. - * - * Returns true on success. */ -static bool LmsWritePrivKey(unsigned char *private_key, - size_t len_private_key, void *lmsKey) -{ - LmsKey * key = (LmsKey *) lmsKey; - enum wc_LmsRc ret = WC_LMS_RC_NONE; - - if (private_key == NULL || key == NULL || len_private_key <= 0) { - WOLFSSL_MSG("error: LmsWritePrivKey: invalid args"); - return false; - } - - if (key->state != WC_LMS_STATE_PARMSET && key->state != WC_LMS_STATE_OK) { - /* The LmsKey is not ready for writing. */ - WOLFSSL_MSG("error: LmsWritePrivKey: LMS key not in writeable state"); - return false; - } - - if (key->write_private_key == NULL) { - WOLFSSL_MSG("error: LmsWritePrivKey: LMS key write callback not set"); - key->state = WC_LMS_STATE_BAD; - return false; - } - - /* Use write callback that saves private key to non-volatile storage. */ - ret = key->write_private_key(private_key, (word32)len_private_key, - key->context); - - if (ret != WC_LMS_RC_SAVED_TO_NV_MEMORY) { - WOLFSSL_MSG("error: LmsKey write_private_key failed"); - WOLFSSL_MSG(wc_LmsKey_RcToStr(ret)); - key->state = WC_LMS_STATE_BAD; - return false; - } - - return true; -} - -/* Read callback passed into hash-sigs hss lib. - * - * Returns true on success. */ -static bool LmsReadPrivKey(unsigned char *private_key, - size_t len_private_key, void *lmsKey) -{ - LmsKey * key = (LmsKey *) lmsKey; - enum wc_LmsRc ret = WC_LMS_RC_NONE; - - if (private_key == NULL || key == NULL || len_private_key <= 0) { - WOLFSSL_MSG("error: LmsReadPrivKey: invalid args"); - return false; - } - - if (key->state != WC_LMS_STATE_PARMSET && key->state != WC_LMS_STATE_OK) { - /* The LmsKey is not ready for reading. */ - WOLFSSL_MSG("error: LmsReadPrivKey: LMS key not in readable state"); - return false; - } - - if (key->read_private_key == NULL) { - WOLFSSL_MSG("error: LmsReadPrivKey: LMS key read callback not set"); - key->state = WC_LMS_STATE_BAD; - return false; - } - - /* Use read callback that reads private key from non-volatile storage. */ - ret = key->read_private_key(private_key, (word32)len_private_key, - key->context); - - if (ret != WC_LMS_RC_READ_TO_MEMORY) { - WOLFSSL_MSG("error: LmsKey read_private_key failed"); - WOLFSSL_MSG(wc_LmsKey_RcToStr(ret)); - key->state = WC_LMS_STATE_BAD; - return false; - } - - return true; -} -#endif /* ifndef WOLFSSL_LMS_VERIFY_ONLY */ - -const char * wc_LmsKey_ParmToStr(enum wc_LmsParm lmsParm) -{ - switch (lmsParm) { - case WC_LMS_PARM_NONE: - return "LMS/HSS NONE"; - case WC_LMS_PARM_L1_H5_W1: - return "LMS/HSS L1_H5_W1"; - case WC_LMS_PARM_L1_H5_W2: - return "LMS/HSS L1_H5_W2"; - case WC_LMS_PARM_L1_H5_W4: - return "LMS/HSS L1_H5_W4"; - case WC_LMS_PARM_L1_H5_W8: - return "LMS/HSS L1_H5_W8"; - case WC_LMS_PARM_L1_H10_W2: - return "LMS/HSS L1_H10_W2"; - case WC_LMS_PARM_L1_H10_W4: - return "LMS/HSS L1_H10_W4"; - case WC_LMS_PARM_L1_H10_W8: - return "LMS/HSS L1_H10_W8"; - case WC_LMS_PARM_L1_H15_W2: - return "LMS/HSS L1_H15_W2"; - case WC_LMS_PARM_L1_H15_W4: - return "LMS/HSS L1_H15_W4"; - case WC_LMS_PARM_L1_H15_W8: - return "LMS/HSS L1_H15_W8"; - case WC_LMS_PARM_L1_H20_W2: - return "LMS/HSS L1_H20_W2"; - case WC_LMS_PARM_L1_H20_W4: - return "LMS/HSS L1_H20_W4"; - case WC_LMS_PARM_L1_H20_W8: - return "LMS/HSS L1_H20_W8"; - case WC_LMS_PARM_L2_H5_W2: - return "LMS/HSS L2_H5_W2"; - case WC_LMS_PARM_L2_H5_W4: - return "LMS/HSS L2_H5_W4"; - case WC_LMS_PARM_L2_H5_W8: - return "LMS/HSS L2_H5_W8"; - case WC_LMS_PARM_L2_H10_W2: - return "LMS/HSS L2_H10_W2"; - case WC_LMS_PARM_L2_H10_W4: - return "LMS/HSS L2_H10_W4"; - case WC_LMS_PARM_L2_H10_W8: - return "LMS/HSS L2_H10_W8"; - case WC_LMS_PARM_L2_H15_W2: - return "LMS/HSS L2_H15_W2"; - case WC_LMS_PARM_L2_H15_W4: - return "LMS/HSS L2_H15_W4"; - case WC_LMS_PARM_L2_H15_W8: - return "LMS/HSS L2_H15_W8"; - case WC_LMS_PARM_L2_H20_W2: - return "LMS/HSS L2_H20_W2"; - case WC_LMS_PARM_L2_H20_W4: - return "LMS/HSS L2_H20_W4"; - case WC_LMS_PARM_L2_H20_W8: - return "LMS/HSS L2_H20_W8"; - case WC_LMS_PARM_L3_H5_W2: - return "LMS/HSS L3_H5_W2"; - case WC_LMS_PARM_L3_H5_W4: - return "LMS/HSS L3_H5_W4"; - case WC_LMS_PARM_L3_H5_W8: - return "LMS/HSS L3_H5_W8"; - case WC_LMS_PARM_L3_H10_W4: - return "LMS/HSS L3_H10_W4"; - case WC_LMS_PARM_L3_H10_W8: - return "LMS/HSS L3_H10_W8"; - case WC_LMS_PARM_L4_H5_W2: - return "LMS/HSS L4_H5_W2"; - case WC_LMS_PARM_L4_H5_W4: - return "LMS/HSS L4_H5_W4"; - case WC_LMS_PARM_L4_H5_W8: - return "LMS/HSS L4_H5_W8"; - case WC_LMS_PARM_L4_H10_W4: - return "LMS/HSS L4_H10_W4"; - case WC_LMS_PARM_L4_H10_W8: - return "LMS/HSS L4_H10_W8"; - case WC_LMS_PARM_L1_H25_W1: - return "LMS/HSS L1_H25_W1"; - case WC_LMS_PARM_L1_H25_W2: - return "LMS/HSS L1_H25_W2"; - case WC_LMS_PARM_L1_H25_W4: - return "LMS/HSS L1_H25_W4"; - case WC_LMS_PARM_L1_H25_W8: - return "LMS/HSS L1_H25_W8"; - case WC_LMS_PARM_L1_H10_W1: - return "LMS/HSS L1_H10_W1"; - case WC_LMS_PARM_L1_H15_W1: - return "LMS/HSS L1_H15_W1"; - case WC_LMS_PARM_L1_H20_W1: - return "LMS/HSS L1_H20_W1"; - default: - WOLFSSL_MSG("error: invalid LMS parameter"); - break; - } - - return "LMS_INVALID"; -} - -const char * wc_LmsKey_RcToStr(enum wc_LmsRc lmsEc) -{ - switch (lmsEc) { - case WC_LMS_RC_NONE: - return "LMS_RC_NONE"; - - case WC_LMS_RC_BAD_ARG: - return "LMS_RC_BAD_ARG"; - - case WC_LMS_RC_WRITE_FAIL: - return "LMS_RC_WRITE_FAIL"; - - case WC_LMS_RC_READ_FAIL: - return "LMS_RC_READ_FAIL"; - - case WC_LMS_RC_SAVED_TO_NV_MEMORY: - return "LMS_RC_SAVED_TO_NV_MEMORY"; - - case WC_LMS_RC_READ_TO_MEMORY: - return "LMS_RC_READ_TO_MEMORY"; - - default: - WOLFSSL_MSG("error: invalid LMS error code"); - break; - } - - return "LMS_RC_INVALID"; -} - -/* Init an LMS key. - * - * Call this before setting the params of an LMS key. - * - * Returns 0 on success. - * */ -int wc_LmsKey_Init(LmsKey * key, void * heap, int devId) -{ - if (key == NULL) { - return BAD_FUNC_ARG; - } - - (void) heap; - (void) devId; - - ForceZero(key, sizeof(LmsKey)); - -#ifndef WOLFSSL_LMS_VERIFY_ONLY - hss_init_extra_info(&key->info); - /* Set the max number of worker threads that hash-sigs can spawn. */ - hss_extra_info_set_threads(&key->info, EXT_LMS_MAX_THREADS); - - key->working_key = NULL; - key->write_private_key = NULL; - key->read_private_key = NULL; - key->context = NULL; -#endif /* ifndef WOLFSSL_LMS_VERIFY_ONLY */ - key->state = WC_LMS_STATE_INITED; - - return 0; -} - -/* Set the wc_LmsParm of an LMS key. - * - * Use this if you wish to set a key with a predefined parameter set, - * such as WC_LMS_PARM_L2_H10_W8. - * - * Key must be inited before calling this. - * - * Returns 0 on success. - * */ -int wc_LmsKey_SetLmsParm(LmsKey * key, enum wc_LmsParm lmsParm) -{ - if (key == NULL) { - return BAD_FUNC_ARG; - } - - /* If NONE is passed, default to the lowest predefined set. */ - switch (lmsParm) { - case WC_LMS_PARM_NONE: - case WC_LMS_PARM_L1_H5_W1: - return wc_LmsKey_SetParameters(key, 1, 5, 1); - case WC_LMS_PARM_L1_H5_W2: - return wc_LmsKey_SetParameters(key, 1, 5, 2); - case WC_LMS_PARM_L1_H5_W4: - return wc_LmsKey_SetParameters(key, 1, 5, 4); - case WC_LMS_PARM_L1_H5_W8: - return wc_LmsKey_SetParameters(key, 1, 5, 8); - case WC_LMS_PARM_L1_H10_W2: - return wc_LmsKey_SetParameters(key, 1, 10, 2); - case WC_LMS_PARM_L1_H10_W4: - return wc_LmsKey_SetParameters(key, 1, 10, 4); - case WC_LMS_PARM_L1_H10_W8: - return wc_LmsKey_SetParameters(key, 1, 10, 8); - case WC_LMS_PARM_L1_H15_W2: - return wc_LmsKey_SetParameters(key, 1, 15, 2); - case WC_LMS_PARM_L1_H15_W4: - return wc_LmsKey_SetParameters(key, 1, 15, 4); - case WC_LMS_PARM_L1_H15_W8: - return wc_LmsKey_SetParameters(key, 1, 15, 8); - case WC_LMS_PARM_L1_H20_W2: - return wc_LmsKey_SetParameters(key, 1, 20, 2); - case WC_LMS_PARM_L1_H20_W4: - return wc_LmsKey_SetParameters(key, 1, 20, 4); - case WC_LMS_PARM_L1_H20_W8: - return wc_LmsKey_SetParameters(key, 1, 20, 8); - case WC_LMS_PARM_L2_H5_W2: - return wc_LmsKey_SetParameters(key, 2, 5, 2); - case WC_LMS_PARM_L2_H5_W4: - return wc_LmsKey_SetParameters(key, 2, 5, 4); - case WC_LMS_PARM_L2_H5_W8: - return wc_LmsKey_SetParameters(key, 2, 5, 8); - case WC_LMS_PARM_L2_H10_W2: - return wc_LmsKey_SetParameters(key, 2, 10, 2); - case WC_LMS_PARM_L2_H10_W4: - return wc_LmsKey_SetParameters(key, 2, 10, 4); - case WC_LMS_PARM_L2_H10_W8: - return wc_LmsKey_SetParameters(key, 2, 10, 8); - case WC_LMS_PARM_L2_H15_W2: - return wc_LmsKey_SetParameters(key, 2, 15, 2); - case WC_LMS_PARM_L2_H15_W4: - return wc_LmsKey_SetParameters(key, 2, 15, 4); - case WC_LMS_PARM_L2_H15_W8: - return wc_LmsKey_SetParameters(key, 2, 15, 8); - case WC_LMS_PARM_L2_H20_W2: - return wc_LmsKey_SetParameters(key, 2, 20, 2); - case WC_LMS_PARM_L2_H20_W4: - return wc_LmsKey_SetParameters(key, 2, 20, 4); - case WC_LMS_PARM_L2_H20_W8: - return wc_LmsKey_SetParameters(key, 2, 20, 8); - case WC_LMS_PARM_L3_H5_W2: - return wc_LmsKey_SetParameters(key, 3, 5, 2); - case WC_LMS_PARM_L3_H5_W4: - return wc_LmsKey_SetParameters(key, 3, 5, 4); - case WC_LMS_PARM_L3_H5_W8: - return wc_LmsKey_SetParameters(key, 3, 5, 8); - case WC_LMS_PARM_L3_H10_W4: - return wc_LmsKey_SetParameters(key, 3, 10, 4); - case WC_LMS_PARM_L3_H10_W8: - return wc_LmsKey_SetParameters(key, 3, 10, 8); - case WC_LMS_PARM_L4_H5_W2: - return wc_LmsKey_SetParameters(key, 4, 5, 2); - case WC_LMS_PARM_L4_H5_W4: - return wc_LmsKey_SetParameters(key, 4, 5, 4); - case WC_LMS_PARM_L4_H5_W8: - return wc_LmsKey_SetParameters(key, 4, 5, 8); - case WC_LMS_PARM_L4_H10_W4: - return wc_LmsKey_SetParameters(key, 4, 10, 4); - case WC_LMS_PARM_L4_H10_W8: - return wc_LmsKey_SetParameters(key, 4, 10, 8); - case WC_LMS_PARM_L1_H25_W1: - return wc_LmsKey_SetParameters(key, 1, 25, 1); - case WC_LMS_PARM_L1_H25_W2: - return wc_LmsKey_SetParameters(key, 1, 25, 2); - case WC_LMS_PARM_L1_H25_W4: - return wc_LmsKey_SetParameters(key, 1, 25, 4); - case WC_LMS_PARM_L1_H25_W8: - return wc_LmsKey_SetParameters(key, 1, 25, 8); - case WC_LMS_PARM_L1_H10_W1: - return wc_LmsKey_SetParameters(key, 1, 10, 1); - case WC_LMS_PARM_L1_H15_W1: - return wc_LmsKey_SetParameters(key, 1, 15, 1); - case WC_LMS_PARM_L1_H20_W1: - return wc_LmsKey_SetParameters(key, 1, 20, 1); - default: - WOLFSSL_MSG("error: invalid LMS parameter set"); - break; - } - - return BAD_FUNC_ARG; -} - -/* Set the parameters of an LMS key. - * - * Use this if you wish to set specific parameters not found in the - * wc_LmsParm predefined sets. See comments in lms.h for allowed - * parameters. - * - * Key must be inited before calling this. - * - * Returns 0 on success. - * */ -int wc_LmsKey_SetParameters(LmsKey * key, int levels, int height, - int winternitz) -{ - int i = 0; - param_set_t lm = LMS_SHA256_N32_H5; - param_set_t ots = LMOTS_SHA256_N32_W1; - - if (key == NULL) { - return BAD_FUNC_ARG; - } - - if (key->state != WC_LMS_STATE_INITED) { - WOLFSSL_MSG("error: LmsKey needs init"); - return -1; - } - - /* Verify inputs make sense. - * - * Note: there does not seem to be a define for min or - * max Winternitz integer in hash-sigs lib or RFC8554. */ - - if (levels < MIN_HSS_LEVELS || levels > MAX_HSS_LEVELS) { - WOLFSSL_MSG("error: invalid level parameter"); - return BAD_FUNC_ARG; - } - - if (height < MIN_MERKLE_HEIGHT || height > MAX_MERKLE_HEIGHT) { - WOLFSSL_MSG("error: invalid height parameter"); - return BAD_FUNC_ARG; - } - - switch (height) { - case 5: - lm = LMS_SHA256_N32_H5; - break; - case 10: - lm = LMS_SHA256_N32_H10; - break; - case 15: - lm = LMS_SHA256_N32_H15; - break; - case 20: - lm = LMS_SHA256_N32_H20; - break; - case 25: - lm = LMS_SHA256_N32_H25; - break; - default: - WOLFSSL_MSG("error: invalid height parameter"); - return BAD_FUNC_ARG; - } - - switch (winternitz) { - case 1: - ots = LMOTS_SHA256_N32_W1; - break; - case 2: - ots = LMOTS_SHA256_N32_W2; - break; - case 4: - ots = LMOTS_SHA256_N32_W4; - break; - case 8: - ots = LMOTS_SHA256_N32_W8; - break; - default: - WOLFSSL_MSG("error: invalid winternitz parameter"); - return BAD_FUNC_ARG; - } - - key->levels = levels; - - for (i = 0; i < levels; ++i) { - key->lm_type[i] = lm; - key->lm_ots_type[i] = ots; - } - - /* Move the state to params set. - * Key is ready for MakeKey or Reload. */ - key->state = WC_LMS_STATE_PARMSET; - - return 0; -} - -/* Get the parameters of an LMS key. - * - * Key must be inited and parameters set before calling this. - * - * Returns 0 on success. - * */ -int wc_LmsKey_GetParameters(const LmsKey * key, int * levels, int * height, - int * winternitz) -{ - if (key == NULL || levels == NULL || height == NULL || winternitz == NULL) { - return BAD_FUNC_ARG; - } - - /* This shouldn't happen, but check the LmsKey parameters aren't invalid. */ - - if (key->levels < MIN_HSS_LEVELS || key->levels > MAX_HSS_LEVELS) { - WOLFSSL_MSG("error: LmsKey invalid level parameter"); - return -1; - } - - *levels = key->levels; - - switch (key->lm_type[0]) { - case LMS_SHA256_N32_H5: - *height = 5; - break; - case LMS_SHA256_N32_H10: - *height = 10; - break; - case LMS_SHA256_N32_H15: - *height = 15; - break; - case LMS_SHA256_N32_H20: - *height = 20; - break; - case LMS_SHA256_N32_H25: - *height = 25; - break; - default: - WOLFSSL_MSG("error: LmsKey invalid height parameter"); - return -1; - } - - switch (key->lm_ots_type[0]) { - case LMOTS_SHA256_N32_W1: - *winternitz = 1; - break; - case LMOTS_SHA256_N32_W2: - *winternitz = 2; - break; - case LMOTS_SHA256_N32_W4: - *winternitz = 4; - break; - case LMOTS_SHA256_N32_W8: - *winternitz = 8; - break; - default: - WOLFSSL_MSG("error: LmsKey invalid winternitz parameter"); - return -1; - } - - return 0; -} - -/* Frees the LMS key from memory. - * - * This does not affect the private key saved to non-volatile storage. - * */ -void wc_LmsKey_Free(LmsKey* key) -{ - if (key == NULL) { - return; - } - -#ifndef WOLFSSL_LMS_VERIFY_ONLY - if (key->working_key != NULL) { - hss_free_working_key(key->working_key); - key->working_key = NULL; - } -#endif /* ifndef WOLFSSL_LMS_VERIFY_ONLY */ - - ForceZero(key, sizeof(LmsKey)); - - key->state = WC_LMS_STATE_FREED; - - return; -} - -#ifndef WOLFSSL_LMS_VERIFY_ONLY -/* Set the write private key callback to the LMS key structure. - * - * The callback must be able to write/update the private key to - * non-volatile storage. - * - * Returns 0 on success. - * */ -int wc_LmsKey_SetWriteCb(LmsKey * key, wc_lms_write_private_key_cb write_cb) -{ - if (key == NULL || write_cb == NULL) { - return BAD_FUNC_ARG; - } - - /* Changing the write callback of an already working key is forbidden. */ - if (key->state == WC_LMS_STATE_OK) { - WOLFSSL_MSG("error: wc_LmsKey_SetWriteCb: key in use"); - return -1; - } - - key->write_private_key = write_cb; - - return 0; -} - -/* Set the read private key callback to the LMS key structure. - * - * The callback must be able to read the private key from - * non-volatile storage. - * - * Returns 0 on success. - * */ -int wc_LmsKey_SetReadCb(LmsKey * key, wc_lms_read_private_key_cb read_cb) -{ - if (key == NULL || read_cb == NULL) { - return BAD_FUNC_ARG; - } - - /* Changing the read callback of an already working key is forbidden. */ - if (key->state == WC_LMS_STATE_OK) { - WOLFSSL_MSG("error: wc_LmsKey_SetReadCb: key in use"); - return -1; - } - - key->read_private_key = read_cb; - - return 0; -} - -/* Sets the context to be used by write and read callbacks. - * - * E.g. this could be a filename if the callbacks write/read to file. - * - * Returns 0 on success. - * */ -int wc_LmsKey_SetContext(LmsKey * key, void * context) -{ - if (key == NULL || context == NULL) { - return BAD_FUNC_ARG; - } - - /* Setting context of an already working key is forbidden. */ - if (key->state == WC_LMS_STATE_OK) { - WOLFSSL_MSG("error: wc_LmsKey_SetContext: key in use"); - return -1; - } - - key->context = context; - - return 0; -} - -/* Make the LMS private/public key pair. The key must have its parameters - * set before calling this. - * - * Write/read callbacks, and context data, must be set prior. - * Key must have parameters set. - * - * Returns 0 on success. - * */ -int wc_LmsKey_MakeKey(LmsKey* key, WC_RNG * rng) -{ - bool result = true; - - if (key == NULL || rng == NULL) { - return BAD_FUNC_ARG; - } - - if (key->state != WC_LMS_STATE_PARMSET) { - WOLFSSL_MSG("error: LmsKey not ready for generation"); - return -1; - } - - if (key->write_private_key == NULL || key->read_private_key == NULL) { - WOLFSSL_MSG("error: LmsKey write/read callbacks are not set"); - return -1; - } - - if (key->context == NULL) { - WOLFSSL_MSG("error: LmsKey context is not set"); - return -1; - } - - LmsRng = rng; - - /* TODO: The hash-sigs lib allows you to save variable length auxiliary - * data, which can be used to speed up key reloading when signing. The - * aux data can be 300B - 1KB in size. - * - * Not implemented at the moment. - * - * key->aux_data_len = hss_get_aux_data_len(AUX_DATA_MAX_LEN, key->levels, - * key->lm_type, - * key->lm_ots_type); - * - * key->aux_data = XMALLOC(key->aux_data_len, NULL, - * DYNAMIC_TYPE_TMP_BUFFER); - */ - - /* First generate the private key using the parameters and callbacks. - * If successful, private key will be saved to non-volatile storage, - * and the public key will be in memory. */ - result = hss_generate_private_key(LmsGenerateRand, key->levels, - key->lm_type, key->lm_ots_type, - LmsWritePrivKey, key, - key->pub, sizeof(key->pub), - NULL, 0, &key->info); - - if (!result) { - WOLFSSL_MSG("error: hss_generate_private_key failed"); - key->state = WC_LMS_STATE_BAD; - return -1; - } - - /* Once generated, now we must load the private key so we have - * an hss working key for signing operations. */ - key->working_key = hss_load_private_key(LmsReadPrivKey, key, - 0, NULL, 0, &key->info); - - if (key->working_key == NULL) { - WOLFSSL_MSG("error: hss_load_private_key failed"); - key->state = WC_LMS_STATE_BAD; - return -1; - } - - /* This should not happen, but check just in case. */ - if (wc_LmsKey_SigsLeft(key) == 0) { - WOLFSSL_MSG("error: generated LMS key signatures exhausted"); - key->state = WC_LMS_STATE_NOSIGS; - return -1; - } - - key->state = WC_LMS_STATE_OK; - - return 0; -} - -/* Reload a key that has been prepared with the appropriate params and - * data. Use this if you wish to resume signing with an existing key. - * - * Write/read callbacks, and context data, must be set prior. - * Key must have parameters set. - * - * Returns 0 on success. */ -int wc_LmsKey_Reload(LmsKey * key) -{ - bool result = true; - - if (key == NULL) { - return BAD_FUNC_ARG; - } - - if (key->state != WC_LMS_STATE_PARMSET) { - WOLFSSL_MSG("error: LmsKey not ready for reload"); - return -1; - } - - if (key->write_private_key == NULL || key->read_private_key == NULL) { - WOLFSSL_MSG("error: LmsKey write/read callbacks are not set"); - return -1; - } - - if (key->context == NULL) { - WOLFSSL_MSG("error: LmsKey context is not set"); - return -1; - } - - key->working_key = hss_load_private_key(LmsReadPrivKey, key, - 0, NULL, 0, &key->info); - - if (key->working_key == NULL) { - WOLFSSL_MSG("error: hss_load_private_key failed"); - key->state = WC_LMS_STATE_BAD; - return -1; - } - - result = hss_get_parameter_set(&key->levels, key->lm_type, - key->lm_ots_type, LmsReadPrivKey, key); - - if (!result) { - WOLFSSL_MSG("error: hss_get_parameter_set failed"); - key->state = WC_LMS_STATE_BAD; - hss_free_working_key(key->working_key); - key->working_key = NULL; - return -1; - } - - /* Double check the key actually has signatures left. */ - if (wc_LmsKey_SigsLeft(key) == 0) { - WOLFSSL_MSG("error: reloaded LMS key signatures exhausted"); - key->state = WC_LMS_STATE_NOSIGS; - return -1; - } - - key->state = WC_LMS_STATE_OK; - - return 0; -} - -/* Given a levels, height, winternitz parameter set, determine - * the private key length */ -int wc_LmsKey_GetPrivLen(const LmsKey * key, word32 * len) -{ - if (key == NULL || len == NULL) { - return BAD_FUNC_ARG; - } - - *len = (word32) hss_get_private_key_len(key->levels, key->lm_type, - key->lm_ots_type); - - return 0; -} - -int wc_LmsKey_Sign(LmsKey* key, byte * sig, word32 * sigSz, const byte * msg, - int msgSz) -{ - bool result = true; - size_t len = 0; - - if (key == NULL || sig == NULL || sigSz == NULL || msg == NULL) { - return BAD_FUNC_ARG; - } - - if (msgSz <= 0) { - return BAD_FUNC_ARG; - } - - if (key->state == WC_LMS_STATE_NOSIGS) { - WOLFSSL_MSG("error: LMS signatures exhausted"); - return -1; - } - else if (key->state != WC_LMS_STATE_OK) { - /* The key had an error the last time it was used, and we - * can't guarantee its state. */ - WOLFSSL_MSG("error: can't sign, LMS key not in good state"); - return -1; - } - - len = hss_get_signature_len(key->levels, key->lm_type, key->lm_ots_type); - - if (len == 0) { - /* Key parameters are invalid. */ - WOLFSSL_MSG("error: hss_get_signature_len failed"); - key->state = WC_LMS_STATE_BAD; - return -1; - } - - if ((size_t)*sigSz < len) { - /* Signature buffer too small. */ - WOLFSSL_MSG("error: LMS sig buffer too small"); - return BUFFER_E; - } - - if (key->write_private_key == NULL) { - WOLFSSL_MSG("error: LmsKey write/read callbacks are not set"); - return BAD_FUNC_ARG; - } - - if (key->context == NULL) { - WOLFSSL_MSG("error: LmsKey context is not set"); - return BAD_FUNC_ARG; - } - - result = hss_generate_signature(key->working_key, LmsWritePrivKey, - key, (const void *) msg, msgSz, - sig, len, &key->info); - - if (!result) { - /* Erase any partial signature to prevent OTS key reuse if state - * is rolled back. */ - ForceZero(sig, len); - - if (wc_LmsKey_SigsLeft(key) == 0) { - WOLFSSL_MSG("error: LMS signatures exhausted"); - key->state = WC_LMS_STATE_NOSIGS; - return -1; - } - - WOLFSSL_MSG("error: hss_generate_signature failed"); - key->state = WC_LMS_STATE_BAD; - return -1; - } - - *sigSz = (word32) len; - - return 0; -} - -/* Returns 1 if there are signatures remaining. - * Returns 0 if available signatures are exhausted. - * - * Note: the number of remaining signatures is hidden behind an opaque - * pointer in the hash-sigs lib. We could add a counter here that is - * decremented on every signature. The number of available signatures - * grows as - * N = 2 ** (levels * height) - * so it would need to be a big integer. */ -int wc_LmsKey_SigsLeft(LmsKey * key) -{ - if (key == NULL) { - return BAD_FUNC_ARG; - } - - if (hss_extra_info_test_last_signature(&key->info)) { - return 0; - } - - return 1; -} - -#endif /* ifndef WOLFSSL_LMS_VERIFY_ONLY*/ - -/* Given a levels, height, winternitz parameter set, determine - * the public key length */ -int wc_LmsKey_GetPubLen(const LmsKey * key, word32 * len) -{ - if (key == NULL || len == NULL) { - return BAD_FUNC_ARG; - } - - *len = (word32) hss_get_public_key_len(key->levels, key->lm_type, - key->lm_ots_type); - - return 0; -} - -/* Export a generated public key and parameter set from one LmsKey - * to another. Use this to prepare a signature verification LmsKey - * that is pub only. - * - * Though the public key is all that is used to verify signatures, - * the parameter set is needed to calculate the signature length - * before hand. */ -int wc_LmsKey_ExportPub(LmsKey * keyDst, const LmsKey * keySrc) -{ - if (keyDst == NULL || keySrc == NULL) { - return BAD_FUNC_ARG; - } - - ForceZero(keyDst, sizeof(LmsKey)); - - XMEMCPY(keyDst->pub, keySrc->pub, sizeof(keySrc->pub)); - XMEMCPY(keyDst->lm_type, keySrc->lm_type, sizeof(keySrc->lm_type)); - XMEMCPY(keyDst->lm_ots_type, keySrc->lm_ots_type, - sizeof(keySrc->lm_ots_type)); - - keyDst->levels = keySrc->levels; - - /* Mark this key as verify only, to prevent misuse. */ - keyDst->state = WC_LMS_STATE_VERIFYONLY; - - return 0; -} - -/* Exports the raw LMS public key buffer from key to out buffer. - * The out buffer should be large enough to hold the public key, and - * outLen should indicate the size of the buffer. - * - * - Returns 0 on success, and sets outLen to LMS pubLen. - * - Returns BUFFER_E if outLen < LMS pubLen. - * - * Call wc_LmsKey_GetPubLen beforehand to determine pubLen. - * */ -int wc_LmsKey_ExportPubRaw(const LmsKey * key, byte * out, word32 * outLen) -{ - int ret = 0; - word32 pubLen = 0; - - if (key == NULL || out == NULL || outLen == NULL) { - return BAD_FUNC_ARG; - } - - ret = wc_LmsKey_GetPubLen(key, &pubLen); - - if (ret != 0) { - WOLFSSL_MSG("error: wc_LmsKey_GetPubLen failed"); - return -1; - } - - if (*outLen < pubLen) { - return BUFFER_E; - } - - XMEMCPY(out, key->pub, pubLen); - *outLen = pubLen; - - return 0; -} - -/* Imports a raw public key buffer from in array to LmsKey key. - * - * The LMS parameters must be set first with wc_LmsKey_SetLmsParm or - * wc_LmsKey_SetParameters, and inLen must match the length returned - * by wc_LmsKey_GetPubLen. - * - * - Returns 0 on success. - * - Returns BUFFER_E if inlen != LMS pubLen. - * - * Call wc_LmsKey_GetPubLen beforehand to determine pubLen. - * */ -int wc_LmsKey_ImportPubRaw(LmsKey * key, const byte * in, word32 inLen) -{ - int ret = 0; - word32 pubLen = 0; - - if (key == NULL || in == NULL) { - return BAD_FUNC_ARG; - } - - ret = wc_LmsKey_GetPubLen(key, &pubLen); - - if (ret != 0) { - WOLFSSL_MSG("error: wc_LmsKey_GetPubLen failed"); - return -1; - } - - if (inLen != pubLen) { - /* Something inconsistent. Parameters weren't set, or input - * pub key is wrong.*/ - return BUFFER_E; - } - - XMEMCPY(key->pub, in, pubLen); - - return 0; -} - -/* Given a levels, height, winternitz parameter set, determine - * the signature length. - * - * Call this before wc_LmsKey_Sign so you know the length of - * the required signature buffer. */ -int wc_LmsKey_GetSigLen(const LmsKey * key, word32 * len) -{ - if (key == NULL || len == NULL) { - return BAD_FUNC_ARG; - } - - *len = (word32) hss_get_signature_len(key->levels, key->lm_type, - key->lm_ots_type); - - return 0; -} - -int wc_LmsKey_Verify(LmsKey * key, const byte * sig, word32 sigSz, - const byte * msg, int msgSz) -{ - bool result = true; - - if (key == NULL || sig == NULL || msg == NULL) { - return BAD_FUNC_ARG; - } - -#ifdef WOLFSSL_LMS_VERIFY_ONLY - result = hss_validate_signature(key->pub, (const void *) msg, msgSz, sig, - sigSz, NULL); -#else - result = hss_validate_signature(key->pub, (const void *) msg, msgSz, sig, - sigSz, &key->info); -#endif - - - if (!result) { - WOLFSSL_MSG("error: hss_validate_signature failed"); - return -1; - } - - return 0; -} - -int wc_LmsKey_GetKid(LmsKey * key, const byte ** kid, word32* kidSz) -{ - if ((key == NULL) || (kid == NULL) || (kidSz == NULL)) { - return BAD_FUNC_ARG; - } - - return NOT_COMPILED_IN; -} - -const byte * wc_LmsKey_GetKidFromPrivRaw(const byte * priv, word32 privSz) -{ - if ((priv == NULL) || (privSz < 16)) { - return NULL; - } - return priv - 16; -} - -#endif /* WOLFSSL_HAVE_LMS && HAVE_LIBLMS */ diff --git a/wolfcrypt/src/ext_xmss.c b/wolfcrypt/src/ext_xmss.c deleted file mode 100644 index a3ddb6f454..0000000000 --- a/wolfcrypt/src/ext_xmss.c +++ /dev/null @@ -1,1041 +0,0 @@ -/* ext_xmss.c - * - * Copyright (C) 2006-2026 wolfSSL Inc. - * - * This file is part of wolfSSL. - * - * wolfSSL is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * wolfSSL is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA - */ - -#include - -#include - -#if defined(WOLFSSL_HAVE_XMSS) && defined(HAVE_LIBXMSS) - -#include - -#ifdef NO_INLINE - #include -#else - #define WOLFSSL_MISC_INCLUDED - #include -#endif - -#include -#include - -#ifndef WOLFSSL_XMSS_VERIFY_ONLY -static THREAD_LS_T WC_RNG * xmssRng = NULL; - -/* RNG callback used by xmss. - * */ -static int rng_cb(void * output, size_t length) -{ - int ret = 0; - - if (output == NULL || xmssRng == NULL) { - return -1; - } - - if (length == 0) { - return 0; - } - - ret = wc_RNG_GenerateBlock(xmssRng, (byte *)output, (word32)length); - - if (ret) { - WOLFSSL_MSG("error: XMSS rng_cb failed"); - return -1; - } - - return 0; -} -#endif /* ifndef WOLFSSL_XMSS_VERIFY_ONLY */ - -/* SHA256 callback used by XMSS. - * */ -static int sha256_cb(const unsigned char *in, unsigned long long inlen, - unsigned char *out) -{ - wc_Sha256 sha; - - if (wc_InitSha256_ex(&sha, NULL, INVALID_DEVID) != 0) { - WOLFSSL_MSG("SHA256 Init failed"); - return -1; - } - - if (wc_Sha256Update(&sha, in, (word32) inlen) != 0) { - WOLFSSL_MSG("SHA256 Update failed"); - return -1; - } - - if (wc_Sha256Final(&sha, out) != 0) { - WOLFSSL_MSG("SHA256 Final failed"); - wc_Sha256Free(&sha); - return -1; - } - wc_Sha256Free(&sha); - - return 0; -} - -/* Init an XMSS key. - * - * Call this before setting the params of an XMSS key. - * - * key [in] The XMSS key to init. - * heap [in] Unused. - * devId [in] Unused. - * - * returns 0 on success. - * returns BAD_FUNC_ARG when a parameter is NULL. - * */ -int wc_XmssKey_Init(XmssKey * key, void * heap, int devId) -{ - if (key == NULL) { - return BAD_FUNC_ARG; - } - - (void) heap; - (void) devId; - - ForceZero(key, sizeof(XmssKey)); - -#ifndef WOLFSSL_XMSS_VERIFY_ONLY - key->sk = NULL; - key->sk_len = 0; - key->write_private_key = NULL; - key->read_private_key = NULL; - key->context = NULL; -#endif /* ifndef WOLFSSL_XMSS_VERIFY_ONLY */ - key->state = WC_XMSS_STATE_INITED; - - return 0; -} - -/* Sets the XMSS key parameters, given an OID. - * - * Note: XMSS and XMSS^MT parameter sets do have overlapping - * OIDs, therefore is_xmssmt is necessary to toggle. - * - * key [in] The XMSS key to set. - * OID [in] The XMSS parameter set OID. - * is_xmssmt [in] 1 The OID is assumed to be XMSS^MT. - * 0 The OID is assumed to be XMSS. - * - * returns 0 on success. - * returns BAD_FUNC_ARG when a parameter is NULL. - * returns -1 on parse failure. - * */ -static int wc_XmssKey_SetOid(XmssKey * key, uint32_t oid, int is_xmssmt) -{ - int ret = 0; - - if (key == NULL || oid == 0) { - return BAD_FUNC_ARG; - } - - /* Parse the OID and load the XMSS params structure. */ - if (is_xmssmt) { - ret = xmssmt_parse_oid(&key->params, oid); - } - else { - ret = xmss_parse_oid(&key->params, oid); - } - - if (ret != 0) { - WOLFSSL_MSG("error: XMSS parse oid failed"); - return -1; - } - - /* Finally, sanity check that this is a supported parameter set. - * - * We are only supporting XMSS/XMSS^MT with SHA256 parameter sets - * that NIST SP 800-208 has standardized. See patched xmss-reference - * params.h for the defines. */ - if (key->params.func != XMSS_SHA2 || - key->params.n != XMSS_SHA256_N || - key->params.padding_len != XMSS_SHA256_PADDING_LEN || - key->params.wots_w != 16 || - key->params.wots_len != XMSS_SHA256_WOTS_LEN) { - WOLFSSL_MSG("error: unsupported XMSS/XMSS^MT parameter set"); - return -1; - } - if ((key->params.full_height < WOLFSSL_XMSS_MIN_HEIGHT) || - (key->params.full_height > WOLFSSL_XMSS_MAX_HEIGHT)) { - WOLFSSL_MSG("error: unsupported XMSS/XMSS^MT parameter set - height"); - return -1; - } - - ret = xmss_set_sha_cb(sha256_cb); - if (ret != 0) { - WOLFSSL_MSG("error: xmss_set_sha_cb failed"); - return -1; - } - -#ifndef WOLFSSL_XMSS_VERIFY_ONLY - ret = xmss_set_rng_cb(rng_cb); - if (ret != 0) { - WOLFSSL_MSG("error: xmss_set_rng_cb failed"); - return -1; - } -#endif - - key->oid = oid; - key->is_xmssmt = is_xmssmt; - key->state = WC_XMSS_STATE_PARMSET; - - return 0; -} - -/* Set the XMSS key parameter string. - * - * The input string must be one of the supported param set names in - * the "Name" section from the table in wolfssl/wolfcrypt/xmss.h, - * e.g. "XMSS-SHA2_10_256" or "XMSSMT-SHA2_20/4_256". - * - * key [in] The XMSS key to set. - * str [in] The XMSS/XMSS^MT parameter string. - * - * returns 0 on success. - * returns BAD_FUNC_ARG when a parameter is NULL. - * returns -1 on failure. - * */ -int wc_XmssKey_SetParamStr(XmssKey * key, const char * str) -{ - int ret = 0; - uint32_t oid = 0; - int is_xmssmt = 0; - - if (key == NULL || str == NULL) { - return BAD_FUNC_ARG; - } - - if (key->state != WC_XMSS_STATE_INITED) { - WOLFSSL_MSG("error: XMSS key needs init"); - return BAD_FUNC_ARG; - } - - switch(XSTRLEN(str)) { - case XMSS_NAME_LEN: - is_xmssmt = 0; - break; - case XMSSMT_NAME_MIN_LEN: - case XMSSMT_NAME_MAX_LEN: - is_xmssmt = 1; - break; - default: - WOLFSSL_MSG("error: XMSS param str invalid length"); - return BAD_FUNC_ARG; - } - - /* Convert XMSS param string to OID. */ - if (is_xmssmt) { - ret = xmssmt_str_to_oid(&oid, str); - } - else { - ret = xmss_str_to_oid(&oid, str); - } - - if (ret != 0) { - WOLFSSL_MSG("error: xmssmt_str_to_oid failed"); - return -1; - } - - return wc_XmssKey_SetOid(key, oid, is_xmssmt); -} - -/* Force zeros and frees the XMSS key from memory. - * - * This does not touch the private key saved to non-volatile storage. - * - * This is the only function that frees the key->sk array. - * - * key [in] The XMSS key. - * - * returns void - * */ -void wc_XmssKey_Free(XmssKey* key) -{ - if (key == NULL) { - return; - } - -#ifndef WOLFSSL_XMSS_VERIFY_ONLY - if (key->sk != NULL) { - ForceZero(key->sk, key->sk_len); - XFREE(key->sk, NULL, DYNAMIC_TYPE_TMP_BUFFER); - key->sk = NULL; - key->sk_len = 0; - } -#endif /* ifndef WOLFSSL_XMSS_VERIFY_ONLY */ - - ForceZero(key, sizeof(XmssKey)); - - key->state = WC_XMSS_STATE_FREED; - - return; -} - -#ifndef WOLFSSL_XMSS_VERIFY_ONLY -/* Sets the XMSS write private key callback. - * - * The callback must be able to write/update the private key to - * non-volatile storage. - * - * key [in] The XMSS key. - * write_cb [in] The write private key callback. - * - * returns 0 on success. - * returns BAD_FUNC_ARG when a parameter is NULL. - * returns -1 on failure. - * */ -int wc_XmssKey_SetWriteCb(XmssKey * key, wc_xmss_write_private_key_cb write_cb) -{ - if (key == NULL || write_cb == NULL) { - return BAD_FUNC_ARG; - } - - /* Changing the write callback of an already working key is forbidden. */ - if (key->state == WC_XMSS_STATE_OK) { - WOLFSSL_MSG("error: wc_XmssKey_SetWriteCb: key in use"); - return -1; - } - - key->write_private_key = write_cb; - - return 0; -} - -/* Sets the XMSS read private key callback. - * - * The callback must be able to read the private key from - * non-volatile storage. - * - * key [in] The XMSS key. - * read_cb [in] The read private key callback. - * - * returns 0 on success. - * returns BAD_FUNC_ARG when a parameter is NULL. - * returns -1 on failure. - * */ -int wc_XmssKey_SetReadCb(XmssKey * key, wc_xmss_read_private_key_cb read_cb) -{ - if (key == NULL || read_cb == NULL) { - return BAD_FUNC_ARG; - } - - /* Changing the read callback of an already working key is forbidden. */ - if (key->state == WC_XMSS_STATE_OK) { - WOLFSSL_MSG("error: wc_XmssKey_SetReadCb: key in use"); - return -1; - } - - key->read_private_key = read_cb; - - return 0; -} - -/* Sets the XMSS context to be used by write and read callbacks. - * - * E.g. this could be a filename if the callbacks write/read to file. - * - * key [in] The XMSS key. - * context [in] The context pointer. - * - * returns 0 on success. - * returns BAD_FUNC_ARG when a parameter is NULL. - * returns -1 on failure. - * */ -int wc_XmssKey_SetContext(XmssKey * key, void * context) -{ - if (key == NULL || context == NULL) { - return BAD_FUNC_ARG; - } - - /* Setting context of an already working key is forbidden. */ - if (key->state == WC_XMSS_STATE_OK) { - WOLFSSL_MSG("error: wc_XmssKey_SetContext: key in use"); - return -1; - } - - key->context = context; - - return 0; -} - - -/* Allocates the XMSS secret key (sk) array. - * - * The XMSS/XMSS^MT secret key length is a function of the - * parameters, and can't be allocated until the param string - * has been set with SetParamStr. - * - * This is only called by MakeKey() and Reload(). - * - * Note: the XMSS sk array is force zeroed after every use. - * - * key [in] The XMSS key. - * - * returns 0 on success. - * returns BAD_FUNC_ARG when a parameter is NULL. - * returns -1 on failure. - * */ -static int wc_XmssKey_AllocSk(XmssKey* key) -{ - int ret = 0; - - if (key == NULL) { - return BAD_FUNC_ARG; - } - - if (key->sk != NULL) { - WOLFSSL_MSG("error: XMSS secret key already exists"); - return -1; - } - - /* The XMSS/XMSS^MT secret key length is a function of the - * parameters. Therefore can't allocate this until param - * string has been set. */ - ret = wc_XmssKey_GetPrivLen(key, &key->sk_len); - - if (ret != 0 || key->sk_len <= 0) { - WOLFSSL_MSG("error: wc_XmssKey_GetPrivLen failed"); - return -1; - } - - key->sk = (unsigned char *)XMALLOC(key->sk_len, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - - if (key->sk == NULL) { - WOLFSSL_MSG("error: malloc XMSS key->sk failed"); - return -1; - } - - ForceZero(key->sk, key->sk_len); - - return 0; -} - -/* Make the XMSS/XMSS^MT private/public key pair. The key must have its parameters - * set before calling this. - * - * Write/read callbacks, and context data, must be set prior. - * Key must have parameters set. - * - * This function and Reload() are the only functions that allocate - * key->sk array. wc_XmssKey_FreeKey is the only function that - * deallocates key->sk. - * - * key [in] The XMSS key to make. - * rng [in] Initialized WC_RNG pointer. - * - * returns 0 on success. - * returns BAD_FUNC_ARG when a parameter is NULL. - * returns -1 on verify fail. - * */ -int wc_XmssKey_MakeKey(XmssKey* key, WC_RNG * rng) -{ - int ret = 0; - enum wc_XmssRc cb_rc = WC_XMSS_RC_NONE; - - if (key == NULL || rng == NULL) { - return BAD_FUNC_ARG; - } - - if (key->state != WC_XMSS_STATE_PARMSET) { - WOLFSSL_MSG("error: XmssKey not ready for generation"); - return -1; - } - - if (key->write_private_key == NULL || key->read_private_key == NULL) { - WOLFSSL_MSG("error: XmssKey write/read callbacks are not set"); - return -1; - } - - if (key->context == NULL) { - WOLFSSL_MSG("error: XmssKey context is not set"); - return -1; - } - - /* Allocate sk array. */ - ret = wc_XmssKey_AllocSk(key); - - if (ret != 0) { - return ret; - } - - xmssRng = rng; - - /* Finally make the secret public key pair. Immediately write it to NV - * storage and then clear from memory. */ - if (key->is_xmssmt) { - ret = xmssmt_keypair(key->pk, key->sk, key->oid); - } - else { - ret = xmss_keypair(key->pk, key->sk, key->oid); - } - - if (ret == 0) { - cb_rc = key->write_private_key(key->sk, key->sk_len, key->context); - } - - ForceZero(key->sk, key->sk_len); - - if (ret != 0) { - WOLFSSL_MSG("error: XMSS keypair failed"); - key->state = WC_XMSS_STATE_BAD; - return -1; - } - - if (cb_rc != WC_XMSS_RC_SAVED_TO_NV_MEMORY) { - WOLFSSL_MSG("error: XMSS write to NV storage failed"); - key->state = WC_XMSS_STATE_BAD; - return -1; - } - - key->state = WC_XMSS_STATE_OK; - - return 0; -} - -/* This function allocates the secret key buffer, and does a - * quick sanity check to verify the secret key is readable - * from NV storage, and then force zeros the key from memory. - * - * On success it sets the key state to OK. - * - * Use this function to resume signing with an already existing - * XMSS key pair. - * - * Write/read callbacks, and context data, must be set prior. - * Key must have parameters set. - * - * Returns 0 on success. - * - * This function and MakeKey are the only functions that allocate - * key->sk array. wc_XmssKey_FreeKey is the only function that - * deallocates key->sk. - * - * key [in] XMSS key to load. - * - * returns 0 on success. - * returns BAD_FUNC_ARG when a parameter is NULL. - * returns -1 on load fail. - * */ -int wc_XmssKey_Reload(XmssKey * key) -{ - int ret = 0; - enum wc_XmssRc cb_rc = WC_XMSS_RC_NONE; - - if (key == NULL) { - return BAD_FUNC_ARG; - } - - if (key->state != WC_XMSS_STATE_PARMSET) { - WOLFSSL_MSG("error: XmssKey not ready for reload"); - return -1; - } - - if (key->write_private_key == NULL || key->read_private_key == NULL) { - WOLFSSL_MSG("error: XmssKey write/read callbacks are not set"); - return -1; - } - - if (key->context == NULL) { - WOLFSSL_MSG("error: XmssKey context is not set"); - return -1; - } - - /* Allocate sk array. */ - ret = wc_XmssKey_AllocSk(key); - - if (ret != 0) { - return ret; - } - - /* Read the current secret key from NV storage. Force clear it - * immediately. This is just to sanity check the secret key - * is readable from permanent storage. */ - cb_rc = key->read_private_key(key->sk, key->sk_len, key->context); - ForceZero(key->sk, key->sk_len); - - if (cb_rc != WC_XMSS_RC_READ_TO_MEMORY) { - WOLFSSL_MSG("error: XMSS read from NV storage failed"); - key->state = WC_XMSS_STATE_BAD; - return -1; - } - - key->state = WC_XMSS_STATE_OK; - - return 0; -} - -/* Gets the XMSS/XMSS^MT private key length. - * - * Parameters must be set before calling this, as the key size (sk_bytes) - * is a function of the parameters. - * - * Note: the XMSS/XMSS^MT private key format is implementation specific, - * and not standardized. Interoperability of XMSS private keys should - * not be expected. - * - * key [in] The XMSS key. - * len [out] The length of the private key in bytes. - * - * returns 0 on success. - * returns BAD_FUNC_ARG when a parameter is NULL. - * returns -1 on sign fail. - * */ -int wc_XmssKey_GetPrivLen(const XmssKey * key, word32 * len) -{ - if (key == NULL || len == NULL) { - return BAD_FUNC_ARG; - } - - if (key->state != WC_XMSS_STATE_OK && key->state != WC_XMSS_STATE_PARMSET) { - /* params.sk_bytes not set yet. */ - return -1; - } - - *len = XMSS_OID_LEN + (word32) key->params.sk_bytes; - - return 0; -} - -/* Signs the message using the XMSS secret key, and - * updates the secret key on NV storage. - * - * Both operations must succeed to be considered - * successful. - * - * On success: sets key state to WC_XMSS_STATE_OK. - * On failure: sets key state to WC_XMSS_STATE_BAD - * - * If no signatures are left, sets state to WC_XMSS_STATE_NOSIGS. - */ -static void wc_XmssKey_SignUpdate(XmssKey* key, byte * sig, word32 * sigLen, - const byte * msg, int msgLen) -{ - int ret = -1; - unsigned long long len = *sigLen; - enum wc_XmssRc cb_rc = WC_XMSS_RC_NONE; - - /* Set the key state to bad by default. State is presumed bad - * unless a correct sign and update operation happen together. */ - key->state = WC_XMSS_STATE_BAD; - *sigLen = 0; - - /* Read the current secret key from NV storage.*/ - cb_rc = key->read_private_key(key->sk, key->sk_len, key->context); - - if (cb_rc == WC_XMSS_RC_READ_TO_MEMORY) { - /* Read was good. Now sign and update the secret key in memory. */ - if (key->is_xmssmt) { - ret = xmssmt_sign(key->sk, sig, &len, msg, msgLen); - } - else { - ret = xmss_sign(key->sk, sig, &len, msg, msgLen); - } - - if (ret == 0 && len == key->params.sig_bytes) { - /* The signature succeeded. key->sk is now updated and must be - * committed to NV storage. */ - cb_rc = key->write_private_key(key->sk, key->sk_len, key->context); - - if (cb_rc == WC_XMSS_RC_SAVED_TO_NV_MEMORY) { - /* key->sk was successfully committed to NV storage. Set the - * key state to OK, and set the sigLen. */ - key->state = WC_XMSS_STATE_OK; - *sigLen = (word32) len; - } - else { - /* Write to NV storage failed. Erase the signature from - * memory. */ - ForceZero(sig, key->params.sig_bytes); - WOLFSSL_MSG("error: XMSS write_private_key failed"); - } - } - else if (ret == -2) { - /* Signature space exhausted. */ - key->state = WC_XMSS_STATE_NOSIGS; - WOLFSSL_MSG("error: no XMSS signatures remaining"); - } - else { - /* Something failed or inconsistent in signature. Erase the - * signature just to be safe. */ - ForceZero(sig, key->params.sig_bytes); - WOLFSSL_MSG("error: XMSS sign failed"); - } - } - else { - /* Read from NV storage failed. */ - WOLFSSL_MSG("error: XMSS read_private_key failed"); - } - - /* Force zero the secret key from memory always. */ - ForceZero(key->sk, key->sk_len); - - return; -} - -/* Sign the message using the XMSS secret key. - * - * key [in] XMSS key to use to sign. - * sig [in] Buffer to write signature into. - * sigLen [in/out] On in, size of buffer. - * On out, the length of the signature in bytes. - * msg [in] Message to sign. - * msgLen [in] Length of the message in bytes. - * - * returns 0 on success. - * returns -1 on sign fail. - * returns BAD_FUNC_ARG when a parameter is NULL. - * returns BUFFER_E when sigLen is too small. - */ -int wc_XmssKey_Sign(XmssKey* key, byte * sig, word32 * sigLen, const byte * msg, - int msgLen) -{ - if (key == NULL || sig == NULL || sigLen == NULL || msg == NULL) { - return BAD_FUNC_ARG; - } - - if (msgLen <= 0) { - return BAD_FUNC_ARG; - } - - if (*sigLen < key->params.sig_bytes) { - /* Signature buffer too small. */ - WOLFSSL_MSG("error: XMSS sig buffer too small"); - return BUFFER_E; - } - - if (key->state == WC_XMSS_STATE_NOSIGS) { - WOLFSSL_MSG("error: XMSS signatures exhausted"); - return -1; - } - else if (key->state != WC_XMSS_STATE_OK) { - /* The key had an error the last time it was used, and we - * can't guarantee its state. */ - WOLFSSL_MSG("error: can't sign, XMSS key not in good state"); - return -1; - } - - if (key->write_private_key == NULL || key->read_private_key == NULL) { - WOLFSSL_MSG("error: XmssKey write/read callbacks are not set"); - return -1; - } - - if (key->context == NULL) { - WOLFSSL_MSG("error: XmssKey context is not set"); - return -1; - } - - /* Finally, sign and update the secret key. */ - wc_XmssKey_SignUpdate(key, sig, sigLen, msg, msgLen); - - return (key->state == WC_XMSS_STATE_OK) ? 0 : -1; -} - - -/* Check if more signatures are possible with key. - * - * @param [in] key XMSS key to check. - * @return 1 when signatures possible. - * @return 0 when key exhausted. - */ -int wc_XmssKey_SigsLeft(XmssKey* key) -{ - int ret = 0; - - /* Validate parameter. */ - if (key == NULL) { - ret = 0; - } - /* Validate state. */ - else if (key->state == WC_XMSS_STATE_NOSIGS) { - WOLFSSL_MSG("error: XMSS signatures exhausted"); - ret = 0; - } - else if (key->state != WC_XMSS_STATE_OK) { - WOLFSSL_MSG("error: can't sign, XMSS key not in good state"); - ret = 0; - } - /* Read the current secret key from NV storage.*/ - else if (key->read_private_key(key->sk, key->sk_len, key->context) != - WC_XMSS_RC_READ_TO_MEMORY) { - WOLFSSL_MSG("error: XMSS read_private_key failed"); - ret = 0; - } - else { - /* The following assumes core_fast implementation is used - * from patched xmss-reference. */ - const unsigned char* sk = (key->sk + XMSS_OID_LEN); - const xmss_params* params = &key->params; - unsigned long long idx = 0; - - if (key->is_xmssmt) { - for (uint64_t i = 0; i < params->index_bytes; i++) { - idx |= ((unsigned long long)sk[i]) - << 8 * (params->index_bytes - 1 - i); - } - } - else { - idx = ((unsigned long)sk[0] << 24) | - ((unsigned long)sk[1] << 16) | - ((unsigned long)sk[2] << 8) | sk[3]; - } - - ret = idx < ((1ULL << params->full_height) - 1); - - /* Force zero the secret key from memory always. */ - ForceZero(key->sk, key->sk_len); - } - - return ret; -} -#endif /* ifndef WOLFSSL_XMSS_VERIFY_ONLY*/ - -/* Get the XMSS/XMSS^MT public key length. The public key - * is static in size and does not depend on parameters, - * other than the choice of SHA256 as hashing function. - * - * key [in] The XMSS key. - * len [out] The length of the public key. - * - * returns 0 on success. - * returns BAD_FUNC_ARG when a parameter is NULL. - */ -int wc_XmssKey_GetPubLen(const XmssKey * key, word32 * len) -{ - if (key == NULL || len == NULL) { - return BAD_FUNC_ARG; - } - - *len = XMSS_SHA256_PUBLEN; - - return 0; -} - -/* Export a generated public key and parameter set from one XmssKey - * to another. Use this to prepare a signature verification XmssKey - * that is pub only. - * - * keyDst [out] Destination key for copy. - * keySrc [in] Source key for copy. - * - * returns 0 on success. - * returns BAD_FUNC_ARG when a parameter is NULL. - * */ -int wc_XmssKey_ExportPub(XmssKey * keyDst, const XmssKey * keySrc) -{ - if (keyDst == NULL || keySrc == NULL) { - return BAD_FUNC_ARG; - } - - ForceZero(keyDst, sizeof(XmssKey)); - - XMEMCPY(keyDst->pk, keySrc->pk, sizeof(keySrc->pk)); - - keyDst->oid = keySrc->oid; - keyDst->is_xmssmt = keySrc->is_xmssmt; - - /* Mark keyDst as verify only, to prevent misuse. */ - keyDst->state = WC_XMSS_STATE_VERIFYONLY; - - return 0; -} - -/* Exports the raw XMSS public key buffer from key to out buffer. - * The out buffer should be large enough to hold the public key, and - * outLen should indicate the size of the buffer. - * - * key [in] XMSS key. - * out [out] Array holding public key. - * outLen [in/out] On in, size of buffer. - * On out, the length of the public key. - * - * returns 0 on success. - * returns -1 on failure. - * returns BAD_FUNC_ARG when a parameter is NULL. - * returns BUFFER_E if array is too small. - * */ -int wc_XmssKey_ExportPubRaw(const XmssKey * key, byte * out, word32 * outLen) -{ - int ret = 0; - word32 pubLen = 0; - - if (key == NULL || out == NULL || outLen == NULL) { - return BAD_FUNC_ARG; - } - - ret = wc_XmssKey_GetPubLen(key, &pubLen); - - if (ret != 0) { - WOLFSSL_MSG("error: wc_XmssKey_GetPubLen failed"); - return -1; - } - - if (*outLen < pubLen) { - return BUFFER_E; - } - - XMEMCPY(out, key->pk, pubLen); - *outLen = pubLen; - - return 0; -} - -/* Imports a raw public key buffer from in array to XmssKey key. - * - * The XMSS parameters must be set first with wc_XmssKey_SetParamStr, - * and inLen must match the length returned by wc_XmssKey_GetPubLen. - * - * key [in] XMSS key. - * in [in] Array holding public key. - * inLen [in] Length of array in bytes. - * - * returns 0 on success. - * returns BAD_FUNC_ARG when a parameter is NULL. - * returns BUFFER_E if array is incorrect size. - * returns -1 on failure. - * */ -int wc_XmssKey_ImportPubRaw(XmssKey * key, const byte * in, word32 inLen) -{ - int ret = 0; - word32 pubLen = 0; - - if (key == NULL || in == NULL) { - return BAD_FUNC_ARG; - } - - if (key->state != WC_XMSS_STATE_PARMSET) { - /* XMSS key not ready for import. Param str must be set first. */ - WOLFSSL_MSG("error: XMSS key not ready for import"); - return -1; - } - - ret = wc_XmssKey_GetPubLen(key, &pubLen); - - if (ret != 0) { - WOLFSSL_MSG("error: wc_XmssKey_GetPubLen failed"); - return -1; - } - - if (inLen != pubLen) { - /* Something inconsistent. Parameters weren't set, or input - * pub key is wrong.*/ - return BUFFER_E; - } - - XMEMCPY(key->pk, in, pubLen); - - key->state = WC_XMSS_STATE_VERIFYONLY; - - return 0; -} - -/* Gets the XMSS/XMSS^MT signature length. - * - * Parameters must be set before calling this, as the signature size - * is a function of the parameters. - * - * Note: call this before wc_XmssKey_Sign or Verify so you know the - * length of the required signature buffer. - * - * key [in] XMSS key to use to sign. - * len [out] The length of the signature in bytes. - * - * returns 0 on success. - * returns BAD_FUNC_ARG when a parameter is NULL. - * returns -1 on sign fail. - * */ -int wc_XmssKey_GetSigLen(const XmssKey * key, word32 * len) -{ - if (key == NULL || len == NULL) { - return BAD_FUNC_ARG; - } - - if (key->state != WC_XMSS_STATE_OK && key->state != WC_XMSS_STATE_PARMSET) { - return -1; - } - - *len = key->params.sig_bytes; - - return 0; -} - -/* Verify the signature using the XMSS public key. - * - * Requires that XMSS parameters have been set with - * wc_XmssKey_SetParamStr, and that a public key is available - * from importing or MakeKey(). - * - * Call wc_XmssKey_GetSigLen() before this function to determine - * length of the signature buffer. - * - * key [in] XMSS key to use to verify. - * sig [in] Signature to verify. - * sigLen [in] Size of signature in bytes. - * msg [in] Message to verify. - * msgLen [in] Length of the message in bytes. - * - * returns 0 on success. - * returns -1 on verify fail. - * returns BAD_FUNC_ARG when a parameter is NULL. - * returns BUFFER_E when sigLen is too small. - */ -int wc_XmssKey_Verify(XmssKey * key, const byte * sig, word32 sigLen, - const byte * msg, int msgLen) -{ - int ret = 0; - unsigned long long msg_len = 0; - - msg_len = msgLen; - - if (key == NULL || sig == NULL || msg == NULL) { - return BAD_FUNC_ARG; - } - - if (sigLen < key->params.sig_bytes) { - /* Signature buffer too small. */ - return BUFFER_E; - } - - if (key->state != WC_XMSS_STATE_OK && - key->state != WC_XMSS_STATE_VERIFYONLY) { - /* XMSS key not ready for verification. Param str must be - * set first, and Reload() called. */ - WOLFSSL_MSG("error: XMSS key not ready for verification"); - return -1; - } - - if (key->is_xmssmt) { - ret = xmssmt_sign_open(msg, &msg_len, sig, sigLen, key->pk); - } - else { - ret = xmss_sign_open(msg, &msg_len, sig, sigLen, key->pk); - } - - if (ret != 0 || (int) msg_len != msgLen) { - WOLFSSL_MSG("error: XMSS verify failed"); - return -1; - } - - return ret; -} - -#endif /* WOLFSSL_HAVE_XMSS && HAVE_LIBXMSS */ diff --git a/wolfcrypt/src/wc_lms.c b/wolfcrypt/src/wc_lms.c index 01286cdc2b..99a3e19e81 100644 --- a/wolfcrypt/src/wc_lms.c +++ b/wolfcrypt/src/wc_lms.c @@ -21,7 +21,7 @@ #include -#if defined(WOLFSSL_HAVE_LMS) && defined(WOLFSSL_WC_LMS) +#if defined(WOLFSSL_HAVE_LMS) #if FIPS_VERSION3_GE(2,0,0) /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */ @@ -721,7 +721,7 @@ int wc_LmsKey_SetLmsParm(LmsKey* key, enum wc_LmsParm lmsParm) /* Set the parameters of an LMS key. * * Use this if you wish to set specific parameters not found in the - * wc_LmsParm predefined sets. See comments in lms.h for allowed + * wc_LmsParm predefined sets. See comments in wc_lms.h for allowed * parameters. * * Key must be inited before calling this. @@ -1597,4 +1597,4 @@ const byte * wc_LmsKey_GetKidFromPrivRaw(const byte * priv, word32 privSz) #endif -#endif /* WOLFSSL_HAVE_LMS && WOLFSSL_WC_LMS */ +#endif /* WOLFSSL_HAVE_LMS */ diff --git a/wolfcrypt/src/wc_lms_impl.c b/wolfcrypt/src/wc_lms_impl.c index a6fc89da7f..3d20bc0e0d 100644 --- a/wolfcrypt/src/wc_lms_impl.c +++ b/wolfcrypt/src/wc_lms_impl.c @@ -48,7 +48,7 @@ #include #endif -#if defined(WOLFSSL_HAVE_LMS) && defined(WOLFSSL_WC_LMS) +#ifdef WOLFSSL_HAVE_LMS /* Length of R in bytes. */ #define LMS_R_LEN 4 @@ -4108,5 +4108,5 @@ int wc_hss_verify(LmsState* state, const byte* pub, const byte* msg, return ret; } -#endif /* WOLFSSL_HAVE_LMS && WOLFSSL_WC_LMS */ +#endif /* WOLFSSL_HAVE_LMS */ diff --git a/wolfcrypt/src/wc_xmss.c b/wolfcrypt/src/wc_xmss.c index dfc6375e4e..2a80deb217 100644 --- a/wolfcrypt/src/wc_xmss.c +++ b/wolfcrypt/src/wc_xmss.c @@ -839,7 +839,7 @@ int wc_XmssKey_Init(XmssKey* key, void* heap, int devId) /* Set the XMSS key parameter string. * * The input string must be one of the supported parm set names in - * the "Name" section from the table in wolfssl/wolfcrypt/xmss.h, + * the "Name" section from the table in wolfssl/wolfcrypt/wc_xmss.h, * e.g. "XMSS-SHA2_10_256" or "XMSSMT-SHA2_20/4_256". * * @param [in] key The XMSS key to set. diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index afcf8b4f3c..0062efe6df 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -401,21 +401,11 @@ static const byte const_byte_array[] = "A+Gd\0\0\0"; #include #endif #if defined(WOLFSSL_HAVE_XMSS) - #include -#ifdef HAVE_LIBXMSS - #include -#else #include #endif -#endif #if defined(WOLFSSL_HAVE_LMS) - #include -#ifdef HAVE_LIBLMS - #include -#else #include #endif -#endif #if defined(WOLFSSL_HAVE_SLHDSA) #include #endif @@ -978,11 +968,9 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t scrypt_test(void); #endif #endif #if defined(WOLFSSL_HAVE_LMS) - #if !defined(WOLFSSL_SMALL_STACK) - #if (defined(WOLFSSL_WC_LMS) && (LMS_MAX_HEIGHT >= 10) && \ - !defined(WOLFSSL_NO_LMS_SHA256_256)) || defined(HAVE_LIBLMS) + #if !defined(WOLFSSL_SMALL_STACK) && (LMS_MAX_HEIGHT >= 10) && \ + !defined(WOLFSSL_NO_LMS_SHA256_256) WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test_verify_only(void); - #endif #endif #if !defined(WOLFSSL_LMS_VERIFY_ONLY) WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test(void); @@ -3178,14 +3166,12 @@ options: [-s max_relative_stack_bytes] [-m max_relative_heap_memory_bytes]\n\ #endif /* if defined(WOLFSSL_HAVE_XMSS) */ #if defined(WOLFSSL_HAVE_LMS) - #if !defined(WOLFSSL_SMALL_STACK) - #if (defined(WOLFSSL_WC_LMS) && (LMS_MAX_HEIGHT >= 10) && \ - !defined(WOLFSSL_NO_LMS_SHA256_256)) || defined(HAVE_LIBLMS) + #if !defined(WOLFSSL_SMALL_STACK) && (LMS_MAX_HEIGHT >= 10) && \ + !defined(WOLFSSL_NO_LMS_SHA256_256) if ( (ret = lms_test_verify_only()) != 0) TEST_FAIL("LMS Vfy test failed!\n", ret); else TEST_PASS("LMS Vfy test passed!\n"); - #endif #endif #if !defined(WOLFSSL_LMS_VERIFY_ONLY) @@ -53463,10 +53449,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test(void) #else byte sig[WC_TEST_LMS_SIG_LEN]; #endif -#if !defined(HAVE_LIBLMS) const byte * kid; word32 kidSz; -#endif WOLFSSL_ENTER("lms_test"); @@ -53525,7 +53509,6 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test(void) XMEMCPY(old_priv, priv, sizeof(priv)); -#if !defined(HAVE_LIBLMS) ret = wc_LmsKey_GetKid(NULL, NULL, NULL); if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); @@ -53552,7 +53535,6 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test(void) if (kidSz != WC_LMS_I_LEN) { ERROR_OUT(WC_TEST_RET_ENC_I(kidSz), out); } -#endif ret = wc_LmsKey_ExportPub(&verifyKey, &signingKey); if (ret != 0) { ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); } @@ -53663,9 +53645,8 @@ out: #endif /* if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) */ -#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_SMALL_STACK) -#if (defined(WOLFSSL_WC_LMS) && (LMS_MAX_HEIGHT >= 10) && \ - !defined(WOLFSSL_NO_LMS_SHA256_256)) || defined(HAVE_LIBLMS) +#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_SMALL_STACK) && \ + (LMS_MAX_HEIGHT >= 10) && !defined(WOLFSSL_NO_LMS_SHA256_256) /* A simple LMS verify only test. * @@ -54009,7 +53990,6 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test_verify_only(void) return ret; } -#endif #endif /* if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_SMALL_STACK) */ #if defined(WOLFSSL_HAVE_SLHDSA) diff --git a/wolfcrypt/test/test.h b/wolfcrypt/test/test.h index 75ea16234a..016ca6553a 100644 --- a/wolfcrypt/test/test.h +++ b/wolfcrypt/test/test.h @@ -314,8 +314,7 @@ extern WOLFSSL_TEST_SUBROUTINE wc_test_ret_t scrypt_test(void); #endif #if defined(WOLFSSL_HAVE_LMS) #if !defined(WOLFSSL_SMALL_STACK) - #if (defined(WOLFSSL_WC_LMS) && (LMS_MAX_HEIGHT >= 10) && \ - !defined(WOLFSSL_NO_LMS_SHA256_256)) || defined(HAVE_LIBLMS) + #if (LMS_MAX_HEIGHT >= 10) && !defined(WOLFSSL_NO_LMS_SHA256_256) extern WOLFSSL_TEST_SUBROUTINE wc_test_ret_t lms_test_verify_only(void); #endif #endif diff --git a/wolfssl/wolfcrypt/ext_lms.h b/wolfssl/wolfcrypt/ext_lms.h deleted file mode 100644 index b1bc4fccd2..0000000000 --- a/wolfssl/wolfcrypt/ext_lms.h +++ /dev/null @@ -1,62 +0,0 @@ -/* ext_lms.h - * - * Copyright (C) 2006-2026 wolfSSL Inc. - * - * This file is part of wolfSSL. - * - * wolfSSL is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * wolfSSL is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA - */ - -#ifndef EXT_LMS_H -#define EXT_LMS_H - -#if defined(WOLFSSL_HAVE_LMS) && defined(HAVE_LIBLMS) - -#include - -/* hash-sigs LMS HSS includes */ -#include - -#if defined(WOLFSSL_WC_LMS) -#error "This code is incompatible with wolfCrypt's implementation of LMS." -#endif - -/* - * The hash-sigs LMS lib supports from MIN_HSS_LEVELS to MAX_HSS_LEVELS - * number of levels of Merkle trees. It allows for the tree height and - * winternitz parameter to be unique per level. - */ - -/* hss structs */ -typedef struct hss_working_key hss_working_key; -typedef struct hss_extra_info hss_extra_info; - -struct LmsKey { - unsigned levels; /* Number of tree levels. */ - param_set_t lm_type[MAX_HSS_LEVELS]; /* Height param per level. */ - param_set_t lm_ots_type[MAX_HSS_LEVELS]; /* Winternitz param per level. */ - unsigned char pub[HSS_MAX_PUBLIC_KEY_LEN]; -#ifndef WOLFSSL_LMS_VERIFY_ONLY - hss_working_key * working_key; - wc_lms_write_private_key_cb write_private_key; /* Callback to write/update key. */ - wc_lms_read_private_key_cb read_private_key; /* Callback to read key. */ - void * context; /* Context arg passed to callbacks. */ - hss_extra_info info; -#endif /* ifndef WOLFSSL_LMS_VERIFY_ONLY */ - enum wc_LmsState state; -}; - -#endif /* WOLFSSL_HAVE_LMS */ -#endif /* EXT_LMS_H */ diff --git a/wolfssl/wolfcrypt/ext_xmss.h b/wolfssl/wolfcrypt/ext_xmss.h deleted file mode 100644 index d21d03ffbf..0000000000 --- a/wolfssl/wolfcrypt/ext_xmss.h +++ /dev/null @@ -1,53 +0,0 @@ -/* ext_xmss.h - * - * Copyright (C) 2006-2026 wolfSSL Inc. - * - * This file is part of wolfSSL. - * - * wolfSSL is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * wolfSSL is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA - */ - -#ifndef EXT_XMSS_H -#define EXT_XMSS_H - -#if defined(WOLFSSL_HAVE_XMSS) && defined(HAVE_LIBXMSS) - -#include - -#include -#include - -#if defined(WOLFSSL_WC_XMSS) - #error "This code is incompatible with wolfCrypt's implementation of XMSS." -#endif - -struct XmssKey { - unsigned char pk[XMSS_SHA256_PUBLEN]; - word32 oid; - int is_xmssmt; - xmss_params params; -#ifndef WOLFSSL_XMSS_VERIFY_ONLY - /* The secret key length is a function of xmss_params. */ - unsigned char * sk; - word32 sk_len; - wc_xmss_write_private_key_cb write_private_key; /* Callback to write/update key. */ - wc_xmss_read_private_key_cb read_private_key; /* Callback to read key. */ - void * context; /* Context arg passed to callbacks. */ -#endif /* ifndef WOLFSSL_XMSS_VERIFY_ONLY */ - enum wc_XmssState state; -}; - -#endif /* WOLFSSL_HAVE_XMSS */ -#endif /* EXT_XMSS_H */ diff --git a/wolfssl/wolfcrypt/include.am b/wolfssl/wolfcrypt/include.am index 7f07389a07..cbbc1442a6 100644 --- a/wolfssl/wolfcrypt/include.am +++ b/wolfssl/wolfcrypt/include.am @@ -83,12 +83,8 @@ nobase_include_HEADERS+= \ wolfssl/wolfcrypt/sm2.h \ wolfssl/wolfcrypt/sm3.h \ wolfssl/wolfcrypt/sm4.h \ - wolfssl/wolfcrypt/lms.h \ wolfssl/wolfcrypt/wc_lms.h \ - wolfssl/wolfcrypt/ext_lms.h \ - wolfssl/wolfcrypt/xmss.h \ wolfssl/wolfcrypt/wc_xmss.h \ - wolfssl/wolfcrypt/ext_xmss.h \ wolfssl/wolfcrypt/wc_slhdsa.h \ wolfssl/wolfcrypt/puf.h \ wolfssl/wolfcrypt/oid_sum.h diff --git a/wolfssl/wolfcrypt/lms.h b/wolfssl/wolfcrypt/lms.h deleted file mode 100644 index 19a7a0543c..0000000000 --- a/wolfssl/wolfcrypt/lms.h +++ /dev/null @@ -1,266 +0,0 @@ -/* lms.h - * - * Copyright (C) 2006-2026 wolfSSL Inc. - * - * This file is part of wolfSSL. - * - * wolfSSL is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * wolfSSL is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA - */ - -/*! - \file wolfssl/wolfcrypt/lms.h - */ - -#ifndef WOLF_CRYPT_LMS_H -#define WOLF_CRYPT_LMS_H - -#include -#include - -#ifdef WOLFSSL_HAVE_LMS - -/* Length of the Key ID. */ -#define WC_LMS_I_LEN 16 - -typedef struct LmsKey LmsKey; - -/* Private key write and read callbacks. */ -typedef int (*wc_lms_write_private_key_cb)(const byte * priv, word32 privSz, void *context); -typedef int (*wc_lms_read_private_key_cb)(byte * priv, word32 privSz, void *context); - -/* Return codes returned by private key callbacks. */ -enum wc_LmsRc { - WC_LMS_RC_NONE, - WC_LMS_RC_BAD_ARG, /* Bad arg in read or write callback. */ - WC_LMS_RC_WRITE_FAIL, /* Write or update private key failed. */ - WC_LMS_RC_READ_FAIL, /* Read private key failed. */ - WC_LMS_RC_SAVED_TO_NV_MEMORY, /* Wrote private key to nonvolatile storage. */ - WC_LMS_RC_READ_TO_MEMORY /* Read private key from storage. */ -}; - -/* LMS/HSS signatures are defined by 3 parameters: - * levels: number of levels of Merkle trees. - * height: height of an individual Merkle tree. - * winternitz: number of bits from hash used in a Winternitz chain. - * - * The acceptable parameter values are those in RFC8554: - * levels = {1..8} - * height = {5, 10, 15, 20, 25} - * winternitz = {1, 2, 4, 8} - * - * The number of available signatures is: - * N = 2 ** (levels * height) - * - * Signature sizes are determined by levels and winternitz - * parameters primarily, and height to a lesser extent: - * - Larger levels values increase signature size significantly. - * - Larger height values increase signature size moderately. - * - Larger winternitz values will reduce the signature size, at - * the expense of longer key generation and sign/verify times. - * - * Key generation time is strongly determined by the height of - * the first level tree. A 3 level, 5 height tree is much faster - * than 1 level, 15 height at initial key gen, even if the number - * of available signatures is the same. - * */ - -/* Predefined LMS/HSS parameter sets for convenience. - * - * Not predefining many sets with Winternitz=1, because the signatures - * will be large. */ -enum wc_LmsParm { -#ifndef WOLFSSL_NO_LMS_SHA256_256 - WC_LMS_PARM_NONE = 0, - WC_LMS_PARM_L1_H5_W1 = 1, - WC_LMS_PARM_L1_H5_W2 = 2, - WC_LMS_PARM_L1_H5_W4 = 3, - WC_LMS_PARM_L1_H5_W8 = 4, - WC_LMS_PARM_L1_H10_W2 = 5, - WC_LMS_PARM_L1_H10_W4 = 6, - WC_LMS_PARM_L1_H10_W8 = 7, - WC_LMS_PARM_L1_H15_W2 = 8, - WC_LMS_PARM_L1_H15_W4 = 9, - WC_LMS_PARM_L1_H15_W8 = 10, - WC_LMS_PARM_L1_H20_W2 = 11, - WC_LMS_PARM_L1_H20_W4 = 12, - WC_LMS_PARM_L1_H20_W8 = 13, - WC_LMS_PARM_L2_H5_W2 = 14, - WC_LMS_PARM_L2_H5_W4 = 15, - WC_LMS_PARM_L2_H5_W8 = 16, - WC_LMS_PARM_L2_H10_W2 = 17, - WC_LMS_PARM_L2_H10_W4 = 18, - WC_LMS_PARM_L2_H10_W8 = 19, - WC_LMS_PARM_L2_H15_W2 = 20, - WC_LMS_PARM_L2_H15_W4 = 21, - WC_LMS_PARM_L2_H15_W8 = 22, - WC_LMS_PARM_L2_H20_W2 = 23, - WC_LMS_PARM_L2_H20_W4 = 24, - WC_LMS_PARM_L2_H20_W8 = 25, - WC_LMS_PARM_L3_H5_W2 = 26, - WC_LMS_PARM_L3_H5_W4 = 27, - WC_LMS_PARM_L3_H5_W8 = 28, - WC_LMS_PARM_L3_H10_W4 = 29, - WC_LMS_PARM_L3_H10_W8 = 30, - WC_LMS_PARM_L4_H5_W2 = 31, - WC_LMS_PARM_L4_H5_W4 = 32, - WC_LMS_PARM_L4_H5_W8 = 33, - WC_LMS_PARM_L4_H10_W4 = 34, - WC_LMS_PARM_L4_H10_W8 = 35, - /* H25 parameter sets for SHA-256/256 */ - WC_LMS_PARM_L1_H25_W1 = 56, - WC_LMS_PARM_L1_H25_W2 = 57, - WC_LMS_PARM_L1_H25_W4 = 58, - WC_LMS_PARM_L1_H25_W8 = 59, - /* W1 for non-H5 heights */ - WC_LMS_PARM_L1_H10_W1 = 60, - WC_LMS_PARM_L1_H15_W1 = 61, - WC_LMS_PARM_L1_H20_W1 = 62, -#endif - -#ifdef WOLFSSL_LMS_SHA256_192 - WC_LMS_PARM_SHA256_192_L1_H5_W1 = 36, - WC_LMS_PARM_SHA256_192_L1_H5_W2 = 37, - WC_LMS_PARM_SHA256_192_L1_H5_W4 = 38, - WC_LMS_PARM_SHA256_192_L1_H5_W8 = 39, - WC_LMS_PARM_SHA256_192_L1_H10_W2 = 40, - WC_LMS_PARM_SHA256_192_L1_H10_W4 = 41, - WC_LMS_PARM_SHA256_192_L1_H10_W8 = 42, - WC_LMS_PARM_SHA256_192_L1_H15_W2 = 43, - WC_LMS_PARM_SHA256_192_L1_H15_W4 = 44, - WC_LMS_PARM_SHA256_192_L1_H20_W2 = 53, - WC_LMS_PARM_SHA256_192_L1_H20_W4 = 54, - WC_LMS_PARM_SHA256_192_L1_H20_W8 = 55, - WC_LMS_PARM_SHA256_192_L2_H10_W2 = 45, - WC_LMS_PARM_SHA256_192_L2_H10_W4 = 46, - WC_LMS_PARM_SHA256_192_L2_H10_W8 = 47, - WC_LMS_PARM_SHA256_192_L3_H5_W2 = 48, - WC_LMS_PARM_SHA256_192_L3_H5_W4 = 49, - WC_LMS_PARM_SHA256_192_L3_H5_W8 = 50, - WC_LMS_PARM_SHA256_192_L3_H10_W4 = 51, - WC_LMS_PARM_SHA256_192_L4_H5_W8 = 52, - /* H25 for SHA-256/192 */ - WC_LMS_PARM_SHA256_192_L1_H25_W1 = 63, - WC_LMS_PARM_SHA256_192_L1_H25_W2 = 64, - WC_LMS_PARM_SHA256_192_L1_H25_W4 = 65, - WC_LMS_PARM_SHA256_192_L1_H25_W8 = 66, - /* W1 for non-H5 heights (SHA-256/192) */ - WC_LMS_PARM_SHA256_192_L1_H10_W1 = 67, - WC_LMS_PARM_SHA256_192_L1_H15_W1 = 68, - WC_LMS_PARM_SHA256_192_L1_H20_W1 = 69, - WC_LMS_PARM_SHA256_192_L1_H15_W8 = 70, -#endif - -#ifdef WOLFSSL_LMS_SHAKE256 - /* SHAKE256/256, 32-byte output */ - WC_LMS_PARM_SHAKE_L1_H5_W1 = 100, - WC_LMS_PARM_SHAKE_L1_H5_W2 = 101, - WC_LMS_PARM_SHAKE_L1_H5_W4 = 102, - WC_LMS_PARM_SHAKE_L1_H5_W8 = 103, - WC_LMS_PARM_SHAKE_L1_H10_W1 = 104, - WC_LMS_PARM_SHAKE_L1_H10_W2 = 105, - WC_LMS_PARM_SHAKE_L1_H10_W4 = 106, - WC_LMS_PARM_SHAKE_L1_H10_W8 = 107, - WC_LMS_PARM_SHAKE_L1_H15_W1 = 108, - WC_LMS_PARM_SHAKE_L1_H15_W2 = 109, - WC_LMS_PARM_SHAKE_L1_H15_W4 = 110, - WC_LMS_PARM_SHAKE_L1_H15_W8 = 111, - WC_LMS_PARM_SHAKE_L1_H20_W1 = 112, - WC_LMS_PARM_SHAKE_L1_H20_W2 = 113, - WC_LMS_PARM_SHAKE_L1_H20_W4 = 114, - WC_LMS_PARM_SHAKE_L1_H20_W8 = 115, - WC_LMS_PARM_SHAKE_L1_H25_W1 = 116, - WC_LMS_PARM_SHAKE_L1_H25_W2 = 117, - WC_LMS_PARM_SHAKE_L1_H25_W4 = 118, - WC_LMS_PARM_SHAKE_L1_H25_W8 = 119, - /* SHAKE256/192, 24-byte output */ - WC_LMS_PARM_SHAKE192_L1_H5_W1 = 120, - WC_LMS_PARM_SHAKE192_L1_H5_W2 = 121, - WC_LMS_PARM_SHAKE192_L1_H5_W4 = 122, - WC_LMS_PARM_SHAKE192_L1_H5_W8 = 123, - WC_LMS_PARM_SHAKE192_L1_H10_W1 = 124, - WC_LMS_PARM_SHAKE192_L1_H10_W2 = 125, - WC_LMS_PARM_SHAKE192_L1_H10_W4 = 126, - WC_LMS_PARM_SHAKE192_L1_H10_W8 = 127, - WC_LMS_PARM_SHAKE192_L1_H15_W1 = 128, - WC_LMS_PARM_SHAKE192_L1_H15_W2 = 129, - WC_LMS_PARM_SHAKE192_L1_H15_W4 = 130, - WC_LMS_PARM_SHAKE192_L1_H15_W8 = 131, - WC_LMS_PARM_SHAKE192_L1_H20_W1 = 132, - WC_LMS_PARM_SHAKE192_L1_H20_W2 = 133, - WC_LMS_PARM_SHAKE192_L1_H20_W4 = 134, - WC_LMS_PARM_SHAKE192_L1_H20_W8 = 135, - WC_LMS_PARM_SHAKE192_L1_H25_W1 = 136, - WC_LMS_PARM_SHAKE192_L1_H25_W2 = 137, - WC_LMS_PARM_SHAKE192_L1_H25_W4 = 138, - WC_LMS_PARM_SHAKE192_L1_H25_W8 = 139, -#endif -}; - -/* enum wc_LmsState is to help track the state of an LMS/HSS Key. */ -enum wc_LmsState { - WC_LMS_STATE_FREED, /* Key has been freed from memory. */ - WC_LMS_STATE_INITED, /* Key has been inited, ready to set params.*/ - WC_LMS_STATE_PARMSET, /* Params are set, ready to MakeKey or Reload. */ - WC_LMS_STATE_OK, /* Able to sign signatures and verify. */ - WC_LMS_STATE_VERIFYONLY, /* A public only LmsKey. */ - WC_LMS_STATE_BAD, /* Can't guarantee key's state. */ - WC_LMS_STATE_NOSIGS /* Signatures exhausted. */ -}; - -#ifdef __cplusplus - extern "C" { -#endif -WOLFSSL_API int wc_LmsKey_Init(LmsKey * key, void * heap, int devId); -WOLFSSL_API int wc_LmsKey_SetLmsParm(LmsKey * key, enum wc_LmsParm lmsParm); -WOLFSSL_API int wc_LmsKey_SetParameters(LmsKey * key, int levels, - int height, int winternitz); -WOLFSSL_API int wc_LmsKey_GetParameters(const LmsKey * key, int * levels, - int * height, int * winternitz); -#ifndef WOLFSSL_LMS_VERIFY_ONLY -WOLFSSL_API int wc_LmsKey_SetWriteCb(LmsKey * key, - wc_lms_write_private_key_cb write_cb); -WOLFSSL_API int wc_LmsKey_SetReadCb(LmsKey * key, - wc_lms_read_private_key_cb read_cb); -WOLFSSL_API int wc_LmsKey_SetContext(LmsKey * key, void * context); -WOLFSSL_API int wc_LmsKey_MakeKey(LmsKey * key, WC_RNG * rng); -WOLFSSL_API int wc_LmsKey_Reload(LmsKey * key); -WOLFSSL_API int wc_LmsKey_GetPrivLen(const LmsKey * key, word32 * len); -WOLFSSL_API int wc_LmsKey_Sign(LmsKey * key, byte * sig, word32 * sigSz, - const byte * msg, int msgSz); -WOLFSSL_API int wc_LmsKey_SigsLeft(LmsKey * key); -#endif /* ifndef WOLFSSL_LMS_VERIFY_ONLY */ -WOLFSSL_API void wc_LmsKey_Free(LmsKey * key); -WOLFSSL_API int wc_LmsKey_GetSigLen(const LmsKey * key, word32 * len); -WOLFSSL_API int wc_LmsKey_GetPubLen(const LmsKey * key, word32 * len); -WOLFSSL_API int wc_LmsKey_ExportPub(LmsKey * keyDst, const LmsKey * keySrc); -WOLFSSL_API int wc_LmsKey_ExportPubRaw(const LmsKey * key, byte * out, - word32 * outLen); -WOLFSSL_API int wc_LmsKey_ImportPubRaw(LmsKey * key, const byte * in, - word32 inLen); -WOLFSSL_API int wc_LmsKey_Verify(LmsKey * key, const byte * sig, word32 sigSz, - const byte * msg, int msgSz); -WOLFSSL_API const char * wc_LmsKey_ParmToStr(enum wc_LmsParm lmsParm); -WOLFSSL_API const char * wc_LmsKey_RcToStr(enum wc_LmsRc lmsRc); - -WOLFSSL_API int wc_LmsKey_GetKid(LmsKey * key, const byte ** kid, - word32* kidSz); -WOLFSSL_API const byte * wc_LmsKey_GetKidFromPrivRaw(const byte * priv, - word32 privSz); -#ifdef __cplusplus - } /* extern "C" */ -#endif - -#endif /* WOLFSSL_HAVE_LMS */ -#endif /* WOLF_CRYPT_LMS_H */ diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index b56fc5e190..c1746c5fd1 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -4596,8 +4596,6 @@ extern void uITRON4_free(void *p) ; #endif #if (defined(HAVE_LIBOQS) || \ - defined(HAVE_LIBXMSS) || \ - defined(HAVE_LIBLMS) || \ defined(WOLFSSL_DUAL_ALG_CERTS) || \ defined(HAVE_ASCON)) && \ !defined(WOLFSSL_EXPERIMENTAL_SETTINGS) @@ -4658,15 +4656,15 @@ extern void uITRON4_free(void *p) ; /* (D)TLS v1.3 requires 64-bit number wrappers as does XMSS and LMS. */ #if defined(WOLFSSL_TLS13) || defined(WOLFSSL_DTLS_DROP_STATS) || \ - (defined(WOLFSSL_WC_XMSS) && (!defined(WOLFSSL_XMSS_MAX_HEIGHT) || \ - WOLFSSL_XMSS_MAX_HEIGHT > 32)) || (defined(WOLFSSL_WC_LMS) && \ + (defined(WOLFSSL_HAVE_XMSS) && (!defined(WOLFSSL_XMSS_MAX_HEIGHT) || \ + WOLFSSL_XMSS_MAX_HEIGHT > 32)) || (defined(WOLFSSL_HAVE_LMS) && \ !defined(WOLFSSL_LMS_VERIFY_ONLY)) #undef WOLFSSL_W64_WRAPPER #define WOLFSSL_W64_WRAPPER #endif /* wc_xmss and wc_lms require these misc.c functions. */ -#if defined(WOLFSSL_WC_XMSS) || defined(WOLFSSL_WC_LMS) +#if defined(WOLFSSL_HAVE_XMSS) || defined(WOLFSSL_HAVE_LMS) #undef WOLFSSL_NO_INT_ENCODE #undef WOLFSSL_NO_INT_DECODE #endif diff --git a/wolfssl/wolfcrypt/wc_lms.h b/wolfssl/wolfcrypt/wc_lms.h index 34f77279a0..e12d99431e 100644 --- a/wolfssl/wolfcrypt/wc_lms.h +++ b/wolfssl/wolfcrypt/wc_lms.h @@ -19,6 +19,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ +/*! + \file wolfssl/wolfcrypt/wc_lms.h + */ + /* Implementation based on: * RFC 8554: Leighton-Micali Hash-Based Signatures * https://datatracker.ietf.org/doc/html/rfc8554 @@ -58,7 +62,7 @@ * C = Cache bits * To mimic the dynamic memory usage of XMSS, use 3/3. * - * WOLFSSL_LMS_NO_SIGN SMOOTHING Default: OFF + * WOLFSSL_LMS_NO_SIGN_SMOOTHING Default: OFF * Disable precalculation of next subtree. * Use less dynamic memory. * At certain indexes, signing will take a long time compared to the mean. @@ -90,9 +94,9 @@ #include -#if defined(WOLFSSL_HAVE_LMS) && defined(WOLFSSL_WC_LMS) +#ifdef WOLFSSL_HAVE_LMS -#include +#include #include #ifdef WOLFSSL_LMS_SHAKE256 #include @@ -104,6 +108,192 @@ #define WC_LMS_FULL_HASH #endif +/* Length of the Key ID. */ +#define WC_LMS_I_LEN 16 + +/* Private key write and read callbacks. */ +typedef int (*wc_lms_write_private_key_cb)(const byte * priv, word32 privSz, void *context); +typedef int (*wc_lms_read_private_key_cb)(byte * priv, word32 privSz, void *context); + +/* Return codes returned by private key callbacks. */ +enum wc_LmsRc { + WC_LMS_RC_NONE, + WC_LMS_RC_BAD_ARG, /* Bad arg in read or write callback. */ + WC_LMS_RC_WRITE_FAIL, /* Write or update private key failed. */ + WC_LMS_RC_READ_FAIL, /* Read private key failed. */ + WC_LMS_RC_SAVED_TO_NV_MEMORY, /* Wrote private key to nonvolatile storage. */ + WC_LMS_RC_READ_TO_MEMORY /* Read private key from storage. */ +}; + +/* LMS/HSS signatures are defined by 3 parameters: + * levels: number of levels of Merkle trees. + * height: height of an individual Merkle tree. + * winternitz: number of bits from hash used in a Winternitz chain. + * + * The acceptable parameter values are those in RFC8554: + * levels = {1..8} + * height = {5, 10, 15, 20, 25} + * winternitz = {1, 2, 4, 8} + * + * The number of available signatures is: + * N = 2 ** (levels * height) + * + * Signature sizes are determined by levels and winternitz + * parameters primarily, and height to a lesser extent: + * - Larger levels values increase signature size significantly. + * - Larger height values increase signature size moderately. + * - Larger winternitz values will reduce the signature size, at + * the expense of longer key generation and sign/verify times. + * + * Key generation time is strongly determined by the height of + * the first level tree. A 3 level, 5 height tree is much faster + * than 1 level, 15 height at initial key gen, even if the number + * of available signatures is the same. + * */ + +/* Predefined LMS/HSS parameter sets for convenience. + * + * Not predefining many sets with Winternitz=1, because the signatures + * will be large. */ +enum wc_LmsParm { +#ifndef WOLFSSL_NO_LMS_SHA256_256 + WC_LMS_PARM_NONE = 0, + WC_LMS_PARM_L1_H5_W1 = 1, + WC_LMS_PARM_L1_H5_W2 = 2, + WC_LMS_PARM_L1_H5_W4 = 3, + WC_LMS_PARM_L1_H5_W8 = 4, + WC_LMS_PARM_L1_H10_W2 = 5, + WC_LMS_PARM_L1_H10_W4 = 6, + WC_LMS_PARM_L1_H10_W8 = 7, + WC_LMS_PARM_L1_H15_W2 = 8, + WC_LMS_PARM_L1_H15_W4 = 9, + WC_LMS_PARM_L1_H15_W8 = 10, + WC_LMS_PARM_L1_H20_W2 = 11, + WC_LMS_PARM_L1_H20_W4 = 12, + WC_LMS_PARM_L1_H20_W8 = 13, + WC_LMS_PARM_L2_H5_W2 = 14, + WC_LMS_PARM_L2_H5_W4 = 15, + WC_LMS_PARM_L2_H5_W8 = 16, + WC_LMS_PARM_L2_H10_W2 = 17, + WC_LMS_PARM_L2_H10_W4 = 18, + WC_LMS_PARM_L2_H10_W8 = 19, + WC_LMS_PARM_L2_H15_W2 = 20, + WC_LMS_PARM_L2_H15_W4 = 21, + WC_LMS_PARM_L2_H15_W8 = 22, + WC_LMS_PARM_L2_H20_W2 = 23, + WC_LMS_PARM_L2_H20_W4 = 24, + WC_LMS_PARM_L2_H20_W8 = 25, + WC_LMS_PARM_L3_H5_W2 = 26, + WC_LMS_PARM_L3_H5_W4 = 27, + WC_LMS_PARM_L3_H5_W8 = 28, + WC_LMS_PARM_L3_H10_W4 = 29, + WC_LMS_PARM_L3_H10_W8 = 30, + WC_LMS_PARM_L4_H5_W2 = 31, + WC_LMS_PARM_L4_H5_W4 = 32, + WC_LMS_PARM_L4_H5_W8 = 33, + WC_LMS_PARM_L4_H10_W4 = 34, + WC_LMS_PARM_L4_H10_W8 = 35, + /* H25 parameter sets for SHA-256/256 */ + WC_LMS_PARM_L1_H25_W1 = 56, + WC_LMS_PARM_L1_H25_W2 = 57, + WC_LMS_PARM_L1_H25_W4 = 58, + WC_LMS_PARM_L1_H25_W8 = 59, + /* W1 for non-H5 heights */ + WC_LMS_PARM_L1_H10_W1 = 60, + WC_LMS_PARM_L1_H15_W1 = 61, + WC_LMS_PARM_L1_H20_W1 = 62, +#endif + +#ifdef WOLFSSL_LMS_SHA256_192 + WC_LMS_PARM_SHA256_192_L1_H5_W1 = 36, + WC_LMS_PARM_SHA256_192_L1_H5_W2 = 37, + WC_LMS_PARM_SHA256_192_L1_H5_W4 = 38, + WC_LMS_PARM_SHA256_192_L1_H5_W8 = 39, + WC_LMS_PARM_SHA256_192_L1_H10_W2 = 40, + WC_LMS_PARM_SHA256_192_L1_H10_W4 = 41, + WC_LMS_PARM_SHA256_192_L1_H10_W8 = 42, + WC_LMS_PARM_SHA256_192_L1_H15_W2 = 43, + WC_LMS_PARM_SHA256_192_L1_H15_W4 = 44, + WC_LMS_PARM_SHA256_192_L1_H20_W2 = 53, + WC_LMS_PARM_SHA256_192_L1_H20_W4 = 54, + WC_LMS_PARM_SHA256_192_L1_H20_W8 = 55, + WC_LMS_PARM_SHA256_192_L2_H10_W2 = 45, + WC_LMS_PARM_SHA256_192_L2_H10_W4 = 46, + WC_LMS_PARM_SHA256_192_L2_H10_W8 = 47, + WC_LMS_PARM_SHA256_192_L3_H5_W2 = 48, + WC_LMS_PARM_SHA256_192_L3_H5_W4 = 49, + WC_LMS_PARM_SHA256_192_L3_H5_W8 = 50, + WC_LMS_PARM_SHA256_192_L3_H10_W4 = 51, + WC_LMS_PARM_SHA256_192_L4_H5_W8 = 52, + /* H25 for SHA-256/192 */ + WC_LMS_PARM_SHA256_192_L1_H25_W1 = 63, + WC_LMS_PARM_SHA256_192_L1_H25_W2 = 64, + WC_LMS_PARM_SHA256_192_L1_H25_W4 = 65, + WC_LMS_PARM_SHA256_192_L1_H25_W8 = 66, + /* W1 for non-H5 heights (SHA-256/192) */ + WC_LMS_PARM_SHA256_192_L1_H10_W1 = 67, + WC_LMS_PARM_SHA256_192_L1_H15_W1 = 68, + WC_LMS_PARM_SHA256_192_L1_H20_W1 = 69, + WC_LMS_PARM_SHA256_192_L1_H15_W8 = 70, +#endif + +#ifdef WOLFSSL_LMS_SHAKE256 + /* SHAKE256/256, 32-byte output */ + WC_LMS_PARM_SHAKE_L1_H5_W1 = 100, + WC_LMS_PARM_SHAKE_L1_H5_W2 = 101, + WC_LMS_PARM_SHAKE_L1_H5_W4 = 102, + WC_LMS_PARM_SHAKE_L1_H5_W8 = 103, + WC_LMS_PARM_SHAKE_L1_H10_W1 = 104, + WC_LMS_PARM_SHAKE_L1_H10_W2 = 105, + WC_LMS_PARM_SHAKE_L1_H10_W4 = 106, + WC_LMS_PARM_SHAKE_L1_H10_W8 = 107, + WC_LMS_PARM_SHAKE_L1_H15_W1 = 108, + WC_LMS_PARM_SHAKE_L1_H15_W2 = 109, + WC_LMS_PARM_SHAKE_L1_H15_W4 = 110, + WC_LMS_PARM_SHAKE_L1_H15_W8 = 111, + WC_LMS_PARM_SHAKE_L1_H20_W1 = 112, + WC_LMS_PARM_SHAKE_L1_H20_W2 = 113, + WC_LMS_PARM_SHAKE_L1_H20_W4 = 114, + WC_LMS_PARM_SHAKE_L1_H20_W8 = 115, + WC_LMS_PARM_SHAKE_L1_H25_W1 = 116, + WC_LMS_PARM_SHAKE_L1_H25_W2 = 117, + WC_LMS_PARM_SHAKE_L1_H25_W4 = 118, + WC_LMS_PARM_SHAKE_L1_H25_W8 = 119, + /* SHAKE256/192, 24-byte output */ + WC_LMS_PARM_SHAKE192_L1_H5_W1 = 120, + WC_LMS_PARM_SHAKE192_L1_H5_W2 = 121, + WC_LMS_PARM_SHAKE192_L1_H5_W4 = 122, + WC_LMS_PARM_SHAKE192_L1_H5_W8 = 123, + WC_LMS_PARM_SHAKE192_L1_H10_W1 = 124, + WC_LMS_PARM_SHAKE192_L1_H10_W2 = 125, + WC_LMS_PARM_SHAKE192_L1_H10_W4 = 126, + WC_LMS_PARM_SHAKE192_L1_H10_W8 = 127, + WC_LMS_PARM_SHAKE192_L1_H15_W1 = 128, + WC_LMS_PARM_SHAKE192_L1_H15_W2 = 129, + WC_LMS_PARM_SHAKE192_L1_H15_W4 = 130, + WC_LMS_PARM_SHAKE192_L1_H15_W8 = 131, + WC_LMS_PARM_SHAKE192_L1_H20_W1 = 132, + WC_LMS_PARM_SHAKE192_L1_H20_W2 = 133, + WC_LMS_PARM_SHAKE192_L1_H20_W4 = 134, + WC_LMS_PARM_SHAKE192_L1_H20_W8 = 135, + WC_LMS_PARM_SHAKE192_L1_H25_W1 = 136, + WC_LMS_PARM_SHAKE192_L1_H25_W2 = 137, + WC_LMS_PARM_SHAKE192_L1_H25_W4 = 138, + WC_LMS_PARM_SHAKE192_L1_H25_W8 = 139, +#endif +}; + +/* enum wc_LmsState is to help track the state of an LMS/HSS Key. */ +enum wc_LmsState { + WC_LMS_STATE_FREED, /* Key has been freed from memory. */ + WC_LMS_STATE_INITED, /* Key has been inited, ready to set params.*/ + WC_LMS_STATE_PARMSET, /* Params are set, ready to MakeKey or Reload. */ + WC_LMS_STATE_OK, /* Able to sign signatures and verify. */ + WC_LMS_STATE_VERIFYONLY, /* A public only LmsKey. */ + WC_LMS_STATE_BAD, /* Can't guarantee key's state. */ + WC_LMS_STATE_NOSIGS /* Signatures exhausted. */ +}; + #ifdef WOLFSSL_LMS_MAX_LEVELS /* Maximum number of levels of trees supported by implementation. */ #define LMS_MAX_LEVELS WOLFSSL_LMS_MAX_LEVELS @@ -546,7 +736,7 @@ typedef struct HssPrivKey { #endif } HssPrivKey; -struct LmsKey { +typedef struct LmsKey { /* Public key. */ ALIGN16 byte pub[HSS_PUBLIC_KEY_LEN(LMS_MAX_NODE_LEN)]; #ifndef WOLFSSL_LMS_VERIFY_ONLY @@ -575,7 +765,48 @@ struct LmsKey { /* Device Identifier. */ int devId; #endif -}; +} LmsKey; + +#ifdef __cplusplus + extern "C" { +#endif + +WOLFSSL_API int wc_LmsKey_Init(LmsKey * key, void * heap, int devId); +WOLFSSL_API int wc_LmsKey_SetLmsParm(LmsKey * key, enum wc_LmsParm lmsParm); +WOLFSSL_API int wc_LmsKey_SetParameters(LmsKey * key, int levels, + int height, int winternitz); +WOLFSSL_API int wc_LmsKey_GetParameters(const LmsKey * key, int * levels, + int * height, int * winternitz); +#ifndef WOLFSSL_LMS_VERIFY_ONLY +WOLFSSL_API int wc_LmsKey_SetWriteCb(LmsKey * key, + wc_lms_write_private_key_cb write_cb); +WOLFSSL_API int wc_LmsKey_SetReadCb(LmsKey * key, + wc_lms_read_private_key_cb read_cb); +WOLFSSL_API int wc_LmsKey_SetContext(LmsKey * key, void * context); +WOLFSSL_API int wc_LmsKey_MakeKey(LmsKey * key, WC_RNG * rng); +WOLFSSL_API int wc_LmsKey_Reload(LmsKey * key); +WOLFSSL_API int wc_LmsKey_GetPrivLen(const LmsKey * key, word32 * len); +WOLFSSL_API int wc_LmsKey_Sign(LmsKey * key, byte * sig, word32 * sigSz, + const byte * msg, int msgSz); +WOLFSSL_API int wc_LmsKey_SigsLeft(LmsKey * key); +#endif /* ifndef WOLFSSL_LMS_VERIFY_ONLY */ +WOLFSSL_API void wc_LmsKey_Free(LmsKey * key); +WOLFSSL_API int wc_LmsKey_GetSigLen(const LmsKey * key, word32 * len); +WOLFSSL_API int wc_LmsKey_GetPubLen(const LmsKey * key, word32 * len); +WOLFSSL_API int wc_LmsKey_ExportPub(LmsKey * keyDst, const LmsKey * keySrc); +WOLFSSL_API int wc_LmsKey_ExportPubRaw(const LmsKey * key, byte * out, + word32 * outLen); +WOLFSSL_API int wc_LmsKey_ImportPubRaw(LmsKey * key, const byte * in, + word32 inLen); +WOLFSSL_API int wc_LmsKey_Verify(LmsKey * key, const byte * sig, word32 sigSz, + const byte * msg, int msgSz); +WOLFSSL_API const char * wc_LmsKey_ParmToStr(enum wc_LmsParm lmsParm); +WOLFSSL_API const char * wc_LmsKey_RcToStr(enum wc_LmsRc lmsRc); + +WOLFSSL_API int wc_LmsKey_GetKid(LmsKey * key, const byte ** kid, + word32* kidSz); +WOLFSSL_API const byte * wc_LmsKey_GetKidFromPrivRaw(const byte * priv, + word32 privSz); int wc_hss_make_key(LmsState* state, WC_RNG* rng, byte* priv_raw, HssPrivKey* priv_key, byte* priv_data, byte* pub); @@ -588,6 +819,10 @@ WOLFSSL_API int wc_hss_verify(LmsState* state, const byte* pub, const byte* msg, word32 msgSz, const byte* sig, word32 sigSz); -#endif /* WOLFSSL_HAVE_LMS && WOLFSSL_WC_LMS */ +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* WOLFSSL_HAVE_LMS */ #endif /* WC_LMS_H */ diff --git a/wolfssl/wolfcrypt/wc_xmss.h b/wolfssl/wolfcrypt/wc_xmss.h index 200cd4322e..5ed8823b65 100644 --- a/wolfssl/wolfcrypt/wc_xmss.h +++ b/wolfssl/wolfcrypt/wc_xmss.h @@ -19,6 +19,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ +/*! + \file wolfssl/wolfcrypt/wc_xmss.h + */ + /* Based on: * o RFC 8391 - XMSS: eXtended Merkle Signature Scheme * o [HDSS] "Hash-based Digital Signature Schemes", Buchmann, Dahmen and Szydlo @@ -28,22 +32,150 @@ #ifndef WC_XMSS_H #define WC_XMSS_H +#include + #ifdef WOLFSSL_HAVE_XMSS -#include + +#include #include #include #include + /* When raw hash access APIs are disabled or unavailable (WOLFSSL_NO_HASH_RAW), * fall back to using the full hash API calls. */ #if defined(WOLFSSL_NO_HASH_RAW) && !defined(WC_XMSS_FULL_HASH) #define WC_XMSS_FULL_HASH #endif -#if !defined(WOLFSSL_WC_XMSS) - #error "This code is incompatible with external implementation of XMSS." +/* Note on XMSS/XMSS^MT pub/priv key sizes: + * - The XMSS/XMSS^MT pub key has a defined format and size. + * - The XMSS/XMSS^MT private key is implementation and parameter + * specific. It does not have a standardized format or size. + * + * The XMSS/XMSS^MT public and secret key format and length is: + * PK = OID || root || SEED; + * PK_len = 4 + 2 * n + * + * SK = OID || (implementation defined) + * SK_len = 4 + (implementation defined) + * + * where n is the number of bytes in the hash function, which is 32 + * in this SHA256 implementation. + * + * However the private key is implementation specific. For example, + * in xmss-reference the private key size varies from 137 bytes to + * 1377 bytes between slow and fast implementations with param name + * "XMSSMT-SHA2_20/2_256". + * + * References: + * - RFC 8391 + * - Table 2 of Kampanakis, Fluhrer, IACR, 2017. + * */ + +#define XMSS_SHA256_PUBLEN (68) + +/* Supported XMSS/XMSS^MT parameter set names: + * We are supporting all SHA256 parameter sets with n=32 and + * Winternitz=16, from RFC 8391 and NIST SP 800-208. + * + * ---------------------------------------------------------- + * | Name OID n w len h d | + * XMSS: | "XMSS-SHA2_10_256" 0x00000001 32 16 67 10 1 | + * | "XMSS-SHA2_16_256" 0x00000002 32 16 67 16 1 | + * | "XMSS-SHA2_20_256" 0x00000003 32 16 67 20 1 | + * | | + * XMSSMT: | "XMSSMT-SHA2_20/2_256" 0x00000001 32 16 67 20 2 | + * | "XMSSMT-SHA2_20/4_256" 0x00000002 32 16 67 20 4 | + * | "XMSSMT-SHA2_40/2_256" 0x00000003 32 16 67 40 2 | + * | "XMSSMT-SHA2_40/4_256" 0x00000004 32 16 67 40 4 | + * | "XMSSMT-SHA2_40/8_256" 0x00000005 32 16 67 40 8 | + * | "XMSSMT-SHA2_60/3_256" 0x00000006 32 16 67 60 3 | + * | "XMSSMT-SHA2_60/6_256" 0x00000007 32 16 67 60 6 | + * | "XMSSMT-SHA2_60/12_256" 0x00000008 32 16 67 60 12 | + * ---------------------------------------------------------- + * + * Note that some XMSS and XMSSMT names do have overlapping OIDs. + * + * References: + * 1. NIST SP 800-208 + * 2. RFC 8391 + * */ + +#define XMSS_NAME_LEN (16) /* strlen("XMSS-SHA2_10_256") */ +#define XMSSMT_NAME_MIN_LEN (20) /* strlen("XMSSMT-SHA2_20/2_256") */ +#define XMSSMT_NAME_MAX_LEN (21) /* strlen("XMSSMT-SHA2_60/12_256") */ + +#if defined(HAVE_FIPS) + #undef WOLFSSL_WC_XMSS_NO_SHA512 + #define WOLFSSL_WC_XMSS_NO_SHA512 + #undef WOLFSSL_WC_XMSS_NO_SHAKE128 + #define WOLFSSL_WC_XMSS_NO_SHAKE128 + #undef WOLFSSL_WC_XMSS_MAX_HASH_SIZE + #define WOLFSSL_WC_XMSS_MIN_HASH_SIZE 192 + #define WOLFSSL_WC_XMSS_MAX_HASH_SIZE 256 #endif +#if !defined(NO_SHA256) && !defined(WOLFSSL_WC_XMSS_NO_SHA256) + #define WC_XMSS_SHA256 +#endif +#if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_WC_XMSS_NO_SHA512) + #define WC_XMSS_SHA512 +#endif +#if defined(WOLFSSL_SHAKE128) && !defined(WOLFSSL_WC_XMSS_NO_SHAKE128) + #define WC_XMSS_SHAKE128 +#endif +#if defined(WOLFSSL_SHAKE256) && !defined(WOLFSSL_WC_XMSS_NO_SHAKE256) + #define WC_XMSS_SHAKE256 +#endif + +#ifndef WOLFSSL_WC_XMSS_MIN_HASH_SIZE + #define WOLFSSL_WC_XMSS_MIN_HASH_SIZE 192 +#endif +#ifndef WOLFSSL_WC_XMSS_MAX_HASH_SIZE + #define WOLFSSL_WC_XMSS_MAX_HASH_SIZE 512 +#endif +#if WOLFSSL_WC_XMSS_MIN_HASH_SIZE > WOLFSSL_WC_XMSS_MAX_HASH_SIZE + #error "XMSS minimum hash size is greater than maximum hash size" +#endif + +#ifndef WOLFSSL_XMSS_MIN_HEIGHT + #define WOLFSSL_XMSS_MIN_HEIGHT 10 +#endif +#ifndef WOLFSSL_XMSS_MAX_HEIGHT + #define WOLFSSL_XMSS_MAX_HEIGHT 60 +#endif +#if WOLFSSL_XMSS_MIN_HEIGHT > WOLFSSL_XMSS_MAX_HEIGHT + #error "XMSS minimum height is greater than maximum height" +#endif + +/* Return codes returned by private key callbacks. */ +enum wc_XmssRc { + WC_XMSS_RC_NONE, + WC_XMSS_RC_BAD_ARG, /* Bad arg in read or write callback. */ + WC_XMSS_RC_WRITE_FAIL, /* Write or update private key failed. */ + WC_XMSS_RC_READ_FAIL, /* Read private key failed. */ + WC_XMSS_RC_SAVED_TO_NV_MEMORY, /* Wrote private key to nonvolatile storage. */ + WC_XMSS_RC_READ_TO_MEMORY /* Read private key from storage. */ +}; + +/* enum wc_XmssState is to help track the state of an XMSS Key. */ +enum wc_XmssState { + WC_XMSS_STATE_FREED, /* Key has been freed from memory. */ + WC_XMSS_STATE_INITED, /* Key has been inited, ready to set params.*/ + WC_XMSS_STATE_PARMSET, /* Params are set, ready to MakeKey or Reload. */ + WC_XMSS_STATE_OK, /* Able to sign signatures and verify. */ + WC_XMSS_STATE_VERIFYONLY, /* A public only XmssKey. */ + WC_XMSS_STATE_BAD, /* Can't guarantee key's state. */ + WC_XMSS_STATE_NOSIGS /* Signatures exhausted. */ +}; + +/* Private key write and read callbacks. */ +typedef enum wc_XmssRc (*wc_xmss_write_private_key_cb)(const byte* priv, word32 privSz, + void* context); +typedef enum wc_XmssRc (*wc_xmss_read_private_key_cb)(byte* priv, word32 privSz, + void* context); + #if (defined(WC_XMSS_SHA512) || defined(WC_XMSS_SHAKE256)) && \ (WOLFSSL_WC_XMSS_MAX_HASH_SIZE >= 512) #define WC_XMSS_MAX_N 64 @@ -205,7 +337,7 @@ typedef struct XmssParams { word8 bds_k; } XmssParams; -struct XmssKey { +typedef struct XmssKey { /* Public key. */ unsigned char pk[2 * WC_XMSS_MAX_N]; /* OID that identifies parameters. */ @@ -228,7 +360,7 @@ struct XmssKey { #endif /* ifndef WOLFSSL_XMSS_VERIFY_ONLY */ /* State of key. */ enum wc_XmssState state; -}; +} XmssKey; typedef struct XmssState { const XmssParams* params; @@ -267,6 +399,32 @@ typedef struct XmssState { extern "C" { #endif +WOLFSSL_API int wc_XmssKey_Init(XmssKey* key, void* heap, int devId); +WOLFSSL_API int wc_XmssKey_SetParamStr(XmssKey* key, const char* str); +#ifndef WOLFSSL_XMSS_VERIFY_ONLY +WOLFSSL_API int wc_XmssKey_SetWriteCb(XmssKey* key, + wc_xmss_write_private_key_cb write_cb); +WOLFSSL_API int wc_XmssKey_SetReadCb(XmssKey* key, + wc_xmss_read_private_key_cb read_cb); +WOLFSSL_API int wc_XmssKey_SetContext(XmssKey* key, void* context); +WOLFSSL_API int wc_XmssKey_MakeKey(XmssKey* key, WC_RNG* rng); +WOLFSSL_API int wc_XmssKey_Reload(XmssKey* key); +WOLFSSL_API int wc_XmssKey_GetPrivLen(const XmssKey* key, word32* len); +WOLFSSL_API int wc_XmssKey_Sign(XmssKey* key, byte* sig, word32* sigSz, + const byte* msg, int msgSz); +WOLFSSL_API int wc_XmssKey_SigsLeft(XmssKey* key); +#endif /* ifndef WOLFSSL_XMSS_VERIFY_ONLY */ +WOLFSSL_API void wc_XmssKey_Free(XmssKey* key); +WOLFSSL_API int wc_XmssKey_GetSigLen(const XmssKey* key, word32* len); +WOLFSSL_API int wc_XmssKey_GetPubLen(const XmssKey* key, word32* len); +WOLFSSL_API int wc_XmssKey_ExportPub(XmssKey* keyDst, const XmssKey* keySrc); +WOLFSSL_API int wc_XmssKey_ExportPubRaw(const XmssKey* key, byte* out, + word32* outLen); +WOLFSSL_API int wc_XmssKey_ImportPubRaw(XmssKey* key, const byte* in, + word32 inLen); +WOLFSSL_API int wc_XmssKey_Verify(XmssKey* key, const byte* sig, word32 sigSz, + const byte* msg, int msgSz); + WOLFSSL_LOCAL int wc_xmssmt_keygen(XmssState *state, const unsigned char* seed, unsigned char *sk, unsigned char *pk); WOLFSSL_LOCAL int wc_xmss_keygen(XmssState *state, const unsigned char* seed, @@ -283,9 +441,8 @@ WOLFSSL_LOCAL int wc_xmssmt_verify(XmssState *state, const unsigned char *m, word32 mlen, const unsigned char *sm, const unsigned char *pk); #ifdef __cplusplus - } /* extern "C" */ +} /* extern "C" */ #endif #endif /* WOLFSSL_HAVE_XMSS */ #endif /* WC_XMSS_H */ - diff --git a/wolfssl/wolfcrypt/xmss.h b/wolfssl/wolfcrypt/xmss.h deleted file mode 100644 index 4fd4da1cca..0000000000 --- a/wolfssl/wolfcrypt/xmss.h +++ /dev/null @@ -1,203 +0,0 @@ -/* xmss.h - * - * Copyright (C) 2006-2026 wolfSSL Inc. - * - * This file is part of wolfSSL. - * - * wolfSSL is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * wolfSSL is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA - */ - -/*! - \file wolfssl/wolfcrypt/xmss.h - */ - -#ifndef WOLF_CRYPT_XMSS_H -#define WOLF_CRYPT_XMSS_H - -#include -#include - -#ifdef WOLFSSL_HAVE_XMSS - -/* Note on XMSS/XMSS^MT pub/priv key sizes: - * - The XMSS/XMSS^MT pub key has a defined format and size. - * - The XMSS/XMSS^MT private key is implementation and parameter - * specific. It does not have a standardized format or size. - * - * The XMSS/XMSS^MT public and secret key format and length is: - * PK = OID || root || SEED; - * PK_len = 4 + 2 * n - * - * SK = OID || (implementation defined) - * SK_len = 4 + (implementation defined) - * - * where n is the number of bytes in the hash function, which is 32 - * in this SHA256 implementation. - * - * However the private key is implementation specific. For example, - * in xmss-reference the private key size varies from 137 bytes to - * 1377 bytes between slow and fast implementations with param name - * "XMSSMT-SHA2_20/2_256". - * - * References: - * - RFC 8391 - * - Table 2 of Kampanakis, Fluhrer, IACR, 2017. - * */ - -#define XMSS_SHA256_PUBLEN (68) - -/* Supported XMSS/XMSS^MT parameter set names: - * We are supporting all SHA256 parameter sets with n=32 and - * Winternitz=16, from RFC 8391 and NIST SP 800-208. - * - * ---------------------------------------------------------- - * | Name OID n w len h d | - * XMSS: | "XMSS-SHA2_10_256" 0x00000001 32 16 67 10 1 | - * | "XMSS-SHA2_16_256" 0x00000002 32 16 67 16 1 | - * | "XMSS-SHA2_20_256" 0x00000003 32 16 67 20 1 | - * | | - * XMSSMT: | "XMSSMT-SHA2_20/2_256" 0x00000001 32 16 67 20 2 | - * | "XMSSMT-SHA2_20/4_256" 0x00000002 32 16 67 20 4 | - * | "XMSSMT-SHA2_40/2_256" 0x00000003 32 16 67 40 2 | - * | "XMSSMT-SHA2_40/4_256" 0x00000004 32 16 67 40 4 | - * | "XMSSMT-SHA2_40/8_256" 0x00000005 32 16 67 40 8 | - * | "XMSSMT-SHA2_60/3_256" 0x00000006 32 16 67 60 3 | - * | "XMSSMT-SHA2_60/6_256" 0x00000007 32 16 67 60 6 | - * | "XMSSMT-SHA2_60/12_256" 0x00000008 32 16 67 60 12 | - * ---------------------------------------------------------- - * - * Note that some XMSS and XMSSMT names do have overlapping OIDs. - * - * References: - * 1. NIST SP 800-208 - * 2. RFC 8391 - * */ - -#define XMSS_NAME_LEN (16) /* strlen("XMSS-SHA2_10_256") */ -#define XMSSMT_NAME_MIN_LEN (20) /* strlen("XMSSMT-SHA2_20/2_256") */ -#define XMSSMT_NAME_MAX_LEN (21) /* strlen("XMSSMT-SHA2_60/12_256") */ - -#if defined(HAVE_FIPS) || defined(HAVE_LIBXMSS) - #undef WOLFSSL_WC_XMSS_NO_SHA512 - #define WOLFSSL_WC_XMSS_NO_SHA512 - #undef WOLFSSL_WC_XMSS_NO_SHAKE128 - #define WOLFSSL_WC_XMSS_NO_SHAKE128 - #undef WOLFSSL_WC_XMSS_MAX_HASH_SIZE - #ifdef HAVE_LIBXMSS - #define WOLFSSL_WC_XMSS_MIN_HASH_SIZE 256 - #else - #define WOLFSSL_WC_XMSS_MIN_HASH_SIZE 192 - #endif - #define WOLFSSL_WC_XMSS_MAX_HASH_SIZE 256 -#endif - -#if !defined(NO_SHA256) && !defined(WOLFSSL_WC_XMSS_NO_SHA256) - #define WC_XMSS_SHA256 -#endif -#if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_WC_XMSS_NO_SHA512) - #define WC_XMSS_SHA512 -#endif -#if defined(WOLFSSL_SHAKE128) && !defined(WOLFSSL_WC_XMSS_NO_SHAKE128) - #define WC_XMSS_SHAKE128 -#endif -#if defined(WOLFSSL_SHAKE256) && !defined(WOLFSSL_WC_XMSS_NO_SHAKE256) - #define WC_XMSS_SHAKE256 -#endif - -#ifndef WOLFSSL_WC_XMSS_MIN_HASH_SIZE - #define WOLFSSL_WC_XMSS_MIN_HASH_SIZE 192 -#endif -#ifndef WOLFSSL_WC_XMSS_MAX_HASH_SIZE - #define WOLFSSL_WC_XMSS_MAX_HASH_SIZE 512 -#endif -#if WOLFSSL_WC_XMSS_MIN_HASH_SIZE > WOLFSSL_WC_XMSS_MAX_HASH_SIZE - #error "XMSS minimum hash size is greater than maximum hash size" -#endif - -#ifndef WOLFSSL_XMSS_MIN_HEIGHT - #define WOLFSSL_XMSS_MIN_HEIGHT 10 -#endif -#ifndef WOLFSSL_XMSS_MAX_HEIGHT - #define WOLFSSL_XMSS_MAX_HEIGHT 60 -#endif -#if WOLFSSL_XMSS_MIN_HEIGHT > WOLFSSL_XMSS_MAX_HEIGHT - #error "XMSS minimum height is greater than maximum height" -#endif - -typedef struct XmssKey XmssKey; - -/* Return codes returned by private key callbacks. */ -enum wc_XmssRc { - WC_XMSS_RC_NONE, - WC_XMSS_RC_BAD_ARG, /* Bad arg in read or write callback. */ - WC_XMSS_RC_WRITE_FAIL, /* Write or update private key failed. */ - WC_XMSS_RC_READ_FAIL, /* Read private key failed. */ - WC_XMSS_RC_SAVED_TO_NV_MEMORY, /* Wrote private key to nonvolatile storage. */ - WC_XMSS_RC_READ_TO_MEMORY /* Read private key from storage. */ -}; - -/* enum wc_XmssState is to help track the state of an XMSS Key. */ -enum wc_XmssState { - WC_XMSS_STATE_FREED, /* Key has been freed from memory. */ - WC_XMSS_STATE_INITED, /* Key has been inited, ready to set params.*/ - WC_XMSS_STATE_PARMSET, /* Params are set, ready to MakeKey or Reload. */ - WC_XMSS_STATE_OK, /* Able to sign signatures and verify. */ - WC_XMSS_STATE_VERIFYONLY, /* A public only XmssKey. */ - WC_XMSS_STATE_BAD, /* Can't guarantee key's state. */ - WC_XMSS_STATE_NOSIGS /* Signatures exhausted. */ -}; - -/* Private key write and read callbacks. */ -typedef enum wc_XmssRc (*wc_xmss_write_private_key_cb)(const byte* priv, word32 privSz, - void* context); -typedef enum wc_XmssRc (*wc_xmss_read_private_key_cb)(byte* priv, word32 privSz, - void* context); - -#ifdef __cplusplus - extern "C" { -#endif - -WOLFSSL_API int wc_XmssKey_Init(XmssKey* key, void* heap, int devId); -WOLFSSL_API int wc_XmssKey_SetParamStr(XmssKey* key, const char* str); -#ifndef WOLFSSL_XMSS_VERIFY_ONLY -WOLFSSL_API int wc_XmssKey_SetWriteCb(XmssKey* key, - wc_xmss_write_private_key_cb write_cb); -WOLFSSL_API int wc_XmssKey_SetReadCb(XmssKey* key, - wc_xmss_read_private_key_cb read_cb); -WOLFSSL_API int wc_XmssKey_SetContext(XmssKey* key, void* context); -WOLFSSL_API int wc_XmssKey_MakeKey(XmssKey* key, WC_RNG* rng); -WOLFSSL_API int wc_XmssKey_Reload(XmssKey* key); -WOLFSSL_API int wc_XmssKey_GetPrivLen(const XmssKey* key, word32* len); -WOLFSSL_API int wc_XmssKey_Sign(XmssKey* key, byte* sig, word32* sigSz, - const byte* msg, int msgSz); -WOLFSSL_API int wc_XmssKey_SigsLeft(XmssKey* key); -#endif /* ifndef WOLFSSL_XMSS_VERIFY_ONLY */ -WOLFSSL_API void wc_XmssKey_Free(XmssKey* key); -WOLFSSL_API int wc_XmssKey_GetSigLen(const XmssKey* key, word32* len); -WOLFSSL_API int wc_XmssKey_GetPubLen(const XmssKey* key, word32* len); -WOLFSSL_API int wc_XmssKey_ExportPub(XmssKey* keyDst, const XmssKey* keySrc); -WOLFSSL_API int wc_XmssKey_ExportPubRaw(const XmssKey* key, byte* out, - word32* outLen); -WOLFSSL_API int wc_XmssKey_ImportPubRaw(XmssKey* key, const byte* in, - word32 inLen); -WOLFSSL_API int wc_XmssKey_Verify(XmssKey* key, const byte* sig, word32 sigSz, - const byte* msg, int msgSz); - -#ifdef __cplusplus - } /* extern "C" */ -#endif - -#endif /* WOLFSSL_HAVE_XMSS */ -#endif /* WOLF_CRYPT_XMSS_H */ From 5dbf2e7382dcd923945cfc01e86811c71ea80c98 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Wed, 29 Apr 2026 17:35:11 -0500 Subject: [PATCH 163/167] linuxkm/linuxkm_memory.c: in wc_fips_generate_hash(), fix handling of failed hmac_update() in text segment loop; linuxkm/module_hooks.c: in wolfssl_init() DEBUG_LINUXKM_PIE_SUPPORT section, render stabilized_rodata_hash; in my_kallsyms_lookup_name(), gate kprobe failure messages behind WOLFSSL_LINUXKM_VERBOSE_DEBUG. --- linuxkm/linuxkm_memory.c | 12 ++++++++++-- linuxkm/module_hooks.c | 9 +++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/linuxkm/linuxkm_memory.c b/linuxkm/linuxkm_memory.c index 9969a7fc73..27814207e6 100644 --- a/linuxkm/linuxkm_memory.c +++ b/linuxkm/linuxkm_memory.c @@ -865,6 +865,11 @@ int wc_fips_generate_hash( text_p += progress; } + if (ret) { + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + goto out; + } + cur_reloc_index = -1; while (rodata_p < (const byte *)seg_map->fips_rodata_end) { size_t rodata_in_out_len = min(WOLFSSL_SEGMENT_CANONICALIZER_BUFSIZ, @@ -905,6 +910,9 @@ int wc_fips_generate_hash( } XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + if (ret) + goto out; } #else /* ! (WC_SYM_RELOC_TABLES || WC_SYM_RELOC_TABLES_SUPPORT) */ @@ -936,14 +944,14 @@ int wc_fips_generate_hash( WC_SANITIZE_ENABLE(); -#endif /* ! (WC_SYM_RELOC_TABLES || WC_SYM_RELOC_TABLES_SUPPORT) */ - if (ret) { RELOC_DEBUG_PRINTF("ERROR: hmac_update failed: err %d\n", ret); ret = BAD_STATE_E; goto out; } +#endif /* ! (WC_SYM_RELOC_TABLES || WC_SYM_RELOC_TABLES_SUPPORT) */ + ret = hmac_final(hmac_ctx, hash, digest_size); if (ret) { RELOC_DEBUG_PRINTF("ERROR: hmac_final failed: err %d\n", ret); diff --git a/linuxkm/module_hooks.c b/linuxkm/module_hooks.c index fa0067acc2..1cbde5a6ee 100644 --- a/linuxkm/module_hooks.c +++ b/linuxkm/module_hooks.c @@ -778,12 +778,13 @@ static int wolfssl_init(void) * the true module start address, which is potentially useful to an * attacker. */ - pr_info("wolfCrypt segment hashes (spans): text 0x%x (%llu), rodata 0x%x (%llu), offset %c0x%llx, canon text 0x%x\n", + pr_info("wolfCrypt segment hashes (spans): text 0x%x (%llu), rodata 0x%x (%llu), offset %c0x%llx, canon text 0x%x, canon rodata 0x%x\n", text_hash, (unsigned long long)((uintptr_t)__wc_text_end - (uintptr_t)__wc_text_start), rodata_hash, (unsigned long long)((uintptr_t)__wc_rodata_end - (uintptr_t)__wc_rodata_start), (uintptr_t)__wc_text_start < (uintptr_t)&__wc_rodata_start[0] ? '+' : '-', (uintptr_t)__wc_text_start < (uintptr_t)&__wc_rodata_start[0] ? (unsigned long long)((uintptr_t)&__wc_rodata_start[0] - (uintptr_t)__wc_text_start) : (unsigned long long)((uintptr_t)__wc_text_start - (uintptr_t)&__wc_rodata_start[0]), - stabilized_text_hash); + stabilized_text_hash, + stabilized_rodata_hash); pr_info("wolfCrypt segments: text=%llx-%llx, rodata=%llx-%llx, " "rwdata=%llx-%llx, bss=%llx-%llx\n", @@ -1847,13 +1848,17 @@ static WC_MAYBE_UNUSED void *my_kallsyms_lookup_name(const char *name) { int ret; kallsyms_lookup_name_kp.addr = NULL; if ((ret = register_kprobe(&kallsyms_lookup_name_kp)) != 0) { +#ifdef WOLFSSL_LINUXKM_VERBOSE_DEBUG pr_err_once("ERROR: register_kprobe(&kallsyms_lookup_name_kp) failed: %d\n", ret); +#endif return 0; } kallsyms_lookup_name_ptr = (typeof(kallsyms_lookup_name_ptr))kallsyms_lookup_name_kp.addr; unregister_kprobe(&kallsyms_lookup_name_kp); if (! kallsyms_lookup_name_ptr) { +#ifdef WOLFSSL_LINUXKM_VERBOSE_DEBUG pr_err_once("ERROR: kallsyms_lookup_name_kp.addr is null.\n"); +#endif return 0; } } From 7a2cf5b655541013ed8c93ecc9f598146abf2916 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Thu, 23 Apr 2026 19:31:04 +0200 Subject: [PATCH 164/167] Remove liboqs for ML-KEM and ML-DSA, update for Falcon --- .wolfssl_known_macro_extras | 1 + CMakeLists.txt | 29 +- .../template/components/wolfssl/component.mk | 1 - .../wolfssl/include/user_settings.h | 3 +- .../components/wolfssl/component.mk | 1 - .../wolfssl/include/user_settings.h | 3 +- .../components/wolfssl/component.mk | 1 - .../wolfssl/include/user_settings.h | 3 +- .../examples/wolfssl_client/main/client-tls.c | 3 +- .../components/wolfssl/component.mk | 1 - .../wolfssl/include/user_settings.h | 3 +- .../examples/wolfssl_server/main/server-tls.c | 3 +- .../components/wolfssl/component.mk | 1 - .../wolfssl/include/user_settings.h | 3 +- IDE/STM32Cube/STM32_Benchmarks.md | 1 - IDE/STM32Cube/default_conf.ftl | 3 - .../wolfssl-FIPS.xcodeproj/project.pbxproj | 10 +- IDE/XCODE/wolfssl.xcodeproj/project.pbxproj | 10 +- INSTALL | 14 +- certs/falcon/bench_falcon_level1_key.der | Bin 2202 -> 2206 bytes certs/falcon/bench_falcon_level5_key.der | Bin 4122 -> 4126 bytes cmake/functions.cmake | 11 +- cmake/options.h.in | 4 - configure.ac | 167 +-- examples/benchmark/tls_bench.c | 2 +- examples/client/client.c | 14 +- examples/configs/user_settings_ca.h | 1 - examples/configs/user_settings_espressif.h | 3 +- examples/configs/user_settings_platformio.h | 1 - examples/configs/user_settings_pq.h | 1 - examples/configs/user_settings_stm32.h | 3 - .../configs/user_settings_wolfboot_keytools.h | 1 - examples/server/server.c | 14 +- gencertbuf.pl | 4 +- linuxkm/module_exports.c.template | 3 - scripts/asn1_oid_sum.pl | 10 +- src/include.am | 2 - src/internal.c | 10 +- src/ssl.c | 74 +- src/ssl_load.c | 104 +- src/tls.c | 119 +- src/tls13.c | 7 +- tests/api.c | 7 +- tests/api/test_mldsa.c | 52 +- tests/api/test_mlkem.c | 13 +- tests/suites.c | 4 +- wolfcrypt/benchmark/benchmark.c | 23 +- wolfcrypt/src/asn.c | 16 +- wolfcrypt/src/dilithium.c | 309 +--- wolfcrypt/src/evp_pk.c | 4 +- wolfcrypt/src/ext_mlkem.c | 768 ---------- wolfcrypt/src/falcon.c | 186 +-- wolfcrypt/src/port/arm/armv8-32-mlkem-asm.S | 4 +- wolfcrypt/src/port/arm/armv8-32-mlkem-asm_c.c | 4 +- wolfcrypt/src/port/arm/armv8-mlkem-asm.S | 4 +- wolfcrypt/src/port/arm/armv8-mlkem-asm_c.c | 4 +- wolfcrypt/src/port/arm/thumb2-mlkem-asm.S | 4 +- wolfcrypt/src/port/arm/thumb2-mlkem-asm_c.c | 4 +- wolfcrypt/src/sha3_asm.S | 12 +- wolfcrypt/src/sphincs.c | 4 +- wolfcrypt/src/wc_mldsa_asm.S | 4 +- wolfcrypt/src/wc_mlkem.c | 5 +- wolfcrypt/src/wc_mlkem_asm.S | 4 +- wolfcrypt/src/wc_mlkem_poly.c | 6 +- wolfcrypt/src/wc_pkcs11.c | 39 +- wolfcrypt/test/test.c | 41 +- wolfssl-VS2022.vcxproj | 1 - wolfssl.vcproj | 4 - wolfssl.vcxproj | 1 - wolfssl/certs_test.h | 1268 ++++++++--------- wolfssl/internal.h | 4 +- wolfssl/ssl.h | 6 +- wolfssl/wolfcrypt/cryptocb.h | 5 - wolfssl/wolfcrypt/dilithium.h | 109 +- wolfssl/wolfcrypt/ext_mlkem.h | 74 - wolfssl/wolfcrypt/falcon.h | 12 +- wolfssl/wolfcrypt/include.am | 2 - wolfssl/wolfcrypt/mlkem.h | 390 ----- wolfssl/wolfcrypt/oid_sum.h | 38 +- wolfssl/wolfcrypt/settings.h | 43 +- wolfssl/wolfcrypt/sphincs.h | 4 +- wolfssl/wolfcrypt/types.h | 2 - wolfssl/wolfcrypt/wc_mlkem.h | 394 ++++- wrapper/CSharp/user_settings.h | 2 - wrapper/CSharp/wolfssl.vcxproj | 1 - wrapper/rust/wolfssl-wolfcrypt/headers.h | 2 +- zephyr/CMakeLists.txt | 1 - zephyr/user_settings.h | 1 - 88 files changed, 1417 insertions(+), 3117 deletions(-) delete mode 100644 wolfcrypt/src/ext_mlkem.c delete mode 100644 wolfssl/wolfcrypt/ext_mlkem.h delete mode 100644 wolfssl/wolfcrypt/mlkem.h diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 4d5c99f71d..5f3ba17498 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -299,6 +299,7 @@ HAVE_PKCS7_RSA_RAW_SIGN_CALLBACK HAVE_POCO_LIB HAVE_RTP_SYS HAVE_SECURE_GETENV +HAVE_SPHINCS HAVE_STACK_SIZE_VERBOSE_LOG HAVE_THREADX HAVE_TM_TYPE diff --git a/CMakeLists.txt b/CMakeLists.txt index 317aa9c8e8..6d047cf5b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -625,6 +625,11 @@ add_option(WOLFSSL_OQS "Enable integration with the OQS (Open Quantum Safe) liboqs library (default: disabled)" "no" "yes;no") +# Falcon (provided via liboqs) +add_option(WOLFSSL_FALCON + "Enable Falcon post-quantum signatures via liboqs (default: disabled)" + "no" "yes;no") + # ML-KEM/Kyber add_option(WOLFSSL_MLKEM "Enable the wolfSSL PQ ML-KEM library (default: disabled)" @@ -632,13 +637,11 @@ add_option(WOLFSSL_MLKEM if (WOLFSSL_MLKEM) list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_HAVE_MLKEM") - list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_WC_MLKEM") list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_SHA3") list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_SHAKE128") list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_SHAKE256") set_wolfssl_definitions("WOLFSSL_HAVE_MLKEM" RESULT) - set_wolfssl_definitions("WOLFSSL_WC_MLKEM" RESULT) set_wolfssl_definitions("WOLFSSL_SHA3" RESULT) set_wolfssl_definitions("WOLFSSL_SHAKE128" RESULT) set_wolfssl_definitions("WOLFSSL_SHAKE256" RESULT) @@ -677,13 +680,11 @@ add_option(WOLFSSL_DILITHIUM if (WOLFSSL_DILITHIUM) list(APPEND WOLFSSL_DEFINITIONS "-DHAVE_DILITHIUM") - list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_WC_DILITHIUM") list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_SHA3") list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_SHAKE128") list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_SHAKE256") set_wolfssl_definitions("HAVE_DILITHIUM" RESULT) - set_wolfssl_definitions("WOLFSSL_WC_DILITHIUM" RESULT) set_wolfssl_definitions("WOLFSSL_SHA3" RESULT) set_wolfssl_definitions("WOLFSSL_SHAKE128" RESULT) set_wolfssl_definitions("WOLFSSL_SHAKE256" RESULT) @@ -733,6 +734,15 @@ if (WOLFSSL_EXPERIMENTAL) set_wolfssl_definitions("WOLFSSL_EXPERIMENTAL_SETTINGS" RESULT) + # Cross-validate WOLFSSL_OQS and WOLFSSL_FALCON: liboqs is only linked + # when a liboqs-backed algorithm (Falcon) is actually enabled. + if (WOLFSSL_FALCON AND NOT WOLFSSL_OQS) + message(FATAL_ERROR "WOLFSSL_FALCON requires WOLFSSL_OQS.") + endif() + if (WOLFSSL_OQS AND NOT WOLFSSL_FALCON) + message(FATAL_ERROR "WOLFSSL_OQS requires WOLFSSL_FALCON.") + endif() + # Checking for experimental feature: OQS message(STATUS "Looking for WOLFSSL_OQS") if (WOLFSSL_OQS) @@ -749,6 +759,7 @@ if (WOLFSSL_EXPERIMENTAL) set_wolfssl_definitions("HAVE_LIBOQS" RESULT) set_wolfssl_definitions("HAVE_TLS_EXTENSIONS" RESULT) set_wolfssl_definitions("OPENSSL_EXTRA" RESULT) + set_wolfssl_definitions("HAVE_FALCON" RESULT) else() message(STATUS "Checking OQS - not found") @@ -777,19 +788,15 @@ if (WOLFSSL_EXPERIMENTAL) message(STATUS "Warning: WOLFSSL_EXPERIMENTAL enabled, but no experimental features enabled.") endif() - # Sanity checks - if(WOLFSSL_OQS AND WOLFSSL_MLKEM) - message(FATAL_ERROR "Error: cannot enable both WOLFSSL_OQS and WOLFSSL_MLKEM at the same time.") - endif() - if(WOLFSSL_OQS AND WOLFSSL_DILITHIUM) - message(FATAL_ERROR "Error: cannot enable both WOLFSSL_OQS and WOLFSSL_DILITHIUM at the same time.") - endif() else() # Experimental mode not enabled, but were any experimental features enabled? Error out if so: message(STATUS "Looking for WOLFSSL_EXPERIMENTAL - not found") if (WOLFSSL_OQS) message(FATAL_ERROR "Error: WOLFSSL_OQS requires WOLFSSL_EXPERIMENTAL at this time.") endif() + if (WOLFSSL_FALCON) + message(FATAL_ERROR "Error: WOLFSSL_FALCON requires WOLFSSL_EXPERIMENTAL at this time.") + endif() endif() # LMS diff --git a/IDE/Espressif/ESP-IDF/examples/template/components/wolfssl/component.mk b/IDE/Espressif/ESP-IDF/examples/template/components/wolfssl/component.mk index 6b1c052988..3b85dfa9e0 100644 --- a/IDE/Espressif/ESP-IDF/examples/template/components/wolfssl/component.mk +++ b/IDE/Espressif/ESP-IDF/examples/template/components/wolfssl/component.mk @@ -203,7 +203,6 @@ COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/ed25519.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/ed448.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/error.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/evp.o -# COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/ext_mlkem.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/ext_lms.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/ext_xmss.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/falcon.o diff --git a/IDE/Espressif/ESP-IDF/examples/template/components/wolfssl/include/user_settings.h b/IDE/Espressif/ESP-IDF/examples/template/components/wolfssl/include/user_settings.h index 0da0f637a9..4e48738843 100644 --- a/IDE/Espressif/ESP-IDF/examples/template/components/wolfssl/include/user_settings.h +++ b/IDE/Espressif/ESP-IDF/examples/template/components/wolfssl/include/user_settings.h @@ -215,7 +215,6 @@ #ifdef CONFIG_ESP_WOLFSSL_ENABLE_MLKEM /* Kyber typically needs a minimum 10K stack */ #define WOLFSSL_HAVE_MLKEM - #define WOLFSSL_WC_MLKEM #define WOLFSSL_SHAKE128 #define WOLFSSL_SHAKE256 @@ -234,7 +233,7 @@ #define WOLFSSL_NO_ML_KEM_768 #define NO_SESSION_CACHE #else - /* Only needed for older wolfssl versions, see mlkem.h */ + /* Only needed for older wolfssl versions, see wc_mlkem.h */ #define WOLFSSL_KYBER1024 /* optional alternative sizes: */ /* #define WOLFSSL_KYBER768 */ diff --git a/IDE/Espressif/ESP-IDF/examples/wolfssl_benchmark/components/wolfssl/component.mk b/IDE/Espressif/ESP-IDF/examples/wolfssl_benchmark/components/wolfssl/component.mk index 82a56d2a55..15939e4e58 100644 --- a/IDE/Espressif/ESP-IDF/examples/wolfssl_benchmark/components/wolfssl/component.mk +++ b/IDE/Espressif/ESP-IDF/examples/wolfssl_benchmark/components/wolfssl/component.mk @@ -203,7 +203,6 @@ COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/ed25519.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/ed448.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/error.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/evp.o -# COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/ext_mlkem.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/ext_lms.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/ext_xmss.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/falcon.o diff --git a/IDE/Espressif/ESP-IDF/examples/wolfssl_benchmark/components/wolfssl/include/user_settings.h b/IDE/Espressif/ESP-IDF/examples/wolfssl_benchmark/components/wolfssl/include/user_settings.h index 0da0f637a9..4e48738843 100644 --- a/IDE/Espressif/ESP-IDF/examples/wolfssl_benchmark/components/wolfssl/include/user_settings.h +++ b/IDE/Espressif/ESP-IDF/examples/wolfssl_benchmark/components/wolfssl/include/user_settings.h @@ -215,7 +215,6 @@ #ifdef CONFIG_ESP_WOLFSSL_ENABLE_MLKEM /* Kyber typically needs a minimum 10K stack */ #define WOLFSSL_HAVE_MLKEM - #define WOLFSSL_WC_MLKEM #define WOLFSSL_SHAKE128 #define WOLFSSL_SHAKE256 @@ -234,7 +233,7 @@ #define WOLFSSL_NO_ML_KEM_768 #define NO_SESSION_CACHE #else - /* Only needed for older wolfssl versions, see mlkem.h */ + /* Only needed for older wolfssl versions, see wc_mlkem.h */ #define WOLFSSL_KYBER1024 /* optional alternative sizes: */ /* #define WOLFSSL_KYBER768 */ diff --git a/IDE/Espressif/ESP-IDF/examples/wolfssl_client/components/wolfssl/component.mk b/IDE/Espressif/ESP-IDF/examples/wolfssl_client/components/wolfssl/component.mk index 6b1c052988..3b85dfa9e0 100644 --- a/IDE/Espressif/ESP-IDF/examples/wolfssl_client/components/wolfssl/component.mk +++ b/IDE/Espressif/ESP-IDF/examples/wolfssl_client/components/wolfssl/component.mk @@ -203,7 +203,6 @@ COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/ed25519.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/ed448.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/error.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/evp.o -# COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/ext_mlkem.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/ext_lms.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/ext_xmss.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/falcon.o diff --git a/IDE/Espressif/ESP-IDF/examples/wolfssl_client/components/wolfssl/include/user_settings.h b/IDE/Espressif/ESP-IDF/examples/wolfssl_client/components/wolfssl/include/user_settings.h index 0da0f637a9..4e48738843 100644 --- a/IDE/Espressif/ESP-IDF/examples/wolfssl_client/components/wolfssl/include/user_settings.h +++ b/IDE/Espressif/ESP-IDF/examples/wolfssl_client/components/wolfssl/include/user_settings.h @@ -215,7 +215,6 @@ #ifdef CONFIG_ESP_WOLFSSL_ENABLE_MLKEM /* Kyber typically needs a minimum 10K stack */ #define WOLFSSL_HAVE_MLKEM - #define WOLFSSL_WC_MLKEM #define WOLFSSL_SHAKE128 #define WOLFSSL_SHAKE256 @@ -234,7 +233,7 @@ #define WOLFSSL_NO_ML_KEM_768 #define NO_SESSION_CACHE #else - /* Only needed for older wolfssl versions, see mlkem.h */ + /* Only needed for older wolfssl versions, see wc_mlkem.h */ #define WOLFSSL_KYBER1024 /* optional alternative sizes: */ /* #define WOLFSSL_KYBER768 */ diff --git a/IDE/Espressif/ESP-IDF/examples/wolfssl_client/main/client-tls.c b/IDE/Espressif/ESP-IDF/examples/wolfssl_client/main/client-tls.c index d3d7cd350b..a2ef66cd22 100644 --- a/IDE/Espressif/ESP-IDF/examples/wolfssl_client/main/client-tls.c +++ b/IDE/Espressif/ESP-IDF/examples/wolfssl_client/main/client-tls.c @@ -41,8 +41,7 @@ #undef USE_WOLFSSL_ESP_SDK_WIFI #include -#if defined(WOLFSSL_WC_MLKEM) - #include +#if defined(WOLFSSL_HAVE_MLKEM) #include #endif #if defined(USE_CERT_BUFFERS_2048) || defined(USE_CERT_BUFFERS_1024) diff --git a/IDE/Espressif/ESP-IDF/examples/wolfssl_server/components/wolfssl/component.mk b/IDE/Espressif/ESP-IDF/examples/wolfssl_server/components/wolfssl/component.mk index 6b1c052988..3b85dfa9e0 100644 --- a/IDE/Espressif/ESP-IDF/examples/wolfssl_server/components/wolfssl/component.mk +++ b/IDE/Espressif/ESP-IDF/examples/wolfssl_server/components/wolfssl/component.mk @@ -203,7 +203,6 @@ COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/ed25519.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/ed448.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/error.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/evp.o -# COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/ext_mlkem.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/ext_lms.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/ext_xmss.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/falcon.o diff --git a/IDE/Espressif/ESP-IDF/examples/wolfssl_server/components/wolfssl/include/user_settings.h b/IDE/Espressif/ESP-IDF/examples/wolfssl_server/components/wolfssl/include/user_settings.h index 0da0f637a9..4e48738843 100644 --- a/IDE/Espressif/ESP-IDF/examples/wolfssl_server/components/wolfssl/include/user_settings.h +++ b/IDE/Espressif/ESP-IDF/examples/wolfssl_server/components/wolfssl/include/user_settings.h @@ -215,7 +215,6 @@ #ifdef CONFIG_ESP_WOLFSSL_ENABLE_MLKEM /* Kyber typically needs a minimum 10K stack */ #define WOLFSSL_HAVE_MLKEM - #define WOLFSSL_WC_MLKEM #define WOLFSSL_SHAKE128 #define WOLFSSL_SHAKE256 @@ -234,7 +233,7 @@ #define WOLFSSL_NO_ML_KEM_768 #define NO_SESSION_CACHE #else - /* Only needed for older wolfssl versions, see mlkem.h */ + /* Only needed for older wolfssl versions, see wc_mlkem.h */ #define WOLFSSL_KYBER1024 /* optional alternative sizes: */ /* #define WOLFSSL_KYBER768 */ diff --git a/IDE/Espressif/ESP-IDF/examples/wolfssl_server/main/server-tls.c b/IDE/Espressif/ESP-IDF/examples/wolfssl_server/main/server-tls.c index ff77e5d97f..5f3d153e88 100644 --- a/IDE/Espressif/ESP-IDF/examples/wolfssl_server/main/server-tls.c +++ b/IDE/Espressif/ESP-IDF/examples/wolfssl_server/main/server-tls.c @@ -54,8 +54,7 @@ #error "Missing WOLFSSL_USER_SETTINGS in CMakeLists or Makefile:\ CFLAGS +=-DWOLFSSL_USER_SETTINGS" #endif -#if defined(WOLFSSL_WC_MLKEM) - #include +#if defined(WOLFSSL_HAVE_MLKEM) #include #endif #if defined(USE_CERT_BUFFERS_2048) || defined(USE_CERT_BUFFERS_1024) diff --git a/IDE/Espressif/ESP-IDF/examples/wolfssl_test/components/wolfssl/component.mk b/IDE/Espressif/ESP-IDF/examples/wolfssl_test/components/wolfssl/component.mk index 308aa3d4eb..76cbea8e6a 100644 --- a/IDE/Espressif/ESP-IDF/examples/wolfssl_test/components/wolfssl/component.mk +++ b/IDE/Espressif/ESP-IDF/examples/wolfssl_test/components/wolfssl/component.mk @@ -203,7 +203,6 @@ COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/ed25519.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/ed448.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/error.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/evp.o -# COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/ext_mlkem.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/ext_lms.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/ext_xmss.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/falcon.o diff --git a/IDE/Espressif/ESP-IDF/examples/wolfssl_test/components/wolfssl/include/user_settings.h b/IDE/Espressif/ESP-IDF/examples/wolfssl_test/components/wolfssl/include/user_settings.h index 0da0f637a9..4e48738843 100644 --- a/IDE/Espressif/ESP-IDF/examples/wolfssl_test/components/wolfssl/include/user_settings.h +++ b/IDE/Espressif/ESP-IDF/examples/wolfssl_test/components/wolfssl/include/user_settings.h @@ -215,7 +215,6 @@ #ifdef CONFIG_ESP_WOLFSSL_ENABLE_MLKEM /* Kyber typically needs a minimum 10K stack */ #define WOLFSSL_HAVE_MLKEM - #define WOLFSSL_WC_MLKEM #define WOLFSSL_SHAKE128 #define WOLFSSL_SHAKE256 @@ -234,7 +233,7 @@ #define WOLFSSL_NO_ML_KEM_768 #define NO_SESSION_CACHE #else - /* Only needed for older wolfssl versions, see mlkem.h */ + /* Only needed for older wolfssl versions, see wc_mlkem.h */ #define WOLFSSL_KYBER1024 /* optional alternative sizes: */ /* #define WOLFSSL_KYBER768 */ diff --git a/IDE/STM32Cube/STM32_Benchmarks.md b/IDE/STM32Cube/STM32_Benchmarks.md index 9737e0b95e..47de679eca 100644 --- a/IDE/STM32Cube/STM32_Benchmarks.md +++ b/IDE/STM32Cube/STM32_Benchmarks.md @@ -700,7 +700,6 @@ Tested on commit: fa9e122f1cca32513611f5a24de88d07aced015b #define GCM_TABLE_4BIT #define HAVE_DILITHIUM -#define WOLFSSL_WC_DILITHIUM #define WOLFSSL_DILITHIUM_SMALL #define WOLFSSL_ARMASM diff --git a/IDE/STM32Cube/default_conf.ftl b/IDE/STM32Cube/default_conf.ftl index 951e319baf..b43888931e 100644 --- a/IDE/STM32Cube/default_conf.ftl +++ b/IDE/STM32Cube/default_conf.ftl @@ -660,9 +660,6 @@ extern ${variable.value} ${variable.name}; #undef WOLFSSL_HAVE_MLKEM #define WOLFSSL_HAVE_MLKEM - #undef WOLFSSL_WC_MLKEM - #define WOLFSSL_WC_MLKEM - #undef WOLFSSL_NO_SHAKE128 #undef WOLFSSL_SHAKE128 #define WOLFSSL_SHAKE128 diff --git a/IDE/XCODE/wolfssl-FIPS.xcodeproj/project.pbxproj b/IDE/XCODE/wolfssl-FIPS.xcodeproj/project.pbxproj index c96018c5a8..0115d35159 100644 --- a/IDE/XCODE/wolfssl-FIPS.xcodeproj/project.pbxproj +++ b/IDE/XCODE/wolfssl-FIPS.xcodeproj/project.pbxproj @@ -125,7 +125,6 @@ 700F0CF52A2FC11300755BA7 /* eccsi.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0CDB2A2FC0D500755BA7 /* eccsi.h */; }; 700F0CF62A2FC11300755BA7 /* ed448.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0CD22A2FC0D500755BA7 /* ed448.h */; }; 700F0CF72A2FC11300755BA7 /* ed25519.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0CE12A2FC0D500755BA7 /* ed25519.h */; }; - 700F0CF82A2FC11300755BA7 /* ext_mlkem.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0CD52A2FC0D500755BA7 /* ext_mlkem.h */; }; 700F0CF92A2FC11300755BA7 /* falcon.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0CDD2A2FC0D500755BA7 /* falcon.h */; }; 700F0CFA2A2FC11300755BA7 /* fe_448.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0CDE2A2FC0D500755BA7 /* fe_448.h */; }; 700F0CFB2A2FC11300755BA7 /* fe_operations.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0CC72A2FC0D400755BA7 /* fe_operations.h */; }; @@ -147,7 +146,6 @@ 700F0D0B2A2FC11300755BA7 /* sp.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0CD12A2FC0D500755BA7 /* sp.h */; }; 700F0D0C2A2FC11300755BA7 /* sphincs.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0CEC2A2FC0D500755BA7 /* sphincs.h */; }; 700F0D0D2A2FC11300755BA7 /* srp.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0CDC2A2FC0D500755BA7 /* srp.h */; }; - 700F0D0E2A2FC11300755BA7 /* wc_mlkem.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0CD82A2FC0D500755BA7 /* wc_mlkem.h */; }; 700F0D0F2A2FC11300755BA7 /* wc_pkcs11.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0CE82A2FC0D500755BA7 /* wc_pkcs11.h */; }; 700F0D102A2FC11300755BA7 /* wolfevent.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0CD62A2FC0D500755BA7 /* wolfevent.h */; }; 700F0D112A2FC11300755BA7 /* wolfmath.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0CEB2A2FC0D500755BA7 /* wolfmath.h */; }; @@ -285,7 +283,6 @@ 700F0CF52A2FC11300755BA7 /* eccsi.h in CopyFiles */, 700F0CF62A2FC11300755BA7 /* ed448.h in CopyFiles */, 700F0CF72A2FC11300755BA7 /* ed25519.h in CopyFiles */, - 700F0CF82A2FC11300755BA7 /* ext_mlkem.h in CopyFiles */, 700F0CF92A2FC11300755BA7 /* falcon.h in CopyFiles */, 700F0CFA2A2FC11300755BA7 /* fe_448.h in CopyFiles */, 700F0CFB2A2FC11300755BA7 /* fe_operations.h in CopyFiles */, @@ -307,7 +304,6 @@ 700F0D0B2A2FC11300755BA7 /* sp.h in CopyFiles */, 700F0D0C2A2FC11300755BA7 /* sphincs.h in CopyFiles */, 700F0D0D2A2FC11300755BA7 /* srp.h in CopyFiles */, - 700F0D0E2A2FC11300755BA7 /* wc_mlkem.h in CopyFiles */, 700F0D0F2A2FC11300755BA7 /* wc_pkcs11.h in CopyFiles */, 700F0D102A2FC11300755BA7 /* wolfevent.h in CopyFiles */, 700F0D112A2FC11300755BA7 /* wolfmath.h in CopyFiles */, @@ -563,7 +559,7 @@ 700F0CC92A2FC0D500755BA7 /* selftest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = selftest.h; path = ../../wolfssl/wolfcrypt/selftest.h; sourceTree = ""; }; 700F0CCA2A2FC0D500755BA7 /* ge_operations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ge_operations.h; path = ../../wolfssl/wolfcrypt/ge_operations.h; sourceTree = ""; }; 700F0CCB2A2FC0D500755BA7 /* async.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = async.h; path = ../../wolfssl/wolfcrypt/async.h; sourceTree = ""; }; - 700F0CCC2A2FC0D500755BA7 /* mlkem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mlkem.h; path = ../../wolfssl/wolfcrypt/mlkem.h; sourceTree = ""; }; + 700F0CCC2A2FC0D500755BA7 /* mlkem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mlkem.h; path = ../../wolfssl/wolfcrypt/wc_mlkem.h; sourceTree = ""; }; 700F0CCD2A2FC0D500755BA7 /* hpke.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = hpke.h; path = ../../wolfssl/wolfcrypt/hpke.h; sourceTree = ""; }; 700F0CCE2A2FC0D500755BA7 /* cpuid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cpuid.h; path = ../../wolfssl/wolfcrypt/cpuid.h; sourceTree = ""; }; 700F0CCF2A2FC0D500755BA7 /* fips.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fips.h; path = ../../wolfssl/wolfcrypt/fips.h; sourceTree = ""; }; @@ -572,10 +568,8 @@ 700F0CD22A2FC0D500755BA7 /* ed448.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ed448.h; path = ../../wolfssl/wolfcrypt/ed448.h; sourceTree = ""; }; 700F0CD32A2FC0D500755BA7 /* curve448.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = curve448.h; path = ../../wolfssl/wolfcrypt/curve448.h; sourceTree = ""; }; 700F0CD42A2FC0D500755BA7 /* siphash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = siphash.h; path = ../../wolfssl/wolfcrypt/siphash.h; sourceTree = ""; }; - 700F0CD52A2FC0D500755BA7 /* ext_mlkem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ext_mlkem.h; path = ../../wolfssl/wolfcrypt/ext_mlkem.h; sourceTree = ""; }; 700F0CD62A2FC0D500755BA7 /* wolfevent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wolfevent.h; path = ../../wolfssl/wolfcrypt/wolfevent.h; sourceTree = ""; }; 700F0CD72A2FC0D500755BA7 /* cmac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cmac.h; path = ../../wolfssl/wolfcrypt/cmac.h; sourceTree = ""; }; - 700F0CD82A2FC0D500755BA7 /* wc_mlkem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wc_mlkem.h; path = ../../wolfssl/wolfcrypt/wc_mlkem.h; sourceTree = ""; }; 700F0CD92A2FC0D500755BA7 /* pkcs11.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pkcs11.h; path = ../../wolfssl/wolfcrypt/pkcs11.h; sourceTree = ""; }; 700F0CDA2A2FC0D500755BA7 /* mem_track.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mem_track.h; path = ../../wolfssl/wolfcrypt/mem_track.h; sourceTree = ""; }; 700F0CDB2A2FC0D500755BA7 /* eccsi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eccsi.h; path = ../../wolfssl/wolfcrypt/eccsi.h; sourceTree = ""; }; @@ -643,7 +637,6 @@ 700F0CDB2A2FC0D500755BA7 /* eccsi.h */, 700F0CD22A2FC0D500755BA7 /* ed448.h */, 700F0CE12A2FC0D500755BA7 /* ed25519.h */, - 700F0CD52A2FC0D500755BA7 /* ext_mlkem.h */, 700F0CDD2A2FC0D500755BA7 /* falcon.h */, 700F0CDE2A2FC0D500755BA7 /* fe_448.h */, 700F0CC72A2FC0D400755BA7 /* fe_operations.h */, @@ -665,7 +658,6 @@ 700F0CD12A2FC0D500755BA7 /* sp.h */, 700F0CEC2A2FC0D500755BA7 /* sphincs.h */, 700F0CDC2A2FC0D500755BA7 /* srp.h */, - 700F0CD82A2FC0D500755BA7 /* wc_mlkem.h */, 700F0CE82A2FC0D500755BA7 /* wc_pkcs11.h */, 700F0CD62A2FC0D500755BA7 /* wolfevent.h */, 700F0CEB2A2FC0D500755BA7 /* wolfmath.h */, diff --git a/IDE/XCODE/wolfssl.xcodeproj/project.pbxproj b/IDE/XCODE/wolfssl.xcodeproj/project.pbxproj index 1c5d65d1c5..2481d83d16 100644 --- a/IDE/XCODE/wolfssl.xcodeproj/project.pbxproj +++ b/IDE/XCODE/wolfssl.xcodeproj/project.pbxproj @@ -256,7 +256,6 @@ 700F0C0D2A2FBC5100755BA7 /* eccsi.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0BF72A2FBC1600755BA7 /* eccsi.h */; }; 700F0C0E2A2FBC5100755BA7 /* ed448.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0BF82A2FBC1600755BA7 /* ed448.h */; }; 700F0C0F2A2FBC5100755BA7 /* ed25519.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0BF42A2FBC1600755BA7 /* ed25519.h */; }; - 700F0C102A2FBC5100755BA7 /* ext_mlkem.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0BF92A2FBC1600755BA7 /* ext_mlkem.h */; }; 700F0C112A2FBC5100755BA7 /* falcon.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0C022A2FBC1600755BA7 /* falcon.h */; }; 700F0C122A2FBC5100755BA7 /* fe_448.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0BEB2A2FBC1500755BA7 /* fe_448.h */; }; 700F0C132A2FBC5100755BA7 /* fe_operations.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0BF62A2FBC1600755BA7 /* fe_operations.h */; }; @@ -277,7 +276,6 @@ 700F0C222A2FBC5100755BA7 /* sp.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0BE92A2FBC1500755BA7 /* sp.h */; }; 700F0C232A2FBC5100755BA7 /* sphincs.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0BE22A2FBC1500755BA7 /* sphincs.h */; }; 700F0C242A2FBC5100755BA7 /* srp.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0BF32A2FBC1600755BA7 /* srp.h */; }; - 700F0C252A2FBC5100755BA7 /* wc_mlkem.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0BFF2A2FBC1600755BA7 /* wc_mlkem.h */; }; 700F0C262A2FBC5100755BA7 /* wc_pkcs11.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0BF52A2FBC1600755BA7 /* wc_pkcs11.h */; }; 700F0C272A2FBC5100755BA7 /* wolfevent.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0BE62A2FBC1500755BA7 /* wolfevent.h */; }; 700F0C282A2FBC5100755BA7 /* kdf.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 6AC8513B272CB04F00F2B32A /* kdf.h */; }; @@ -622,7 +620,6 @@ 700F0C0D2A2FBC5100755BA7 /* eccsi.h in CopyFiles */, 700F0C0E2A2FBC5100755BA7 /* ed448.h in CopyFiles */, 700F0C0F2A2FBC5100755BA7 /* ed25519.h in CopyFiles */, - 700F0C102A2FBC5100755BA7 /* ext_mlkem.h in CopyFiles */, 700F0C112A2FBC5100755BA7 /* falcon.h in CopyFiles */, 700F0C122A2FBC5100755BA7 /* fe_448.h in CopyFiles */, 700F0C132A2FBC5100755BA7 /* fe_operations.h in CopyFiles */, @@ -643,7 +640,6 @@ 700F0C222A2FBC5100755BA7 /* sp.h in CopyFiles */, 700F0C232A2FBC5100755BA7 /* sphincs.h in CopyFiles */, 700F0C242A2FBC5100755BA7 /* srp.h in CopyFiles */, - 700F0C252A2FBC5100755BA7 /* wc_mlkem.h in CopyFiles */, 700F0C262A2FBC5100755BA7 /* wc_pkcs11.h in CopyFiles */, 700F0C272A2FBC5100755BA7 /* wolfevent.h in CopyFiles */, 700F0C282A2FBC5100755BA7 /* kdf.h in CopyFiles */, @@ -982,7 +978,7 @@ 700F0BE72A2FBC1500755BA7 /* ge_448.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ge_448.h; path = ../../wolfssl/wolfcrypt/ge_448.h; sourceTree = ""; }; 700F0BE82A2FBC1500755BA7 /* sp_int.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sp_int.h; path = ../../wolfssl/wolfcrypt/sp_int.h; sourceTree = ""; }; 700F0BE92A2FBC1500755BA7 /* sp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sp.h; path = ../../wolfssl/wolfcrypt/sp.h; sourceTree = ""; }; - 700F0BEA2A2FBC1500755BA7 /* mlkem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mlkem.h; path = ../../wolfssl/wolfcrypt/mlkem.h; sourceTree = ""; }; + 700F0BEA2A2FBC1500755BA7 /* mlkem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mlkem.h; path = ../../wolfssl/wolfcrypt/wc_mlkem.h; sourceTree = ""; }; 700F0BEB2A2FBC1500755BA7 /* fe_448.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fe_448.h; path = ../../wolfssl/wolfcrypt/fe_448.h; sourceTree = ""; }; 700F0BEC2A2FBC1500755BA7 /* pkcs12.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pkcs12.h; path = ../../wolfssl/wolfcrypt/pkcs12.h; sourceTree = ""; }; 700F0BED2A2FBC1500755BA7 /* chacha20_poly1305.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = chacha20_poly1305.h; path = ../../wolfssl/wolfcrypt/chacha20_poly1305.h; sourceTree = ""; }; @@ -997,13 +993,11 @@ 700F0BF62A2FBC1600755BA7 /* fe_operations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fe_operations.h; path = ../../wolfssl/wolfcrypt/fe_operations.h; sourceTree = ""; }; 700F0BF72A2FBC1600755BA7 /* eccsi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eccsi.h; path = ../../wolfssl/wolfcrypt/eccsi.h; sourceTree = ""; }; 700F0BF82A2FBC1600755BA7 /* ed448.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ed448.h; path = ../../wolfssl/wolfcrypt/ed448.h; sourceTree = ""; }; - 700F0BF92A2FBC1600755BA7 /* ext_mlkem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ext_mlkem.h; path = ../../wolfssl/wolfcrypt/ext_mlkem.h; sourceTree = ""; }; 700F0BFA2A2FBC1600755BA7 /* sha3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sha3.h; path = ../../wolfssl/wolfcrypt/sha3.h; sourceTree = ""; }; 700F0BFB2A2FBC1600755BA7 /* signature.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = signature.h; path = ../../wolfssl/wolfcrypt/signature.h; sourceTree = ""; }; 700F0BFC2A2FBC1600755BA7 /* cmac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cmac.h; path = ../../wolfssl/wolfcrypt/cmac.h; sourceTree = ""; }; 700F0BFD2A2FBC1600755BA7 /* pkcs11.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pkcs11.h; path = ../../wolfssl/wolfcrypt/pkcs11.h; sourceTree = ""; }; 700F0BFE2A2FBC1600755BA7 /* siphash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = siphash.h; path = ../../wolfssl/wolfcrypt/siphash.h; sourceTree = ""; }; - 700F0BFF2A2FBC1600755BA7 /* wc_mlkem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wc_mlkem.h; path = ../../wolfssl/wolfcrypt/wc_mlkem.h; sourceTree = ""; }; 700F0C002A2FBC1600755BA7 /* fips.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fips.h; path = ../../wolfssl/wolfcrypt/fips.h; sourceTree = ""; }; 700F0C012A2FBC1600755BA7 /* ge_operations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ge_operations.h; path = ../../wolfssl/wolfcrypt/ge_operations.h; sourceTree = ""; }; 700F0C022A2FBC1600755BA7 /* falcon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = falcon.h; path = ../../wolfssl/wolfcrypt/falcon.h; sourceTree = ""; }; @@ -1153,7 +1147,6 @@ 700F0BF72A2FBC1600755BA7 /* eccsi.h */, 700F0BF82A2FBC1600755BA7 /* ed448.h */, 700F0BF42A2FBC1600755BA7 /* ed25519.h */, - 700F0BF92A2FBC1600755BA7 /* ext_mlkem.h */, 700F0C022A2FBC1600755BA7 /* falcon.h */, 700F0BEB2A2FBC1500755BA7 /* fe_448.h */, 700F0BF62A2FBC1600755BA7 /* fe_operations.h */, @@ -1174,7 +1167,6 @@ 700F0BE92A2FBC1500755BA7 /* sp.h */, 700F0BE22A2FBC1500755BA7 /* sphincs.h */, 700F0BF32A2FBC1600755BA7 /* srp.h */, - 700F0BFF2A2FBC1600755BA7 /* wc_mlkem.h */, 700F0BF52A2FBC1600755BA7 /* wc_pkcs11.h */, 700F0BE62A2FBC1500755BA7 /* wolfevent.h */, 5216465E1A8993770062516A /* aes.h */, diff --git a/INSTALL b/INSTALL index dc6e2908c1..c97cc54865 100644 --- a/INSTALL +++ b/INSTALL @@ -250,16 +250,18 @@ Congratulations! You have just achieved a fully quantum-safe TLS 1.3 connection! - The following NIST Competition winning algorithms are supported: + The following NIST Competition winning algorithms are supported by the + native wolfSSL implementation: - ML-KEM (CRYSTALS-KYBER) (key encapsulation mechanism) - ML-DSA (CRYSTALS-Dilithium) (signature scheme) - The following NIST Competition winning algorithms were supported by our - liboqs integration. Support for their standardized specifications will - return when we write our own implementations. + Falcon (signature scheme) is still provided through liboqs integration. + To enable it, pass both --with-liboqs and --enable-falcon to configure + (CMake: -DWOLFSSL_OQS=yes -DWOLFSSL_FALCON=yes). Passing --with-liboqs + without --enable-falcon (or vice versa) is now an error. - - FALCON (signature scheme) - - SPHINCS+ (signature scheme) + SPHINCS+ is in the middle of being replaced with native SLH-DSA; see + PR #10261. Until that lands, SPHINCS+ continues to build via liboqs. The following NIST Competition Round 3 finalist algorithms were supported, but have been removed after 5.3.3 diff --git a/certs/falcon/bench_falcon_level1_key.der b/certs/falcon/bench_falcon_level1_key.der index 1ff376d0ef76f3310648b53e7615e6e08ef28f4b..32d0e84e68e04cf8313ff79730a5d74fa11219ad 100644 GIT binary patch literal 2206 zcmXqL;+Vz6$Y8+E#;SdepP8GbiItV5iIp)@M9_izLj4=v)-U|d5{mXb0=8e|ngkp= zgwG%R{?UQ?10#d{VHQT)*Yn$yH|+Z&(DWnOnAO3#cK}3M@4+F#JdfQX^A`pO2|I@W z5178+XL>!ql_B1NA>Nkz1MC004kGqPnK#;VH#)N9Gyl>1&wQ`p3u6t7f}{BTUtf3+ z{1H4T;dkhTJqrWlzV{nz1Qsyx|KG!-$MD9#<@ev#4+7O90!O(&?EB&Wo%_RI>HI@) z6dYgV|NmlO`}%&(2L)FKh3zZ>zkk&4fBgQ)?}yF&7c9RdFune`PkDYP`-A#FiicU^ z{=6wV#K7XBi0}dX zKM7Ur7wQ-U99ioB{*Y_oh_@E8`^6L2_=C^&k6!El^Gxg?9Hck4G1&k5knr#I1;+R9 zS>Ny-5{PU5|KI8RBfB38&JqbOkMIBde7}|d|32mgOwxaAzQ1qdaIELP$ilq7UHF3| zdmRh=$3NfiHGJOi|MRHJN3x9vtd;WgNq<_$cfzeSy zzy6Iw4f}uN9}G+!@@?-Qw*4rmX0Uho{O>IDBc|{B_p|ixeUY&Bjv=FrpA(P4ZV~>2 z|LdDL`2YX0-~a#Zfe-ezKjNFX@3VdIuY3RKFY|>C?t3TiC_26=WPW}Bko?1auRl2d z|7a^x-z4LINI>8SgTi6<^?M)4A7o+J^T6)F|NH-i-#7k{`@^AMC;tC{^aaNs{D(ON z7+84!eKFX>;n*mkaQyQJXO`SU@6S2?eqgJk|5L>A_YXze=lg2}0-5*^bTIJOzbSAL zKk%RbeBB%V8tHco%=h=R@E_n&I3~cr#QfHsL;r~MfhH0C!@uAER6gLuzMvuMZKi|zBy!`p|(^o#Go2MAK)bH90 z@c!ju;?lm$e)f%ksL~tezw(by3o4v^^7gO#C#Lgv|NZ&&Rz&ot;44`Xc2=Rc7g#mF zGH}R#X8U*L?PsYEzg{yj3!h=(U+vY$M;~5YfBl4okxTIK3)LG^55I~36yOxp zkrIBT$SWiv$uE9IWA~GPXP*Ao7W>B_ckiCSJ7KAxyw{Btc{tuH^8RK2s~r0N7wgwQ z5})6RFn)dfO+?|>fd_m~WkqG!p78t;;pYAIgHMs~$Mr{dMBcNAy=8y%>D{Y$60cal z$iETf{~+@7|NB1zh8#+tzW)FDgHiq`?={_LA33kGzTn_tc_}J<`Kug@z6>v$8KcCz zA1@6!4W-32Uhtm&dh7f5cOMx=-!a|OkYtzrD)dg|8$a7yE~fYYIE}7$h{~ z-w5%^zv1J!|M}xnQLbM%`MB8l1+J;`iauah=DQ>CgEC(r+X_)>|VP39x#r(d$K?(+!!kPzb+Hhdzb#`Wdf3!~@X zIXV8m`|n|8sf^UvMR)_Vh0ioqQ-*!!FmUnmNwV;81{8MOUPx?fXd=GVVFLNG|*s7?+Z1tyXwc zK=arNCNJe}=`2a=OmTs!KXN~G&OGN5(HPM+d3o`%gwwwmtaeT`?hf@+-hH<@WP*EA z^%1QlBJBm1M=n3?m>|QFS$!(Vg zcP>hr-uP+Z|5Ja$ zJ<*$oyjHwW>(HK`%eBtx$prtzgo7(T?UlZ>XiJX8qttMjuct4rk9#3CZ6EWFM+V(L zqi=~_`X6=jFSpm*>#8}{2VK`)U-~Uw@a3}`o_h{OMJRn)TeY!N_dR#)#VJNbQC>Nw zGqyftSu^qFRjY!f58KY98qpbS1v58fb+s2{9Z-{5sHIjb)5Os8CMt+ydo1fd^9hj?+n>b+ zy=YmhzT;9sOo)EeQGN4B5tH16vp*{HU1aqPQ|8USVp^i}O#M-J-M3jMj!I`)ivACF z?A>bQS^fHt*R>kI0O6b0o^ac-d)!;Gb{j(D>e^OdAULN;@7RsS zhtIDLvor}?A>enYEAmS8$IuCLw>M9D#@R8?OIbf)$^k}`{j=^TC*Ap=r2H_vrf%xC zb0z{yuCr-2OT=b$2^XxMsPRf=#@sa-dsU7<;(7Q>VC6@Pc@H=F_bR;RnpL!Q<+7Po zH>9n!7Ov`GFLJu%J#m#sk-Nb=tE!hRs!u|=zoZIk_1yXF6n(C=;M>cz6%vcLO?G5U z=8%%~Kk@7yljxgE&kd%!F&F-NbXDUK<3E`X6|?u+io9R`lh3NBu}WgX-GjlI740bj rzZUWB{l z#(w@7k6`5={e!>%JIF7z=l*z@e}nU%L<+QW|K{*_{Ns3tN1=)N zkh6lq5BC3cKkORc-#g6U-^zTU?uWk9{f&0NKe}>%bd>&ZfcZW1>v{iPC_0Jw9rI50Bk|KYyRAd<-Rgun5Fed8a7rZ0+h+#fs`7_45zvx zz>sM9!@u!$JR67p0T%iH-1~QN|94-`*Gbd)VJM@i^EsC^YbIbowJ;&;EY@2f3y{_6;%thlMZv zdH=qKCx5^6g#Qc$M_Cw{-}g8CV5nzdbbO)c%rW2P`==WI19orx|1%ic3BPmr{ovQ@ z3;S94-TptSWxm(=MSm{`ztj5#4nG(jKVM{EU}O;9Q1|>nJ%_#>^QFVe^Z$##+xA+j zaKG#456vuWoKIf=`g@H*{MAcsXk`?9rdy$Fv>-R5m4t#&#Ns4}Y_VmLa zW_IR(f0#L6y#M+BEf+f%6UT*jvX?(>dd2?BQdr{4tFK(o9?Efxd{(>lO5&LS+y9pw zF9j}q=Xm#?_4QYQt3vYk|9>@RHT*02Oo=OMEjBOA|iGuAs7xtuv!zWw8rXM6pe`6OQ}-Z^(kS>&Ns#v=GrSLQuG zGwT=5=a2ueycPYV|M90RhuhnaJU=boKYM-g9?M_p-v&?5e!KUIli>xAI^#ht)-P`b ze}4bVb?pZ;53AU3`8UGspIMH{aWQgn-s8P<{|2Ax{li~)UOs*E^4%NdPw&LP%Rb@d zlM+uJC%#3p1Kk?oFaryM`fA8OltK4M!diVc(x#!1zGm8i@$Z2c8=F@#C zF3hU0{Po+rkCz|+dGqAot3RxIeBbz=zUO$)_>hyK@soh~bfcx6At}e*WrFtX|JLQs z)h?Gf>3x_-N5^^*?vA}pJB*UPTz6Qz?4=a5OG079;WDlM==myLll+d%w6*M3eSOPv zqGEw|d9uvPYgY}_1kTIeFxvDYrh`RrUe%VoPrem4AD1uvJY!WC$6N7J3+H7Yd+qC9 z&EhC6nJCG>bv@IIF6SLTmpMnhlAh9asZd)#Yrk4t%Nl=X2cC>2W{>}JUogBGarsc$ zBGt@Dh8502t(jsf0iq?+Ogj%$H>T7jZx_q(oRm;~;K=WJb;|9H9#`Vm-desmCdV(q zd5cH%MVluvQC+Qj%HAw>kYoDC)|+t6yvbc@sl>7*7Y^P>Zp(5`_s+ih%h2b1N$#r2 zim#WP+%)x{lg4u?tDP%m=SKdqSa$MQ?3+)rA5z+qB`1d$o^M^M?!3A2lZZI0p4uay z&!?S^D^L6s7;<}RwwnEi&zkpAA_bxf8mIAI+dF$#&=dD9M;rYY%LHrg`@ki+qB4p@ ze6~yo&)xYO{w>;DchTinmZa$HQ{^gMNAj8W=&;LVWp>VOc`5R+&vSun+58aCIHw6x zPqaUnecNs^>+)`nU(-&$cwblf^4`*A(?#dK+R}Yu;r4(E7KT5OAhcJuSFROJnGh0}!3?3}i9t+uGg=9WWq51;69G}Knm}l+qh}iT(F;qlrv1{j9%`$tg zkOa0VO~IZqll1s%1g4v+DlOMgG04z&tGE_=>TyTdlnUQ8wd?b%%#_PbH!!Gfa7=GH zlW42vc6{5^rShJ_JF6x(&1750=(;Xg`dOgKw8kX1m3(eHB;?ksgmgAMz9iVYy}?lN zedAmuj;DNfvwD{7S}k?5^kTM{d9<033EQ&k-c6<_Qx2#3rST^%)h_H(=DNr><)KSo zq@yF}N#E_V@AS5tGInNvd9?BQl*TdOhy$3G#uq zc89hKpIes`#_P3uW_RbCeW#e*b5nX&5NLo+44#tn-use7JJnAdZ7LEen6?>c7I zb*dAt9V+1Y`i6b!y3iCB=EDu4Hs*F0n``t1eeUgWImN%fx=DNMWr4J|KFe>$b9oCk nFa;dtS2xvpAM7U_v17#nuc?W@Jy=hlbhu=-Z{_xiviWiV7^@gY diff --git a/certs/falcon/bench_falcon_level5_key.der b/certs/falcon/bench_falcon_level5_key.der index a0eaa2a3b794163ee8152e6556954d187030f21c..15f25b19f69bf5a4c24ef456f5f7bf0e11efce02 100644 GIT binary patch literal 4126 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 bR##P==17eY&bO_YbR3HJlS2fw#4 zFvtIJQ~V(--oW2|fba0T_I)3|FusxfeoXL(v_$>6|GNa->^}c9v~&2~AmMz0DJqKLq;sidV!xVEJ)~ z|M$P2UqAF8Vzj+jo+xm{k!3#L$@%{e->70>PyE2bpP%@=Lhk=vLnek6hyP9tKbQpm z71lVKA5vO&int%F7m6SMw~PCuD8Gk+{m_R)cI*#0m<0YLe_;LpzLvd>iTx>u zn-llK=YQYlIDKGYXi50lBF{hL#{T!^hd3NR{(c}{{k9@Tz)8RPUcfdb_QwLQ59$}b zWDu-=c;krQ|Nr8D45b(SaJ(;I|HA%%`yqK3h35U@ObRU4KNt@*KQeHLZ%}4$KJX!d z;fMgo{1?0Q|3Bt)TwIeRUc>+U0DJAFH%w$f^$La-`~Qs}HVA%U5Ze)7efRwVdk!Z4iyx*qec(M%qsV`Zv8Iln@ggImyyb)D z`|Ne{+`sjYKQ2g?KPFHU$6&`a!|{6y{})Df)(^`2KDZe)KVYc5&-0kyh2j7G7e_>d z_jA-vVt$~&JW*ibN5*r-E#G%3XV`zJ(PjS6zR$k?rU3In=0mTzfAIX|KOcri>odZD`E z{~>`7vG42ueUaxsB+z1ey+)xy{6*{A9_H(<_rAHa?dFN*&U8FVas@4)cK`G@uT3dRqvZ@T{pSm}TN z&%vN5zL)(F-yc`|gYSM@eK>frCF%v|!3qYxFLL!Z5(n>fEaGnwV5t({f3QSNqVa!@ zHUAm?2Kf(m0v&t*o!r3u?}we@pF{Qy4E+z}ThDbL<#*gz-^|Hm_eb$Xof7*(3)>G3 zHUcgR{P+2*7&{pFfAJOH|ImD?=Ki}g3}2iX?Ef>^{%c3}*80?|pB-(0+t(TW|NnA7}4#+wz}(*TBeV``}NKrsD_p|Nq?* z8)Vi0$$zot|9`&w--{Oi78QQk-?#qpi3u=^K70J*{|)aGPrs-!-`4ue`tUvXABEqB zf-=ma53h0G`6~4Gm4?Do#XHaMv)=piU;e$ll#vvb=DtRzqo(D-^uZhM}+m!ufHdGzF3_7 zb?pf&tK1K3Jw7pZ9f8l%9~n4492dEMm+jE!zXGfhD$nk6-MRhl-?yKV4&2)28pr>B zXTQqB!+1yg#$TR`e}rBz-C@1;nnC8yfA$~zCxqEJnBNG#`1|)i@24Bz|Nj>J^5`Y| z^KUPMg^l0Ihzc{P{CUMG`bOic{O!kon11r`svUOMp?HSwmOhhX5DnSEH-np2+|Ba^uSlE_N}lzal@B z?l9l|_4@J?UY2jNa`(S!sETu+|0r@({I$vVH|G@Ot}3vxE+<*`{yYupUTgB*Q8nhU;g}w_XG1+$$z)G8JLa=vAmV~AS9z9|NidjKTMzA zUVQWP%)f8U@9x|4|7Bq{5|sJ$L5}@ByPUWv3nTOQUraY&OP+nDt@QUg$A>RpKDux| z<^K0hUh3`t-|T=Z|k+i(K*JRy`rYDDX={NSN!v+v|*1zun!#bMwzbcD8qW z<=;ptvHX$v^oo)D+b>}?PWCt49Q^9Q`}>cWu*`!uZ(p)M`1A2LyYf!~ zjwj#0ygB>e=h@G~OsqUVe*G7D%=qdzi_X{20+P>}?`ZvI<7TyeaYg^{JrT*P?|$*J zaXZT2;*3B{YH}%gx$LlM$K0Y)x-N;6xL+hRY zyhCrkUVpUEch1JcDTnfKE@VQK5;oC=afmYTWvI#`o7z{?8NcL?#U@R*H)~Nu!;7_EMKXY zy6Bl&@%OHIhGEy9>7Tv3|C8adcKv5M8UB?|4sm(>@%{3{p>@tfA9r7|j;*HxcV`O) znCI%#^;u|!(Wf2p3%3+ofjL@HXjOJ!$eaLpqIV_U0e1_OAUw6Co2W-KixS)_mf%Nnurjqnpfr18PYDz z4ledND8J_2gzOU!_ROm}*da4PDDsy)GZSqms05%&ez&`^Ccv7Y}#v9ysG!wxh*f<^VC9y@@2+P zb&kDF`{MUS{`KFanDqj-ecJ1Ox^4S5!?gUu9Ill**Yn++T)Xdo=hAuRc=**CHiKIy zpDSr{>lAoKvub*X7(FY^Yczeb;E|79@OCrFgYR7)YI&aEKH&VVJmgx#gQvp2|-0y8Ytv7sdzAq|1A=`!7xAdK{Y|BYAbj?0ft=o4#t> z$OSlU2|20pMBny8wu-Ry+tx)qQv+_q7f)N5@_yNi)X*PGeuk)&v0i^_I^(R#!w+Wa zJz~<^9u?mTzbp7q)a~NUzJ$<`sYr)aGGt2n`G(PS9_*!h$mYFY{)-_I>>A?5V zU`0%-PO0LlGkjAMSy-+(3)c22wp2xbmwmPELoo8kZQU-dL=unDs2O)FzQ}m+@|y3zI<72%*IKNTW%M>vGsg? zBgyNX?n2>Hsdc;7CcazLr<}KZdg)=DRe>NU+4v!-&{~AlboLG=>LFvM^ zT7^iC7V8-^x5l_gzF0a_G;ziwzof|NKNGV*gm=#0YrK19*p67+ECEx;cMfYltuo2t zTwvOKX|>A2=>_K&zSHN8J!#kdO?BngA36^*ojFn@k18v?xxvD)qAig@J}+k8t;CG> z_>D@Q)#B-OfnE<;r423bmOA-76xh9kV+GHI!;upn&1_EH6MJMrd-s#iMwWBk{;MR& z8+on_pZ>ik(yoAWvKP-Eqrf)DR2JXwOq;Scu9C=J#QO4j%t?dconMYpub4mwhr1edgR+9P;MBo7&6i$xZ&tW-a*K+1%&3 zPVq}j9&abdDU&mY4!if95L#{iiY~9_^{Et}xtncz#V@t>x!;ZgU!+ zu3B-ONnCx(kB=c-i`;FVFI&oB*tqa<+xxJ`W;*h1Z!hPv?lSxML9b=jujQPPBHCPk z4v5*U5?-&$23e{&Nys1 n<@!`)^1=%T&ELrhXYTBM*mmYF@1eJsBZcQ~y%3NgwR9N(sP@zD diff --git a/cmake/functions.cmake b/cmake/functions.cmake index 84e2d1039b..6bd57e4ec3 100644 --- a/cmake/functions.cmake +++ b/cmake/functions.cmake @@ -213,11 +213,12 @@ function(generate_build_flags) if(WOLFSSL_DILITHIUM OR WOLFSSL_USER_SETTINGS) set(BUILD_DILITHIUM "yes" PARENT_SCOPE) endif() - if(WOLFSSL_OQS OR WOLFSSL_USER_SETTINGS) + if(WOLFSSL_FALCON OR WOLFSSL_USER_SETTINGS) set(BUILD_FALCON "yes" PARENT_SCOPE) + set(BUILD_OQS_HELPER "yes" PARENT_SCOPE) + endif() + if(WOLFSSL_OQS OR WOLFSSL_USER_SETTINGS) set(BUILD_SPHINCS "yes" PARENT_SCOPE) - set(BUILD_DILITHIUM "yes" PARENT_SCOPE) - set(BUILD_EXT_MLKEM "yes" PARENT_SCOPE) set(BUILD_OQS_HELPER "yes" PARENT_SCOPE) endif() if(WOLFSSL_LMS OR WOLFSSL_USER_SETTINGS) @@ -1073,10 +1074,6 @@ function(generate_lib_src_list LIB_SOURCES) endif() endif() - if(BUILD_EXT_MLKEM) - list(APPEND LIB_SOURCES wolfcrypt/src/ext_mlkem.c) - endif() - if(BUILD_WC_LMS) list(APPEND LIB_SOURCES wolfcrypt/src/wc_lms.c) list(APPEND LIB_SOURCES wolfcrypt/src/wc_lms_impl.c) diff --git a/cmake/options.h.in b/cmake/options.h.in index 12ab8285e4..1fe054b276 100644 --- a/cmake/options.h.in +++ b/cmake/options.h.in @@ -380,12 +380,8 @@ extern "C" { #cmakedefine WOLFSSL_EXPERIMENTAL_SETTINGS #undef WOLFSSL_HAVE_MLKEM #cmakedefine WOLFSSL_HAVE_MLKEM -#undef WOLFSSL_WC_MLKEM -#cmakedefine WOLFSSL_WC_MLKEM #undef WOLFSSL_TLS_NO_MLKEM_STANDALONE #cmakedefine WOLFSSL_TLS_NO_MLKEM_STANDALONE -#undef WOLFSSL_WC_DILITHIUM -#cmakedefine WOLFSSL_WC_DILITHIUM #undef NO_WOLFSSL_STUB #cmakedefine NO_WOLFSSL_STUB #undef HAVE_ECC_SECPR2 diff --git a/configure.ac b/configure.ac index d324fb30d3..554212219f 100644 --- a/configure.ac +++ b/configure.ac @@ -1741,6 +1741,23 @@ AC_ARG_WITH([liboqs], ] ) +# Falcon (provided via liboqs) +AC_ARG_ENABLE([falcon], + [AS_HELP_STRING([--enable-falcon],[Enable Falcon post-quantum signatures via liboqs (default: disabled)])], + [ ENABLED_FALCON=$enableval ], + [ ENABLED_FALCON=no ]) + +if test "$ENABLED_FALCON" = "yes" && test "$ENABLED_LIBOQS" = "no"; then + AC_MSG_ERROR([--enable-falcon requires --with-liboqs.]) +fi +if test "$ENABLED_LIBOQS" = "yes" && test "$ENABLED_FALCON" != "yes"; then + AC_MSG_ERROR([--with-liboqs requires --enable-falcon.]) +fi + +if test "$ENABLED_FALCON" = "yes"; then + AM_CFLAGS="$AM_CFLAGS -DHAVE_FALCON" +fi + # MLKEM # Used: @@ -7080,7 +7097,6 @@ then fi fi -ENABLED_WC_MLKEM=no ENABLED_ML_KEM=unset ENABLED_MLKEM_MAKE_KEY=no ENABLED_MLKEM_ENCAPSULATE=no @@ -7147,99 +7163,6 @@ do esac done -if test "$ENABLED_MLKEM" != "no" -then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_MLKEM" - # Use liboqs if specified. - if test "$ENABLED_LIBOQS" = "no"; then - ENABLED_WC_MLKEM=yes - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_MLKEM" - AM_CCASFLAGS="$AM_CCASFLAGS -DWOLFSSL_WC_MLKEM" - fi - - if test "$ENABLED_ORIGINAL" = "yes"; then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_MLKEM_KYBER" - if test "$ENABLED_MLKEM512" = ""; then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_KYBER512" - fi - if test "$ENABLED_MLKEM768" = ""; then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_KYBER768" - fi - if test "$ENABLED_MLKEM1024" = ""; then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_KYBER1024" - fi - if test "$ENABLED_ML_KEM" = "unset"; then - ENABLED_ML_KEM=no - fi - fi - if test "$ENABLED_ML_KEM" = "unset"; then - ENABLED_ML_KEM=yes - fi - if test "$ENABLED_ML_KEM" = "yes"; then - if test "$ENABLED_MLKEM512" = ""; then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_KEM_512" - fi - if test "$ENABLED_MLKEM768" = ""; then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_KEM_768" - fi - if test "$ENABLED_MLKEM1024" = ""; then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_KEM_1024" - fi - else - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_KEM" - fi - if test "$ENABLED_MLKEM_MAKE_KEY" = "no"; then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_MLKEM_NO_MAKE_KEY" - fi - if test "$ENABLED_MLKEM_ENCAPSULATE" = "no"; then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_MLKEM_NO_ENCAPSULATE" - fi - if test "$ENABLED_MLKEM_DECAPSULATE" = "no"; then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_MLKEM_NO_DECAPSULATE" - fi - - if test "$ENABLED_WC_MLKEM" = "yes" - then - test "$enable_sha3" = "" && enable_sha3=yes - test "$enable_shake128" = "" && enable_shake128=yes - test "$enable_shake256" = "" && enable_shake256=yes - fi -fi - -AS_IF([ test "$ENABLED_MLKEM_STANDALONE" = "yes" && test "$ENABLED_ML_KEM" = "no" ],[AC_MSG_ERROR([ML-KEM as standalone TLS key exchange (non-hybrid) requires ML-KEM.])]) -if test "$ENABLED_MLKEM_STANDALONE" != "yes" -then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_TLS_NO_MLKEM_STANDALONE" -fi - -if test "$ENABLED_PQC_HYBRIDS" = "yes" -then - if test "$ENABLED_ML_KEM" = "no" || test "$ENABLED_MLKEM" = "no" - then - ENABLED_PQC_HYBRIDS=no - elif test "$ENABLED_MLKEM768" = "" && test "$ENABLED_MLKEM1024" = ""; then - AC_MSG_NOTICE([PQC hybrid combinations require either ML-KEM 768 or ML-KEM 1024, but both disabled.]) - ENABLED_PQC_HYBRIDS=no - else - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_PQC_HYBRIDS" - fi -fi - -if test "$ENABLED_ML_KEM" != "no" && test "$ENABLED_MLKEM" != "no" -then - if test "$ENABLED_PQC_HYBRIDS" = "no" && test "$ENABLED_MLKEM_STANDALONE" = "no" && test "$ENABLED_CRYPTONLY" = "no" - then - AC_MSG_ERROR([Both hybrid PQ/T and standalone ML-KEM are disabled, so no PQC hybrid combinations will be available.]) - fi -fi - -if test "$ENABLED_EXTRA_PQC_HYBRIDS" = "yes" -then - AS_IF([ test "$ENABLED_EXPERIMENTAL" != "yes" ],[ AC_MSG_ERROR([extra-pqc-hybrids requires --enable-experimental.]) ]) - AS_IF([ test "$ENABLED_ML_KEM" = "no" ],[ AC_MSG_ERROR([extra-pqc-hybrids requires ML-KEM.]) ]) - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_EXTRA_PQC_HYBRIDS" -fi - # Selftest uses its own random.c which doesn't support SHA-512 DRBG # or runtime DRBG disable/enable APIs AS_IF([test "x$ENABLED_SELFTEST" = "xyes"], @@ -7352,13 +7275,13 @@ fi # ML-KEM and Dilithium require SHA-3 and SHAKE -- force them on before flag # processing so that the correct -D flags are emitted. -if test "$ENABLED_MLKEM" != "no" && test "$ENABLED_LIBOQS" = "no" +if test "$ENABLED_MLKEM" != "no" then ENABLED_SHA3=yes ENABLED_SHAKE128=yes ENABLED_SHAKE256=yes fi -if test "$ENABLED_DILITHIUM" != "no" && test "$ENABLED_LIBOQS" = "no" +if test "$ENABLED_DILITHIUM" != "no" then ENABLED_SHA3=yes ENABLED_SHAKE128=yes @@ -7407,12 +7330,7 @@ fi if test "$ENABLED_MLKEM" != "no" then AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_MLKEM" - # Use liboqs if specified. - if test "$ENABLED_LIBOQS" = "no"; then - ENABLED_WC_MLKEM=yes - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_MLKEM" - AM_CCASFLAGS="$AM_CCASFLAGS -DWOLFSSL_WC_MLKEM" - fi + AM_CCASFLAGS="$AM_CCASFLAGS -DWOLFSSL_HAVE_MLKEM" if test "$ENABLED_ORIGINAL" = "yes"; then # FIPS 203 (ML-KEM) and Kyber use different implicit rejection. @@ -7459,12 +7377,9 @@ then AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_MLKEM_NO_DECAPSULATE" fi - if test "$ENABLED_WC_MLKEM" = "yes" - then - test "$enable_sha3" = "" && enable_sha3=yes - test "$enable_shake128" = "" && enable_shake128=yes - test "$enable_shake256" = "" && enable_shake256=yes - fi + test "$enable_sha3" = "" && enable_sha3=yes + test "$enable_shake128" = "" && enable_shake128=yes + test "$enable_shake256" = "" && enable_shake256=yes fi AC_ARG_ENABLE([tls-mlkem-standalone], @@ -7476,7 +7391,19 @@ AC_ARG_ENABLE([tls-mlkem-standalone], AS_IF([ test "$ENABLED_MLKEM_STANDALONE" = "yes" && test "$ENABLED_ML_KEM" = "no" ],[AC_MSG_ERROR([ML-KEM as standalone TLS key exchange (non-hybrid) requires ML-KEM.])]) if test "$ENABLED_MLKEM_STANDALONE" != "yes" then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_TLS_NO_MLKEM_STANDALONE" + # Hybrid PQ/T groups all combine ML-KEM with an ECC/Curve25519/Curve448 + # base. If none of those is available, hybrids contribute no usable groups + # for TLS 1.3 key exchange. In that case, auto-enable standalone ML-KEM so + # TLS 1.3 has a functional KEM. + if test "$ENABLED_MLKEM" = "yes" && test "$ENABLED_ML_KEM" != "no" && \ + test "x$ENABLED_ECC" = "xno" && test "x$ENABLED_CURVE25519" = "xno" && \ + test "x$ENABLED_CURVE448" = "xno" + then + AC_MSG_NOTICE([No ECC/Curve25519/Curve448 base for ML-KEM hybrids; auto-enabling standalone ML-KEM for TLS 1.3.]) + ENABLED_MLKEM_STANDALONE=yes + else + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_TLS_NO_MLKEM_STANDALONE" + fi fi AC_ARG_ENABLE([pqc-hybrids], @@ -7524,6 +7451,7 @@ fi if test "$ENABLED_DILITHIUM" != "no" then AM_CFLAGS="$AM_CFLAGS -DHAVE_DILITHIUM" + AM_CCASFLAGS="$AM_CCASFLAGS -DHAVE_DILITHIUM" if test "$ENABLED_MLDSA44" = ""; then AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_ML_DSA_44" @@ -7544,13 +7472,10 @@ then AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DILITHIUM_NO_VERIFY" fi - if test "$ENABLED_LIBOQS" = "no"; then - AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_WC_DILITHIUM" - AM_CCASFLAGS="$AM_CCASFLAGS -DWOLFSSL_WC_DILITHIUM" - test "$enable_sha3" = "" && enable_sha3=yes - test "$enable_shake128" = "" && enable_shake128=yes - test "$enable_shake256" = "" && enable_shake256=yes - fi + test "$enable_sha3" = "" && enable_sha3=yes + test "$enable_shake128" = "" && enable_shake128=yes + test "$enable_shake256" = "" && enable_shake256=yes + ENABLED_CERTS=yes fi @@ -8337,18 +8262,18 @@ then AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_REQUIRE_FFDHE" fi -# TLS 1.3 Requires either ECC or (RSA/DH), or CURVE25519/ED25519 or CURVE448/ED448 or libOQS +# TLS 1.3 Requires either ECC or (RSA/DH), or CURVE25519/ED25519 or CURVE448/ED448 or ML-KEM if test "x$ENABLED_PSK" = "xno" && test "x$ENABLED_ECC" = "xno" && \ (test "x$ENABLED_RSA" = "xno" || test "x$ENABLED_DH" = "xno") && \ (test "x$ENABLED_CURVE25519" = "xno" || test "x$ENABLED_ED25519" = "xno") && \ (test "x$ENABLED_CURVE448" = "xno" || test "x$ENABLED_ED448" = "xno") && \ - test "x$ENABLED_LIBOQS" = "xno" + test "x$ENABLED_MLKEM" = "xno" then # disable TLS 1.3 ENABLED_TLS13=no fi if test "$ENABLED_TLS13" = "yes" && (test "x$ENABLED_ECC" = "xyes" || \ - test "$ENABLED_DH" != "no") + test "$ENABLED_DH" != "no" || test "x$ENABLED_MLKEM" = "xyes") then AM_CFLAGS="$AM_CFLAGS -DHAVE_SUPPORTED_CURVES" fi @@ -12208,7 +12133,7 @@ AM_CONDITIONAL([BUILD_CURVE448_SMALL],[test "x$ENABLED_CURVE448_SMALL" = "xyes" AM_CONDITIONAL([BUILD_WC_LMS],[test "x$ENABLED_WC_LMS" != "xno" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_WC_XMSS],[test "x$ENABLED_WC_XMSS" != "xno" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_WC_SLHDSA],[test "x$ENABLED_SLHDSA" != "xno" || test "x$ENABLED_USERSETTINGS" = "xyes"]) -AM_CONDITIONAL([BUILD_WC_MLKEM],[test "x$ENABLED_WC_MLKEM" != "xno" || test "x$ENABLED_USERSETTINGS" = "xyes"]) +AM_CONDITIONAL([BUILD_WC_MLKEM],[test "x$ENABLED_MLKEM" != "xno" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_DILITHIUM],[test "x$ENABLED_DILITHIUM" != "xno" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_ECCSI],[test "x$ENABLED_ECCSI" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_SAKKE],[test "x$ENABLED_SAKKE" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) @@ -12768,7 +12693,6 @@ echo " * XMSS_ROOT: $XMSS_ROOT" fi echo " * SLH-DSA $ENABLED_SLHDSA" echo " * MLKEM: $ENABLED_MLKEM" -echo " * MLKEM wolfSSL impl: $ENABLED_WC_MLKEM" echo " * DILITHIUM: $ENABLED_DILITHIUM" echo " * ECCSI $ENABLED_ECCSI" echo " * SAKKE $ENABLED_SAKKE" @@ -12829,6 +12753,7 @@ echo " * Public Key Callbacks: $ENABLED_PKCALLBACKS" echo " * libxmss: $ENABLED_LIBXMSS" echo " * liblms: $ENABLED_LIBLMS" echo " * liboqs: $ENABLED_LIBOQS" +echo " * Falcon (via liboqs): $ENABLED_FALCON" echo " * Whitewood netRandom: $ENABLED_WNR" echo " * Server Name Indication: $ENABLED_SNI" echo " * ALPN: $ENABLED_ALPN" diff --git a/examples/benchmark/tls_bench.c b/examples/benchmark/tls_bench.c index 85645224fd..d0b799eb46 100644 --- a/examples/benchmark/tls_bench.c +++ b/examples/benchmark/tls_bench.c @@ -294,7 +294,7 @@ static struct group_info groups[] = { { WOLFSSL_FFDHE_4096, "FFDHE_4096" }, { WOLFSSL_FFDHE_6144, "FFDHE_6144" }, { WOLFSSL_FFDHE_8192, "FFDHE_8192" }, -#ifdef HAVE_PQC +#ifdef WOLFSSL_HAVE_MLKEM #ifndef WOLFSSL_NO_ML_KEM #ifndef WOLFSSL_TLS_NO_MLKEM_STANDALONE { WOLFSSL_ML_KEM_512, "ML_KEM_512" }, diff --git a/examples/client/client.c b/examples/client/client.c index dfcfe5942b..1e920bf104 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -417,7 +417,7 @@ static void SetKeyShare(WOLFSSL* ssl, int onlyKeyShare, int useX25519, } while (ret == WC_NO_ERR_TRACE(WC_PENDING_E)); #endif } - #ifdef HAVE_PQC + #ifdef WOLFSSL_HAVE_MLKEM if (onlyKeyShare == 0 || onlyKeyShare == 3) { if (usePqc) { int group = 0; @@ -1414,7 +1414,7 @@ static const char* client_usage_msg[][81] = { "-7 Set minimum downgrade protocol version [0-4] " " SSLv3(0) - TLS1.3(4)\n", /* 68 */ #endif -#ifdef HAVE_PQC +#ifdef WOLFSSL_HAVE_MLKEM "--pqc Key Share with specified post-quantum algorithm only:\n" #ifndef WOLFSSL_NO_ML_KEM " ML_KEM_512, ML_KEM_768, ML_KEM_1024,\n" @@ -1687,7 +1687,7 @@ static const char* client_usage_msg[][81] = { "-7 最小ダウングレード可能なプロトコルバージョンを設定します [0-4] " " SSLv3(0) - TLS1.3(4)\n", /* 68 */ #endif -#ifdef HAVE_PQC +#ifdef WOLFSSL_HAVE_MLKEM "--pqc post-quantum 名前付きグループとの鍵共有のみ:\n" #ifndef WOLFSSL_NO_ML_KEM " ML_KEM_512, ML_KEM_768, ML_KEM_1024,\n" @@ -1959,7 +1959,7 @@ static void Usage(void) printf("%s", msg[++msgid]); /* --wolfsentry-config */ #endif printf("%s", msg[++msgid]); /* -7 */ -#ifdef HAVE_PQC +#ifdef WOLFSSL_HAVE_MLKEM printf("%s", msg[++msgid]); /* --pqc */ #endif #ifdef WOLFSSL_SRTP @@ -2140,7 +2140,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #ifndef NO_MULTIBYTE_PRINT { "ヘルプ", 0, 258 }, #endif -#if defined(HAVE_PQC) +#if defined(WOLFSSL_HAVE_MLKEM) { "pqc", 1, 259 }, #endif #ifdef WOLFSSL_SRTP @@ -3025,7 +3025,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) break; #endif -#if defined(HAVE_PQC) +#if defined(WOLFSSL_HAVE_MLKEM) case 259: { usePqc = 1; @@ -3235,7 +3235,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) err_sys("can't load whitewood net random config file"); #endif -#ifdef HAVE_PQC +#ifdef WOLFSSL_HAVE_MLKEM if (usePqc) { if (version == CLIENT_DOWNGRADE_VERSION || version == EITHER_DOWNGRADE_VERSION) diff --git a/examples/configs/user_settings_ca.h b/examples/configs/user_settings_ca.h index 73e1e06c2f..7bc4e63c82 100644 --- a/examples/configs/user_settings_ca.h +++ b/examples/configs/user_settings_ca.h @@ -149,7 +149,6 @@ extern "C" { #if 0 /* ML-DSA / Dilithium certificates */ #define WOLFSSL_EXPERIMENTAL_SETTINGS #define HAVE_DILITHIUM - #define WOLFSSL_WC_DILITHIUM #define WOLFSSL_SHAKE128 #define WOLFSSL_SHAKE256 #endif diff --git a/examples/configs/user_settings_espressif.h b/examples/configs/user_settings_espressif.h index 5f4e0b81d6..bd2d4e726b 100644 --- a/examples/configs/user_settings_espressif.h +++ b/examples/configs/user_settings_espressif.h @@ -215,7 +215,6 @@ #ifdef CONFIG_ESP_WOLFSSL_ENABLE_MLKEM /* Kyber typically needs a minimum 10K stack */ #define WOLFSSL_HAVE_MLKEM - #define WOLFSSL_WC_MLKEM #define WOLFSSL_SHAKE128 #define WOLFSSL_SHAKE256 @@ -234,7 +233,7 @@ #define WOLFSSL_NO_ML_KEM_768 #define NO_SESSION_CACHE #else - /* Only needed for older wolfssl versions, see mlkem.h */ + /* Only needed for older wolfssl versions, see wc_mlkem.h */ #define WOLFSSL_KYBER1024 /* optional alternative sizes: */ /* #define WOLFSSL_KYBER768 */ diff --git a/examples/configs/user_settings_platformio.h b/examples/configs/user_settings_platformio.h index df422306e7..3abaf6ff8e 100644 --- a/examples/configs/user_settings_platformio.h +++ b/examples/configs/user_settings_platformio.h @@ -59,7 +59,6 @@ #if 0 /* Kyber typically needs a minimum 10K stack */ #define WOLFSSL_HAVE_MLKEM - #define WOLFSSL_WC_MLKEM #define WOLFSSL_SHA3 #endif diff --git a/examples/configs/user_settings_pq.h b/examples/configs/user_settings_pq.h index b207cbd95b..a85bdaf69e 100644 --- a/examples/configs/user_settings_pq.h +++ b/examples/configs/user_settings_pq.h @@ -88,7 +88,6 @@ extern "C" { /* ------------------------------------------------- */ #if 1 /* ML-DSA (FIPS 204) */ #define HAVE_DILITHIUM - #define WOLFSSL_WC_DILITHIUM #define DILITHIUM_LEVEL2 /* Level 2: ~128-bit security */ #define DILITHIUM_LEVEL3 /* Level 3: ~192-bit security */ #define DILITHIUM_LEVEL5 /* Level 5: ~256-bit security */ diff --git a/examples/configs/user_settings_stm32.h b/examples/configs/user_settings_stm32.h index 1084c9d180..765e437514 100644 --- a/examples/configs/user_settings_stm32.h +++ b/examples/configs/user_settings_stm32.h @@ -671,9 +671,6 @@ extern "C" { #undef WOLFSSL_HAVE_MLKEM #define WOLFSSL_HAVE_MLKEM - #undef WOLFSSL_WC_MLKEM - #define WOLFSSL_WC_MLKEM - #undef WOLFSSL_NO_SHAKE128 #undef WOLFSSL_SHAKE128 #define WOLFSSL_SHAKE128 diff --git a/examples/configs/user_settings_wolfboot_keytools.h b/examples/configs/user_settings_wolfboot_keytools.h index 8c44d3f0f7..450f91b970 100644 --- a/examples/configs/user_settings_wolfboot_keytools.h +++ b/examples/configs/user_settings_wolfboot_keytools.h @@ -117,7 +117,6 @@ extern "C" { #if 1 /* ML-DSA / Dilithium */ #define HAVE_DILITHIUM - #define WOLFSSL_WC_DILITHIUM /* Builds to FIPS 204 final standard by default. * Set to 1 for draft version. */ #if 0 /* FIPS 204 Draft */ diff --git a/examples/server/server.c b/examples/server/server.c index 25ae785151..4030af72df 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -704,7 +704,7 @@ static void SetKeyShare(WOLFSSL* ssl, int onlyKeyShare, int useX25519, #endif } else if (usePqc == 1) { - #ifdef HAVE_PQC + #ifdef WOLFSSL_HAVE_MLKEM groups[count] = 0; #ifndef WOLFSSL_NO_ML_KEM #if !defined(WOLFSSL_NO_ML_KEM_512) && \ @@ -1082,7 +1082,7 @@ static const char* server_usage_msg[][71] = { "-7 Set minimum downgrade protocol version [0-4] " " SSLv3(0) - TLS1.3(4)\n", /* 59 */ #endif -#ifdef HAVE_PQC +#ifdef WOLFSSL_HAVE_MLKEM "--pqc Key Share with specified post-quantum algorithm only:\n" #ifndef WOLFSSL_NO_ML_KEM " ML_KEM_512, ML_KEM_768, ML_KEM_1024,\n" @@ -1309,7 +1309,7 @@ static const char* server_usage_msg[][71] = { "-7 最小ダウングレード可能なプロトコルバージョンを設定します [0-4] " " SSLv3(0) - TLS1.3(4)\n", /* 59 */ #endif -#ifdef HAVE_PQC +#ifdef WOLFSSL_HAVE_MLKEM "--pqc post-quantum 名前付きグループとの鍵共有のみ:\n" #ifndef WOLFSSL_NO_ML_KEM " ML_KEM_512, ML_KEM_768, ML_KEM_1024," @@ -1510,7 +1510,7 @@ static void Usage(void) printf("%s", msg[++msgId]); /* --wolfsentry-config */ #endif printf("%s", msg[++msgId]); /* -7 */ -#ifdef HAVE_PQC +#ifdef WOLFSSL_HAVE_MLKEM printf("%s", msg[++msgId]); /* --pqc */ printf("%s", msg[++msgId]); /* --pqc options */ printf("%s", msg[++msgId]); /* more --pqc options */ @@ -1633,7 +1633,7 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) #ifndef NO_MULTIBYTE_PRINT { "ヘルプ", 0, 258 }, #endif -#if defined(HAVE_PQC) +#if defined(WOLFSSL_HAVE_MLKEM) { "pqc", 1, 259 }, #endif #ifdef WOLFSSL_SRTP @@ -2453,7 +2453,7 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) break; #endif -#ifdef HAVE_PQC +#ifdef WOLFSSL_HAVE_MLKEM case 259: { usePqc = 1; @@ -2688,7 +2688,7 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) "file"); #endif -#ifdef HAVE_PQC +#ifdef WOLFSSL_HAVE_MLKEM if (usePqc) { if (version == SERVER_DOWNGRADE_VERSION || version == EITHER_DOWNGRADE_VERSION) { diff --git a/gencertbuf.pl b/gencertbuf.pl index 6699c9f2ad..110465666d 100755 --- a/gencertbuf.pl +++ b/gencertbuf.pl @@ -147,14 +147,14 @@ my @fileList_sm2_der = ( ); #Falcon Post-Quantum Keys -#Used with HAVE_PQC +#Used with HAVE_FALCON my @fileList_falcon = ( ["certs/falcon/bench_falcon_level1_key.der", "bench_falcon_level1_key" ], ["certs/falcon/bench_falcon_level5_key.der", "bench_falcon_level5_key" ], ); #Sphincs+ Post-Quantum Keys -#Used with HAVE_PQC +#Used with HAVE_SPHINCS my @fileList_sphincs = ( ["certs/sphincs/bench_sphincs_fast_level1_key.der", "bench_sphincs_fast_level1_key" ], ["certs/sphincs/bench_sphincs_fast_level3_key.der", "bench_sphincs_fast_level3_key" ], diff --git a/linuxkm/module_exports.c.template b/linuxkm/module_exports.c.template index ad2f07cac9..a0a7afb988 100644 --- a/linuxkm/module_exports.c.template +++ b/linuxkm/module_exports.c.template @@ -152,11 +152,8 @@ #endif #ifdef WOLFSSL_HAVE_MLKEM - #include -#ifdef WOLFSSL_WC_MLKEM #include #endif -#endif #if defined(WOLFSSL_HAVE_XMSS) #include #ifdef HAVE_LIBXMSS diff --git a/scripts/asn1_oid_sum.pl b/scripts/asn1_oid_sum.pl index 8c5200d2d3..fb48857a3b 100755 --- a/scripts/asn1_oid_sum.pl +++ b/scripts/asn1_oid_sum.pl @@ -201,6 +201,10 @@ sub print_header { #ifndef WOLF_CRYPT_OID_SUM_H #define WOLF_CRYPT_OID_SUM_H +/* Note for some CPUs smaller than 32 bit, the upper 16 bits of new OID + * values may be ignored. If collisions are encountered, consider WC_16BIT_CPU + * and/or WOLFSSL_OLD_OID_SUM to force smaller, old OID values. */ + " } @@ -290,8 +294,8 @@ my @x25519 = ( 1, 3, 101, 110 ); my @ed448 = ( 1, 3, 101, 113 ); my @x448 = ( 1, 3, 101, 111 ); my @dh = ( 1, 2, 840, 113549, 1, 3, 1 ); -my @falcon_1 = ( 1, 3, 9999, 3, 6 ); -my @falcon_5 = ( 1, 3, 9999, 3, 9 ); +my @falcon_1 = ( 1, 3, 9999, 3, 11 ); +my @falcon_5 = ( 1, 3, 9999, 3, 14 ); my @dilithium_2 = ( 1, 3, 6, 1, 4, 1, 2, 267, 12, 4, 4 ); my @dilithium_3 = ( 1, 3, 6, 1, 4, 1, 2, 267, 12, 6, 5 ); my @dilithium_5 = ( 1, 3, 6, 1, 4, 1, 2, 267, 12, 8, 7 ); @@ -1149,6 +1153,7 @@ my @p7t_encrypted_data = ( 1, 2, 840, 113549, 1, 7, 6 ); my @p7t_compressed_data = ( 1, 2, 840, 113549, 1, 9, 16, 1, 9 ); my @p7t_firmware_pkg_data = ( 1, 2, 840, 113549, 1, 9, 16, 1, 16 ); my @p7t_auth_env_data = ( 1, 2, 840, 113549, 1, 9, 16, 1, 23 ); +my @p7t_encrypted_key_package = ( 2, 16, 840, 1, 101, 2, 1, 2, 78, 2 ); my @pkcs7_types = ( { name => "PKCS7_MSG", oid => \@p7t_pkcs7_msg }, @@ -1161,6 +1166,7 @@ my @pkcs7_types = ( { name => "ENCRYPTED_DATA", oid => \@p7t_encrypted_data }, { name => "FIRMWARE_PKG_DATA", oid => \@p7t_firmware_pkg_data }, { name => "AUTH_ENVELOPED_DATA", oid => \@p7t_auth_env_data }, + { name => "ENCRYPTED_KEY_PACKAGE", oid => \@p7t_encrypted_key_package }, ); print_enum("PKCS7_TYPES", "", \@pkcs7_types, 32, 46); diff --git a/src/include.am b/src/include.am index 0ac8d62602..0ccb67aba1 100644 --- a/src/include.am +++ b/src/include.am @@ -1978,9 +1978,7 @@ endif if BUILD_LIBOQS src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/falcon.c -src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/dilithium.c src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sphincs.c -src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/ext_mlkem.c src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/liboqs/liboqs.c endif diff --git a/src/internal.c b/src/internal.c index c10b89d6a6..24421df694 100644 --- a/src/internal.c +++ b/src/internal.c @@ -19789,8 +19789,8 @@ static int DoDtlsHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, #if (!defined(NO_PUBLIC_GCM_SET_IV) && \ ((defined(HAVE_FIPS) || defined(HAVE_SELFTEST)) && \ (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2)))) || \ - (defined(HAVE_POLY1305) && defined(HAVE_CHACHA)) || \ - defined(HAVE_ARIA) || \ + (defined(HAVE_POLY1305) && defined(HAVE_CHACHA) && \ + !defined(NO_CHAPOL_AEAD)) || defined(HAVE_ARIA) || \ defined(WOLFSSL_SM4_GCM) || defined(WOLFSSL_SM4_CCM) static WC_INLINE void AeadIncrementExpIV(WOLFSSL* ssl) { @@ -30801,9 +30801,9 @@ static int DecodePrivateKey_ex(WOLFSSL *ssl, byte keyType, const DerBuffer* key, /* Set start of data to beginning of buffer. */ idx = 0; /* Decode the key assuming it is a Falcon private key. */ - ret = wc_falcon_import_private_only(key->buffer, - key->length, - (falcon_key*)*hsKey); + ret = wc_Falcon_PrivateKeyDecode(key->buffer, &idx, + (falcon_key*)*hsKey, + key->length); if (ret == 0) { WOLFSSL_MSG("Using Falcon private key"); diff --git a/src/ssl.c b/src/ssl.c index 1a313e38f4..759580bd8e 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -3231,26 +3231,23 @@ static int isValidCurveGroup(word16 name) case WOLFSSL_ML_KEM_768: case WOLFSSL_ML_KEM_1024: #endif /* !WOLFSSL_TLS_NO_MLKEM_STANDALONE */ - #if defined(WOLFSSL_WC_MLKEM) || defined(HAVE_LIBOQS) - #ifdef WOLFSSL_PQC_HYBRIDS + #ifdef WOLFSSL_PQC_HYBRIDS case WOLFSSL_SECP384R1MLKEM1024: case WOLFSSL_X25519MLKEM768: case WOLFSSL_SECP256R1MLKEM768: - #endif /* WOLFSSL_PQC_HYBRIDS */ - #ifdef WOLFSSL_EXTRA_PQC_HYBRIDS + #endif /* WOLFSSL_PQC_HYBRIDS */ + #ifdef WOLFSSL_EXTRA_PQC_HYBRIDS case WOLFSSL_SECP256R1MLKEM512: case WOLFSSL_SECP384R1MLKEM768: case WOLFSSL_SECP521R1MLKEM1024: case WOLFSSL_X25519MLKEM512: case WOLFSSL_X448MLKEM768: - #endif /* WOLFSSL_EXTRA_PQC_HYBRIDS */ - #endif + #endif /* WOLFSSL_EXTRA_PQC_HYBRIDS */ #endif /* !WOLFSSL_NO_ML_KEM */ #ifdef WOLFSSL_MLKEM_KYBER case WOLFSSL_KYBER_LEVEL1: case WOLFSSL_KYBER_LEVEL3: case WOLFSSL_KYBER_LEVEL5: - #if defined(WOLFSSL_WC_MLKEM) || defined(HAVE_LIBOQS) case WOLFSSL_P256_KYBER_LEVEL1: case WOLFSSL_P384_KYBER_LEVEL3: case WOLFSSL_P521_KYBER_LEVEL5: @@ -3258,7 +3255,6 @@ static int isValidCurveGroup(word16 name) case WOLFSSL_X448_KYBER_LEVEL3: case WOLFSSL_X25519_KYBER_LEVEL3: case WOLFSSL_P256_KYBER_LEVEL3: - #endif #endif /* WOLFSSL_MLKEM_KYBER */ #endif return 1; @@ -10892,7 +10888,7 @@ const WOLFSSL_CIPHER* wolfSSL_get_cipher_by_value(word16 value) #if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || defined(HAVE_CURVE448) || \ - !defined(NO_DH) + !defined(NO_DH) || (defined(WOLFSSL_TLS13) && defined(WOLFSSL_HAVE_MLKEM)) #ifdef HAVE_FFDHE static const char* wolfssl_ffdhe_name(word16 group) { @@ -10939,7 +10935,6 @@ const char* wolfSSL_get_curve_name(WOLFSSL* ssl) if (IsAtLeastTLSv1_3(ssl->version)) { switch (ssl->namedGroup) { #ifndef WOLFSSL_NO_ML_KEM -#if defined(WOLFSSL_WC_MLKEM) #ifndef WOLFSSL_NO_ML_KEM_512 case WOLFSSL_ML_KEM_512: return "ML_KEM_512"; @@ -10996,37 +10991,8 @@ const char* wolfSSL_get_curve_name(WOLFSSL* ssl) return "SecP521r1MLKEM1024"; #endif /* WOLFSSL_EXTRA_PQC_HYBRIDS */ #endif /* WOLFSSL_NO_ML_KEM_1024 */ -#elif defined(HAVE_LIBOQS) - case WOLFSSL_ML_KEM_512: - return "ML_KEM_512"; - case WOLFSSL_ML_KEM_768: - return "ML_KEM_768"; - case WOLFSSL_ML_KEM_1024: - return "ML_KEM_1024"; - case WOLFSSL_SECP256R1MLKEM512: - return "SecP256r1MLKEM512"; - case WOLFSSL_SECP384R1MLKEM768: - return "SecP384r1MLKEM768"; - case WOLFSSL_SECP256R1MLKEM768: - return "SecP256r1MLKEM768"; - case WOLFSSL_SECP521R1MLKEM1024: - return "SecP521r1MLKEM1024"; - case WOLFSSL_SECP384R1MLKEM1024: - return "SecP384r1MLKEM1024"; - #ifdef HAVE_CURVE25519 - case WOLFSSL_X25519MLKEM512: - return "X25519MLKEM512"; - case WOLFSSL_X25519MLKEM768: - return "X25519MLKEM768"; - #endif - #ifdef HAVE_CURVE448 - case WOLFSSL_X448MLKEM768: - return "X448MLKEM768"; - #endif -#endif /* WOLFSSL_WC_MLKEM */ #endif /* WOLFSSL_NO_ML_KEM */ #ifdef WOLFSSL_MLKEM_KYBER -#if defined(WOLFSSL_WC_MLKEM) #ifndef WOLFSSL_NO_KYBER512 case WOLFSSL_KYBER_LEVEL1: return "KYBER_LEVEL1"; @@ -11059,32 +11025,6 @@ const char* wolfSSL_get_curve_name(WOLFSSL* ssl) case WOLFSSL_P521_KYBER_LEVEL5: return "P521_KYBER_LEVEL5"; #endif -#elif defined (HAVE_LIBOQS) - case WOLFSSL_KYBER_LEVEL1: - return "KYBER_LEVEL1"; - case WOLFSSL_KYBER_LEVEL3: - return "KYBER_LEVEL3"; - case WOLFSSL_KYBER_LEVEL5: - return "KYBER_LEVEL5"; - case WOLFSSL_P256_KYBER_LEVEL1: - return "P256_KYBER_LEVEL1"; - case WOLFSSL_P384_KYBER_LEVEL3: - return "P384_KYBER_LEVEL3"; - case WOLFSSL_P256_KYBER_LEVEL3: - return "P256_KYBER_LEVEL3"; - case WOLFSSL_P521_KYBER_LEVEL5: - return "P521_KYBER_LEVEL5"; - #ifdef HAVE_CURVE25519 - case WOLFSSL_X25519_KYBER_LEVEL1: - return "X25519_KYBER_LEVEL1"; - case WOLFSSL_X25519_KYBER_LEVEL3: - return "X25519_KYBER_LEVEL3"; - #endif - #ifdef HAVE_CURVE448 - case WOLFSSL_X448_KYBER_LEVEL3: - return "X448_KYBER_LEVEL3"; - #endif -#endif /* WOLFSSL_WC_MLKEM */ #endif /* WOLFSSL_MLKEM_KYBER */ } } @@ -17207,7 +17147,7 @@ const WOLF_EC_NIST_NAME kNistCurves[] = { {CURVE_NAME("ML_KEM_512"), WOLFSSL_ML_KEM_512, WOLFSSL_ML_KEM_512}, {CURVE_NAME("ML_KEM_768"), WOLFSSL_ML_KEM_768, WOLFSSL_ML_KEM_768}, {CURVE_NAME("ML_KEM_1024"), WOLFSSL_ML_KEM_1024, WOLFSSL_ML_KEM_1024}, -#if (defined(WOLFSSL_WC_MLKEM) || defined(HAVE_LIBOQS)) && defined(HAVE_ECC) +#if defined(HAVE_ECC) #ifdef WOLFSSL_PQC_HYBRIDS {CURVE_NAME("SecP256r1MLKEM768"), WOLFSSL_SECP256R1MLKEM768, WOLFSSL_SECP256R1MLKEM768}, @@ -17234,7 +17174,7 @@ const WOLF_EC_NIST_NAME kNistCurves[] = { {CURVE_NAME("KYBER_LEVEL1"), WOLFSSL_KYBER_LEVEL1, WOLFSSL_KYBER_LEVEL1}, {CURVE_NAME("KYBER_LEVEL3"), WOLFSSL_KYBER_LEVEL3, WOLFSSL_KYBER_LEVEL3}, {CURVE_NAME("KYBER_LEVEL5"), WOLFSSL_KYBER_LEVEL5, WOLFSSL_KYBER_LEVEL5}, -#if (defined(WOLFSSL_WC_MLKEM) || defined(HAVE_LIBOQS)) && defined(HAVE_ECC) +#if defined(HAVE_ECC) {CURVE_NAME("P256_KYBER_LEVEL1"), WOLFSSL_P256_KYBER_LEVEL1, WOLFSSL_P256_KYBER_LEVEL1}, {CURVE_NAME("P384_KYBER_LEVEL3"), WOLFSSL_P384_KYBER_LEVEL3, diff --git a/src/ssl_load.c b/src/ssl_load.c index 2d38dba6d6..367f17e235 100644 --- a/src/ssl_load.c +++ b/src/ssl_load.c @@ -825,16 +825,57 @@ static int ProcessBufferTryDecodeFalcon(WOLFSSL_CTX* ctx, WOLFSSL* ssl, /* Initialize Falcon key. */ ret = wc_falcon_init(key); if (ret == 0) { - /* Set up key to parse the format specified. */ - if ((*keyFormat == FALCON_LEVEL1k) || ((*keyFormat == 0) && - ((der->length == FALCON_LEVEL1_KEY_SIZE) || - (der->length == FALCON_LEVEL1_PRV_KEY_SIZE)))) { - ret = wc_falcon_set_level(key, 1); + byte level = 0; + word32 idx; + + if (*keyFormat == FALCON_LEVEL1k) { + level = 1; } - else if ((*keyFormat == FALCON_LEVEL5k) || ((*keyFormat == 0) && - ((der->length == FALCON_LEVEL5_KEY_SIZE) || - (der->length == FALCON_LEVEL5_PRV_KEY_SIZE)))) { - ret = wc_falcon_set_level(key, 5); + else if (*keyFormat == FALCON_LEVEL5k) { + level = 5; + } + + if (level != 0) { + /* Caller told us the level via the OID sum. */ + ret = wc_falcon_set_level(key, level); + if (ret == 0) { + idx = 0; + ret = wc_Falcon_PrivateKeyDecode(der->buffer, &idx, key, + der->length); + } + } + else if (*keyFormat == 0) { + /* Key format unknown. Try both levels; the expected OID inside + * wc_Falcon_PrivateKeyDecode rejects non-matching DER. Re-init + * between attempts so a partial first decode can't leave stale + * bytes in key->k / key->p. */ + idx = 0; + if (wc_falcon_set_level(key, 1) == 0 && + wc_Falcon_PrivateKeyDecode(der->buffer, &idx, key, + der->length) == 0) { + level = 1; + } + else { + wc_falcon_free(key); + if (wc_falcon_init(key) != 0) { + XFREE(key, heap, DYNAMIC_TYPE_FALCON); + return MEMORY_E; + } + idx = 0; + if (wc_falcon_set_level(key, 5) == 0 && + wc_Falcon_PrivateKeyDecode(der->buffer, &idx, key, + der->length) == 0) { + level = 5; + } + } + if (level == 0) { + /* Not a Falcon key; let caller try another algorithm. */ + WOLFSSL_MSG("Not a Falcon key"); + wc_falcon_free(key); + XFREE(key, heap, DYNAMIC_TYPE_FALCON); + return 0; + } + ret = 0; } else { wc_falcon_free(key); @@ -843,38 +884,27 @@ static int ProcessBufferTryDecodeFalcon(WOLFSSL_CTX* ctx, WOLFSSL* ssl, } if (ret == 0) { - /* Decode as a Falcon private key. */ - ret = wc_falcon_import_private_only(der->buffer, der->length, key); - if (ret == 0) { - /* Get the minimum Falcon key size from SSL or SSL context object. - */ - int minKeySz = ssl ? ssl->options.minFalconKeySz : - ctx->minFalconKeySz; + /* Get the minimum Falcon key size from SSL or SSL context object. */ + int minKeySz = ssl ? ssl->options.minFalconKeySz : + ctx->minFalconKeySz; - /* Format is known. */ - if (*keyFormat == FALCON_LEVEL1k) { - *keyType = falcon_level1_sa_algo; - *keySize = FALCON_LEVEL1_KEY_SIZE; - } - else { - *keyType = falcon_level5_sa_algo; - *keySize = FALCON_LEVEL5_KEY_SIZE; - } - - /* Check that the size of the Falcon key is enough. */ - if (*keySize < minKeySz) { - WOLFSSL_MSG("Falcon private key too small"); - ret = FALCON_KEY_SIZE_E; - } + if (key->level == 1) { + *keyFormat = FALCON_LEVEL1k; + *keyType = falcon_level1_sa_algo; + *keySize = FALCON_LEVEL1_KEY_SIZE; } - /* Not a Falcon key but check whether we know what it is. */ - else if (*keyFormat == 0) { - WOLFSSL_MSG("Not a Falcon key"); - /* Format unknown so keep trying. */ - ret = 0; + else { + *keyFormat = FALCON_LEVEL5k; + *keyType = falcon_level5_sa_algo; + *keySize = FALCON_LEVEL5_KEY_SIZE; + } + + /* Check that the size of the Falcon key is enough. */ + if (*keySize < minKeySz) { + WOLFSSL_MSG("Falcon private key too small"); + ret = FALCON_KEY_SIZE_E; } - /* Free dynamically allocated data in key. */ wc_falcon_free(key); } else if ((ret == WC_NO_ERR_TRACE(ALGO_ID_E)) && (*keyFormat == 0)) { diff --git a/src/tls.c b/src/tls.c index c608261217..7f7e0b0d1b 100644 --- a/src/tls.c +++ b/src/tls.c @@ -76,7 +76,6 @@ * * Post-Quantum: * WOLFSSL_HAVE_MLKEM: Enable ML-KEM (Kyber) support default: off - * WOLFSSL_WC_MLKEM: Use wolfCrypt ML-KEM implementation default: off * WOLFSSL_MLKEM_KYBER: Use Kyber round 3 parameters default: off * WOLFSSL_KYBER512: Enable Kyber/ML-KEM-512 default: off * WOLFSSL_KYBER768: Enable Kyber/ML-KEM-768 default: off @@ -140,12 +139,7 @@ #include #endif #ifdef WOLFSSL_HAVE_MLKEM - #include -#ifdef WOLFSSL_WC_MLKEM #include -#elif defined(HAVE_LIBOQS) - #include -#endif #endif #if defined(WOLFSSL_RENESAS_TSIP_TLS) @@ -4578,12 +4572,6 @@ int TLSX_UseCertificateStatusRequestV2(TLSX** extensions, byte status_type, #if defined(HAVE_SUPPORTED_CURVES) || \ (defined(WOLFSSL_TLS13) && defined(HAVE_SUPPORTED_CURVES)) -/* Functions needed by TLSX_IsGroupSupported */ -#ifdef HAVE_LIBOQS -static int mlkem_id2type(int id, int *type); -static void findEccPqc(int *ecc, int *pqc, int *pqc_first, int group); -#endif - /* Returns whether this group is supported. * * namedGroup The named group to check. @@ -4699,7 +4687,6 @@ int TLSX_IsGroupSupported(int namedGroup) #endif #ifdef WOLFSSL_HAVE_MLKEM #ifndef WOLFSSL_NO_ML_KEM - #ifdef WOLFSSL_WC_MLKEM #ifndef WOLFSSL_NO_ML_KEM_512 #ifndef WOLFSSL_TLS_NO_MLKEM_STANDALONE case WOLFSSL_ML_KEM_512: @@ -4750,50 +4737,8 @@ int TLSX_IsGroupSupported(int namedGroup) case WOLFSSL_P521_ML_KEM_1024_OLD: break; #endif /* WOLFSSL_ML_KEM_USE_OLD_IDS && WOLFSSL_EXTRA_PQC_HYBRIDS */ - #elif defined(HAVE_LIBOQS) - case WOLFSSL_ML_KEM_512: - case WOLFSSL_ML_KEM_768: - case WOLFSSL_ML_KEM_1024: - { - int ret; - int id; - ret = mlkem_id2type(namedGroup, &id); - if (ret == WC_NO_ERR_TRACE(NOT_COMPILED_IN)) { - return 0; - } - - if (! ext_mlkem_enabled(id)) { - return 0; - } - break; - } - - case WOLFSSL_SECP256R1MLKEM512: - case WOLFSSL_SECP384R1MLKEM768: - case WOLFSSL_SECP256R1MLKEM768: - case WOLFSSL_SECP521R1MLKEM1024: - case WOLFSSL_SECP384R1MLKEM1024: - case WOLFSSL_X25519MLKEM512: - case WOLFSSL_X448MLKEM768: - case WOLFSSL_X25519MLKEM768: - { - int ret; - int id; - findEccPqc(NULL, &namedGroup, NULL, namedGroup); - ret = mlkem_id2type(namedGroup, &id); - if (ret == WC_NO_ERR_TRACE(NOT_COMPILED_IN)) { - return 0; - } - - if (! ext_mlkem_enabled(id)) { - return 0; - } - break; - } - #endif #endif /* WOLFSSL_NO_ML_KEM */ #ifdef WOLFSSL_MLKEM_KYBER - #ifdef WOLFSSL_WC_MLKEM #ifdef WOLFSSL_KYBER512 case WOLFSSL_KYBER_LEVEL1: case WOLFSSL_P256_KYBER_LEVEL1: @@ -4817,45 +4762,6 @@ int TLSX_IsGroupSupported(int namedGroup) case WOLFSSL_P521_KYBER_LEVEL5: #endif break; - #elif defined(HAVE_LIBOQS) - case WOLFSSL_KYBER_LEVEL1: - case WOLFSSL_KYBER_LEVEL3: - case WOLFSSL_KYBER_LEVEL5: - { - int ret; - int id; - ret = mlkem_id2type(namedGroup, &id); - if (ret == WC_NO_ERR_TRACE(NOT_COMPILED_IN)) { - return 0; - } - - if (! ext_mlkem_enabled(id)) { - return 0; - } - break; - } - case WOLFSSL_P256_KYBER_LEVEL1: - case WOLFSSL_P384_KYBER_LEVEL3: - case WOLFSSL_P256_KYBER_LEVEL3: - case WOLFSSL_P521_KYBER_LEVEL5: - case WOLFSSL_X25519_KYBER_LEVEL1: - case WOLFSSL_X448_KYBER_LEVEL3: - case WOLFSSL_X25519_KYBER_LEVEL3: - { - int ret; - int id; - findEccPqc(NULL, &namedGroup, NULL, namedGroup); - ret = mlkem_id2type(namedGroup, &id); - if (ret == WC_NO_ERR_TRACE(NOT_COMPILED_IN)) { - return 0; - } - - if (! ext_mlkem_enabled(id)) { - return 0; - } - break; - } - #endif #endif #endif /* WOLFSSL_HAVE_MLKEM */ default: @@ -8631,8 +8537,7 @@ static int TLSX_KeyShare_GenEccKey(WOLFSSL *ssl, KeyShareEntry* kse) #ifdef WOLFSSL_HAVE_MLKEM #if (defined(WOLFSSL_MLKEM_CACHE_A) || \ - (defined(HAVE_PKCS11) && defined(WOLFSSL_WC_MLKEM) && \ - !defined(NO_PKCS11_MLKEM))) && \ + (defined(HAVE_PKCS11) && !defined(NO_PKCS11_MLKEM))) && \ !defined(WOLFSSL_TLSX_PQC_MLKEM_STORE_PRIV_KEY) /* Store KyberKey object rather than private key bytes in key share entry. * Improves performance at cost of more dynamic memory being used. */ @@ -11375,11 +11280,6 @@ static int TLSX_KeyShare_GroupRank(const WOLFSSL* ssl, int group) numGroups = ssl->numGroups; } -#ifdef HAVE_LIBOQS - if (!TLSX_IsGroupSupported(group)) - return WOLFSSL_FATAL_ERROR; -#endif - for (i = 0; i < numGroups; i++) { #if defined(WOLFSSL_ML_KEM_USE_OLD_IDS) && \ defined (WOLFSSL_EXTRA_PQC_HYBRIDS) @@ -15995,11 +15895,7 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) namedGroup = preferredGroup[0]; for (i = 0; i < ssl->numGroups && !set; i++) { for (j = 0; preferredGroup[j] != WOLFSSL_NAMED_GROUP_INVALID; j++) { - if (preferredGroup[j] == ssl->group[i] -#ifdef HAVE_LIBOQS - && TLSX_IsGroupSupported(preferredGroup[j]) -#endif - ) { + if (preferredGroup[j] == ssl->group[i]) { namedGroup = ssl->group[i]; set = 1; break; @@ -16012,17 +15908,6 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) else { /* Choose the most preferred group. */ namedGroup = preferredGroup[0]; -#ifdef HAVE_LIBOQS - if (!TLSX_IsGroupSupported(namedGroup)) { - int i = 1; - for (;preferredGroup[i] != WOLFSSL_NAMED_GROUP_INVALID; - i++) { - if (TLSX_IsGroupSupported(preferredGroup[i])) - break; - } - namedGroup = preferredGroup[i]; - } -#endif } } else { diff --git a/src/tls13.c b/src/tls13.c index fba9a05cad..65378db744 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -8451,9 +8451,10 @@ static WC_INLINE void EncodeSigAlg(const WOLFSSL * ssl, byte hashAlgo, #define HYBRID_RSA3072_DILITHIUM_LEVEL2_SA_MINOR 0xA2 #define HYBRID_P384_DILITHIUM_LEVEL3_SA_MINOR 0xA4 #define HYBRID_P521_DILITHIUM_LEVEL5_SA_MINOR 0xA6 -#define HYBRID_P256_FALCON_LEVEL1_SA_MINOR 0xAF -#define HYBRID_RSA3072_FALCON_LEVEL1_SA_MINOR 0xB0 -#define HYBRID_P521_FALCON_LEVEL5_SA_MINOR 0xB2 +/* Falcon hybrid codepoints aligned with oqs-provider. */ +#define HYBRID_P256_FALCON_LEVEL1_SA_MINOR 0xD8 +#define HYBRID_RSA3072_FALCON_LEVEL1_SA_MINOR 0xD9 +#define HYBRID_P521_FALCON_LEVEL5_SA_MINOR 0xDB /* Custom defined ones for PQC first */ #define HYBRID_DILITHIUM_LEVEL2_P256_SA_MINOR 0xD1 diff --git a/tests/api.c b/tests/api.c index 2dba31d135..f22653948e 100644 --- a/tests/api.c +++ b/tests/api.c @@ -169,7 +169,7 @@ #include #endif #if defined(WOLFSSL_HAVE_MLKEM) - #include + #include #endif #if defined(HAVE_PKCS7) #include @@ -1559,7 +1559,6 @@ static int test_dual_alg_ecdsa_mldsa(void) EXPECT_DECLS; #if defined(WOLFSSL_DUAL_ALG_CERTS) && defined(HAVE_DILITHIUM) && \ defined(HAVE_ECC) && !defined(WC_NO_RNG) && \ - defined(WOLFSSL_WC_DILITHIUM) && \ !defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) && \ !defined(WOLFSSL_DILITHIUM_NO_SIGN) && \ !defined(WOLFSSL_DILITHIUM_NO_VERIFY) && !defined(WOLFSSL_SMALL_STACK) @@ -35911,7 +35910,7 @@ static int test_DhAgree_rejects_p_minus_1(void) static int test_mldsa_verify_hash(void) { EXPECT_DECLS; -#if defined(HAVE_DILITHIUM) && defined(WOLFSSL_WC_DILITHIUM) && \ +#if defined(HAVE_DILITHIUM) && \ !defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) && \ !defined(WOLFSSL_DILITHIUM_NO_VERIFY) dilithium_key key; @@ -36829,7 +36828,7 @@ static int test_pkcs7_enveloped_content_size_overflow(void) static int test_dilithium_hash(void) { EXPECT_DECLS; -#if defined(HAVE_DILITHIUM) && defined(WOLFSSL_WC_DILITHIUM) && \ +#if defined(HAVE_DILITHIUM) && \ !defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) && \ !defined(WOLFSSL_DILITHIUM_NO_VERIFY) dilithium_key key; diff --git a/tests/api/test_mldsa.c b/tests/api/test_mldsa.c index ce924d7b2c..4e8cf78d24 100644 --- a/tests/api/test_mldsa.c +++ b/tests/api/test_mldsa.c @@ -37,7 +37,7 @@ #include -#if defined(HAVE_DILITHIUM) && defined(WOLFSSL_WC_DILITHIUM) && \ +#if defined(HAVE_DILITHIUM) && \ !defined(WOLFSSL_DILITHIUM_NO_VERIFY) && !defined(WOLFSSL_NO_ML_DSA_44) && \ defined(WOLFSSL_DILITHIUM_NO_CTX) static const byte ml_dsa_44_pub_key[] = { @@ -516,7 +516,7 @@ static const byte ml_dsa_44_good_sig[] = { int test_wc_dilithium(void) { EXPECT_DECLS; -#if defined(HAVE_DILITHIUM) && defined(WOLFSSL_WC_DILITHIUM) +#if defined(HAVE_DILITHIUM) dilithium_key* key; byte level; #if !defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) || \ @@ -698,7 +698,7 @@ int test_wc_dilithium_sign_pubonly_fails(void) { EXPECT_DECLS; #if !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0) -#if defined(HAVE_DILITHIUM) && defined(WOLFSSL_WC_DILITHIUM) && \ +#if defined(HAVE_DILITHIUM) && \ !defined(WOLFSSL_DILITHIUM_NO_SIGN) && \ !defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) && \ !defined(WOLFSSL_DILITHIUM_NO_CTX) @@ -771,7 +771,7 @@ int test_wc_dilithium_sign_pubonly_fails(void) int test_wc_dilithium_make_key(void) { EXPECT_DECLS; -#if defined(HAVE_DILITHIUM) && defined(WOLFSSL_WC_DILITHIUM) && \ +#if defined(HAVE_DILITHIUM) && \ !defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) dilithium_key* key; WC_RNG rng; @@ -812,7 +812,7 @@ int test_wc_dilithium_make_key(void) int test_wc_dilithium_sign(void) { EXPECT_DECLS; -#if defined(HAVE_DILITHIUM) && defined(WOLFSSL_WC_DILITHIUM) && \ +#if defined(HAVE_DILITHIUM) && \ !defined(WOLFSSL_DILITHIUM_NO_SIGN) && defined(WOLFSSL_DILITHIUM_NO_CTX) dilithium_key* key; dilithium_key* importKey = NULL; @@ -979,7 +979,7 @@ int test_wc_dilithium_sign(void) int test_wc_dilithium_verify(void) { EXPECT_DECLS; -#if defined(HAVE_DILITHIUM) && defined(WOLFSSL_WC_DILITHIUM) && \ +#if defined(HAVE_DILITHIUM) && \ !defined(WOLFSSL_DILITHIUM_NO_VERIFY) && defined(WOLFSSL_DILITHIUM_NO_CTX) && \ (!defined(WOLFSSL_NO_ML_DSA_44) || !defined(WOLFSSL_DILITHIUM_NO_SIGN)) dilithium_key* key; @@ -1211,7 +1211,7 @@ int test_wc_dilithium_verify(void) int test_wc_dilithium_sign_vfy(void) { EXPECT_DECLS; -#if defined(HAVE_DILITHIUM) && defined(WOLFSSL_WC_DILITHIUM) && \ +#if defined(HAVE_DILITHIUM) && \ !defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) && \ !defined(WOLFSSL_DILITHIUM_NO_SIGN) && !defined(WOLFSSL_DILITHIUM_NO_VERIFY) dilithium_key* key; @@ -1311,7 +1311,7 @@ int test_wc_dilithium_sign_vfy(void) int test_wc_dilithium_check_key(void) { EXPECT_DECLS; -#if defined(HAVE_DILITHIUM) && defined(WOLFSSL_WC_DILITHIUM) && \ +#if defined(HAVE_DILITHIUM) && \ defined(WOLFSSL_DILITHIUM_CHECK_KEY) && \ !defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) dilithium_key* checkKey; @@ -1438,7 +1438,7 @@ int test_wc_dilithium_check_key(void) return EXPECT_RESULT(); } -#if defined(HAVE_DILITHIUM) && defined(WOLFSSL_WC_DILITHIUM) && \ +#if defined(HAVE_DILITHIUM) && \ defined(WOLFSSL_DILITHIUM_PUBLIC_KEY) static const unsigned char ml_dsa_public_der[] = { #ifndef WOLFSSL_NO_ML_DSA_44 @@ -2941,7 +2941,7 @@ static const unsigned char dilithium_public_der[] = { int test_wc_dilithium_public_der_decode(void) { EXPECT_DECLS; -#if defined(HAVE_DILITHIUM) && defined(WOLFSSL_WC_DILITHIUM) && \ +#if defined(HAVE_DILITHIUM) && \ defined(WOLFSSL_DILITHIUM_PUBLIC_KEY) dilithium_key* key; word32 idx = 0; @@ -2985,7 +2985,7 @@ int test_wc_dilithium_public_der_decode(void) int test_wc_dilithium_der(void) { EXPECT_DECLS; -#if defined(HAVE_DILITHIUM) && defined(WOLFSSL_WC_DILITHIUM) && \ +#if defined(HAVE_DILITHIUM) && \ !defined(WOLFSSL_DILITHIUM_NO_ASN1) && \ !defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) #define DILITHIUM_MAX_DER_SIZE 8192 @@ -3198,7 +3198,7 @@ int test_wc_dilithium_der(void) int test_wc_dilithium_make_key_from_seed(void) { EXPECT_DECLS; -#if defined(HAVE_DILITHIUM) && defined(WOLFSSL_WC_DILITHIUM) && \ +#if defined(HAVE_DILITHIUM) && \ !defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) dilithium_key* key; #ifndef WOLFSSL_NO_ML_DSA_44 @@ -7666,7 +7666,7 @@ int test_wc_dilithium_make_key_from_seed(void) int test_wc_dilithium_sig_kats(void) { EXPECT_DECLS; -#if defined(HAVE_DILITHIUM) && defined(WOLFSSL_WC_DILITHIUM) && \ +#if defined(HAVE_DILITHIUM) && \ !defined(WOLFSSL_DILITHIUM_NO_SIGN) && defined(WOLFSSL_DILITHIUM_NO_CTX) dilithium_key* key; #ifndef WOLFSSL_NO_ML_DSA_44 @@ -12485,7 +12485,7 @@ int test_wc_dilithium_sig_kats(void) int test_wc_dilithium_sign_ctx_kats(void) { EXPECT_DECLS; -#if defined(HAVE_DILITHIUM) && defined(WOLFSSL_WC_DILITHIUM) && \ +#if defined(HAVE_DILITHIUM) && \ !defined(WOLFSSL_DILITHIUM_NO_SIGN) dilithium_key* key; word32 sigLen; @@ -16718,7 +16718,7 @@ int test_wc_dilithium_sign_ctx_kats(void) PRIVATE_KEY_LOCK(); XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif /* HAVE_DILITHIUM && WOLFSSL_WC_DILITHIUM && !WOLFSSL_DILITHIUM_NO_SIGN */ +#endif /* HAVE_DILITHIUM && !WOLFSSL_DILITHIUM_NO_SIGN */ return EXPECT_RESULT(); } @@ -16726,7 +16726,7 @@ int test_wc_dilithium_sign_ctx_kats(void) int test_wc_dilithium_verify_ctx_kats(void) { EXPECT_DECLS; -#if defined(HAVE_DILITHIUM) && defined(WOLFSSL_WC_DILITHIUM) && \ +#if defined(HAVE_DILITHIUM) && \ !defined(WOLFSSL_DILITHIUM_NO_VERIFY) dilithium_key* key; int res; @@ -20264,7 +20264,7 @@ int test_wc_dilithium_verify_ctx_kats(void) #endif /* !WOLFSSL_NO_ML_DSA_87 */ XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif /* HAVE_DILITHIUM && WOLFSSL_WC_DILITHIUM && !WOLFSSL_DILITHIUM_NO_VERIFY */ +#endif /* HAVE_DILITHIUM && !WOLFSSL_DILITHIUM_NO_VERIFY */ return EXPECT_RESULT(); } @@ -20272,7 +20272,7 @@ int test_wc_dilithium_verify_ctx_kats(void) int test_wc_dilithium_verify_kats(void) { EXPECT_DECLS; -#if defined(HAVE_DILITHIUM) && defined(WOLFSSL_WC_DILITHIUM) && \ +#if defined(HAVE_DILITHIUM) && \ !defined(WOLFSSL_DILITHIUM_NO_VERIFY) && defined(WOLFSSL_DILITHIUM_NO_CTX) dilithium_key* key; int res; @@ -24555,8 +24555,7 @@ int test_wc_dilithium_verify_kats(void) int test_wc_dilithium_sign_mu_kats(void) { EXPECT_DECLS; -#if defined(HAVE_DILITHIUM) && defined(WOLFSSL_WC_DILITHIUM) && \ - !defined(WOLFSSL_DILITHIUM_NO_SIGN) && \ +#if defined(HAVE_DILITHIUM) && !defined(WOLFSSL_DILITHIUM_NO_SIGN) && \ (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) dilithium_key* key = NULL; word32 sigLen; @@ -27417,8 +27416,7 @@ int test_wc_dilithium_sign_mu_kats(void) int test_wc_dilithium_verify_mu_kats(void) { EXPECT_DECLS; -#if defined(HAVE_DILITHIUM) && defined(WOLFSSL_WC_DILITHIUM) && \ - !defined(WOLFSSL_DILITHIUM_NO_VERIFY) && \ +#if defined(HAVE_DILITHIUM) && !defined(WOLFSSL_DILITHIUM_NO_VERIFY) && \ (!defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0)) dilithium_key* key = NULL; byte* sigBuf = NULL; @@ -29631,7 +29629,7 @@ int test_wc_dilithium_verify_mu_kats(void) } #if !defined(NO_ASN) && defined(HAVE_PKCS8) && \ - defined(HAVE_DILITHIUM) && defined(WOLFSSL_WC_DILITHIUM) && \ + defined(HAVE_DILITHIUM) && \ !defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) && \ !defined(WOLFSSL_DILITHIUM_NO_ASN1) && defined(WOLFSSL_ASN_TEMPLATE) static struct { @@ -29699,7 +29697,7 @@ int test_wc_Dilithium_PrivateKeyDecode_OpenSSL_form(void) EXPECT_DECLS; #if !defined(NO_ASN) && defined(HAVE_PKCS8) && \ - defined(HAVE_DILITHIUM) && defined(WOLFSSL_WC_DILITHIUM) && \ + defined(HAVE_DILITHIUM) && \ !defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) && \ !defined(WOLFSSL_DILITHIUM_NO_ASN1) && defined(WOLFSSL_ASN_TEMPLATE) @@ -29796,7 +29794,7 @@ int test_mldsa_pkcs8_import_OpenSSL_form(void) { EXPECT_DECLS; #if !defined(NO_ASN) && defined(HAVE_PKCS8) && \ - defined(HAVE_DILITHIUM) && defined(WOLFSSL_WC_DILITHIUM) && \ + defined(HAVE_DILITHIUM) && \ !defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) && \ !defined(WOLFSSL_DILITHIUM_NO_SIGN) && \ !defined(WOLFSSL_DILITHIUM_NO_ASN1) && defined(WOLFSSL_ASN_TEMPLATE) && \ @@ -29984,7 +29982,7 @@ int test_mldsa_pkcs8_export_import_wolfSSL_form(void) int test_wc_dilithium_encode_w1_large_values(void) { EXPECT_DECLS; -#if defined(HAVE_DILITHIUM) && defined(WOLFSSL_WC_DILITHIUM) && \ +#if defined(HAVE_DILITHIUM) && \ (!defined(WOLFSSL_DILITHIUM_NO_SIGN) || \ !defined(WOLFSSL_DILITHIUM_NO_VERIFY)) @@ -30096,7 +30094,7 @@ int test_wc_dilithium_encode_w1_large_values(void) } #endif /* !WOLFSSL_NO_ML_DSA_65 || !WOLFSSL_NO_ML_DSA_87 */ -#endif /* HAVE_DILITHIUM && WOLFSSL_WC_DILITHIUM && sign/verify */ +#endif /* HAVE_DILITHIUM && sign/verify */ return EXPECT_RESULT(); } diff --git a/tests/api/test_mlkem.c b/tests/api/test_mlkem.c index 0e3cea39ff..040397ba4a 100644 --- a/tests/api/test_mlkem.c +++ b/tests/api/test_mlkem.c @@ -29,11 +29,8 @@ #endif #ifdef WOLFSSL_HAVE_MLKEM - #include -#ifdef WOLFSSL_WC_MLKEM #include #endif -#endif #include #include #include @@ -41,7 +38,7 @@ int test_wc_mlkem_make_key_kats(void) { EXPECT_DECLS; -#if defined(WOLFSSL_HAVE_MLKEM) && defined(WOLFSSL_WC_MLKEM) && \ +#if defined(WOLFSSL_HAVE_MLKEM) && \ !defined(WOLFSSL_NO_ML_KEM) && !defined(WOLFSSL_MLKEM_NO_MAKE_KEY) MlKemKey* key; #ifndef WOLFSSL_NO_ML_KEM_512 @@ -1500,7 +1497,7 @@ int test_wc_mlkem_make_key_kats(void) int test_wc_mlkem_encapsulate_kats(void) { EXPECT_DECLS; -#if defined(WOLFSSL_HAVE_MLKEM) && defined(WOLFSSL_WC_MLKEM) && \ +#if defined(WOLFSSL_HAVE_MLKEM) && \ !defined(WOLFSSL_NO_ML_KEM) && !defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) MlKemKey* key; #ifndef WOLFSSL_NO_ML_KEM_512 @@ -2474,7 +2471,7 @@ int test_wc_mlkem_encapsulate_kats(void) int test_wc_mlkem_decapsulate_kats(void) { EXPECT_DECLS; -#if defined(WOLFSSL_HAVE_MLKEM) && defined(WOLFSSL_WC_MLKEM) && \ +#if defined(WOLFSSL_HAVE_MLKEM) && \ !defined(WOLFSSL_NO_ML_KEM) && !defined(WOLFSSL_MLKEM_NO_DECAPSULATE) MlKemKey* key; #ifndef WOLFSSL_NO_ML_KEM_512 @@ -3889,7 +3886,7 @@ int test_wc_mlkem_decapsulate_pubonly_fails(void) { EXPECT_DECLS; #if !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0) -#if defined(WOLFSSL_HAVE_MLKEM) && defined(WOLFSSL_WC_MLKEM) && \ +#if defined(WOLFSSL_HAVE_MLKEM) && \ !defined(WOLFSSL_NO_ML_KEM) && !defined(WOLFSSL_MLKEM_NO_DECAPSULATE) && \ !defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) && \ !defined(WOLFSSL_MLKEM_NO_MAKE_KEY) @@ -3966,7 +3963,7 @@ int test_wc_mlkem_decap_fo_reject(void) { EXPECT_DECLS; #if !defined(HAVE_FIPS) || FIPS_VERSION3_GE(7,0,0) -#if defined(WOLFSSL_HAVE_MLKEM) && defined(WOLFSSL_WC_MLKEM) && \ +#if defined(WOLFSSL_HAVE_MLKEM) && \ !defined(WOLFSSL_NO_ML_KEM) && !defined(WOLFSSL_MLKEM_NO_DECAPSULATE) && \ !defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) && \ !defined(WOLFSSL_MLKEM_NO_MAKE_KEY) diff --git a/tests/suites.c b/tests/suites.c index dabc1f2756..0da168ee1d 100644 --- a/tests/suites.c +++ b/tests/suites.c @@ -1127,7 +1127,7 @@ int SuiteTest(int argc, char** argv) goto exit; } #endif - #ifdef HAVE_PQC + #ifdef WOLFSSL_HAVE_MLKEM #ifndef WOLFSSL_TLS_NO_MLKEM_STANDALONE /* add TLSv13 pq standalone tests */ XSTRLCPY(argv0[1], "tests/test-tls13-pq-standalone.conf", sizeof(argv0[1])); @@ -1162,7 +1162,7 @@ int SuiteTest(int argc, char** argv) } #endif #endif - #if defined(HAVE_PQC) && defined(WOLFSSL_DTLS13) + #if defined(WOLFSSL_HAVE_MLKEM) && defined(WOLFSSL_DTLS13) #ifndef WOLFSSL_TLS_NO_MLKEM_STANDALONE /* add DTLSv13 pq standalone tests */ XSTRLCPY(argv0[1], "tests/test-dtls13-pq-standalone.conf", sizeof(argv0[1])); diff --git a/wolfcrypt/benchmark/benchmark.c b/wolfcrypt/benchmark/benchmark.c index 6b77af42e5..c9c287a7b8 100644 --- a/wolfcrypt/benchmark/benchmark.c +++ b/wolfcrypt/benchmark/benchmark.c @@ -169,13 +169,7 @@ #include #endif #ifdef WOLFSSL_HAVE_MLKEM - #include - #ifdef WOLFSSL_WC_MLKEM - #include - #endif - #if defined(HAVE_LIBOQS) - #include - #endif + #include #endif #if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) #include @@ -14944,19 +14938,20 @@ void bench_falconKeySign(byte level) } if (ret == 0) { + word32 idx = 0; if (level == 1) { - ret = wc_falcon_import_private_key(bench_falcon_level1_key, - sizeof_bench_falcon_level1_key, - NULL, 0, &key); + ret = wc_Falcon_PrivateKeyDecode(bench_falcon_level1_key, &idx, + &key, + sizeof_bench_falcon_level1_key); } else { - ret = wc_falcon_import_private_key(bench_falcon_level5_key, - sizeof_bench_falcon_level5_key, - NULL, 0, &key); + ret = wc_Falcon_PrivateKeyDecode(bench_falcon_level5_key, &idx, + &key, + sizeof_bench_falcon_level5_key); } if (ret != 0) { - printf("wc_falcon_import_private_key failed %d\n", ret); + printf("wc_Falcon_PrivateKeyDecode failed %d\n", ret); } } diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index a83d651022..90b964c217 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -4577,11 +4577,11 @@ static int ParseCRL_Extensions(DecodedCRL* dcrl, const byte* buf, word32* inOutI static const byte sigEd448Oid[] = {43, 101, 113}; #endif /* HAVE_ED448 */ #ifdef HAVE_FALCON - /* Falcon Level 1: 1 3 9999 3 6 */ - static const byte sigFalcon_Level1Oid[] = {43, 206, 15, 3, 6}; + /* Falcon Level 1: 1 3 9999 3 11 */ + static const byte sigFalcon_Level1Oid[] = {43, 206, 15, 3, 11}; - /* Falcon Level 5: 1 3 9999 3 9 */ - static const byte sigFalcon_Level5Oid[] = {43, 206, 15, 3, 9}; + /* Falcon Level 5: 1 3 9999 3 14 */ + static const byte sigFalcon_Level5Oid[] = {43, 206, 15, 3, 14}; #endif /* HAVE_FALCON */ #ifdef HAVE_DILITHIUM #ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT @@ -4665,11 +4665,11 @@ static int ParseCRL_Extensions(DecodedCRL* dcrl, const byte* buf, word32* inOutI static const byte keyDhOid[] = {42, 134, 72, 134, 247, 13, 1, 3, 1}; #endif /* !NO_DH */ #ifdef HAVE_FALCON - /* Falcon Level 1: 1 3 9999 3 6 */ - static const byte keyFalcon_Level1Oid[] = {43, 206, 15, 3, 6}; + /* Falcon Level 1: 1 3 9999 3 11 */ + static const byte keyFalcon_Level1Oid[] = {43, 206, 15, 3, 11}; - /* Falcon Level 5: 1 3 9999 3 9 */ - static const byte keyFalcon_Level5Oid[] = {43, 206, 15, 3, 9}; + /* Falcon Level 5: 1 3 9999 3 14 */ + static const byte keyFalcon_Level5Oid[] = {43, 206, 15, 3, 14}; #endif /* HAVE_FALCON */ #ifdef HAVE_DILITHIUM #ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT diff --git a/wolfcrypt/src/dilithium.c b/wolfcrypt/src/dilithium.c index 15e512a3d9..ae5d2f6c34 100644 --- a/wolfcrypt/src/dilithium.c +++ b/wolfcrypt/src/dilithium.c @@ -27,8 +27,6 @@ * * HAVE_DILITHIUM Default: OFF * Enables the code in this file to be compiled. - * WOLFSSL_WC_DILITHIUM Default: OFF - * Compiles the wolfSSL implementation of dilithium. * * WOLFSSL_NO_ML_DSA_44 Default: OFF * Does not compile in parameter set ML-DSA-44 and any code specific to that @@ -149,10 +147,6 @@ #if defined(HAVE_DILITHIUM) -#ifdef HAVE_LIBOQS -#include -#endif - #include #include #include @@ -177,8 +171,6 @@ #endif #endif -#ifdef WOLFSSL_WC_DILITHIUM - #if defined(USE_INTEL_SPEEDUP) static cpuid_flags_t cpuid_flags = WC_CPUID_INITIALIZER; #endif @@ -10106,182 +10098,6 @@ static int dilithium_verify_ctx_hash(dilithium_key* key, const byte* ctx, } #endif /* WOLFSSL_DILITHIUM_NO_VERIFY */ -#elif defined(HAVE_LIBOQS) - -#ifndef WOLFSSL_DILITHIUM_NO_MAKE_KEY -static int oqs_dilithium_make_key(dilithium_key* key, WC_RNG* rng) -{ - int ret = 0; - OQS_SIG *oqssig = NULL; - - if (key->level == WC_ML_DSA_44) { - oqssig = OQS_SIG_new(OQS_SIG_alg_ml_dsa_44_ipd); - } - else if (key->level == WC_ML_DSA_65) { - oqssig = OQS_SIG_new(OQS_SIG_alg_ml_dsa_65_ipd); - } - else if (key->level == WC_ML_DSA_87) { - oqssig = OQS_SIG_new(OQS_SIG_alg_ml_dsa_87_ipd); - } - else { - ret = SIG_TYPE_E; - } - - -#ifdef WOLFSSL_DILITHIUM_DYNAMIC_KEYS - if (ret == 0) { - ret = dilithium_alloc_priv_buf(key); - } - if (ret == 0) { - ret = dilithium_alloc_pub_buf(key); - } -#endif - - if (ret == 0) { - ret = wolfSSL_liboqsRngMutexLock(rng); - if (ret == 0) { - if (OQS_SIG_keypair(oqssig, key->p, key->k) != OQS_SUCCESS) { - ret = BUFFER_E; - } - } - wolfSSL_liboqsRngMutexUnlock(); - } - if (ret == 0) { - key->prvKeySet = 1; - key->pubKeySet = 1; - } - - if (oqssig != NULL) { - OQS_SIG_free(oqssig); - } - - return ret; -} -#endif /* WOLFSSL_DILITHIUM_NO_MAKE_KEY */ - -#ifndef WOLFSSL_DILITHIUM_NO_SIGN -static int oqs_dilithium_sign_msg(const byte* msg, word32 msgLen, byte* sig, - word32 *sigLen, dilithium_key* key, WC_RNG* rng) -{ - int ret = 0; - OQS_SIG *oqssig = NULL; - size_t localOutLen = 0; - - if (!key->prvKeySet) { - ret = BAD_FUNC_ARG; - } - - if (ret == 0) { - if (key->level == WC_ML_DSA_44) { - oqssig = OQS_SIG_new(OQS_SIG_alg_ml_dsa_44_ipd); - } - else if (key->level == WC_ML_DSA_65) { - oqssig = OQS_SIG_new(OQS_SIG_alg_ml_dsa_65_ipd); - } - else if (key->level == WC_ML_DSA_87) { - oqssig = OQS_SIG_new(OQS_SIG_alg_ml_dsa_87_ipd); - } - else { - ret = SIG_TYPE_E; - } - } - - if ((ret == 0) && (oqssig == NULL)) { - ret = BUFFER_E; - } - - /* check and set up out length */ - if (ret == 0) { - if ((key->level == WC_ML_DSA_44) && - (*sigLen < ML_DSA_LEVEL2_SIG_SIZE)) { - *sigLen = ML_DSA_LEVEL2_SIG_SIZE; - ret = BUFFER_E; - } - else if ((key->level == WC_ML_DSA_65) && - (*sigLen < ML_DSA_LEVEL3_SIG_SIZE)) { - *sigLen = ML_DSA_LEVEL3_SIG_SIZE; - ret = BUFFER_E; - } - else if ((key->level == WC_ML_DSA_87) && - (*sigLen < ML_DSA_LEVEL5_SIG_SIZE)) { - *sigLen = ML_DSA_LEVEL5_SIG_SIZE; - ret = BUFFER_E; - } - localOutLen = *sigLen; - } - - if (ret == 0) { - ret = wolfSSL_liboqsRngMutexLock(rng); - if (ret == 0) { - if (OQS_SIG_sign(oqssig, sig, &localOutLen, msg, msgLen, key->k) - == OQS_ERROR) { - ret = BAD_FUNC_ARG; - } - } - if (ret == 0) { - *sigLen = (word32)localOutLen; - } - wolfSSL_liboqsRngMutexUnlock(); - } - - if (oqssig != NULL) { - OQS_SIG_free(oqssig); - } - return ret; -} -#endif - -#ifndef WOLFSSL_DILITHIUM_NO_VERIFY -static int oqs_dilithium_verify_msg(const byte* sig, word32 sigLen, - const byte* msg, word32 msgLen, int* res, dilithium_key* key) -{ - int ret = 0; - OQS_SIG *oqssig = NULL; - - if (!key->pubKeySet) { - ret = BAD_FUNC_ARG; - } - - if (ret == 0) { - if (key->level == WC_ML_DSA_44) { - oqssig = OQS_SIG_new(OQS_SIG_alg_ml_dsa_44_ipd); - } - else if (key->level == WC_ML_DSA_65) { - oqssig = OQS_SIG_new(OQS_SIG_alg_ml_dsa_65_ipd); - } - else if (key->level == WC_ML_DSA_87) { - oqssig = OQS_SIG_new(OQS_SIG_alg_ml_dsa_87_ipd); - } - else { - ret = SIG_TYPE_E; - } - } - - if ((ret == 0) && (oqssig == NULL)) { - ret = BUFFER_E; - } - - if ((ret == 0) && - (OQS_SIG_verify(oqssig, msg, msgLen, sig, sigLen, key->p) - == OQS_ERROR)) { - ret = SIG_VERIFY_E; - } - - if (ret == 0) { - *res = 1; - } - - if (oqssig != NULL) { - OQS_SIG_free(oqssig); - } - return ret; -} -#endif /* !WOLFSSL_DILITHIUM_NO_VERIFY */ - -#else - #error "No dilithium implementation chosen." -#endif - #ifndef WOLFSSL_DILITHIUM_NO_MAKE_KEY int wc_dilithium_make_key(dilithium_key* key, WC_RNG* rng) { @@ -10309,7 +10125,6 @@ int wc_dilithium_make_key(dilithium_key* key, WC_RNG* rng) #endif if (ret == 0) { -#ifdef WOLFSSL_WC_DILITHIUM /* Check the level or parameters have been set. */ if (key->params == NULL) { ret = BAD_STATE_E; @@ -10318,10 +10133,6 @@ int wc_dilithium_make_key(dilithium_key* key, WC_RNG* rng) /* Make the key. */ ret = dilithium_make_key(key, rng); } -#elif defined(HAVE_LIBOQS) - /* Make the key. */ - ret = oqs_dilithium_make_key(key, rng); -#endif } #ifdef HAVE_FIPS @@ -10376,7 +10187,6 @@ int wc_dilithium_make_key_from_seed(dilithium_key* key, const byte* seed) } if (ret == 0) { -#ifdef WOLFSSL_WC_DILITHIUM /* Check the level or parameters have been set. */ if (key->params == NULL) { ret = BAD_STATE_E; @@ -10385,10 +10195,6 @@ int wc_dilithium_make_key_from_seed(dilithium_key* key, const byte* seed) /* Make the key. */ ret = dilithium_make_key_from_seed(key, seed); } -#elif defined(HAVE_LIBOQS) - /* Make the key. */ - ret = NOT_COMPILED_IN; -#endif } /* Note: PCT is performed in wc_dilithium_make_key() which calls this @@ -10448,12 +10254,8 @@ int wc_dilithium_sign_ctx_msg(const byte* ctx, byte ctxLen, const byte* msg, if (ret == 0) { /* Sign message. */ - #ifdef WOLFSSL_WC_DILITHIUM ret = dilithium_sign_ctx_msg(key, rng, ctx, ctxLen, msg, msgLen, sig, sigLen); - #elif defined(HAVE_LIBOQS) - ret = oqs_dilithium_sign_msg(msg, msgLen, sig, sigLen, key, rng); - #endif } return ret; @@ -10502,11 +10304,7 @@ int wc_dilithium_sign_msg(const byte* msg, word32 msgLen, byte* sig, if (ret == 0) { /* Sign message. */ - #ifdef WOLFSSL_WC_DILITHIUM ret = dilithium_sign_msg(key, rng, msg, msgLen, sig, sigLen); - #elif defined(HAVE_LIBOQS) - ret = oqs_dilithium_sign_msg(msg, msgLen, sig, sigLen, key, rng); - #endif } return ret; @@ -10561,16 +10359,8 @@ int wc_dilithium_sign_ctx_hash(const byte* ctx, byte ctxLen, int hashAlg, if (ret == 0) { /* Sign message. */ - #ifdef WOLFSSL_WC_DILITHIUM ret = dilithium_sign_ctx_hash(key, rng, ctx, ctxLen, hashAlg, hash, hashLen, sig, sigLen); - #elif defined(HAVE_LIBOQS) - ret = NOT_COMPILED_IN; - (void)hashAlg; - (void)hash; - (void)hashLen; - (void)rng; - #endif } return ret; @@ -10607,14 +10397,8 @@ int wc_dilithium_sign_ctx_msg_with_seed(const byte* ctx, byte ctxLen, if (ret == 0) { /* Sign message. */ - #ifdef WOLFSSL_WC_DILITHIUM ret = dilithium_sign_ctx_msg_with_seed(key, seed, ctx, ctxLen, msg, msgLen, sig, sigLen); - #elif defined(HAVE_LIBOQS) - ret = NOT_COMPILED_IN; - (void)msgLen; - (void)seed; - #endif } return ret; @@ -10647,13 +10431,7 @@ int wc_dilithium_sign_msg_with_seed(const byte* msg, word32 msgLen, byte* sig, if (ret == 0) { /* Sign message. */ - #ifdef WOLFSSL_WC_DILITHIUM ret = dilithium_sign_msg_with_seed(key, seed, msg, msgLen, sig, sigLen); - #elif defined(HAVE_LIBOQS) - ret = NOT_COMPILED_IN; - (void)msgLen; - (void)seed; - #endif } return ret; @@ -10693,16 +10471,8 @@ int wc_dilithium_sign_ctx_hash_with_seed(const byte* ctx, byte ctxLen, if (ret == 0) { /* Sign message. */ - #ifdef WOLFSSL_WC_DILITHIUM ret = dilithium_sign_ctx_hash_with_seed(key, seed, ctx, ctxLen, hashAlg, hash, hashLen, sig, sigLen); - #elif defined(HAVE_LIBOQS) - ret = NOT_COMPILED_IN; - (void)hashAlg; - (void)hash; - (void)hashLen; - (void)seed; - #endif } return ret; @@ -10728,7 +10498,6 @@ int wc_dilithium_sign_ctx_hash_with_seed(const byte* ctx, byte ctxLen, int wc_dilithium_sign_mu_with_seed(const byte* mu, word32 muLen, byte* sig, word32 *sigLen, dilithium_key* key, const byte* seed) { -#ifdef WOLFSSL_WC_DILITHIUM int ret = 0; /* Validate parameters. */ @@ -10750,16 +10519,6 @@ int wc_dilithium_sign_mu_with_seed(const byte* mu, word32 muLen, } return ret; -#else - /* Internal interface not supported with liboqs backend. */ - (void)mu; - (void)muLen; - (void)sig; - (void)sigLen; - (void)key; - (void)seed; - return NOT_COMPILED_IN; -#endif } #endif /* !WOLFSSL_DILITHIUM_NO_SIGN */ @@ -10814,12 +10573,8 @@ int wc_dilithium_verify_ctx_msg(const byte* sig, word32 sigLen, const byte* ctx, if (ret == 0) { /* Verify message with signature. */ - #ifdef WOLFSSL_WC_DILITHIUM ret = dilithium_verify_ctx_msg(key, ctx, ctxLen, msg, msgLen, sig, sigLen, res); - #elif defined(HAVE_LIBOQS) - ret = oqs_dilithium_verify_msg(sig, sigLen, msg, msgLen, res, key); - #endif } return ret; @@ -10868,11 +10623,7 @@ int wc_dilithium_verify_msg(const byte* sig, word32 sigLen, const byte* msg, if (ret == 0) { /* Verify message with signature. */ - #ifdef WOLFSSL_WC_DILITHIUM ret = dilithium_verify_msg(key, msg, msgLen, sig, sigLen, res); - #elif defined(HAVE_LIBOQS) - ret = oqs_dilithium_verify_msg(sig, sigLen, msg, msgLen, res, key); - #endif } return ret; @@ -10927,16 +10678,8 @@ int wc_dilithium_verify_ctx_hash(const byte* sig, word32 sigLen, if (ret == 0) { /* Verify message with signature. */ - #ifdef WOLFSSL_WC_DILITHIUM ret = dilithium_verify_ctx_hash(key, ctx, ctxLen, hashAlg, hash, hashLen, sig, sigLen, res); - #elif defined(HAVE_LIBOQS) - ret = NOT_COMPILED_IN; - (void)sigLen; - (void)hashAlg; - (void)hash; - (void)hashLen; - #endif } return ret; @@ -10960,7 +10703,6 @@ int wc_dilithium_verify_ctx_hash(const byte* sig, word32 sigLen, int wc_dilithium_verify_mu(const byte* sig, word32 sigLen, const byte* mu, word32 muLen, int* res, dilithium_key* key) { -#ifdef WOLFSSL_WC_DILITHIUM int ret = 0; /* Validate parameters. */ @@ -10976,16 +10718,6 @@ int wc_dilithium_verify_mu(const byte* sig, word32 sigLen, const byte* mu, } return ret; -#else - /* Internal interface not supported with liboqs backend. */ - (void)sig; - (void)sigLen; - (void)mu; - (void)muLen; - (void)res; - (void)key; - return NOT_COMPILED_IN; -#endif } #endif /* WOLFSSL_DILITHIUM_NO_VERIFY */ @@ -11080,7 +10812,7 @@ int wc_dilithium_init_ex(dilithium_key* key, void* heap, int devId) key->heap = heap; } -#if defined(WOLFSSL_WC_DILITHIUM) && defined(USE_INTEL_SPEEDUP) +#if defined(USE_INTEL_SPEEDUP) cpuid_get_flags_ex(&cpuid_flags); #endif @@ -11174,7 +10906,6 @@ int wc_dilithium_set_level(dilithium_key* key, byte level) } if (ret == 0) { -#ifdef WOLFSSL_WC_DILITHIUM /* Get the parameters for level into key. */ ret = dilithium_get_params(level, &key->params); } @@ -11199,7 +10930,6 @@ int wc_dilithium_set_level(dilithium_key* key, byte level) key->pubVecSet = 0; #endif #endif -#endif /* WOLFSSL_WC_DILITHIUM */ #ifdef WOLFSSL_DILITHIUM_DYNAMIC_KEYS if (key->k != NULL) { @@ -11266,7 +10996,6 @@ void wc_dilithium_free(dilithium_key* key) /* always continue to software cleanup */ } #endif -#ifdef WOLFSSL_WC_DILITHIUM #ifndef WC_DILITHIUM_FIXED_ARRAY /* Dispose of cached items. */ #ifdef WC_DILITHIUM_CACHE_PUB_VECTORS @@ -11284,7 +11013,6 @@ void wc_dilithium_free(dilithium_key* key) /* Free the SHAKE-128/256 object. */ wc_Shake256_Free(&key->shake); #endif -#endif #ifdef WOLFSSL_DILITHIUM_DYNAMIC_KEYS if (key->k != NULL) { ForceZero(key->k, key->kSz); @@ -11535,7 +11263,6 @@ int wc_MlDsaKey_GetSigLen(MlDsaKey* key, int* len) int wc_dilithium_check_key(dilithium_key* key) { int ret = 0; -#ifdef WOLFSSL_WC_DILITHIUM const wc_dilithium_params* params = NULL; sword32* a = NULL; sword32* s1 = NULL; @@ -11661,32 +11388,6 @@ int wc_dilithium_check_key(dilithium_key* key) /* Dispose of allocated memory. */ XFREE(s1, key->heap, DYNAMIC_TYPE_DILITHIUM); } -#else - /* Validate parameter. */ - if (key == NULL) { - ret = BAD_FUNC_ARG; - } - if ((ret == 0) && (!key->prvKeySet)) { - ret = BAD_FUNC_ARG; - } - if ((ret == 0) && (!key->pubKeySet)) { - ret = PUBLIC_KEY_E; - } - - if (ret == 0) { - int i; - sword32 x = 0; - - /* Check the public seed is the same in private and public key. */ - for (i = 0; i < 32; i++) { - x |= key->p[i] ^ key->k[i]; - } - - if (x != 0) { - ret = PUBLIC_KEY_E; - } - } -#endif /* WOLFSSL_WC_DILITHIUM */ return ret; } #endif /* WOLFSSL_DILITHIUM_CHECK_KEY */ @@ -12431,7 +12132,7 @@ int wc_Dilithium_PrivateKeyDecode(const byte* input, word32* inOutIdx, if (ret == 0) { /* Generate a key pair if seed exists and decoded key pair is ignored */ if (seedLen != 0) { -#if defined(WOLFSSL_WC_DILITHIUM) && !defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) +#if !defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) if (seedLen == DILITHIUM_SEED_SZ) { ret = wc_dilithium_make_key_from_seed(key, seed); } @@ -12666,11 +12367,7 @@ int wc_Dilithium_PublicKeyDecode(const byte* input, word32* inOutIdx, ret = DecodeAsymKeyPublic_Assign(input, inOutIdx, inSz, &pubKey, &pubKeyLen, &keyType); - if (ret == 0 -#ifdef WOLFSSL_WC_DILITHIUM - && key->params == NULL -#endif - ) { + if (ret == 0 && key->params == NULL) { /* Set the security level based on the decoded key. */ ret = mapOidToSecLevel(keyType); if (ret > 0) { diff --git a/wolfcrypt/src/evp_pk.c b/wolfcrypt/src/evp_pk.c index 7767cb92f4..068bdf19bc 100644 --- a/wolfcrypt/src/evp_pk.c +++ b/wolfcrypt/src/evp_pk.c @@ -448,8 +448,10 @@ static int d2iTryAltDhKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, static int d2i_falcon_priv_key_level(falcon_key* falcon, byte level, const unsigned char* mem, long memSz) { + word32 idx = 0; return (wc_falcon_set_level(falcon, level) == 0) && - (wc_falcon_import_private_only(mem, (word32)memSz, falcon) == 0); + (wc_Falcon_PrivateKeyDecode(mem, &idx, falcon, + (word32)memSz) == 0); } /** diff --git a/wolfcrypt/src/ext_mlkem.c b/wolfcrypt/src/ext_mlkem.c deleted file mode 100644 index 90ffbb1662..0000000000 --- a/wolfcrypt/src/ext_mlkem.c +++ /dev/null @@ -1,768 +0,0 @@ -/* ext_mlkem.c - * - * Copyright (C) 2006-2026 wolfSSL Inc. - * - * This file is part of wolfSSL. - * - * wolfSSL is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * wolfSSL is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA - */ - -#include - -#if defined(WOLFSSL_HAVE_MLKEM) && !defined(WOLFSSL_WC_MLKEM) - -#if FIPS_VERSION3_GE(2,0,0) - /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */ - #define FIPS_NO_WRAPPERS -#endif - -#include - -#ifdef NO_INLINE - #include -#else - #define WOLFSSL_MISC_INCLUDED - #include -#endif - -#if defined (HAVE_LIBOQS) - -#include - -static const char* OQS_ID2name(int id) { - switch (id) { - #ifndef WOLFSSL_NO_ML_KEM - case WC_ML_KEM_512: return OQS_KEM_alg_ml_kem_512; - case WC_ML_KEM_768: return OQS_KEM_alg_ml_kem_768; - case WC_ML_KEM_1024: return OQS_KEM_alg_ml_kem_1024; - #endif - #ifdef WOLFSSL_MLKEM_KYBER - case KYBER_LEVEL1: return OQS_KEM_alg_kyber_512; - case KYBER_LEVEL3: return OQS_KEM_alg_kyber_768; - case KYBER_LEVEL5: return OQS_KEM_alg_kyber_1024; - #endif - default: break; - } - return NULL; -} - -int ext_mlkem_enabled(int id) -{ - const char * name = OQS_ID2name(id); - return OQS_KEM_alg_is_enabled(name); -} -#endif - -/******************************************************************************/ -/* Initializer and cleanup functions. */ - -/** - * Initialize the Kyber key. - * - * @param [out] key Kyber key object to initialize. - * @param [in] type Type of key: KYBER512, KYBER768, KYBER1024. - * @param [in] heap Dynamic memory hint. - * @param [in] devId Device Id. - * @return 0 on success. - * @return BAD_FUNC_ARG when key is NULL or type is unrecognized. - * @return NOT_COMPILED_IN when key type is not supported. - */ -int wc_MlKemKey_Init(MlKemKey* key, int type, void* heap, int devId) -{ - int ret = 0; - - /* Validate key. */ - if (key == NULL) { - ret = BAD_FUNC_ARG; - } - if (ret == 0) { - /* Validate type. */ - switch (type) { -#ifndef WOLFSSL_NO_ML_KEM - case WC_ML_KEM_512: - #ifdef HAVE_LIBOQS - case WC_ML_KEM_768: - case WC_ML_KEM_1024: - #endif /* HAVE_LIBOQS */ -#endif -#ifdef WOLFSSL_MLKEM_KYBER - case KYBER_LEVEL1: - #ifdef HAVE_LIBOQS - case KYBER_LEVEL3: - case KYBER_LEVEL5: - #endif /* HAVE_LIBOQS */ -#endif - break; - default: - /* No other values supported. */ - ret = BAD_FUNC_ARG; - break; - } - } - if (ret == 0) { - /* Zero out all data. */ - XMEMSET(key, 0, sizeof(*key)); - - /* Keep type for parameters. */ - key->type = type; - -#ifdef WOLF_CRYPTO_CB - key->devCtx = NULL; - key->devId = devId; -#endif - } - - (void)heap; - (void)devId; - - return ret; -} - -/** - * Free the Kyber key object. - * - * @param [in, out] key Kyber key object to dispose of. - */ -int wc_MlKemKey_Free(MlKemKey* key) -{ - if (key != NULL) { - /* Ensure all private data is zeroed. */ - ForceZero(key, sizeof(*key)); - } - - return 0; -} - -/******************************************************************************/ -/* Data size getters. */ - -/** - * Get the size in bytes of encoded private key for the key. - * - * @param [in] key Kyber key object. - * @param [out] len Length of encoded private key in bytes. - * @return 0 on success. - * @return BAD_FUNC_ARG when key or len is NULL. - * @return NOT_COMPILED_IN when key type is not supported. - */ -int wc_MlKemKey_PrivateKeySize(MlKemKey* key, word32* len) -{ - int ret = 0; - - /* Validate parameters. */ - if ((key == NULL) || (len == NULL)) { - ret = BAD_FUNC_ARG; - } - -#ifdef HAVE_LIBOQS - /* NOTE: SHAKE and AES variants have the same length private key. */ - if (ret == 0) { - switch (key->type) { - #ifndef WOLFSSL_NO_ML_KEM - case WC_ML_KEM_512: - *len = OQS_KEM_ml_kem_512_length_secret_key; - break; - case WC_ML_KEM_768: - *len = OQS_KEM_ml_kem_768_length_secret_key; - break; - case WC_ML_KEM_1024: - *len = OQS_KEM_ml_kem_1024_length_secret_key; - break; - #endif - #ifdef WOLFSSL_MLKEM_KYBER - case KYBER_LEVEL1: - *len = OQS_KEM_kyber_512_length_secret_key; - break; - case KYBER_LEVEL3: - *len = OQS_KEM_kyber_768_length_secret_key; - break; - case KYBER_LEVEL5: - *len = OQS_KEM_kyber_1024_length_secret_key; - break; - #endif - default: - /* No other values supported. */ - ret = BAD_FUNC_ARG; - break; - } - } -#endif /* HAVE_LIBOQS */ - - return ret; -} - -/** - * Get the size in bytes of encoded public key for the key. - * - * @param [in] key Kyber key object. - * @param [out] len Length of encoded public key in bytes. - * @return 0 on success. - * @return BAD_FUNC_ARG when key or len is NULL. - * @return NOT_COMPILED_IN when key type is not supported. - */ -int wc_MlKemKey_PublicKeySize(MlKemKey* key, word32* len) -{ - int ret = 0; - - /* Validate parameters. */ - if ((key == NULL) || (len == NULL)) { - ret = BAD_FUNC_ARG; - } - -#ifdef HAVE_LIBOQS - /* NOTE: SHAKE and AES variants have the same length public key. */ - if (ret == 0) { - switch (key->type) { - #ifndef WOLFSSL_NO_ML_KEM - case WC_ML_KEM_512: - *len = OQS_KEM_ml_kem_512_length_public_key; - break; - case WC_ML_KEM_768: - *len = OQS_KEM_ml_kem_768_length_public_key; - break; - case WC_ML_KEM_1024: - *len = OQS_KEM_ml_kem_1024_length_public_key; - break; - #endif - #ifdef WOLFSSL_MLKEM_KYBER - case KYBER_LEVEL1: - *len = OQS_KEM_kyber_512_length_public_key; - break; - case KYBER_LEVEL3: - *len = OQS_KEM_kyber_768_length_public_key; - break; - case KYBER_LEVEL5: - *len = OQS_KEM_kyber_1024_length_public_key; - break; - #endif - default: - /* No other values supported. */ - ret = BAD_FUNC_ARG; - break; - } - } -#endif /* HAVE_LIBOQS */ - - return ret; -} - -/** - * Get the size in bytes of cipher text for key. - * - * @param [in] key Kyber key object. - * @param [out] len Length of cipher text in bytes. - * @return 0 on success. - * @return BAD_FUNC_ARG when key or len is NULL. - * @return NOT_COMPILED_IN when key type is not supported. - */ -int wc_MlKemKey_CipherTextSize(MlKemKey* key, word32* len) -{ - int ret = 0; - - /* Validate parameters. */ - if ((key == NULL) || (len == NULL)) { - ret = BAD_FUNC_ARG; - } - -#ifdef HAVE_LIBOQS - /* NOTE: SHAKE and AES variants have the same length ciphertext. */ - if (ret == 0) { - switch (key->type) { - #ifndef WOLFSSL_NO_ML_KEM - case WC_ML_KEM_512: - *len = OQS_KEM_ml_kem_512_length_ciphertext; - break; - case WC_ML_KEM_768: - *len = OQS_KEM_ml_kem_768_length_ciphertext; - break; - case WC_ML_KEM_1024: - *len = OQS_KEM_ml_kem_1024_length_ciphertext; - break; - #endif - #ifdef WOLFSSL_MLKEM_KYBER - case KYBER_LEVEL1: - *len = OQS_KEM_kyber_512_length_ciphertext; - break; - case KYBER_LEVEL3: - *len = OQS_KEM_kyber_768_length_ciphertext; - break; - case KYBER_LEVEL5: - *len = OQS_KEM_kyber_1024_length_ciphertext; - break; - #endif - default: - /* No other values supported. */ - ret = BAD_FUNC_ARG; - break; - } - } -#endif /* HAVE_LIBOQS */ - - return ret; -} - -/** - * Size of a shared secret in bytes. Always KYBER_SS_SZ. - * - * @param [in] key Kyber key object. Not used. - * @param [out] Size of the shared secret created with a Kyber key. - * @return 0 on success. - * @return 0 to indicate success. - */ -int wc_MlKemKey_SharedSecretSize(MlKemKey* key, word32* len) -{ - (void)key; - /* Validate parameters. */ - if (len == NULL) { - return BAD_FUNC_ARG; - } - - *len = KYBER_SS_SZ; - - return 0; -} - -/******************************************************************************/ -/* Cryptographic operations. */ - -/** - * Make a Kyber key object using a random number generator. - * - * NOTE: rng is ignored. OQS doesn't use our RNG. - * - * @param [in, out] key Kyber key ovject. - * @param [in] rng Random number generator. - * @return 0 on success. - * @return BAD_FUNC_ARG when key or rng is NULL. - * @return MEMORY_E when dynamic memory allocation failed. - */ -int wc_MlKemKey_MakeKey(MlKemKey* key, WC_RNG* rng) -{ - int ret = 0; -#ifdef HAVE_LIBOQS - const char* algName = NULL; - OQS_KEM *kem = NULL; -#endif - - /* Validate parameter. */ - if (key == NULL) { - return BAD_FUNC_ARG; - } - -#ifdef WOLF_CRYPTO_CB - #ifndef WOLF_CRYPTO_CB_FIND - if (key->devId != INVALID_DEVID) - #endif - { - ret = wc_CryptoCb_MakePqcKemKey(rng, WC_PQC_KEM_TYPE_KYBER, - key->type, key); - if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) - return ret; - /* fall-through when unavailable */ - ret = 0; - } -#endif - -#ifdef HAVE_LIBOQS - if (ret == 0) { - algName = OQS_ID2name(key->type); - if (algName == NULL) { - ret = BAD_FUNC_ARG; - } - } - - if (ret == 0) { - kem = OQS_KEM_new(algName); - if (kem == NULL) { - ret = BAD_FUNC_ARG; - } - } - if (ret == 0) { - ret = wolfSSL_liboqsRngMutexLock(rng); - } - if (ret == 0) { - if (OQS_KEM_keypair(kem, key->pub, key->priv) != - OQS_SUCCESS) { - ret = BAD_FUNC_ARG; - } - } - wolfSSL_liboqsRngMutexUnlock(); - OQS_KEM_free(kem); -#endif /* HAVE_LIBOQS */ - - if (ret != 0) { - ForceZero(key, sizeof(*key)); - } - - return ret; -} - -/** - * Make a Kyber key object using random data. - * - * @param [in, out] key Kyber key ovject. - * @param [in] rng Random number generator. - * @return 0 on success. - * @return BAD_FUNC_ARG when key or rand is NULL. - * @return BUFFER_E when length is not KYBER_MAKEKEY_RAND_SZ. - * @return NOT_COMPILED_IN when key type is not supported. - * @return MEMORY_E when dynamic memory allocation failed. - */ -int wc_MlKemKey_MakeKeyWithRandom(MlKemKey* key, const unsigned char* rand, - int len) -{ - (void)rand; - (void)len; - /* OQS doesn't support external randomness. */ - return wc_MlKemKey_MakeKey(key, NULL); -} - -/** - * Encapsulate with random number generator and derive secret. - * - * @param [in] key Kyber key object. - * @param [out] ct Cipher text. - * @param [out] ss Shared secret generated. - * @param [in] rng Random number generator. - * @return 0 on success. - * @return BAD_FUNC_ARG when key, ct, ss or RNG is NULL. - * @return NOT_COMPILED_IN when key type is not supported. - * @return MEMORY_E when dynamic memory allocation failed. - */ -int wc_MlKemKey_Encapsulate(MlKemKey* key, unsigned char* ct, unsigned char* ss, - WC_RNG* rng) -{ - int ret = 0; -#ifdef WOLF_CRYPTO_CB - word32 ctlen = 0; -#endif -#ifdef HAVE_LIBOQS - const char * algName = NULL; - OQS_KEM *kem = NULL; -#endif - - (void)rng; - - /* Validate parameters. */ - if ((key == NULL) || (ct == NULL) || (ss == NULL)) { - ret = BAD_FUNC_ARG; - } - -#ifdef WOLF_CRYPTO_CB - if (ret == 0) { - ret = wc_MlKemKey_CipherTextSize(key, &ctlen); - } - if ((ret == 0) - #ifndef WOLF_CRYPTO_CB_FIND - && (key->devId != INVALID_DEVID) - #endif - ) { - ret = wc_CryptoCb_PqcEncapsulate(ct, ctlen, ss, KYBER_SS_SZ, rng, - WC_PQC_KEM_TYPE_KYBER, key); - if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) - return ret; - /* fall-through when unavailable */ - ret = 0; - } -#endif - -#ifdef HAVE_LIBOQS - if (ret == 0) { - algName = OQS_ID2name(key->type); - if (algName == NULL) { - ret = BAD_FUNC_ARG; - } - } - if (ret == 0) { - kem = OQS_KEM_new(algName); - if (kem == NULL) { - ret = BAD_FUNC_ARG; - } - } - if (ret == 0) { - ret = wolfSSL_liboqsRngMutexLock(rng); - } - if (ret == 0) { - if (OQS_KEM_encaps(kem, ct, ss, key->pub) != OQS_SUCCESS) { - ret = BAD_FUNC_ARG; - } - } - wolfSSL_liboqsRngMutexUnlock(); - OQS_KEM_free(kem); -#endif /* HAVE_LIBOQS */ - - return ret; -} - -/** - * Encapsulate with random data and derive secret. - * - * @param [out] ct Cipher text. - * @param [out] ss Shared secret generated. - * @param [in] rand Random data. - * @param [in] len Random data. - * @return 0 on success. - * @return BAD_FUNC_ARG when key, ct, ss or RNG is NULL. - * @return BUFFER_E when len is not KYBER_ENC_RAND_SZ. - * @return NOT_COMPILED_IN when key type is not supported. - * @return MEMORY_E when dynamic memory allocation failed. - */ -int wc_MlKemKey_EncapsulateWithRandom(MlKemKey* key, unsigned char* ct, - unsigned char* ss, const unsigned char* rand, int len) -{ - (void)rand; - (void)len; - /* OQS doesn't support external randomness. */ - return wc_MlKemKey_Encapsulate(key, ct, ss, NULL); -} - -/** - * Decapsulate the cipher text to calculate the shared secret. - * - * Validates the cipher text by encapsulating and comparing with data passed in. - * - * @param [in] key Kyber key object. - * @param [out] ss Shared secret. - * @param [in] ct Cipher text. - * @param [in] len Length of cipher text. - * @return 0 on success. - * @return BAD_FUNC_ARG when key, ss or cr are NULL. - * @return NOT_COMPILED_IN when key type is not supported. - * @return BUFFER_E when len is not the length of cipher text for the key type. - * @return MEMORY_E when dynamic memory allocation failed. - */ -int wc_MlKemKey_Decapsulate(MlKemKey* key, unsigned char* ss, - const unsigned char* ct, word32 len) -{ - int ret = 0; - word32 ctlen = 0; -#ifdef HAVE_LIBOQS - const char * algName = NULL; - OQS_KEM *kem = NULL; -#endif - - /* Validate parameters. */ - if ((key == NULL) || (ss == NULL) || (ct == NULL)) { - ret = BAD_FUNC_ARG; - } - if (ret == 0) { - ret = wc_MlKemKey_CipherTextSize(key, &ctlen); - } - if ((ret == 0) && (len != ctlen)) { - ret = BUFFER_E; - } - -#ifdef WOLF_CRYPTO_CB - if ((ret == 0) - #ifndef WOLF_CRYPTO_CB_FIND - && (key->devId != INVALID_DEVID) - #endif - ) { - ret = wc_CryptoCb_PqcDecapsulate(ct, ctlen, ss, KYBER_SS_SZ, - WC_PQC_KEM_TYPE_KYBER, key); - if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) - return ret; - /* fall-through when unavailable */ - ret = 0; - } -#endif - -#ifdef HAVE_LIBOQS - if (ret == 0) { - algName = OQS_ID2name(key->type); - if (algName == NULL) { - ret = BAD_FUNC_ARG; - } - } - if (ret == 0) { - kem = OQS_KEM_new(algName); - if (kem == NULL) { - ret = BAD_FUNC_ARG; - } - } - if (ret == 0) { - if (OQS_KEM_decaps(kem, ss, ct, key->priv) != OQS_SUCCESS) { - ret = BAD_FUNC_ARG; - } - } - - OQS_KEM_free(kem); -#endif /* HAVE_LIBOQS */ - - return ret; - -} - -/******************************************************************************/ -/* Encoding and decoding functions. */ - -/** - * Decode the private key. - * - * We store the whole thing in the private key buffer. Note this means we cannot - * do the encapsulation operation with the private key. But generally speaking - * this is never done. - * - * @param [in, out] key Kyber key object. - * @param [in] in Buffer holding encoded key. - * @param [in] len Length of data in buffer. - * @return 0 on success. - * @return BAD_FUNC_ARG when key or in is NULL. - * @return NOT_COMPILED_IN when key type is not supported. - * @return BUFFER_E when len is not the correct size. - */ -int wc_MlKemKey_DecodePrivateKey(MlKemKey* key, const unsigned char* in, - word32 len) -{ - int ret = 0; - word32 privLen = 0; - - /* Validate parameters. */ - if ((key == NULL) || (in == NULL)) { - ret = BAD_FUNC_ARG; - } - - if (ret == 0) { - ret = wc_MlKemKey_PrivateKeySize(key, &privLen); - } - - /* Ensure the data is the correct length for the key type. */ - if ((ret == 0) && (len != privLen)) { - ret = BUFFER_E; - } - - if (ret == 0) { - XMEMCPY(key->priv, in, privLen); - } - - return ret; -} - -/** - * Decode public key. - * - * We store the whole thing in the public key buffer. - * - * @param [in, out] key Kyber key object. - * @param [in] in Buffer holding encoded key. - * @param [in] len Length of data in buffer. - * @return 0 on success. - * @return BAD_FUNC_ARG when key or in is NULL. - * @return NOT_COMPILED_IN when key type is not supported. - * @return BUFFER_E when len is not the correct size. - */ -int wc_MlKemKey_DecodePublicKey(MlKemKey* key, const unsigned char* in, - word32 len) -{ - int ret = 0; - word32 pubLen = 0; - - /* Validate parameters. */ - if ((key == NULL) || (in == NULL)) { - ret = BAD_FUNC_ARG; - } - - if (ret == 0) { - ret = wc_MlKemKey_PublicKeySize(key, &pubLen); - } - - /* Ensure the data is the correct length for the key type. */ - if ((ret == 0) && (len != pubLen)) { - ret = BUFFER_E; - } - - if (ret == 0) { - XMEMCPY(key->pub, in, pubLen); - } - - return ret; -} - -/** - * Encode the private key. - * - * We stored it as a blob so we can just copy it over. - * - * @param [in] key Kyber key object. - * @param [out] out Buffer to hold data. - * @param [in] len Size of buffer in bytes. - * @return 0 on success. - * @return BAD_FUNC_ARG when key or out is NULL or private/public key not - * available. - * @return NOT_COMPILED_IN when key type is not supported. - */ -int wc_MlKemKey_EncodePrivateKey(MlKemKey* key, unsigned char* out, word32 len) -{ - int ret = 0; - unsigned int privLen = 0; - - if ((key == NULL) || (out == NULL)) { - ret = BAD_FUNC_ARG; - } - - if (ret == 0) { - ret = wc_MlKemKey_PrivateKeySize(key, &privLen); - } - - /* Check buffer is big enough for encoding. */ - if ((ret == 0) && (len != privLen)) { - ret = BUFFER_E; - } - - if (ret == 0) { - XMEMCPY(out, key->priv, privLen); - } - - return ret; -} - -/** - * Encode the public key. - * - * We stored it as a blob so we can just copy it over. - * - * @param [in] key Kyber key object. - * @param [out] out Buffer to hold data. - * @param [in] len Size of buffer in bytes. - * @return 0 on success. - * @return BAD_FUNC_ARG when key or out is NULL or public key not available. - * @return NOT_COMPILED_IN when key type is not supported. - */ -int wc_MlKemKey_EncodePublicKey(MlKemKey* key, unsigned char* out, word32 len) -{ - int ret = 0; - unsigned int pubLen = 0; - - if ((key == NULL) || (out == NULL)) { - ret = BAD_FUNC_ARG; - } - - if (ret == 0) { - ret = wc_MlKemKey_PublicKeySize(key, &pubLen); - } - - /* Check buffer is big enough for encoding. */ - if ((ret == 0) && (len != pubLen)) { - ret = BUFFER_E; - } - - if (ret == 0) { - XMEMCPY(out, key->pub, pubLen); - } - - return ret; -} - -#endif /* WOLFSSL_HAVE_MLKEM && !WOLFSSL_WC_MLKEM */ diff --git a/wolfcrypt/src/falcon.c b/wolfcrypt/src/falcon.c index 9a9e1eeebb..de21195eda 100644 --- a/wolfcrypt/src/falcon.c +++ b/wolfcrypt/src/falcon.c @@ -23,13 +23,12 @@ /* Based on ed448.c and Reworked for Falcon by Anthony Hu. */ -#if defined(HAVE_PQC) && defined(HAVE_FALCON) +#if defined(HAVE_FALCON) #include -#ifdef HAVE_LIBOQS +/* HAVE_FALCON implies HAVE_LIBOQS (enforced in settings.h and falcon.h). */ #include -#endif #include #ifdef NO_INLINE @@ -437,132 +436,95 @@ int wc_falcon_import_public(const byte* in, word32 inLen, return 0; } -static int parse_private_key(const byte* priv, word32 privSz, - byte** out, word32 *outSz, - falcon_key* key) { - word32 idx = 0; - int ret = 0; - int length = 0; - - /* sanity check on arguments */ - if ((priv == NULL) || (key == NULL)) { - return BAD_FUNC_ARG; - } - - if ((key->level != 1) && (key->level != 5)) { - return BAD_FUNC_ARG; - } - - /* At this point, it is still a PKCS8 private key. */ - if ((ret = ToTraditionalInline(priv, &idx, privSz)) < 0) { - /* ignore error, did not have PKCS8 header */ - (void)ret; - } - - /* Now it is a octet_string(concat(priv,pub)) */ - if ((ret = GetOctetString(priv, &idx, &length, privSz)) < 0) { - return ret; - } - - *out = (byte *)priv + idx; - *outSz = privSz - idx; - - /* And finally it is concat(priv,pub). Key size check. */ - if ((key->level == 1) && (*outSz != FALCON_LEVEL1_KEY_SIZE + - FALCON_LEVEL1_PUB_KEY_SIZE)) { - return BAD_FUNC_ARG; - } - else if ((key->level == 5) && (*outSz != FALCON_LEVEL5_KEY_SIZE + - FALCON_LEVEL5_PUB_KEY_SIZE)) { - return BAD_FUNC_ARG; - } - - return 0; -} - -/* Import a falcon private key from a byte array. +/* Import a raw Falcon private key. * - * priv [in] Array holding private key. - * privSz [in] Number of bytes of data in array. - * key [in] Falcon private key. - * returns BAD_FUNC_ARG when a parameter is NULL or privSz is less than - * FALCON_LEVEL1_KEY_SIZE, - * 0 otherwise. + * Accepts either the raw secret key (FALCON_LEVELx_KEY_SIZE) or the legacy + * concat(priv, pub) layout (FALCON_LEVELx_PRV_KEY_SIZE) produced by older + * wolfSSL releases. In the concat case, the trailing public-key bytes are + * imported as well so verify works on round-tripped keys. + * + * priv [in] Raw private-key bytes. + * privSz [in] Length of priv in bytes. + * key [in] Falcon key. key->level must already be set. + * returns BAD_FUNC_ARG when a parameter is NULL or privSz doesn't match + * either accepted size, 0 otherwise. + * + * This is the raw-bytes import. To decode a DER/PKCS8 Falcon private key, + * use wc_Falcon_PrivateKeyDecode instead. */ int wc_falcon_import_private_only(const byte* priv, word32 privSz, falcon_key* key) { - int ret = 0; - byte *newPriv = NULL; - word32 newPrivSz = 0; + word32 keySz; + word32 concatSz; - if ((ret = parse_private_key(priv, privSz, &newPriv, &newPrivSz, key)) - != 0) { - return ret; + if ((priv == NULL) || (key == NULL)) { + return BAD_FUNC_ARG; } - XMEMCPY(key->k, newPriv, newPrivSz); + if (key->level == 1) { + keySz = FALCON_LEVEL1_KEY_SIZE; + concatSz = FALCON_LEVEL1_PRV_KEY_SIZE; + } + else if (key->level == 5) { + keySz = FALCON_LEVEL5_KEY_SIZE; + concatSz = FALCON_LEVEL5_PRV_KEY_SIZE; + } + else { + return BAD_FUNC_ARG; + } + + if ((privSz != keySz) && (privSz != concatSz)) { + return BAD_FUNC_ARG; + } + + XMEMCPY(key->k, priv, keySz); key->prvKeySet = 1; + /* Legacy concat layout carries the public key after the private key. */ + if (privSz == concatSz) { + XMEMCPY(key->p, priv + keySz, concatSz - keySz); + key->pubKeySet = 1; + } + return 0; } -/* Import a falcon private and public keys from byte array(s). +/* Import a raw Falcon private (and optionally public) key. * - * priv [in] Array holding private key or private+public keys - * privSz [in] Number of bytes of data in private key array. - * pub [in] Array holding public key (or NULL). - * pubSz [in] Number of bytes of data in public key array (or 0). - * key [in] Falcon private/public key. - * returns BAD_FUNC_ARG when a required parameter is NULL or an invalid - * combination of keys/lengths is supplied, 0 otherwise. + * If pub is NULL (and pubSz is 0), only the private key is imported. The + * private buffer may be in the legacy concat(priv,pub) layout, in which case + * the public part is recovered from it. + * + * priv [in] Raw private-key bytes (FALCON_LEVELx_KEY_SIZE or the legacy + * FALCON_LEVELx_PRV_KEY_SIZE concat layout). + * privSz [in] Length of priv in bytes. + * pub [in] Raw public-key bytes (FALCON_LEVELx_PUB_KEY_SIZE), or NULL. + * pubSz [in] Length of pub in bytes (0 if pub is NULL). + * key [in] Falcon key. key->level must already be set. + * returns BAD_FUNC_ARG when a required parameter is NULL or a length doesn't + * match an expected size, 0 otherwise. + * + * This is the raw-bytes import. To decode a DER/PKCS8 Falcon private key, + * use wc_Falcon_PrivateKeyDecode instead. */ int wc_falcon_import_private_key(const byte* priv, word32 privSz, const byte* pub, word32 pubSz, falcon_key* key) { - int ret = 0; - byte *newPriv = NULL; - word32 newPrivSz = 0; + int ret; - if ((ret = parse_private_key(priv, privSz, &newPriv, &newPrivSz, key)) - != 0) { - return ret; + if ((priv == NULL) || (key == NULL)) { + return BAD_FUNC_ARG; } - - if (pub == NULL) { - if (pubSz != 0) { - return BAD_FUNC_ARG; - } - - if ((newPrivSz != FALCON_LEVEL1_PRV_KEY_SIZE) && - (newPrivSz != FALCON_LEVEL5_PRV_KEY_SIZE)) { - return BAD_FUNC_ARG; - } - - if (key->level == 1) { - pub = newPriv + FALCON_LEVEL1_KEY_SIZE; - pubSz = FALCON_LEVEL1_PUB_KEY_SIZE; - } - else if (key->level == 5) { - pub = newPriv + FALCON_LEVEL5_KEY_SIZE; - pubSz = FALCON_LEVEL5_PUB_KEY_SIZE; - } - } - else if ((pubSz != FALCON_LEVEL1_PUB_KEY_SIZE) && - (pubSz != FALCON_LEVEL5_PUB_KEY_SIZE)) { + if ((pub == NULL) && (pubSz != 0)) { return BAD_FUNC_ARG; } - /* import public key */ - ret = wc_falcon_import_public(pub, pubSz, key); - - if (ret == 0) { - /* make the private key (priv + pub) */ - XMEMCPY(key->k, newPriv, newPrivSz); - key->prvKeySet = 1; + ret = wc_falcon_import_private_only(priv, privSz, key); + if ((ret == 0) && (pub != NULL)) { + ret = wc_falcon_import_public(pub, pubSz, key); } - return ret; } @@ -844,12 +806,16 @@ int wc_Falcon_PrivateKeyDecode(const byte* input, word32* inOutIdx, ret = DecodeAsymKey(input, inOutIdx, inSz, privKey, &privKeyLen, pubKey, &pubKeyLen, keytype); if (ret == 0) { + /* PKCS8 may carry only the private key; pass NULL/0 in that case + * so import_private_key can recover the public part from the legacy + * concat layout (or leave pubKeySet = 0 for a strict raw private). */ if (pubKeyLen == 0) { - ret = wc_falcon_import_private_key(input, inSz, NULL, 0, key); + ret = wc_falcon_import_private_key(privKey, privKeyLen, + NULL, 0, key); } else { - ret = wc_falcon_import_private_key(input, inSz, pubKey, - pubKeyLen, key); + ret = wc_falcon_import_private_key(privKey, privKeyLen, + pubKey, pubKeyLen, key); } } @@ -955,12 +921,12 @@ int wc_Falcon_KeyToDer(falcon_key* key, byte* output, word32 inLen) if (key->level == 1) { return SetAsymKeyDer(key->k, FALCON_LEVEL1_KEY_SIZE, key->p, - FALCON_LEVEL1_KEY_SIZE, output, inLen, + FALCON_LEVEL1_PUB_KEY_SIZE, output, inLen, FALCON_LEVEL1k); } else if (key->level == 5) { return SetAsymKeyDer(key->k, FALCON_LEVEL5_KEY_SIZE, key->p, - FALCON_LEVEL5_KEY_SIZE, output, inLen, + FALCON_LEVEL5_PUB_KEY_SIZE, output, inLen, FALCON_LEVEL5k); } @@ -984,4 +950,4 @@ int wc_Falcon_PrivateKeyToDer(falcon_key* key, byte* output, word32 inLen) return BAD_FUNC_ARG; } -#endif /* HAVE_PQC && HAVE_FALCON */ +#endif /* HAVE_FALCON */ diff --git a/wolfcrypt/src/port/arm/armv8-32-mlkem-asm.S b/wolfcrypt/src/port/arm/armv8-32-mlkem-asm.S index 638a0310d1..2089663a2f 100644 --- a/wolfcrypt/src/port/arm/armv8-32-mlkem-asm.S +++ b/wolfcrypt/src/port/arm/armv8-32-mlkem-asm.S @@ -30,7 +30,7 @@ #ifdef WOLFSSL_ARMASM #if !defined(__aarch64__) && !defined(WOLFSSL_ARMASM_THUMB2) #ifndef WOLFSSL_ARMASM_INLINE -#ifdef WOLFSSL_WC_MLKEM +#ifdef WOLFSSL_HAVE_MLKEM #ifndef __APPLE__ .text .type L_mlkem_arm32_ntt_zetas, %object @@ -8507,7 +8507,7 @@ L_mlkem_arm32_rej_uniform_done: lsr r0, r12, #1 pop {r4, r5, r6, r7, r8, pc} .size mlkem_arm32_rej_uniform,.-mlkem_arm32_rej_uniform -#endif /* WOLFSSL_WC_MLKEM */ +#endif /* WOLFSSL_HAVE_MLKEM */ #endif /* !__aarch64__ && !WOLFSSL_ARMASM_THUMB2 */ #endif /* WOLFSSL_ARMASM */ diff --git a/wolfcrypt/src/port/arm/armv8-32-mlkem-asm_c.c b/wolfcrypt/src/port/arm/armv8-32-mlkem-asm_c.c index 686fd9f8ef..78f85cef66 100644 --- a/wolfcrypt/src/port/arm/armv8-32-mlkem-asm_c.c +++ b/wolfcrypt/src/port/arm/armv8-32-mlkem-asm_c.c @@ -49,7 +49,7 @@ #include -#ifdef WOLFSSL_WC_MLKEM +#ifdef WOLFSSL_HAVE_MLKEM XALIGNED(4) static const word16 L_mlkem_arm32_ntt_zetas[] = { 0x08ed, 0x0a0b, 0x0b9a, 0x0714, 0x05d5, 0x058e, 0x011f, 0x00ca, 0x0c56, 0x026e, 0x0629, 0x00b6, 0x03c2, 0x084f, 0x073f, 0x05bc, @@ -8663,7 +8663,7 @@ WC_OMIT_FRAME_POINTER unsigned int mlkem_arm32_rej_uniform(sword16* p, return (word32)(size_t)p; } -#endif /* WOLFSSL_WC_MLKEM */ +#endif /* WOLFSSL_HAVE_MLKEM */ #endif /* !__aarch64__ && !WOLFSSL_ARMASM_THUMB2 */ #endif /* WOLFSSL_ARMASM */ diff --git a/wolfcrypt/src/port/arm/armv8-mlkem-asm.S b/wolfcrypt/src/port/arm/armv8-mlkem-asm.S index 566e10fcda..2ee1506a7e 100644 --- a/wolfcrypt/src/port/arm/armv8-mlkem-asm.S +++ b/wolfcrypt/src/port/arm/armv8-mlkem-asm.S @@ -45,7 +45,7 @@ #endif /* __APPLE__ */ L_mlkem_aarch64_consts: .short 0x0d01,0xf301,0x4ebf,0x0549,0x5049,0x0000,0x0000,0x0000 -#ifdef WOLFSSL_WC_MLKEM +#ifdef WOLFSSL_HAVE_MLKEM #ifndef __APPLE__ .text .section .rodata @@ -12024,7 +12024,7 @@ L_SHA3_shake256_blocksx3_seed_neon_begin: .size mlkem_shake256_blocksx3_seed_neon,.-mlkem_shake256_blocksx3_seed_neon #endif /* __APPLE__ */ #endif /* WOLFSSL_ARMASM_CRYPTO_SHA3 */ -#endif /* WOLFSSL_WC_MLKEM */ +#endif /* WOLFSSL_HAVE_MLKEM */ #endif /* __aarch64__ */ #endif /* WOLFSSL_ARMASM */ diff --git a/wolfcrypt/src/port/arm/armv8-mlkem-asm_c.c b/wolfcrypt/src/port/arm/armv8-mlkem-asm_c.c index 6f7ba392a2..54a92c47fc 100644 --- a/wolfcrypt/src/port/arm/armv8-mlkem-asm_c.c +++ b/wolfcrypt/src/port/arm/armv8-mlkem-asm_c.c @@ -36,7 +36,7 @@ XALIGNED(4) static const word16 L_mlkem_aarch64_consts[] = { #include -#ifdef WOLFSSL_WC_MLKEM +#ifdef WOLFSSL_HAVE_MLKEM XALIGNED(4) static const word16 L_mlkem_aarch64_zetas[] = { 0x08ed, 0x0a0b, 0x0b9a, 0x0714, 0x05d5, 0x058e, 0x011f, 0x00ca, 0x0c56, 0x026e, 0x0629, 0x00b6, 0x03c2, 0x084f, 0x073f, 0x05bc, @@ -11255,7 +11255,7 @@ void mlkem_shake256_blocksx3_seed_neon(word64* state, byte* seed) } #endif /* WOLFSSL_ARMASM_CRYPTO_SHA3 */ -#endif /* WOLFSSL_WC_MLKEM */ +#endif /* WOLFSSL_HAVE_MLKEM */ #endif /* __aarch64__ */ #endif /* WOLFSSL_ARMASM */ #endif /* WOLFSSL_ARMASM_INLINE */ diff --git a/wolfcrypt/src/port/arm/thumb2-mlkem-asm.S b/wolfcrypt/src/port/arm/thumb2-mlkem-asm.S index 42cd8622f6..49b638a67c 100644 --- a/wolfcrypt/src/port/arm/thumb2-mlkem-asm.S +++ b/wolfcrypt/src/port/arm/thumb2-mlkem-asm.S @@ -32,7 +32,7 @@ #ifndef WOLFSSL_ARMASM_INLINE .thumb .syntax unified -#ifdef WOLFSSL_WC_MLKEM +#ifdef WOLFSSL_HAVE_MLKEM #ifndef __APPLE__ .text .type L_mlkem_thumb2_ntt_zetas, %object @@ -3582,7 +3582,7 @@ L_mlkem_thumb2_rej_uniform_done: POP {r4, r5, r6, r7, r8, r9, r10, pc} /* Cycle Count = 225 */ .size mlkem_thumb2_rej_uniform,.-mlkem_thumb2_rej_uniform -#endif /* WOLFSSL_WC_MLKEM */ +#endif /* WOLFSSL_HAVE_MLKEM */ #endif /* WOLFSSL_ARMASM_THUMB2 */ #endif /* WOLFSSL_ARMASM */ diff --git a/wolfcrypt/src/port/arm/thumb2-mlkem-asm_c.c b/wolfcrypt/src/port/arm/thumb2-mlkem-asm_c.c index 5f45fc7051..30a403959c 100644 --- a/wolfcrypt/src/port/arm/thumb2-mlkem-asm_c.c +++ b/wolfcrypt/src/port/arm/thumb2-mlkem-asm_c.c @@ -49,7 +49,7 @@ #include -#ifdef WOLFSSL_WC_MLKEM +#ifdef WOLFSSL_HAVE_MLKEM XALIGNED(4) static const word16 L_mlkem_thumb2_ntt_zetas[] = { 0x08ed, 0x0a0b, 0x0b9a, 0x0714, 0x05d5, 0x058e, 0x011f, 0x00ca, 0x0c56, 0x026e, 0x0629, 0x00b6, 0x03c2, 0x084f, 0x073f, 0x05bc, @@ -3884,7 +3884,7 @@ WC_OMIT_FRAME_POINTER unsigned int mlkem_thumb2_rej_uniform(sword16* p, return (word32)(size_t)p; } -#endif /* WOLFSSL_WC_MLKEM */ +#endif /* WOLFSSL_HAVE_MLKEM */ #endif /* WOLFSSL_ARMASM_THUMB2 */ #endif /* WOLFSSL_ARMASM */ diff --git a/wolfcrypt/src/sha3_asm.S b/wolfcrypt/src/sha3_asm.S index 387a42a4c8..a0dfc6b8a9 100644 --- a/wolfcrypt/src/sha3_asm.S +++ b/wolfcrypt/src/sha3_asm.S @@ -9928,7 +9928,7 @@ L_sha3_block_n_avx2_rounds: #ifndef __APPLE__ .size sha3_block_n_avx2,.-sha3_block_n_avx2 #endif /* __APPLE__ */ -#if defined(WOLFSSL_WC_MLKEM) || defined(WOLFSSL_WC_DILITHIUM) || defined(WOLFSSL_HAVE_SLHDSA) +#if defined(WOLFSSL_HAVE_MLKEM) || defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_SLHDSA) #ifndef __APPLE__ .text .globl sha3_blocksx4_avx2 @@ -20664,8 +20664,8 @@ _sha3_128_blocksx4_seed_avx2: #ifndef __APPLE__ .size sha3_128_blocksx4_seed_avx2,.-sha3_128_blocksx4_seed_avx2 #endif /* __APPLE__ */ -#endif /* defined(WOLFSSL_WC_MLKEM) || defined(WOLFSSL_WC_DILITHIUM) || defined(WOLFSSL_HAVE_SLHDSA) */ -#ifdef WOLFSSL_WC_MLKEM +#endif /* defined(WOLFSSL_HAVE_MLKEM) || defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_SLHDSA) */ +#ifdef WOLFSSL_HAVE_MLKEM #ifndef __APPLE__ .data #else @@ -26044,8 +26044,8 @@ _sha3_256_blocksx4_seed_avx2: #ifndef __APPLE__ .size sha3_256_blocksx4_seed_avx2,.-sha3_256_blocksx4_seed_avx2 #endif /* __APPLE__ */ -#endif /* WOLFSSL_WC_MLKEM */ -#ifdef WOLFSSL_WC_DILITHIUM +#endif /* WOLFSSL_HAVE_MLKEM */ +#ifdef HAVE_DILITHIUM #ifndef __APPLE__ .data #else @@ -31448,7 +31448,7 @@ _sha3_256_blocksx4_seed_64_avx2: #ifndef __APPLE__ .size sha3_256_blocksx4_seed_64_avx2,.-sha3_256_blocksx4_seed_64_avx2 #endif /* __APPLE__ */ -#endif /* WOLFSSL_WC_DILITHIUM */ +#endif /* HAVE_DILITHIUM */ #endif /* HAVE_INTEL_AVX2 */ #if defined(__linux__) && defined(__ELF__) diff --git a/wolfcrypt/src/sphincs.c b/wolfcrypt/src/sphincs.c index 587b99375e..61d858e3e7 100644 --- a/wolfcrypt/src/sphincs.c +++ b/wolfcrypt/src/sphincs.c @@ -25,7 +25,7 @@ #include -#if defined(HAVE_PQC) && defined(HAVE_SPHINCS) +#if defined(HAVE_SPHINCS) #ifdef HAVE_LIBOQS #include @@ -1054,4 +1054,4 @@ int wc_Sphincs_PrivateKeyToDer(sphincs_key* key, byte* output, word32 inLen) return BAD_FUNC_ARG; } -#endif /* HAVE_PQC && HAVE_SPHINCS */ +#endif /* HAVE_SPHINCS */ diff --git a/wolfcrypt/src/wc_mldsa_asm.S b/wolfcrypt/src/wc_mldsa_asm.S index 52acb659dc..7cf4b58569 100644 --- a/wolfcrypt/src/wc_mldsa_asm.S +++ b/wolfcrypt/src/wc_mldsa_asm.S @@ -47,7 +47,7 @@ #endif /* HAVE_INTEL_AVX2 */ #endif /* NO_AVX2_SUPPORT */ -#ifdef WOLFSSL_WC_DILITHIUM +#ifdef HAVE_DILITHIUM #ifdef HAVE_INTEL_AVX2 #ifndef __APPLE__ .data @@ -35284,7 +35284,7 @@ _wc_mldsa_poly_make_pos_avx2: .size wc_mldsa_poly_make_pos_avx2,.-wc_mldsa_poly_make_pos_avx2 #endif /* __APPLE__ */ #endif /* HAVE_INTEL_AVX2 */ -#endif /* WOLFSSL_WC_DILITHIUM */ +#endif /* HAVE_DILITHIUM */ #if defined(__linux__) && defined(__ELF__) .section .note.GNU-stack,"",%progbits diff --git a/wolfcrypt/src/wc_mlkem.c b/wolfcrypt/src/wc_mlkem.c index 9e40b2ba18..ccdd671256 100644 --- a/wolfcrypt/src/wc_mlkem.c +++ b/wolfcrypt/src/wc_mlkem.c @@ -83,7 +83,6 @@ #define FIPS_NO_WRAPPERS #endif -#include #include #include #include @@ -121,7 +120,7 @@ #error "Cannot use dynamic key buffers without malloc" #endif -#ifdef WOLFSSL_WC_MLKEM +#ifdef WOLFSSL_HAVE_MLKEM #ifdef DEBUG_MLKEM void print_polys(const char* name, const sword16* a, int d1, int d2); @@ -2567,4 +2566,4 @@ int wc_MlKemKey_EncodePublicKey(MlKemKey* key, unsigned char* out, word32 len) return ret; } -#endif /* WOLFSSL_WC_MLKEM */ +#endif /* WOLFSSL_HAVE_MLKEM */ diff --git a/wolfcrypt/src/wc_mlkem_asm.S b/wolfcrypt/src/wc_mlkem_asm.S index 5eb503c1f5..7e69add127 100644 --- a/wolfcrypt/src/wc_mlkem_asm.S +++ b/wolfcrypt/src/wc_mlkem_asm.S @@ -47,7 +47,7 @@ #endif /* HAVE_INTEL_AVX2 */ #endif /* NO_AVX2_SUPPORT */ -#ifdef WOLFSSL_WC_MLKEM +#ifdef WOLFSSL_HAVE_MLKEM #ifdef HAVE_INTEL_AVX2 #ifndef __APPLE__ .data @@ -15869,7 +15869,7 @@ _mlkem_redistribute_8_rand_avx2: .size mlkem_redistribute_8_rand_avx2,.-mlkem_redistribute_8_rand_avx2 #endif /* __APPLE__ */ #endif /* HAVE_INTEL_AVX2 */ -#endif /* WOLFSSL_WC_MLKEM */ +#endif /* WOLFSSL_HAVE_MLKEM */ #if defined(__linux__) && defined(__ELF__) .section .note.GNU-stack,"",%progbits diff --git a/wolfcrypt/src/wc_mlkem_poly.c b/wolfcrypt/src/wc_mlkem_poly.c index 8d768d4ca8..1df80823cc 100644 --- a/wolfcrypt/src/wc_mlkem_poly.c +++ b/wolfcrypt/src/wc_mlkem_poly.c @@ -34,7 +34,7 @@ /* Possible Kyber options: * - * WOLFSSL_WC_MLKEM Default: OFF + * WOLFSSL_HAVE_MLKEM Default: OFF * Enables this code, wolfSSL implementation, to be built. * * WOLFSSL_WC_ML_KEM_512 Default: OFF @@ -79,7 +79,7 @@ #include #include -#ifdef WOLFSSL_WC_MLKEM +#ifdef WOLFSSL_HAVE_MLKEM #ifdef NO_INLINE #include @@ -6114,4 +6114,4 @@ int mlkem_check_public(sword16* pub, int k) return ret; } -#endif /* WOLFSSL_WC_MLKEM */ +#endif /* WOLFSSL_HAVE_MLKEM */ diff --git a/wolfcrypt/src/wc_pkcs11.c b/wolfcrypt/src/wc_pkcs11.c index fbc394780a..8c387eec6f 100644 --- a/wolfcrypt/src/wc_pkcs11.c +++ b/wolfcrypt/src/wc_pkcs11.c @@ -69,23 +69,20 @@ #if defined(NO_PKCS11_MLDSA) && defined(HAVE_DILITHIUM) #undef HAVE_DILITHIUM #endif -#if defined(WOLFSSL_HAVE_MLKEM) && defined(WOLFSSL_WC_MLKEM) - #define HAVE_PKCS11_MLKEM -#endif -#if defined(NO_PKCS11_MLKEM) && defined(HAVE_PKCS11_MLKEM) - #undef HAVE_PKCS11_MLKEM +#if defined(NO_PKCS11_MLKEM) && defined(WOLFSSL_HAVE_MLKEM) + #undef WOLFSSL_HAVE_MLKEM #endif #if (defined(HAVE_ECC) && !defined(NO_PKCS11_ECDH)) || \ - defined(HAVE_PKCS11_MLKEM) + defined(WOLFSSL_HAVE_MLKEM) /* Pointer to false required for templates. */ static CK_BBOOL ckFalse = CK_FALSE; #endif #if !defined(NO_RSA) || defined(HAVE_ECC) || (!defined(NO_AES) && \ (defined(HAVE_AESGCM) || defined(HAVE_AES_CBC))) || \ !defined(NO_HMAC) || defined(HAVE_DILITHIUM) || \ - defined(HAVE_PKCS11_MLKEM) + defined(WOLFSSL_HAVE_MLKEM) /* Pointer to true required for templates. */ static CK_BBOOL ckTrue = CK_TRUE; #endif @@ -98,7 +95,7 @@ static CK_KEY_TYPE rsaKeyType = CKK_RSA; /* Pointer to EC key type required for templates. */ static CK_KEY_TYPE ecKeyType = CKK_EC; #endif -#if defined(HAVE_PKCS11_MLKEM) +#if defined(WOLFSSL_HAVE_MLKEM) /* Pointer to ML-KEM key type required for templates. */ static CK_KEY_TYPE mlkemKeyType = CKK_ML_KEM; #endif @@ -107,7 +104,7 @@ static CK_KEY_TYPE mlkemKeyType = CKK_ML_KEM; static CK_KEY_TYPE mldsaKeyType = CKK_ML_DSA; #endif #if !defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_DILITHIUM) || \ - defined(HAVE_PKCS11_MLKEM) + defined(WOLFSSL_HAVE_MLKEM) /* Pointer to public key class required for templates. */ static CK_OBJECT_CLASS pubKeyClass = CKO_PUBLIC_KEY; /* Pointer to private key class required for templates. */ @@ -115,7 +112,7 @@ static CK_OBJECT_CLASS privKeyClass = CKO_PRIVATE_KEY; #endif #if (!defined(NO_AES) && (defined(HAVE_AESGCM) || defined(HAVE_AES_CBC))) || \ !defined(NO_HMAC) || (defined(HAVE_ECC) && !defined(NO_PKCS11_ECDH)) || \ - defined(HAVE_PKCS11_MLKEM) + defined(WOLFSSL_HAVE_MLKEM) /* Pointer to secret key class required for templates. */ static CK_OBJECT_CLASS secretKeyClass = CKO_SECRET_KEY; #endif @@ -1572,7 +1569,7 @@ static int Pkcs11CreateEccPrivateKey(CK_OBJECT_HANDLE* privateKey, } #endif -#ifdef HAVE_PKCS11_MLKEM +#ifdef WOLFSSL_HAVE_MLKEM /** * Create a PKCS#11 object containing the ML-KEM public key data. */ @@ -1772,7 +1769,7 @@ static int Pkcs11CreateMlKemPrivateKey(CK_OBJECT_HANDLE* privateKey, return ret; } -#endif /* HAVE_PKCS11_MLKEM */ +#endif /* WOLFSSL_HAVE_MLKEM */ #ifdef HAVE_DILITHIUM /** @@ -1949,7 +1946,7 @@ static int Pkcs11CreateMldsaPrivateKey(CK_OBJECT_HANDLE* privateKey, #if !defined(NO_RSA) || defined(HAVE_ECC) || (!defined(NO_AES) && \ (defined(HAVE_AESGCM) || defined(HAVE_AES_CBC))) || \ !defined(NO_HMAC) || defined(HAVE_DILITHIUM) || \ - defined(HAVE_PKCS11_MLKEM) + defined(WOLFSSL_HAVE_MLKEM) /** * Check if mechanism is available in session on token. * @@ -2191,7 +2188,7 @@ int wc_Pkcs11StoreKey(Pkcs11Token* token, int type, int clear, void* key) break; } #endif - #ifdef HAVE_PKCS11_MLKEM + #ifdef WOLFSSL_HAVE_MLKEM case PKCS11_KEY_TYPE_MLKEM: { MlKemKey* mlkemKey = (MlKemKey*)key; CK_MECHANISM_INFO mechInfo; @@ -2220,7 +2217,7 @@ int wc_Pkcs11StoreKey(Pkcs11Token* token, int type, int clear, void* key) } break; } - #endif /* HAVE_PKCS11_MLKEM */ + #endif /* WOLFSSL_HAVE_MLKEM */ #if defined(HAVE_DILITHIUM) case PKCS11_KEY_TYPE_MLDSA: { MlDsaKey* mldsaKey = (MlDsaKey*) key; @@ -4243,7 +4240,7 @@ static int Pkcs11EccDeletePrivKey(Pkcs11Session* session, ecc_key* key) } #endif -#ifdef HAVE_PKCS11_MLKEM +#ifdef WOLFSSL_HAVE_MLKEM /* Finds the first ML-KEM key matching the key type. */ static int Pkcs11FindMlKemKey(CK_OBJECT_HANDLE* handle, CK_OBJECT_CLASS keyClass, @@ -4747,7 +4744,7 @@ static int Pkcs11PqcKemDecapsulate(Pkcs11Session* session, wc_CryptoInfo* info) return ret; } -#endif /* HAVE_PKCS11_MLKEM */ +#endif /* WOLFSSL_HAVE_MLKEM */ #if defined(HAVE_DILITHIUM) /** @@ -6330,7 +6327,7 @@ int wc_Pkcs11_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) if (ret == 0) { if (info->algo_type == WC_ALGO_TYPE_PK) { #if !defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_DILITHIUM) || \ - defined(HAVE_PKCS11_MLKEM) + defined(WOLFSSL_HAVE_MLKEM) switch (info->pk.type) { #ifndef NO_RSA case WC_PK_TYPE_RSA: @@ -6410,7 +6407,7 @@ int wc_Pkcs11_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) } break; #endif - #ifdef HAVE_PKCS11_MLKEM + #ifdef WOLFSSL_HAVE_MLKEM case WC_PK_TYPE_PQC_KEM_KEYGEN: ret = Pkcs11OpenSession(token, &session, readWrite); if (ret == 0) { @@ -6469,7 +6466,7 @@ int wc_Pkcs11_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) } #else ret = NOT_COMPILED_IN; -#endif /* !NO_RSA || HAVE_ECC || HAVE_DILITHIUM || HAVE_PKCS11_MLKEM */ +#endif /* !NO_RSA || HAVE_ECC || HAVE_DILITHIUM || WOLFSSL_HAVE_MLKEM */ } else if (info->algo_type == WC_ALGO_TYPE_CIPHER) { #ifndef NO_AES @@ -6603,7 +6600,7 @@ int wc_Pkcs11_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) } else #endif - #ifdef HAVE_PKCS11_MLKEM + #ifdef WOLFSSL_HAVE_MLKEM if (info->free.algo == WC_ALGO_TYPE_PK && info->free.type == WC_PK_TYPE_PQC_KEM_KEYGEN && info->free.subType == WC_PQC_KEM_TYPE_KYBER) { diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index afcf8b4f3c..7964c870f1 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -389,14 +389,8 @@ static const byte const_byte_array[] = "A+Gd\0\0\0"; #include #endif #ifdef WOLFSSL_HAVE_MLKEM - #include -#ifdef WOLFSSL_WC_MLKEM #include #endif -#if defined(HAVE_LIBOQS) - #include -#endif -#endif #ifdef HAVE_DILITHIUM #include #endif @@ -44500,7 +44494,6 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ed448_test(void) #endif /* HAVE_ED448 */ #ifdef WOLFSSL_HAVE_MLKEM -#ifdef WOLFSSL_WC_MLKEM /* OQS does not support KATs */ #if !defined(WOLFSSL_NO_KYBER512) && !defined(WOLFSSL_NO_ML_KEM_512) static wc_test_ret_t mlkem512_kat(void) { @@ -48881,7 +48874,6 @@ out: return ret; } #endif /* !WOLFSSL_NO_KYBER1024 && !WOLFSSL_NO_ML_KEM_1024 */ -#endif /* WOLFSSL_WC_MLKEM */ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t mlkem_test(void) { @@ -48922,8 +48914,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t mlkem_test(void) #endif #endif #endif -#if defined(WOLFSSL_WC_MLKEM) && !defined(WOLFSSL_NO_MALLOC) && \ - !defined(WOLFSSL_MLKEM_NO_MAKE_KEY) +#if !defined(WOLFSSL_NO_MALLOC) && !defined(WOLFSSL_MLKEM_NO_MAKE_KEY) MlKemKey *tmpKey = NULL; #endif int key_inited = 0; @@ -49111,7 +49102,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t mlkem_test(void) if (XMEMCMP(priv, priv2, testData[i][2]) != 0) ERROR_OUT(WC_TEST_RET_ENC_I(i), out); -#if defined(WOLFSSL_WC_MLKEM) && !defined(WOLFSSL_NO_MALLOC) +#if !defined(WOLFSSL_NO_MALLOC) tmpKey = wc_MlKemKey_New(testData[i][0], HEAP_HINT, devId); if (tmpKey == NULL) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); @@ -49122,7 +49113,6 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t mlkem_test(void) #endif } -#ifdef WOLFSSL_WC_MLKEM #if !defined(WOLFSSL_NO_KYBER512) && !defined(WOLFSSL_NO_ML_KEM_512) ret = mlkem512_kat(); if (ret != 0) @@ -49138,7 +49128,6 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t mlkem_test(void) if (ret != 0) goto out; #endif -#endif /* WOLFSSL_WC_MLKEM */ out: @@ -52677,13 +52666,11 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t dilithium_test(void) } #ifndef WOLFSSL_NO_ML_DSA_44 -#ifdef WOLFSSL_WC_DILITHIUM #ifndef WOLFSSL_DILITHIUM_NO_VERIFY ret = dilithium_param_44_vfy_test(); if (ret != 0) ERROR_OUT(ret, out); #endif -#endif #ifndef WOLFSSL_DILITHIUM_NO_MAKE_KEY ret = dilithium_param_test(WC_ML_DSA_44, &rng); if (ret != 0) @@ -52691,13 +52678,11 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t dilithium_test(void) #endif #endif #ifndef WOLFSSL_NO_ML_DSA_65 -#ifdef WOLFSSL_WC_DILITHIUM #ifndef WOLFSSL_DILITHIUM_NO_VERIFY ret = dilithium_param_65_vfy_test(); if (ret != 0) ERROR_OUT(ret, out); #endif -#endif #ifndef WOLFSSL_DILITHIUM_NO_MAKE_KEY ret = dilithium_param_test(WC_ML_DSA_65, &rng); if (ret != 0) @@ -52705,13 +52690,11 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t dilithium_test(void) #endif #endif #ifndef WOLFSSL_NO_ML_DSA_87 -#ifdef WOLFSSL_WC_DILITHIUM #ifndef WOLFSSL_DILITHIUM_NO_VERIFY ret = dilithium_param_87_vfy_test(); if (ret != 0) ERROR_OUT(ret, out); #endif -#endif #ifndef WOLFSSL_DILITHIUM_NO_MAKE_KEY ret = dilithium_param_test(WC_ML_DSA_87, &rng); if (ret != 0) @@ -68396,43 +68379,33 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx) if ((info->pk.pqc_kem_kg.type == WC_PQC_KEM_TYPE_KYBER) && (info->pk.pqc_kem_kg.key != NULL)) { MlKemKey* key = (MlKemKey*)info->pk.pqc_kem_kg.key; -#ifdef WOLFSSL_WC_MLKEM int hashDevId = key->hash.devId; int prfDevId = key->prf.devId; -#endif /* set devId to invalid, so software is used */ key->devId = INVALID_DEVID; -#ifdef WOLFSSL_WC_MLKEM key->hash.devId = INVALID_DEVID; key->prf.devId = INVALID_DEVID; -#endif ret = wc_MlKemKey_MakeKey(key, info->pk.pqc_kem_kg.rng); /* reset devId */ key->devId = devIdArg; -#ifdef WOLFSSL_WC_MLKEM key->hash.devId = hashDevId; key->prf.devId = prfDevId; -#endif } } else if (info->pk.type == WC_PK_TYPE_PQC_KEM_ENCAPS) { if ((info->pk.pqc_encaps.type == WC_PQC_KEM_TYPE_KYBER) && (info->pk.pqc_encaps.key != NULL)) { MlKemKey* key = (MlKemKey*)info->pk.pqc_encaps.key; -#ifdef WOLFSSL_WC_MLKEM int hashDevId = key->hash.devId; int prfDevId = key->prf.devId; -#endif /* set devId to invalid, so software is used */ key->devId = INVALID_DEVID; -#ifdef WOLFSSL_WC_MLKEM key->hash.devId = INVALID_DEVID; key->prf.devId = INVALID_DEVID; -#endif ret = wc_MlKemKey_Encapsulate(key, info->pk.pqc_encaps.ciphertext, @@ -68441,27 +68414,21 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx) /* reset devId */ key->devId = devIdArg; -#ifdef WOLFSSL_WC_MLKEM key->hash.devId = hashDevId; key->prf.devId = prfDevId; -#endif } } else if (info->pk.type == WC_PK_TYPE_PQC_KEM_DECAPS) { if ((info->pk.pqc_decaps.type == WC_PQC_KEM_TYPE_KYBER) && (info->pk.pqc_decaps.key != NULL)) { MlKemKey* key = (MlKemKey*)info->pk.pqc_decaps.key; -#ifdef WOLFSSL_WC_MLKEM int hashDevId = key->hash.devId; int prfDevId = key->prf.devId; -#endif /* set devId to invalid, so software is used */ key->devId = INVALID_DEVID; -#ifdef WOLFSSL_WC_MLKEM key->hash.devId = INVALID_DEVID; key->prf.devId = INVALID_DEVID; -#endif ret = wc_MlKemKey_Decapsulate(key, info->pk.pqc_decaps.sharedSecret, @@ -68470,10 +68437,8 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx) /* reset devId */ key->devId = devIdArg; -#ifdef WOLFSSL_WC_MLKEM key->hash.devId = hashDevId; key->prf.devId = prfDevId; -#endif } } #endif /* WOLFSSL_HAVE_MLKEM */ @@ -69197,10 +69162,8 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx) if (info->free.subType == WC_PQC_KEM_TYPE_KYBER) { MlKemKey* mlkem = (MlKemKey*)info->free.obj; mlkem->devId = INVALID_DEVID; -#ifdef WOLFSSL_WC_MLKEM mlkem->hash.devId = INVALID_DEVID; mlkem->prf.devId = INVALID_DEVID; -#endif ret = wc_MlKemKey_Free(mlkem); } break; diff --git a/wolfssl-VS2022.vcxproj b/wolfssl-VS2022.vcxproj index d5e13a3964..7bb1661a1b 100644 --- a/wolfssl-VS2022.vcxproj +++ b/wolfssl-VS2022.vcxproj @@ -428,7 +428,6 @@ - diff --git a/wolfssl.vcproj b/wolfssl.vcproj index 02554722d2..a35cff8c7a 100644 --- a/wolfssl.vcproj +++ b/wolfssl.vcproj @@ -263,10 +263,6 @@ RelativePath=".\wolfcrypt\src\error.c" > - - diff --git a/wolfssl.vcxproj b/wolfssl.vcxproj index 58410b144a..c0cab55b3b 100644 --- a/wolfssl.vcxproj +++ b/wolfssl.vcxproj @@ -427,7 +427,6 @@ - diff --git a/wolfssl/certs_test.h b/wolfssl/certs_test.h index efd4c1bd28..3b01e501ac 100644 --- a/wolfssl/certs_test.h +++ b/wolfssl/certs_test.h @@ -3462,646 +3462,646 @@ static const unsigned char dh_key_der_4096[] = /* certs/falcon/bench_falcon_level1_key.der */ static const unsigned char bench_falcon_level1_key[] = { - 0x30, 0x82, 0x08, 0x96, 0x02, 0x01, 0x00, 0x30, 0x07, 0x06, - 0x05, 0x2B, 0xCE, 0x0F, 0x03, 0x01, 0x04, 0x82, 0x08, 0x86, - 0x04, 0x82, 0x08, 0x82, 0x59, 0xFC, 0x32, 0x7D, 0x04, 0x41, - 0x01, 0xEC, 0x41, 0x7B, 0x04, 0x1F, 0x7F, 0xFC, 0x30, 0xBF, - 0x08, 0x80, 0x41, 0x10, 0x3F, 0x81, 0xFB, 0xFF, 0xC6, 0x07, - 0xCF, 0xC6, 0x0C, 0x11, 0x79, 0xFC, 0x2F, 0xC1, 0xFB, 0xFF, - 0x40, 0x1F, 0xA1, 0x3F, 0x0B, 0xF1, 0xC3, 0x0F, 0xB0, 0x43, - 0xFC, 0x61, 0x40, 0x0C, 0x1E, 0xFE, 0x08, 0x5E, 0xBE, 0x00, - 0x41, 0x3D, 0x13, 0xA0, 0xC0, 0xDB, 0xCF, 0x80, 0xF0, 0x20, - 0x80, 0x1C, 0x5F, 0x07, 0x07, 0xBF, 0xC3, 0x18, 0x5E, 0x85, - 0x0C, 0x1F, 0xC7, 0xD8, 0x0F, 0x86, 0x04, 0x10, 0xC0, 0xFC, - 0x32, 0x7E, 0xEF, 0xEF, 0x81, 0xF0, 0x2F, 0xC1, 0x04, 0x0E, - 0xC3, 0xF3, 0xD1, 0x47, 0xF7, 0xE0, 0xC0, 0xF8, 0x40, 0x42, - 0x13, 0xED, 0x82, 0xF0, 0x3E, 0xFB, 0xFF, 0xE0, 0x00, 0xFF, - 0xFF, 0xFA, 0x1F, 0xF1, 0x3D, 0x03, 0xCF, 0xBA, 0xFC, 0x90, - 0x43, 0x0B, 0x6F, 0xC7, 0xEF, 0xDF, 0x02, 0xFF, 0xCF, 0x41, - 0x03, 0xDF, 0xC2, 0x1B, 0xDE, 0xF9, 0x00, 0x90, 0x03, 0xFC, - 0x20, 0xBD, 0x04, 0x10, 0x38, 0xEF, 0xF1, 0x07, 0xE8, 0x51, - 0x07, 0xF7, 0x9F, 0xC2, 0x14, 0x00, 0x04, 0x04, 0x00, 0x00, - 0x04, 0x0F, 0x3F, 0xFF, 0xFF, 0x7D, 0xE0, 0x2F, 0x00, 0xF7, - 0xC1, 0x83, 0xFF, 0xBF, 0x87, 0x03, 0xA0, 0xC4, 0xEF, 0xEF, - 0xFF, 0xFC, 0x00, 0xFE, 0x20, 0x6F, 0xBE, 0x14, 0x9F, 0x01, - 0x17, 0xAE, 0xFE, 0x08, 0x3F, 0x7A, 0x17, 0xFF, 0x80, 0x14, - 0x3E, 0xC2, 0x04, 0x1F, 0xFB, 0x08, 0x4F, 0x41, 0xFC, 0x41, - 0xC2, 0x0C, 0x20, 0x82, 0x03, 0xC2, 0x43, 0x20, 0x20, 0xF8, - 0x07, 0xFF, 0x7E, 0xF8, 0x3E, 0x81, 0xEF, 0xDE, 0xC3, 0x00, - 0x4F, 0x85, 0x03, 0xD0, 0x7E, 0xF8, 0x2F, 0x42, 0xDF, 0xB1, - 0x3E, 0xFB, 0xF1, 0x45, 0x0B, 0xF1, 0x41, 0x1B, 0xF0, 0xC0, - 0x03, 0xEF, 0x03, 0xEB, 0x9E, 0xFE, 0xE8, 0x21, 0x42, 0x14, - 0x4E, 0xC4, 0xFC, 0x3E, 0x00, 0xF3, 0xFF, 0xBC, 0x18, 0x40, - 0x87, 0x08, 0x51, 0x7D, 0x03, 0xFF, 0x42, 0x18, 0x00, 0x43, - 0xF8, 0x6F, 0x7F, 0xFC, 0x21, 0x05, 0xFB, 0xF0, 0xFA, 0x00, - 0x2F, 0xC2, 0x04, 0x00, 0x43, 0x1B, 0xE1, 0x07, 0xF0, 0x50, - 0x05, 0x00, 0x11, 0x41, 0xF4, 0x4E, 0xC9, 0x0B, 0xDF, 0xBD, - 0x20, 0xB0, 0x7B, 0x04, 0xE0, 0xFF, 0xF3, 0xEF, 0x3F, 0x20, - 0x5F, 0xC8, 0xFF, 0xF0, 0xFE, 0xFB, 0x9F, 0x3C, 0xFB, 0xFF, - 0xC1, 0x13, 0x51, 0x05, 0x03, 0xFF, 0x03, 0xFB, 0xE1, 0xBE, - 0x1B, 0xC0, 0x8B, 0x03, 0xF1, 0x7F, 0x10, 0x6E, 0x39, 0x08, - 0x3F, 0xC9, 0xFC, 0x40, 0x82, 0xFB, 0xE0, 0xBC, 0xF0, 0x21, - 0x03, 0xE4, 0x6F, 0x7E, 0xD8, 0x00, 0x81, 0xF8, 0x41, 0x46, - 0x07, 0xC0, 0x45, 0x24, 0x2F, 0x80, 0x0C, 0x3F, 0x05, 0x20, - 0x8F, 0x84, 0xF8, 0x6F, 0xFF, 0xEC, 0x30, 0x85, 0xFF, 0xF0, - 0xBD, 0xF4, 0x50, 0x87, 0x00, 0x3F, 0xC2, 0xFB, 0xC0, 0xC1, - 0x03, 0xEF, 0xB8, 0xFF, 0xFF, 0x45, 0x13, 0xBE, 0xC1, 0x03, - 0xC0, 0x40, 0x07, 0x90, 0x3E, 0xE0, 0x0E, 0xFD, 0xFB, 0xA0, - 0xFF, 0xF8, 0x0F, 0xC5, 0xFF, 0xFF, 0x43, 0xE3, 0xFF, 0x06, - 0x0F, 0xB0, 0x43, 0xF0, 0x90, 0x7B, 0xE7, 0xD1, 0x79, 0x07, - 0xDF, 0xFB, 0x03, 0xE0, 0x04, 0xF7, 0xD0, 0x45, 0xFF, 0xEF, - 0xBB, 0x20, 0x01, 0x42, 0xD0, 0x7E, 0xC3, 0x13, 0xEF, 0xC8, - 0x0B, 0x8E, 0xBE, 0xF8, 0x1F, 0xFE, 0xDF, 0xCF, 0xBE, 0x13, - 0xD1, 0xFC, 0x0C, 0x61, 0xC2, 0x04, 0x40, 0x01, 0x00, 0x2F, - 0xFC, 0x0B, 0xDF, 0x00, 0x14, 0x61, 0x02, 0xE4, 0x0F, 0x81, - 0xF0, 0x3F, 0x81, 0xFC, 0x00, 0x82, 0xF4, 0x21, 0x7E, 0x0B, - 0xF0, 0x48, 0x00, 0x00, 0x3A, 0xE8, 0x5F, 0x05, 0x17, 0xF0, - 0xC0, 0x00, 0x61, 0x39, 0xF8, 0x4F, 0x81, 0xEB, 0x5F, 0x06, - 0x08, 0x2F, 0xC0, 0x04, 0x1F, 0xFF, 0x0B, 0xBF, 0xBA, 0x0B, - 0xFF, 0x40, 0x07, 0xCF, 0x42, 0x10, 0x1F, 0x3D, 0xDB, 0xC0, - 0x85, 0x03, 0xD1, 0xC0, 0x04, 0x0F, 0x7E, 0x03, 0xBF, 0x81, - 0xF7, 0xD0, 0x7D, 0xE8, 0x1E, 0x00, 0x00, 0x31, 0x46, 0x04, - 0x21, 0x40, 0xF3, 0xBF, 0x05, 0x03, 0xD1, 0x40, 0xFB, 0xEE, - 0xFD, 0x03, 0xF0, 0xBA, 0xE7, 0xFE, 0xBD, 0xE8, 0x6F, 0xBC, - 0x07, 0xEF, 0x82, 0x0C, 0x40, 0x3F, 0x00, 0x20, 0x80, 0x0F, - 0xB1, 0x42, 0xFC, 0x10, 0x3F, 0x07, 0xEF, 0xBF, 0xF0, 0x1E, - 0x82, 0xFC, 0x3F, 0x80, 0x1C, 0x50, 0xC3, 0x13, 0xD0, 0xFC, - 0xEF, 0xEF, 0x7C, 0x0C, 0x6F, 0xBF, 0x1B, 0x90, 0xFF, 0x00, - 0x70, 0xC5, 0x04, 0x00, 0x03, 0xEF, 0x8F, 0x80, 0xF8, 0x00, - 0x7F, 0x04, 0x01, 0x41, 0xE8, 0x21, 0x43, 0x08, 0x9F, 0x44, - 0xF7, 0xF2, 0x7C, 0x0F, 0xC0, 0x3E, 0xEC, 0x4F, 0xFF, 0x00, - 0x31, 0x3E, 0x13, 0xEE, 0x40, 0xFB, 0xE0, 0xFA, 0xEB, 0xD0, - 0xBF, 0x04, 0x0F, 0x46, 0xFF, 0xE2, 0x7D, 0x03, 0xDE, 0x81, - 0xF4, 0x2F, 0xBD, 0x08, 0x0F, 0x42, 0xEF, 0xA0, 0x40, 0xF8, - 0x01, 0x41, 0xF3, 0xD1, 0x00, 0x00, 0x01, 0x00, 0x13, 0xB0, - 0x7E, 0xE7, 0xE0, 0x7F, 0x08, 0x2F, 0x3E, 0x03, 0xD2, 0xC3, - 0x23, 0x9F, 0xFF, 0x17, 0xEE, 0xBB, 0xF0, 0x2E, 0xBE, 0xFC, - 0x2F, 0x3F, 0xF4, 0x00, 0x48, 0xE3, 0xDE, 0x7B, 0x0B, 0xFF, - 0xC4, 0x04, 0x01, 0x02, 0xFF, 0xB1, 0x84, 0x00, 0x7E, 0xC5, - 0x08, 0x11, 0xBE, 0xF7, 0x90, 0xC5, 0xEF, 0xDE, 0x09, 0x0B, - 0xD0, 0x86, 0xEC, 0x4F, 0xFC, 0x0B, 0xA1, 0x06, 0xEC, 0x50, - 0xC3, 0xFF, 0xA1, 0x3D, 0x20, 0x4F, 0xFF, 0x13, 0x8F, 0x45, - 0xF3, 0xF0, 0x83, 0x04, 0x06, 0x09, 0xE4, 0xEB, 0xFA, 0xFD, - 0xD6, 0x04, 0x2A, 0x25, 0x0F, 0xF3, 0xE6, 0x10, 0xFD, 0xEB, - 0x0C, 0x0B, 0x0C, 0xF3, 0x1F, 0x06, 0x21, 0xFF, 0x2E, 0xDD, - 0xFA, 0xF3, 0xF1, 0x21, 0xEE, 0x1B, 0x06, 0xC6, 0x05, 0x21, - 0xF7, 0x07, 0xE1, 0x01, 0x19, 0x0D, 0xEE, 0xE2, 0xD2, 0x0F, - 0xF9, 0xEE, 0xEC, 0x13, 0xF3, 0xE5, 0x1C, 0xF6, 0xF4, 0xE5, - 0x09, 0xF0, 0x32, 0x09, 0x0D, 0xD4, 0x17, 0x1F, 0xE4, 0xDA, - 0xF7, 0x08, 0xD9, 0xD6, 0x01, 0xED, 0x07, 0xDD, 0xE4, 0x1A, - 0x09, 0x34, 0xE0, 0xFE, 0x0D, 0xD4, 0xF8, 0x03, 0xF8, 0xF6, - 0xFB, 0x1C, 0xDF, 0x11, 0x1C, 0x08, 0x13, 0x0F, 0xE8, 0xF5, - 0xFA, 0x19, 0x06, 0xEF, 0xFC, 0x09, 0x1B, 0x22, 0xED, 0x02, - 0xE6, 0x09, 0x04, 0xD8, 0xF5, 0x10, 0x02, 0x24, 0x15, 0x26, - 0xEA, 0xFA, 0x1D, 0x15, 0x09, 0xFD, 0xD1, 0x02, 0x0D, 0xF5, - 0xF7, 0xF4, 0x1E, 0x40, 0x0E, 0xFD, 0xEE, 0x19, 0x15, 0xF2, - 0xE6, 0xE5, 0xF0, 0xFC, 0x03, 0x07, 0x03, 0xFE, 0xFC, 0x03, - 0x09, 0xE8, 0xEF, 0xF9, 0xEF, 0xED, 0x0A, 0x07, 0x0A, 0x02, - 0x08, 0xD0, 0xEE, 0x1D, 0xD3, 0xF0, 0xB2, 0xEA, 0x07, 0xFA, - 0x39, 0x13, 0x18, 0xF4, 0xEA, 0xF5, 0x0A, 0xE6, 0xE1, 0x1E, - 0x0B, 0x14, 0xF3, 0x26, 0xDA, 0xEA, 0x18, 0xE6, 0x10, 0x06, - 0xFF, 0xE9, 0x08, 0xE9, 0x10, 0xD0, 0xF7, 0x08, 0xEE, 0xEF, - 0x05, 0xEB, 0xF5, 0x10, 0xD5, 0x12, 0x1F, 0xDF, 0xFF, 0xF5, - 0x33, 0x05, 0x31, 0xFD, 0x19, 0xF8, 0xEE, 0x2B, 0x08, 0x01, - 0x17, 0x0A, 0xF6, 0x21, 0xF7, 0x11, 0x00, 0x23, 0xFF, 0x03, - 0xD7, 0xEF, 0x16, 0xF5, 0xED, 0x0A, 0xF7, 0x00, 0x00, 0xDD, - 0xF8, 0x07, 0x0A, 0xF0, 0xFB, 0xF1, 0xCC, 0x11, 0x1F, 0xFC, - 0xE1, 0x03, 0x46, 0x01, 0x06, 0x0C, 0xE7, 0x36, 0x05, 0xDC, - 0xD1, 0x0A, 0x43, 0x09, 0x04, 0xF6, 0xFE, 0x09, 0x1F, 0x06, - 0xEB, 0xE7, 0x08, 0xFD, 0xDA, 0x0D, 0x23, 0xC6, 0x13, 0x30, - 0x02, 0x23, 0x03, 0xED, 0xE1, 0x0B, 0x12, 0x27, 0x1E, 0x1B, - 0x01, 0xF5, 0xF5, 0xF4, 0xED, 0xDC, 0xF7, 0x14, 0xF1, 0x3E, - 0x2F, 0x18, 0x04, 0x22, 0x08, 0x03, 0x1F, 0x0E, 0x19, 0xEB, - 0x21, 0xDC, 0xCE, 0xD2, 0x23, 0x14, 0xE3, 0x16, 0xF7, 0x29, - 0x0A, 0x0F, 0x04, 0xF7, 0xEF, 0x15, 0xFA, 0x30, 0xE7, 0xD3, - 0x13, 0x05, 0x0E, 0x06, 0x04, 0x11, 0xF9, 0x2D, 0x1C, 0xEF, - 0x0F, 0x03, 0x05, 0xF4, 0x09, 0xE7, 0xE3, 0xFC, 0x04, 0xED, - 0x15, 0xF2, 0x2F, 0xF1, 0xF9, 0x1D, 0x08, 0x46, 0xED, 0xF1, - 0x0C, 0xF9, 0x38, 0xEF, 0xE6, 0xEB, 0xD1, 0xDE, 0x04, 0xFD, - 0x1B, 0xFB, 0x30, 0xE5, 0xCD, 0xF6, 0xDE, 0xEA, 0x09, 0x00, - 0xE8, 0x0C, 0x27, 0x01, 0xC1, 0x2A, 0x05, 0xF4, 0xED, 0x11, - 0xF9, 0xF7, 0xFD, 0x0A, 0xD6, 0xF8, 0x03, 0x0C, 0x05, 0x16, - 0xFB, 0x1F, 0xEC, 0x13, 0x07, 0xF3, 0x04, 0xC6, 0x1E, 0x0A, - 0x01, 0x0A, 0x09, 0xDE, 0x0D, 0xDC, 0xDF, 0xD8, 0x0E, 0x25, - 0xDF, 0xC3, 0xF4, 0x0C, 0xE9, 0xE5, 0xEC, 0xE9, 0xEE, 0xEC, - 0x23, 0xF2, 0xEE, 0x17, 0xF7, 0x1D, 0xE4, 0x0D, 0x0E, 0x0E, - 0x0A, 0xF5, 0xFF, 0x0B, 0x0F, 0xF3, 0xF1, 0x18, 0x08, 0xEB, - 0x03, 0x01, 0x1E, 0xF7, 0xF2, 0x0E, 0xDF, 0xF8, 0xD3, 0xCB, - 0xFB, 0xFE, 0xEF, 0xED, 0x17, 0x24, 0xD9, 0x06, 0xF5, 0xDD, - 0xFF, 0xEF, 0x1E, 0xE7, 0xC6, 0xFB, 0x03, 0x14, 0x12, 0x00, - 0x1E, 0x2B, 0x2B, 0xEB, 0x0E, 0x2D, 0xE9, 0x17, 0x13, 0x05, - 0x2F, 0x23, 0xF5, 0xF6, 0xEE, 0xF1, 0xD3, 0xE3, 0xFC, 0xEC, - 0xE4, 0xFE, 0xEA, 0xFC, 0x05, 0x2E, 0x0E, 0xF6, 0x0F, 0xE5, - 0xEF, 0x08, 0xEF, 0x01, 0xE1, 0x09, 0x00, 0x81, 0xF2, 0x10, - 0x17, 0x97, 0x32, 0xA5, 0x89, 0x54, 0x64, 0xC7, 0x47, 0x1C, - 0x52, 0xBC, 0xBF, 0xF6, 0x8A, 0x47, 0x0A, 0x87, 0x1E, 0x61, - 0x92, 0xEF, 0x56, 0x48, 0x88, 0x88, 0xAF, 0x14, 0x0B, 0x88, - 0xBD, 0x82, 0xB8, 0x32, 0x62, 0xF4, 0xD7, 0x40, 0xAD, 0xA6, - 0xE9, 0x1A, 0x03, 0x44, 0x60, 0x71, 0x58, 0xC3, 0x76, 0x2A, - 0x8F, 0x5B, 0x9F, 0x24, 0x8A, 0x92, 0x4E, 0xC4, 0x99, 0x3D, - 0x39, 0x8B, 0x25, 0xEB, 0xDA, 0x39, 0x91, 0x21, 0x70, 0x2B, - 0x77, 0x63, 0x1C, 0xA9, 0xD6, 0xD5, 0x30, 0x26, 0x10, 0xCF, - 0x1D, 0xD8, 0x32, 0xB2, 0xE8, 0x5C, 0x88, 0x04, 0x11, 0x9E, - 0x7A, 0xB4, 0x6E, 0xF2, 0x4D, 0x78, 0x3C, 0xF1, 0xA7, 0xA5, - 0xF3, 0x98, 0xAA, 0x8A, 0x08, 0xED, 0x17, 0xCA, 0xA1, 0x9E, - 0x6B, 0xC6, 0xEB, 0x4D, 0x47, 0x7B, 0x04, 0x41, 0x1B, 0x19, - 0x61, 0x19, 0x0F, 0xB5, 0xAF, 0x02, 0xE8, 0x8A, 0x43, 0xB8, - 0xF9, 0xA6, 0x43, 0x5A, 0xEA, 0x1B, 0x94, 0x8A, 0xD2, 0x71, - 0x2B, 0x2F, 0x6A, 0xBF, 0x26, 0x5E, 0x84, 0xAC, 0x4F, 0x03, - 0x40, 0x0C, 0x68, 0xA4, 0x36, 0xE3, 0xFD, 0x0B, 0xD0, 0x31, - 0xD9, 0x58, 0xD3, 0xC2, 0x76, 0xA2, 0x25, 0x69, 0x59, 0x00, - 0xA8, 0x43, 0x12, 0x85, 0x69, 0x16, 0x24, 0x50, 0x15, 0x74, - 0x1B, 0x02, 0xB9, 0xC0, 0x7B, 0x81, 0x64, 0x7E, 0x63, 0xB7, - 0x16, 0x68, 0x49, 0x92, 0x60, 0x7B, 0xC0, 0xC4, 0xFB, 0x9E, - 0x7E, 0x23, 0x87, 0x81, 0x48, 0xD4, 0x5F, 0xAD, 0xDA, 0xA7, - 0xA3, 0x5C, 0x6C, 0x4E, 0x60, 0x43, 0xB4, 0x48, 0x5B, 0xD1, - 0x3C, 0xE4, 0x5C, 0x5A, 0x8A, 0x85, 0xBC, 0x76, 0xEC, 0xA5, - 0x40, 0x1E, 0x02, 0xFE, 0x06, 0x8D, 0x60, 0xD6, 0x37, 0x82, - 0x47, 0x22, 0xA5, 0x18, 0xA6, 0x62, 0x44, 0x08, 0x0D, 0xE2, - 0x46, 0xA6, 0x6C, 0xCB, 0x8D, 0x9B, 0xD5, 0xFA, 0x31, 0x4C, - 0xCF, 0x74, 0x6D, 0xAA, 0x93, 0x21, 0xEB, 0xA4, 0xC9, 0xB2, - 0x95, 0xFE, 0x42, 0x28, 0xE7, 0x1A, 0x3A, 0xB9, 0xA8, 0x9B, - 0x6D, 0x59, 0xFC, 0x38, 0xA6, 0xC9, 0xC6, 0x5D, 0xEC, 0xF2, - 0x1D, 0xF0, 0x64, 0x86, 0x63, 0x19, 0x93, 0x57, 0x71, 0xCF, - 0x85, 0xA5, 0x27, 0x43, 0xB3, 0x81, 0xF2, 0x14, 0x17, 0x05, - 0x2E, 0x26, 0xE2, 0x4C, 0xF3, 0xCB, 0x42, 0xC7, 0x23, 0x91, - 0xF2, 0x51, 0x54, 0xDB, 0x95, 0x6B, 0x26, 0x3F, 0xF0, 0xF3, - 0x29, 0xDE, 0x64, 0x59, 0x10, 0x5A, 0x70, 0x81, 0x96, 0x0D, - 0xD6, 0xBD, 0x9B, 0xBA, 0x52, 0xE4, 0x47, 0xB4, 0xC5, 0x81, - 0x4F, 0xA3, 0x1C, 0x53, 0x29, 0xBE, 0xF0, 0x0A, 0x19, 0xA8, - 0x79, 0x5A, 0x08, 0x17, 0x9B, 0x1C, 0x54, 0x0C, 0xDD, 0x9F, - 0xB0, 0xFE, 0xA2, 0xBD, 0x7E, 0xD1, 0x44, 0xFA, 0x6A, 0x19, - 0x15, 0x9B, 0xCA, 0x77, 0x24, 0x8A, 0xC4, 0x6F, 0x02, 0xBC, - 0x2C, 0x07, 0x1C, 0x6A, 0x69, 0x89, 0x9D, 0x84, 0xE9, 0x14, - 0xE1, 0x8E, 0x49, 0xA0, 0x1D, 0x76, 0x9F, 0x54, 0x49, 0x5E, - 0x42, 0x90, 0x1A, 0xE4, 0x2B, 0xF0, 0x36, 0xF6, 0xB7, 0x38, - 0x9A, 0xD3, 0xBB, 0x08, 0xFA, 0x96, 0xC9, 0xE8, 0xEF, 0x7E, - 0x79, 0xE9, 0xDE, 0xA5, 0xA6, 0x97, 0x15, 0x9E, 0xEA, 0xB4, - 0x8B, 0xC8, 0xA1, 0xB7, 0x50, 0x78, 0x04, 0x00, 0xFC, 0x13, - 0xF0, 0x96, 0xCC, 0x45, 0xC8, 0x74, 0x2B, 0xCA, 0x98, 0x7E, - 0x6C, 0x91, 0x22, 0x0B, 0x49, 0x07, 0xB6, 0xE0, 0x44, 0xD8, - 0x44, 0x4A, 0x0E, 0x65, 0x3F, 0x45, 0x90, 0x95, 0x59, 0x72, - 0xCD, 0xB3, 0xE7, 0x56, 0x65, 0x23, 0xB0, 0x9D, 0x13, 0x66, - 0x13, 0xCC, 0xB9, 0x96, 0xB9, 0xAD, 0x2B, 0x15, 0x48, 0xB3, - 0x84, 0xC2, 0x9D, 0xC3, 0xC8, 0x8C, 0x41, 0x32, 0xBE, 0x1A, - 0x98, 0xAE, 0xD8, 0x66, 0x5B, 0xA6, 0x4A, 0xA8, 0x75, 0xCC, - 0x58, 0x63, 0x34, 0xD6, 0x23, 0xDF, 0xA3, 0x72, 0x07, 0xA2, - 0x7B, 0xD5, 0x81, 0x14, 0xDB, 0x56, 0xF4, 0x07, 0x22, 0x0E, - 0x2C, 0x03, 0x9A, 0xB8, 0x48, 0x58, 0xB2, 0xE8, 0x21, 0x55, - 0x14, 0x2A, 0xA3, 0x45, 0x89, 0xCD, 0x29, 0x76, 0x3F, 0x0A, - 0x54, 0x60, 0x06, 0x94, 0x82, 0x53, 0x49, 0x5C, 0x92, 0x2E, - 0x0E, 0x7C, 0x10, 0x97, 0x35, 0x25, 0x22, 0xA7, 0x28, 0x24, - 0x30, 0x68, 0x2F, 0x46, 0x78, 0xD6, 0x55, 0xCA, 0xE3, 0x88, - 0x56, 0x94, 0x78, 0x4D, 0x66, 0x26, 0xD7, 0x9F, 0x7A, 0x36, - 0x23, 0x77, 0x35, 0xB0, 0x00, 0x25, 0xB0, 0x41, 0x67, 0x82, - 0xCC, 0x61, 0x3D, 0x26, 0x46, 0xC7, 0xB6, 0x95, 0xA5, 0x1F, - 0x49, 0x13, 0xB9, 0x7A, 0x91, 0x82, 0x99, 0x06, 0xAE, 0x01, - 0x45, 0xAE, 0x53, 0x1B, 0xE6, 0x51, 0x34, 0x96, 0x81, 0x62, - 0x06, 0xA9, 0x0E, 0x46, 0xB8, 0x18, 0x1E, 0xAF, 0x24, 0x54, - 0x89, 0x80, 0xE3, 0xD2, 0x11, 0x8D, 0xB7, 0x80, 0x31, 0x21, - 0xEF, 0x81, 0x9D, 0x22, 0x08, 0xE5, 0x0E, 0x3E, 0x9A, 0x8C, - 0xA4, 0xBA, 0xAB, 0x1A, 0xC9, 0x75, 0xD1, 0x6B, 0x16, 0x37, - 0x5B, 0x36, 0x12, 0x34, 0x06, 0xA6, 0xD7, 0x4B, 0x82, 0x35, - 0xC9, 0x64, 0xC3, 0x66, 0x4E, 0x66, 0x0F, 0x62, 0xA5, 0x2B, - 0x71, 0x8A, 0x23, 0x0A, 0xD1, 0x06, 0x94, 0xE1, 0x44, 0x8E, - 0x59, 0x41, 0x41, 0x09, 0xC9, 0x4D, 0xB7, 0x1D, 0xEE, 0x2E, - 0xB7, 0x35, 0x01, 0x89, 0x6B, 0xF4, 0xE2, 0xB1, 0xE7, 0x94, - 0xD3, 0x30, 0x34, 0xB8, 0x36, 0xA4, 0x59, 0xBE, 0x0E, 0xC9, - 0x49, 0x34, 0x70, 0x55, 0xDB, 0x87, 0x46, 0x2F, 0x68, 0xED, - 0x59, 0xB3, 0x7F, 0x2E, 0x0B, 0x8B, 0x90, 0x1F, 0x51, 0x3D, - 0x3E, 0xC2, 0xB5, 0x13, 0xCE, 0xAE, 0x6C, 0x56, 0x0D, 0x4A, - 0xAB, 0x99, 0x8B, 0x89, 0xEC, 0xBE, 0xCA, 0x02, 0x47, 0x6C, - 0xA8, 0x31, 0xEC, 0x98, 0xAA, 0xC1, 0xE1, 0x36, 0x22, 0x2E, - 0x81, 0xB0, 0xA2, 0xD2, 0x27, 0x49, 0xCF, 0x60, 0x9E, 0x8C, - 0xC3, 0xA0, 0x6E, 0x98, 0x8A, 0xF7, 0x2C, 0x36, 0x3B, 0x7E, - 0x25, 0x90, 0xD6, 0xC2, 0x70, 0x0C, 0xF5, 0xEC, 0x07, 0xA5, - 0xAE, 0x55, 0x64, 0x04, 0x03, 0xC3, 0x80, 0x55, 0x3C, 0x37, - 0x3E, 0xD1, 0x83, 0x7C, 0x2F, 0x11, 0x4C, 0xDE, 0xB8, 0x44, - 0xCA, 0x0F, 0xBF, 0x7B, 0x82, 0x2B, 0xB5, 0xD3, 0x10, 0x66, - 0x86, 0x8E, 0x39, 0xF6, 0x33, 0x9D, 0x0D, 0x70, 0xB0, 0x02, - 0x50, 0xC5, 0x0F, 0x27, 0x35, 0x2C, 0xEF, 0x53, 0x4E, 0x13, - 0x58, 0xB8, 0xA8, 0xC0, 0x4A, 0x95, 0x61, 0xFB, 0x48, 0x05, - 0xCB, 0xC9, 0x40, 0xD2, 0x3A, 0xBE, 0xA9, 0xB7, 0x78, 0x76, - 0x9F, 0x1E + 0x30, 0x82, 0x08, 0x9A, 0x02, 0x01, 0x00, 0x30, 0x07, 0x06, + 0x05, 0x2B, 0xCE, 0x0F, 0x03, 0x0B, 0x04, 0x82, 0x05, 0x05, + 0x04, 0x82, 0x05, 0x01, 0x59, 0x14, 0x11, 0x40, 0x0B, 0xD0, + 0x7F, 0xEC, 0x2D, 0x85, 0xF4, 0x0F, 0x43, 0x18, 0x21, 0x3F, + 0x0C, 0x10, 0x3D, 0xF4, 0x1E, 0x82, 0x10, 0x40, 0x88, 0x13, + 0xCF, 0xC1, 0xF7, 0xF1, 0x40, 0x03, 0xF0, 0x01, 0x00, 0x1F, + 0xC3, 0x04, 0x01, 0x3D, 0xEB, 0x9F, 0x86, 0x23, 0xB0, 0xBE, + 0xF4, 0x10, 0x82, 0xF8, 0x63, 0x4B, 0x08, 0x50, 0xC6, 0x04, + 0x00, 0x39, 0xF8, 0x10, 0x7E, 0xDF, 0x8F, 0xBE, 0xEC, 0x5F, + 0xBE, 0x08, 0x3F, 0x7E, 0x00, 0x10, 0x7D, 0xEC, 0x1F, 0x01, + 0x03, 0xE0, 0x39, 0x03, 0xFF, 0xBF, 0x23, 0xD2, 0xC2, 0xEC, + 0x70, 0x3D, 0x07, 0xED, 0x85, 0xFB, 0xE0, 0xBF, 0x27, 0xAE, + 0xBB, 0x10, 0xA0, 0xC0, 0xEF, 0xFF, 0x7E, 0x04, 0x1F, 0xC0, + 0xFF, 0xAF, 0x84, 0x27, 0xE0, 0x3F, 0xFF, 0x7F, 0x83, 0xFC, + 0x0E, 0xC4, 0xF0, 0x00, 0x82, 0xE3, 0xC1, 0xBF, 0x0C, 0x1F, + 0xC8, 0x0B, 0xA0, 0x00, 0x0C, 0x2F, 0x46, 0x03, 0xEF, 0xC3, + 0xF7, 0xCF, 0x40, 0x14, 0x10, 0x01, 0xFC, 0x00, 0x00, 0xF3, + 0x6F, 0x40, 0x0B, 0x80, 0x7F, 0x08, 0x1F, 0x7F, 0x0B, 0xB0, + 0x3C, 0xEF, 0xE0, 0xC5, 0xFF, 0xE0, 0x3E, 0x0B, 0xC0, 0x43, + 0xF4, 0x00, 0x40, 0x18, 0x3E, 0x00, 0xFF, 0xE0, 0x02, 0xF7, + 0xDF, 0x02, 0xEB, 0x9F, 0x85, 0x00, 0x5F, 0x40, 0x00, 0x5F, + 0x3D, 0x0B, 0xF0, 0x05, 0xFF, 0xDD, 0x40, 0x14, 0x3F, 0xC5, + 0x03, 0xB1, 0x3F, 0x0B, 0x81, 0x41, 0x04, 0x6F, 0x03, 0xFC, + 0x2E, 0xFF, 0x03, 0xDE, 0x80, 0xF4, 0x01, 0x7C, 0x04, 0x20, + 0x41, 0x17, 0xDF, 0xFA, 0xF4, 0x0D, 0xC0, 0xFC, 0x11, 0xC1, + 0x18, 0x4E, 0xC2, 0xE8, 0x3F, 0x04, 0x00, 0x01, 0xBE, 0xEF, + 0xB1, 0x7C, 0x10, 0xA0, 0x00, 0x0F, 0xFF, 0xBC, 0x0C, 0x2E, + 0x00, 0xEC, 0x4F, 0x84, 0xFB, 0xFD, 0x85, 0xF0, 0x10, 0x7B, + 0x14, 0x10, 0xC5, 0x0B, 0xF0, 0xBE, 0xF8, 0x4F, 0xF7, 0x0B, + 0xF0, 0xFD, 0x1B, 0x6F, 0xC2, 0xEC, 0x20, 0x41, 0xE8, 0x6F, + 0xFF, 0xF4, 0x30, 0x3D, 0xEB, 0xDF, 0x7C, 0xF0, 0x20, 0x45, + 0x00, 0x20, 0xB7, 0x04, 0x50, 0xFB, 0xF8, 0x7F, 0xBF, 0xE3, + 0xEF, 0xC4, 0xFB, 0xE1, 0x83, 0x0F, 0xD0, 0x39, 0xF4, 0x60, + 0x02, 0xEB, 0xF1, 0xBE, 0x23, 0x9F, 0x89, 0x07, 0xE0, 0x7F, + 0xFC, 0x21, 0xC3, 0x04, 0x5E, 0xFC, 0xEC, 0x72, 0xC2, 0x00, + 0x0F, 0x40, 0xF4, 0x00, 0xFF, 0xF3, 0xAF, 0xBF, 0x0C, 0x3F, + 0x84, 0xE4, 0x20, 0x81, 0xF4, 0x10, 0x38, 0x0C, 0x20, 0xBD, + 0x17, 0xBF, 0x80, 0x03, 0xBE, 0xBF, 0xF3, 0xE0, 0x83, 0x0F, + 0xD0, 0x3A, 0xFB, 0xB0, 0x00, 0xFC, 0x51, 0x41, 0x0C, 0x30, + 0xC4, 0x13, 0xC0, 0x3F, 0xFC, 0x60, 0x7A, 0x07, 0xD0, 0x7E, + 0x00, 0x10, 0x41, 0x04, 0x7F, 0xFD, 0xF8, 0x1E, 0x84, 0x08, + 0x5F, 0x3B, 0x14, 0x3E, 0xFA, 0x0C, 0x5E, 0x81, 0xF8, 0x0E, + 0x45, 0xFC, 0x2E, 0x85, 0xFF, 0xCF, 0x02, 0x07, 0xF0, 0x40, + 0x1B, 0xB1, 0x86, 0x00, 0x3F, 0xFA, 0xF0, 0x60, 0xFE, 0xEB, + 0xD0, 0x01, 0xEF, 0xEF, 0x05, 0xEC, 0x0E, 0xC2, 0x10, 0x5E, + 0x83, 0xFF, 0xFF, 0x42, 0xF7, 0xE2, 0x3E, 0xF8, 0x20, 0x43, + 0x18, 0x60, 0x44, 0xE3, 0xDF, 0xF9, 0xF3, 0xDF, 0x85, 0x0F, + 0xFF, 0xBE, 0x03, 0xA0, 0x02, 0x1B, 0xFD, 0x7C, 0xF7, 0xEF, + 0x86, 0x08, 0x41, 0x7F, 0x0B, 0xD1, 0x04, 0x03, 0xAF, 0x87, + 0x13, 0xF0, 0x41, 0x07, 0x7E, 0x04, 0x07, 0xF1, 0xFC, 0xF7, + 0xDE, 0x80, 0xF3, 0xB0, 0xFF, 0xF3, 0xEE, 0x7F, 0x14, 0x50, + 0xBB, 0x0C, 0x8F, 0x05, 0xEF, 0xBE, 0xFE, 0x0C, 0x20, 0x3F, + 0xF7, 0xFE, 0x80, 0xD0, 0x32, 0x7B, 0xF7, 0xD0, 0xFD, 0xFB, + 0x7F, 0x49, 0xFB, 0xE1, 0x02, 0x2F, 0xC1, 0x3C, 0x00, 0x01, + 0x41, 0x18, 0x2F, 0x7F, 0xEC, 0x40, 0x7C, 0x07, 0xFF, 0x33, + 0xF8, 0x00, 0x02, 0x08, 0x1F, 0x86, 0xEF, 0xE1, 0x86, 0xF8, + 0x70, 0x7B, 0x00, 0x3F, 0x40, 0xF3, 0xFE, 0xCD, 0x03, 0xE2, + 0x02, 0xF7, 0xBF, 0xBF, 0x04, 0x8F, 0xBD, 0xE8, 0x60, 0xB5, + 0xDC, 0x31, 0x01, 0x1C, 0x4E, 0x42, 0x0C, 0x30, 0xBB, 0x14, + 0x0F, 0xC1, 0xFF, 0x7F, 0x82, 0x08, 0x0F, 0xFF, 0xFC, 0x3F, + 0xBF, 0xFF, 0xED, 0xC0, 0xF0, 0x3F, 0x7D, 0xF8, 0x5F, 0x82, + 0x0B, 0xDF, 0x06, 0xF0, 0x4F, 0x7E, 0xEF, 0xE2, 0xFD, 0x03, + 0xD0, 0x88, 0x0B, 0xDE, 0xC9, 0xDC, 0x21, 0x41, 0xEC, 0x71, + 0x03, 0xEB, 0xDF, 0xC2, 0x1F, 0xE1, 0xBE, 0xEB, 0xF0, 0x43, + 0xFF, 0xF1, 0x3D, 0x14, 0x7F, 0x82, 0x1C, 0x4F, 0xC2, 0x10, + 0x10, 0xC4, 0x00, 0x20, 0xC3, 0x07, 0xAF, 0xBD, 0xE0, 0x1F, + 0xC1, 0x04, 0x00, 0xBC, 0xE0, 0x3E, 0xC0, 0xFF, 0xDF, 0xFF, + 0x13, 0xEF, 0x81, 0xF8, 0x1E, 0xFC, 0x08, 0x2F, 0x7E, 0x17, + 0xFF, 0xC0, 0x1B, 0xD0, 0x41, 0xF8, 0x0F, 0xC3, 0x08, 0x10, + 0x00, 0x04, 0x0D, 0xFE, 0xF4, 0x30, 0xBC, 0x08, 0x41, 0x81, + 0x10, 0x20, 0xC7, 0xF3, 0xF0, 0x43, 0x04, 0x6D, 0xC2, 0xEF, + 0xCE, 0x42, 0xFB, 0xE0, 0x3D, 0x2C, 0x2F, 0xF9, 0x14, 0x41, + 0xFB, 0xF8, 0x21, 0x3D, 0xE7, 0xBF, 0x7C, 0x10, 0x51, 0x02, + 0x0F, 0xC0, 0x88, 0x00, 0x0F, 0x7F, 0xEC, 0x70, 0x44, 0x17, + 0xC0, 0xFF, 0x0F, 0xCF, 0x7E, 0xEC, 0x0F, 0x7C, 0x1B, 0xEE, + 0x00, 0x03, 0xDF, 0xBF, 0x04, 0x0F, 0xC0, 0x0C, 0x20, 0xC6, + 0x10, 0x00, 0x02, 0x03, 0xED, 0x47, 0x08, 0x2F, 0xC4, 0x1B, + 0xC0, 0x82, 0x14, 0x2F, 0xC3, 0xFB, 0xEF, 0xF9, 0x23, 0xC0, + 0x42, 0x07, 0xB0, 0x80, 0xE8, 0x31, 0xB5, 0xEB, 0xBD, 0xFA, + 0xF7, 0xB0, 0xC3, 0xC8, 0x3C, 0xDE, 0x37, 0x0C, 0xE4, 0xCE, + 0xEE, 0x07, 0x02, 0x10, 0x01, 0xFA, 0xFC, 0x42, 0x06, 0x20, + 0x0F, 0xE0, 0x05, 0x04, 0x20, 0xF5, 0xF7, 0x06, 0x18, 0xFC, + 0xF7, 0x36, 0xE0, 0xE9, 0xF9, 0xF9, 0xF2, 0xF5, 0x0E, 0x02, + 0xD9, 0xCA, 0x00, 0x0A, 0x27, 0xDD, 0x3F, 0x10, 0x0D, 0xFD, + 0x0A, 0x02, 0x0A, 0x2B, 0xDD, 0x07, 0xCD, 0xEC, 0x10, 0x15, + 0x22, 0xEC, 0x03, 0xFD, 0x1F, 0xE3, 0xCB, 0x11, 0x20, 0xC9, + 0xE4, 0xED, 0xFD, 0x27, 0xF2, 0x02, 0xCF, 0xDD, 0xFE, 0xFC, + 0xF2, 0xED, 0x14, 0x15, 0xF9, 0x11, 0xEA, 0x1D, 0x14, 0x07, + 0x05, 0x12, 0xED, 0xD0, 0x05, 0x29, 0xF5, 0x00, 0x08, 0x1D, + 0xF3, 0x06, 0xFE, 0xD4, 0xED, 0xF3, 0x1A, 0xF0, 0xFA, 0xEB, + 0x02, 0x03, 0x13, 0xCC, 0x04, 0x0D, 0x0C, 0x14, 0x07, 0x17, + 0xDA, 0xC1, 0xF1, 0x1E, 0x29, 0x1C, 0x33, 0x0F, 0x16, 0x18, + 0x09, 0x08, 0xD1, 0x0B, 0x00, 0xF9, 0x0C, 0xDC, 0xC1, 0x33, + 0x16, 0x02, 0xDA, 0x07, 0xF8, 0x03, 0x40, 0xFA, 0xFE, 0x0A, + 0xDF, 0x0A, 0xE5, 0xF7, 0x15, 0xE8, 0x0B, 0x01, 0x1E, 0x29, + 0x0D, 0x11, 0xF2, 0x07, 0x24, 0x11, 0x08, 0xEF, 0x0C, 0xDF, + 0x26, 0xEA, 0xF1, 0xE2, 0xF0, 0xEA, 0xD7, 0xEB, 0xE4, 0x04, + 0x01, 0x0A, 0x11, 0xC3, 0xE8, 0x25, 0xD8, 0x1A, 0xE1, 0xF6, + 0x17, 0xF9, 0x10, 0x09, 0x11, 0x2C, 0x1A, 0x13, 0xEA, 0x21, + 0x0D, 0x12, 0x18, 0x19, 0x0F, 0x17, 0xD4, 0x28, 0xBB, 0xE4, + 0xFE, 0xCC, 0xE5, 0xFF, 0x2B, 0x16, 0xFE, 0x00, 0x1E, 0xDE, + 0xDE, 0x10, 0xEE, 0x13, 0x1A, 0xF9, 0x0D, 0xD7, 0x33, 0x21, + 0x0C, 0x08, 0xEF, 0x21, 0x0D, 0xFD, 0x07, 0xFD, 0x23, 0x55, + 0xEF, 0xFA, 0x05, 0xF5, 0xFC, 0x18, 0xF3, 0xEE, 0x14, 0x01, + 0xF5, 0xE3, 0xF6, 0x14, 0x20, 0xFA, 0xC0, 0xE0, 0x0E, 0xE5, + 0x1D, 0x15, 0x1C, 0x06, 0xE4, 0x0C, 0xFC, 0x14, 0x0B, 0x0D, + 0xFA, 0xF8, 0x0E, 0x21, 0x0E, 0xF8, 0xD7, 0xE2, 0xDC, 0x14, + 0xEF, 0x04, 0x16, 0xED, 0x07, 0xEC, 0xF2, 0xEE, 0xEA, 0xEE, + 0x18, 0xEA, 0x05, 0xF4, 0x1F, 0xEC, 0x11, 0x0F, 0xF0, 0x14, + 0xF9, 0xFF, 0xEF, 0xFC, 0x10, 0x31, 0x08, 0x22, 0xF2, 0xF5, + 0xFF, 0xF9, 0xF8, 0x01, 0x1F, 0xF9, 0x0D, 0xD6, 0x2D, 0xE6, + 0xF1, 0x09, 0xD5, 0x05, 0xE8, 0x08, 0x0C, 0x04, 0xE9, 0x15, + 0x13, 0xD3, 0xF5, 0x1E, 0x04, 0x2F, 0x1C, 0x0D, 0x06, 0x36, + 0x01, 0x18, 0xEE, 0xF8, 0xE9, 0x30, 0x09, 0x31, 0x1B, 0x16, + 0x28, 0xE8, 0x0D, 0xCB, 0xF5, 0xDA, 0xF7, 0xF7, 0xEE, 0xF1, + 0x01, 0x15, 0xEE, 0x02, 0xDE, 0x28, 0x19, 0x07, 0x1D, 0xF5, + 0x12, 0xEE, 0x14, 0xF6, 0x0F, 0x06, 0xED, 0x0A, 0x02, 0xEF, + 0xFE, 0x09, 0x32, 0xD7, 0xF2, 0xDE, 0xFD, 0xF8, 0x05, 0xF6, + 0xCE, 0xCF, 0xEC, 0x12, 0x0E, 0x1F, 0xEC, 0x0E, 0x08, 0xDF, + 0xF3, 0xF1, 0xE5, 0x15, 0x0A, 0xFA, 0xD9, 0x0E, 0x0A, 0x06, + 0x0F, 0x10, 0xD6, 0x25, 0x0D, 0x15, 0xE0, 0x07, 0x23, 0x0E, + 0xDC, 0x10, 0xF4, 0xED, 0xFA, 0xDB, 0xD7, 0xEA, 0xFA, 0x0D, + 0x09, 0xC9, 0x08, 0x2D, 0x02, 0xFF, 0xF0, 0xD3, 0x34, 0xEB, + 0x17, 0xE3, 0xF2, 0xD3, 0x14, 0xF3, 0x1A, 0x04, 0x03, 0x04, + 0xE2, 0xDC, 0x04, 0x1E, 0xE9, 0xF4, 0xC9, 0xCF, 0xFF, 0xE1, + 0xE9, 0x22, 0x0F, 0x06, 0x1C, 0xF1, 0x09, 0xF2, 0xFA, 0x1D, + 0xEA, 0xDF, 0x0C, 0x12, 0xF8, 0x18, 0x16, 0x0F, 0x13, 0x31, + 0xE4, 0x1A, 0x26, 0x0A, 0xF4, 0xF6, 0xE8, 0x32, 0xE7, 0xF7, + 0x09, 0x08, 0xFD, 0xEE, 0xF8, 0xE1, 0xED, 0xE8, 0xDB, 0xD5, + 0x19, 0xFD, 0xFF, 0x05, 0x0D, 0xF6, 0x11, 0xDF, 0x10, 0xF4, + 0x2D, 0xE6, 0xFD, 0xE8, 0xF9, 0x81, 0x82, 0x03, 0x81, 0x09, + 0x41, 0xFE, 0xD2, 0xB3, 0x3C, 0x2A, 0x2D, 0x66, 0xAE, 0x99, + 0x04, 0x61, 0xA6, 0x17, 0x8B, 0xF1, 0x9C, 0x82, 0xCE, 0x81, + 0x40, 0x60, 0xED, 0x66, 0xD0, 0x3A, 0x89, 0xFC, 0xBB, 0x8A, + 0xFE, 0xF0, 0x29, 0x82, 0xB6, 0x19, 0x22, 0x07, 0xC7, 0x07, + 0xA9, 0xBF, 0xAE, 0xD0, 0x86, 0x00, 0xF4, 0x04, 0x37, 0x37, + 0x78, 0x6E, 0x06, 0x39, 0xA6, 0xC5, 0x31, 0xC1, 0xB0, 0x10, + 0xEE, 0xAC, 0x07, 0x21, 0x70, 0x2F, 0x62, 0xFC, 0xEA, 0x1B, + 0x9E, 0x74, 0x6D, 0x56, 0xDC, 0x89, 0x8C, 0x8F, 0xA4, 0x15, + 0x93, 0xC2, 0x53, 0x28, 0x3E, 0x6D, 0x42, 0x7B, 0x03, 0x5E, + 0x41, 0x30, 0xC2, 0x50, 0x2A, 0x78, 0x8A, 0x59, 0x19, 0x3D, + 0xEF, 0x92, 0xD0, 0x68, 0xDE, 0x41, 0x44, 0x19, 0xA1, 0xF1, + 0x51, 0x5E, 0x64, 0x69, 0x3B, 0x26, 0x71, 0xC5, 0x10, 0x29, + 0xC6, 0xA8, 0x02, 0x4A, 0x23, 0xB6, 0x67, 0x04, 0x62, 0x27, + 0x02, 0x5E, 0x51, 0x65, 0xF8, 0x6D, 0xF0, 0x89, 0x99, 0xCE, + 0x44, 0x58, 0x81, 0x58, 0x8A, 0x93, 0xA7, 0x73, 0xC6, 0x60, + 0xCB, 0xFA, 0x00, 0x3A, 0xB9, 0x91, 0x33, 0x8B, 0x55, 0x4E, + 0x23, 0xBB, 0xDD, 0x83, 0x54, 0x90, 0x47, 0x62, 0x7B, 0xC4, + 0x2A, 0xA4, 0x14, 0x87, 0x70, 0x39, 0xC4, 0xD3, 0xE1, 0x88, + 0x90, 0x1C, 0x04, 0x69, 0x7B, 0xCA, 0x52, 0x48, 0xF7, 0x4C, + 0xCE, 0xA4, 0x0B, 0x64, 0x8F, 0xB1, 0x42, 0x0E, 0x9D, 0x46, + 0xE0, 0x50, 0xD0, 0x1A, 0x38, 0x85, 0xE9, 0x3B, 0x09, 0x27, + 0x05, 0x9A, 0x01, 0x13, 0x49, 0x4F, 0x51, 0xAF, 0xB9, 0x1E, + 0x89, 0xD3, 0xA9, 0xB2, 0x3B, 0x1D, 0xDF, 0x56, 0x41, 0x10, + 0xE8, 0x47, 0x5D, 0x2D, 0xB2, 0x0C, 0x1B, 0xDB, 0xA2, 0xE0, + 0x71, 0x23, 0x5D, 0x12, 0xD7, 0x00, 0xBE, 0x84, 0xA8, 0x0A, + 0xD6, 0x6A, 0x40, 0x78, 0x0B, 0x96, 0xD2, 0x1C, 0x19, 0x7A, + 0x55, 0x78, 0x48, 0x94, 0x95, 0x5E, 0x74, 0x59, 0xA5, 0xD3, + 0xFC, 0x16, 0x72, 0x46, 0xB2, 0xA9, 0x9A, 0x85, 0x6D, 0xB0, + 0xB9, 0x80, 0x4A, 0xB0, 0xC6, 0x6C, 0xA2, 0x5F, 0x20, 0xE8, + 0x80, 0x25, 0x81, 0x37, 0xAC, 0xB8, 0xFA, 0xA3, 0x68, 0x06, + 0xEE, 0x16, 0xE0, 0x81, 0x21, 0x81, 0x1B, 0x86, 0xB8, 0x80, + 0x50, 0x62, 0x2D, 0xDC, 0x71, 0x5A, 0xB9, 0xD3, 0xCA, 0xA3, + 0xA1, 0xAE, 0x5F, 0xFA, 0x29, 0x5A, 0x7C, 0x81, 0xC2, 0x9C, + 0xBD, 0x76, 0x48, 0x0D, 0x67, 0xE4, 0x20, 0x75, 0x3E, 0x22, + 0xDC, 0x41, 0xB7, 0x8E, 0x99, 0x38, 0xF7, 0xDE, 0xAB, 0xB1, + 0x70, 0x3D, 0x44, 0xDA, 0x0F, 0xDC, 0xD1, 0x19, 0x35, 0xD8, + 0xF9, 0x38, 0x4F, 0xF9, 0x2F, 0x90, 0xDE, 0x15, 0xD9, 0xC2, + 0x4A, 0xA8, 0xE8, 0x26, 0x88, 0x2B, 0x9F, 0x6D, 0x0A, 0xAE, + 0x3A, 0xE4, 0x90, 0x4F, 0x61, 0x60, 0xC1, 0xA9, 0xF2, 0xBD, + 0x1B, 0xDC, 0xA2, 0xB4, 0x6C, 0x38, 0xE2, 0x65, 0x57, 0x1C, + 0xF5, 0xCB, 0xD1, 0xAF, 0x5E, 0xE8, 0x1A, 0x96, 0xBE, 0x03, + 0xB8, 0xE2, 0x30, 0x8B, 0xF9, 0x5B, 0xDA, 0x16, 0xD2, 0xFF, + 0x5A, 0xC9, 0xFD, 0x0B, 0x4A, 0xED, 0xD7, 0x25, 0x6C, 0x3B, + 0xC1, 0x45, 0xAE, 0xD7, 0xA5, 0xF6, 0x67, 0x11, 0xE9, 0xE6, + 0xD8, 0x49, 0xBC, 0xC2, 0x5A, 0x58, 0x22, 0xF4, 0xAD, 0x7A, + 0xB1, 0x75, 0x2D, 0xEF, 0x0B, 0x5D, 0xD1, 0x94, 0x32, 0x72, + 0x5A, 0x4A, 0x6C, 0x35, 0x98, 0xB5, 0xE1, 0x04, 0xAC, 0x91, + 0xE9, 0xD5, 0x3A, 0x70, 0xA5, 0xE1, 0x87, 0x86, 0x4A, 0x50, + 0xE2, 0x17, 0x88, 0x9F, 0x46, 0x69, 0x3B, 0xE0, 0x55, 0x45, + 0x4D, 0x10, 0x09, 0x9B, 0x40, 0x61, 0x0A, 0x6F, 0x70, 0x96, + 0x53, 0x89, 0xAF, 0x0A, 0x5B, 0x59, 0xB7, 0xD3, 0x9B, 0x58, + 0xA7, 0x45, 0x32, 0x51, 0x51, 0x03, 0xE4, 0xD0, 0x59, 0x38, + 0xE4, 0x34, 0x3F, 0x28, 0x52, 0xAC, 0x15, 0x98, 0x06, 0x70, + 0x99, 0xB0, 0x6A, 0x8A, 0x87, 0x70, 0x6A, 0xC0, 0x26, 0x1C, + 0xA1, 0x2A, 0x26, 0x7D, 0x1C, 0x82, 0x00, 0x8C, 0xEC, 0x5A, + 0x52, 0x08, 0xB7, 0x5D, 0x05, 0xBE, 0x37, 0x90, 0x59, 0x91, + 0x87, 0xE6, 0x5E, 0x52, 0xE8, 0x84, 0xAD, 0x27, 0xB8, 0xD2, + 0x70, 0x5C, 0x54, 0x2F, 0x5A, 0xC5, 0x2F, 0x37, 0x59, 0x14, + 0x34, 0x6D, 0x60, 0xCD, 0xF8, 0x79, 0x6F, 0x44, 0x1D, 0x2E, + 0x31, 0x64, 0x9E, 0x9B, 0xD4, 0x35, 0x74, 0x2C, 0xE6, 0x27, + 0xE2, 0x8B, 0x7E, 0xF6, 0x9A, 0xC8, 0xC5, 0x1B, 0x6A, 0x39, + 0x15, 0xFF, 0x53, 0x41, 0x8D, 0xB5, 0x32, 0x49, 0x7B, 0xEB, + 0xFC, 0x4A, 0xD6, 0x7C, 0x4E, 0x50, 0x13, 0xD9, 0xD6, 0xE4, + 0x0B, 0x3E, 0x07, 0x48, 0xDE, 0xA8, 0xB5, 0xA2, 0xED, 0x8D, + 0x82, 0xE8, 0x6F, 0x45, 0x92, 0x65, 0x46, 0xD0, 0xBB, 0x25, + 0x4C, 0x72, 0x8A, 0xB6, 0x70, 0x30, 0x11, 0x9C, 0x72, 0x2E, + 0xC6, 0xD8, 0xA3, 0xC3, 0xCF, 0xAB, 0x56, 0x39, 0x34, 0x56, + 0xA8, 0x10, 0x4E, 0xC2, 0x8A, 0x59, 0xD4, 0x5B, 0xF1, 0x55, + 0x90, 0x9D, 0xB7, 0x83, 0x94, 0xE6, 0x09, 0x88, 0x9E, 0x4A, + 0x23, 0x2F, 0x50, 0x94, 0xC0, 0x01, 0x34, 0xBF, 0x9A, 0xDF, + 0x63, 0x62, 0xDC, 0xF0, 0x22, 0x23, 0xE1, 0x57, 0x7C, 0x7E, + 0x95, 0xB6, 0xCE, 0x34, 0x10, 0xA4, 0xD7, 0x06, 0x29, 0x83, + 0x18, 0x5D, 0x68, 0x8A, 0x13, 0x70, 0xAB, 0x91, 0x28, 0xEA, + 0x24, 0x98, 0x9D, 0xAC, 0x68, 0xBD, 0x24, 0xC7, 0xE2, 0x0C, + 0xE1, 0xFA, 0x10, 0xA9, 0xF1, 0x38, 0x9E, 0xE1, 0xB2, 0x4F, + 0x8D, 0x20, 0xEB, 0x0A, 0x9A, 0x72, 0xB5, 0xA9, 0xA6, 0x99, + 0x7A, 0xD8, 0x1B, 0x3A, 0x2A, 0xA1, 0xAA, 0x88, 0x07, 0x72, + 0x42, 0xD2, 0x4B, 0x91, 0xAA, 0x48, 0x72, 0x47, 0x30, 0xEE, + 0x3A, 0x7A, 0xE9, 0x84, 0x25, 0xE4, 0x54, 0x0B, 0xF4, 0x65, + 0x11, 0x2A, 0x8C, 0xDC, 0xF3, 0x42, 0x5B, 0xCE, 0x75, 0x70, + 0xF6, 0xE9, 0x66, 0xA8, 0x18, 0xA3, 0xB6, 0x93, 0x41, 0x06, + 0x63, 0x08, 0x1A, 0x19, 0x4F, 0xC8, 0xE6, 0xDE, 0x02, 0x15, + 0xEC, 0xD2, 0xE7, 0x30, 0x95, 0x46, 0x03, 0x71, 0xFA, 0xE2, + 0xD5, 0x28, 0xE2, 0x01, 0xFE, 0x1C, 0xF0, 0x78, 0x9B, 0xBD, + 0x3D, 0x14, 0xEF, 0xA7, 0xF9, 0x0E, 0x3A, 0x8C, 0x81, 0x7A, + 0x18, 0x90, 0xDD, 0xC1, 0x53, 0x69, 0x78, 0x87, 0x64, 0x50, + 0xFA, 0xA2, 0x0E, 0xBB, 0xF2, 0xB8, 0xDC, 0x5A, 0xA6, 0x58, + 0x7A, 0xDB, 0xFF, 0x92, 0x91, 0x14, 0x45, 0xC2, 0xEA, 0x2E, + 0xDA, 0x45, 0x1C, 0xC5, 0xF8, 0x46, 0xF3, 0x20, 0xD4, 0x40, + 0xED, 0x07, 0xD9, 0xA7, 0x00, 0xF6 }; #define sizeof_bench_falcon_level1_key (sizeof(bench_falcon_level1_key)) /* certs/falcon/bench_falcon_level5_key.der */ static const unsigned char bench_falcon_level5_key[] = { - 0x30, 0x82, 0x10, 0x16, 0x02, 0x01, 0x00, 0x30, 0x07, 0x06, - 0x05, 0x2B, 0xCE, 0x0F, 0x03, 0x04, 0x04, 0x82, 0x10, 0x06, - 0x04, 0x82, 0x10, 0x02, 0x5A, 0xDF, 0x13, 0xB0, 0x70, 0x81, - 0x21, 0x02, 0x3D, 0x7F, 0xFF, 0xD0, 0x47, 0xFE, 0x0F, 0xC2, - 0xE6, 0xC5, 0xFF, 0x9F, 0xDB, 0xF0, 0x0D, 0xE0, 0xFC, 0x43, - 0x07, 0xFE, 0x01, 0x80, 0x20, 0x00, 0xC3, 0xD0, 0x74, 0x3F, - 0x07, 0x41, 0xFF, 0xF7, 0x81, 0xEF, 0xFF, 0xF1, 0x10, 0x04, - 0x10, 0x4C, 0x32, 0x7C, 0x42, 0x30, 0x08, 0x42, 0x70, 0x45, - 0xFF, 0x3F, 0xCF, 0x07, 0x60, 0x00, 0x82, 0x00, 0x84, 0x01, - 0x20, 0x04, 0x00, 0x7B, 0xC0, 0x18, 0x42, 0x11, 0x00, 0x22, - 0x17, 0x46, 0x00, 0x70, 0x43, 0xDF, 0x82, 0x10, 0x0B, 0xDA, - 0x17, 0x01, 0xE0, 0x0B, 0xFF, 0xF7, 0xBD, 0xE0, 0x7C, 0x1E, - 0xF7, 0x7E, 0x40, 0x78, 0x1E, 0x17, 0xC5, 0xD0, 0x18, 0x3D, - 0x19, 0x3E, 0x31, 0x68, 0x3F, 0xF8, 0x87, 0xCF, 0xF8, 0x9F, - 0x37, 0x7F, 0xE0, 0x7B, 0xC0, 0xF1, 0x40, 0x1F, 0x04, 0x5F, - 0x08, 0x42, 0x2E, 0x03, 0xA5, 0xD8, 0x06, 0x52, 0xF0, 0x24, - 0x00, 0x01, 0xEF, 0xE8, 0x42, 0xE9, 0xBD, 0xF2, 0x9B, 0xBA, - 0x16, 0xFD, 0xCF, 0x83, 0x81, 0x08, 0x3F, 0xFE, 0x88, 0x40, - 0x01, 0xB0, 0x12, 0x8B, 0xA1, 0x10, 0xBD, 0xF1, 0x7C, 0x1F, - 0x18, 0x47, 0xC0, 0x13, 0xC1, 0xF7, 0x84, 0x00, 0x03, 0x5F, - 0xF8, 0x46, 0x21, 0xF8, 0x1D, 0x17, 0x80, 0x0F, 0x8B, 0xC0, - 0x0E, 0xC3, 0xEE, 0x87, 0xBE, 0xF0, 0xF4, 0x01, 0xEC, 0x1D, - 0xF7, 0xC6, 0x11, 0xF8, 0x1B, 0x18, 0x7F, 0xCE, 0xFF, 0xBA, - 0x10, 0x46, 0x3E, 0xF3, 0xFE, 0x31, 0x3E, 0x40, 0xFB, 0x80, - 0x18, 0x43, 0xD0, 0x04, 0xFE, 0x00, 0x70, 0x0E, 0x08, 0x3F, - 0xF7, 0xFE, 0x0F, 0x70, 0x22, 0xE7, 0x86, 0x20, 0x94, 0x3F, - 0x10, 0xF6, 0x4F, 0x80, 0x00, 0x17, 0x86, 0x3F, 0x6F, 0x41, - 0xE8, 0x44, 0x0F, 0x8B, 0xE3, 0xF0, 0x82, 0x2E, 0xEC, 0x00, - 0x20, 0xFE, 0x00, 0x78, 0x1B, 0x27, 0xF8, 0x10, 0x8F, 0xBD, - 0x17, 0x78, 0x5F, 0xE0, 0x04, 0xF8, 0xC2, 0x0F, 0xFB, 0xFE, - 0xF9, 0xF5, 0xF0, 0x8F, 0xC2, 0x01, 0x3D, 0xD1, 0x77, 0x61, - 0x10, 0xC4, 0x41, 0x04, 0x9F, 0x0E, 0xC9, 0x9F, 0xFF, 0xC3, - 0xD8, 0x7A, 0x00, 0x07, 0x61, 0xF0, 0x04, 0x0F, 0x6F, 0x61, - 0xE7, 0x78, 0x1E, 0xFF, 0xDD, 0x31, 0x02, 0x00, 0x84, 0x40, - 0xFF, 0x42, 0x00, 0xF8, 0x02, 0x10, 0xFE, 0x71, 0x7C, 0x41, - 0x37, 0xC2, 0x22, 0x83, 0x9B, 0xEF, 0xFD, 0xFF, 0x78, 0x5E, - 0xF8, 0x05, 0xD0, 0x73, 0xE3, 0xFF, 0x3E, 0x5E, 0xFC, 0x21, - 0x1F, 0xBC, 0x00, 0x07, 0xC2, 0xF0, 0xC2, 0x3E, 0x07, 0xE0, - 0x08, 0x02, 0x10, 0xFC, 0x63, 0xF0, 0x05, 0xFF, 0xEF, 0x7D, - 0x07, 0x86, 0x02, 0x07, 0xE5, 0x08, 0x46, 0x42, 0x0B, 0xA1, - 0xE7, 0xFD, 0xEF, 0x6C, 0x42, 0xF0, 0x04, 0x00, 0x84, 0x60, - 0xF9, 0x84, 0x1F, 0x0F, 0x98, 0xD8, 0xBF, 0xEF, 0x77, 0xC2, - 0x08, 0x41, 0xF1, 0xFB, 0xE0, 0x17, 0x7B, 0xED, 0x78, 0x5C, - 0x10, 0x42, 0x2F, 0x83, 0xDE, 0x50, 0xB6, 0x22, 0x07, 0xE3, - 0x10, 0x45, 0xE0, 0x7F, 0xA1, 0xE9, 0x00, 0x11, 0x7B, 0xE1, - 0xD8, 0xC4, 0x4E, 0xFF, 0xFF, 0x17, 0xFC, 0x31, 0x1B, 0xA2, - 0xF8, 0x41, 0xDF, 0x10, 0x3F, 0xE8, 0x3F, 0xFF, 0x87, 0xC2, - 0x1F, 0x44, 0x20, 0x83, 0xBF, 0x17, 0x02, 0x20, 0x04, 0x3B, - 0xF8, 0x01, 0xC0, 0x83, 0xE2, 0x30, 0x40, 0x5F, 0x80, 0x23, - 0x07, 0x83, 0xC0, 0xF0, 0x60, 0x00, 0xC4, 0x10, 0x08, 0x9F, - 0xE8, 0xBA, 0x2F, 0xFF, 0xE3, 0x0E, 0x41, 0xA3, 0x7C, 0x62, - 0x17, 0x7C, 0x0F, 0xFB, 0xC0, 0x07, 0x7D, 0xD2, 0xEC, 0x82, - 0xFF, 0x49, 0xB0, 0x74, 0x9F, 0x07, 0xFC, 0x5F, 0x14, 0x7F, - 0x17, 0x3C, 0x42, 0x08, 0x5C, 0xD9, 0x36, 0x50, 0xFB, 0xC1, - 0x09, 0x80, 0x41, 0x93, 0xE6, 0xF8, 0xBC, 0x11, 0x0C, 0x05, - 0x0E, 0x83, 0xBF, 0xFB, 0x9C, 0xF8, 0x3E, 0x20, 0x7C, 0x3F, - 0x09, 0x3E, 0x01, 0x8B, 0xA1, 0xFF, 0xFC, 0x3F, 0x00, 0x24, - 0x17, 0x82, 0x23, 0x7C, 0x3D, 0xD7, 0x76, 0x1F, 0x0C, 0x3E, - 0x1F, 0xFE, 0x22, 0xFF, 0xFE, 0xE0, 0x82, 0x00, 0x97, 0xC3, - 0xE0, 0x45, 0xD1, 0x06, 0xC2, 0x17, 0xF7, 0xEE, 0x7B, 0xA8, - 0x00, 0x84, 0x3F, 0xFF, 0x81, 0xF0, 0xB0, 0x11, 0xF4, 0x00, - 0x16, 0xB8, 0x5F, 0x7B, 0xDD, 0xEF, 0xC0, 0x3F, 0x08, 0x02, - 0x0F, 0xD1, 0xF0, 0x94, 0x42, 0xF0, 0x0D, 0xC0, 0x7C, 0x21, - 0x0F, 0xC6, 0x01, 0x7C, 0x7E, 0x0F, 0x01, 0xD1, 0x01, 0x01, - 0x1F, 0x39, 0xE0, 0x83, 0xDF, 0x07, 0x7E, 0x1F, 0x0B, 0xFB, - 0x2F, 0xC7, 0xE3, 0x70, 0x63, 0x1F, 0xC6, 0x10, 0x7C, 0x5E, - 0x00, 0x3E, 0x02, 0x98, 0x41, 0xF7, 0x84, 0x0F, 0xF4, 0x01, - 0x07, 0x05, 0xF0, 0x23, 0xBE, 0xF0, 0x46, 0x30, 0x83, 0xE0, - 0x00, 0x79, 0xDF, 0x0C, 0xE3, 0x0F, 0x44, 0x00, 0xFF, 0xDF, - 0xE8, 0xC4, 0x14, 0x13, 0xBF, 0x08, 0x7D, 0x92, 0x03, 0xE0, - 0x20, 0x03, 0x91, 0x10, 0xA1, 0xF1, 0x01, 0xCE, 0x73, 0x84, - 0xF7, 0xBA, 0x23, 0x68, 0x3F, 0xF0, 0x7C, 0x2D, 0x03, 0xFF, - 0x07, 0xBE, 0x3F, 0x7F, 0xD9, 0x10, 0x03, 0xC1, 0x03, 0xC2, - 0xEA, 0x0A, 0x1E, 0x00, 0x03, 0xF8, 0x46, 0x3E, 0xF8, 0x02, - 0x18, 0x44, 0x3F, 0x00, 0xA0, 0xF7, 0x3C, 0x0D, 0x73, 0xFF, - 0xEE, 0xC0, 0x30, 0x10, 0x5F, 0xFF, 0xCA, 0x3E, 0xF3, 0xE1, - 0xE9, 0x02, 0x0D, 0x77, 0xDF, 0xF8, 0xBF, 0xCF, 0xFC, 0x62, - 0xE8, 0xBE, 0x40, 0xF4, 0x01, 0x0E, 0xF9, 0xE1, 0x7B, 0xC1, - 0x18, 0x7C, 0x3F, 0xF7, 0xE4, 0x10, 0xC2, 0x20, 0x88, 0x41, - 0x1F, 0x0F, 0xFF, 0x0C, 0x45, 0x10, 0xFF, 0xCF, 0x7B, 0xA0, - 0xFF, 0x4B, 0xF0, 0x78, 0x39, 0x07, 0x84, 0x2F, 0x04, 0xBC, - 0xE8, 0x04, 0x0F, 0x00, 0x3E, 0xFF, 0xC1, 0xCF, 0x93, 0xFC, - 0xF0, 0x33, 0xCE, 0x80, 0x21, 0x01, 0x4B, 0xD1, 0xF7, 0x9B, - 0xD8, 0x44, 0x00, 0x8F, 0xC3, 0x37, 0x38, 0x12, 0x7F, 0xA0, - 0x09, 0x00, 0x22, 0x00, 0x7E, 0xF8, 0x44, 0x5F, 0x17, 0xFE, - 0xF8, 0x7C, 0x1F, 0x88, 0x82, 0x17, 0x36, 0x0F, 0x0C, 0x24, - 0x08, 0x39, 0x80, 0x6F, 0xC1, 0x10, 0x44, 0x1F, 0x9B, 0xFE, - 0x27, 0x03, 0xF2, 0x04, 0xBF, 0xE0, 0xCC, 0x0E, 0xFB, 0xC4, - 0x00, 0x40, 0x50, 0x74, 0x23, 0x17, 0xBE, 0x0F, 0x7C, 0xDB, - 0xE9, 0x00, 0x41, 0x80, 0xBF, 0x20, 0xF8, 0x00, 0x87, 0xFE, - 0x08, 0x3F, 0xFF, 0x00, 0x21, 0x18, 0x83, 0x50, 0xF7, 0xC2, - 0x09, 0x81, 0xC2, 0x07, 0x9D, 0x27, 0x83, 0xD0, 0x04, 0x1C, - 0xE8, 0x06, 0x41, 0xFC, 0x44, 0xD9, 0x3F, 0xFF, 0x04, 0x41, - 0x29, 0x80, 0x0B, 0x7F, 0xC0, 0xF0, 0x7C, 0x00, 0x77, 0xA2, - 0x08, 0xB7, 0xE0, 0xF7, 0xDD, 0xF7, 0xC7, 0xF1, 0x6B, 0xE1, - 0x00, 0x09, 0xF4, 0xFB, 0xDD, 0xF6, 0xC9, 0xE2, 0x0B, 0xE1, - 0x00, 0xB9, 0xDD, 0x78, 0x41, 0x18, 0xFF, 0xE1, 0xFC, 0x3F, - 0xF7, 0xBF, 0xE0, 0x93, 0xBD, 0x28, 0x4D, 0xFF, 0xF8, 0x01, - 0x00, 0x09, 0xDE, 0x88, 0x24, 0xE8, 0x85, 0xD0, 0x7B, 0x80, - 0xFF, 0xC2, 0x10, 0xF0, 0x5D, 0xEF, 0x7F, 0xFE, 0xF4, 0x1F, - 0x0F, 0xC2, 0x10, 0x84, 0x3D, 0xD7, 0x7C, 0x20, 0x80, 0x17, - 0xE8, 0x85, 0xED, 0x8C, 0x03, 0xD7, 0x85, 0xDE, 0xF4, 0x9E, - 0x00, 0x80, 0x01, 0x08, 0x03, 0x08, 0x3D, 0xFE, 0x08, 0x3F, - 0xE8, 0x08, 0x31, 0x08, 0x02, 0x06, 0xFF, 0xFE, 0x8C, 0xC0, - 0xF8, 0x40, 0x00, 0x14, 0x60, 0x06, 0xC2, 0x2C, 0x88, 0x01, - 0x30, 0x34, 0x20, 0x94, 0x5D, 0x17, 0x7F, 0xBF, 0x9B, 0x62, - 0xDF, 0xBE, 0x4F, 0xF4, 0x21, 0xFF, 0xC2, 0x30, 0x88, 0xA1, - 0xEF, 0x40, 0x00, 0xFC, 0x43, 0xF8, 0x3B, 0xAF, 0x78, 0x01, - 0xF0, 0x45, 0xEC, 0x8B, 0xFE, 0x10, 0x3A, 0x2F, 0xF7, 0xFF, - 0x08, 0x00, 0x21, 0x17, 0xBD, 0x07, 0xC2, 0x0E, 0xFC, 0x45, - 0x3F, 0xC1, 0xEE, 0xFB, 0x3A, 0xF0, 0xC1, 0xD1, 0x84, 0x5A, - 0xE8, 0x09, 0xC1, 0x78, 0x00, 0x0E, 0xF4, 0x1E, 0x7F, 0x3C, - 0x18, 0xC1, 0xDE, 0x88, 0xA2, 0x0F, 0x84, 0x10, 0x04, 0x7A, - 0x17, 0xBF, 0xC1, 0x74, 0x26, 0x18, 0x81, 0xFF, 0x6C, 0x3B, - 0x0F, 0xCC, 0x2F, 0x80, 0x1F, 0xF0, 0x3E, 0x10, 0x88, 0xBD, - 0xFE, 0xC9, 0xB0, 0x03, 0xFE, 0xF8, 0x3E, 0x21, 0xFC, 0xC2, - 0x3F, 0x80, 0x00, 0x8F, 0xE0, 0x1F, 0x85, 0xCE, 0x8B, 0xC5, - 0x0F, 0x41, 0xB1, 0x7F, 0x83, 0x09, 0x02, 0x3E, 0xFC, 0x21, - 0xE8, 0x7E, 0x22, 0x07, 0xA1, 0x38, 0x3D, 0xF0, 0x80, 0x3C, - 0x10, 0x44, 0x20, 0x0F, 0xDF, 0x0F, 0x7A, 0x01, 0x88, 0x00, - 0x0F, 0xFA, 0x0E, 0x73, 0xDF, 0xF0, 0x83, 0xD2, 0x7C, 0xDF, - 0xEE, 0xCC, 0x00, 0xF4, 0x43, 0x00, 0x3F, 0xFF, 0x00, 0x3D, - 0xFE, 0x83, 0xA0, 0xFC, 0x43, 0x07, 0x81, 0xED, 0xFC, 0x01, - 0x20, 0x42, 0x2F, 0x87, 0xFE, 0xF7, 0x47, 0xB1, 0x1B, 0xDE, - 0x10, 0x08, 0x10, 0x78, 0xBD, 0xE9, 0xB9, 0xCE, 0x7C, 0x9D, - 0x00, 0x36, 0x1F, 0xEF, 0xDE, 0xF7, 0x87, 0xD0, 0x87, 0xC4, - 0x0E, 0xB6, 0x8D, 0x8B, 0xE1, 0xF8, 0xCD, 0xDF, 0x0B, 0x3D, - 0x0F, 0xCF, 0xEE, 0x80, 0x01, 0x01, 0x3D, 0xE0, 0xFC, 0x62, - 0x29, 0x41, 0xF0, 0x07, 0xFF, 0xFF, 0x46, 0x61, 0x80, 0x1D, - 0x27, 0xFE, 0x1F, 0xF4, 0x3B, 0x0F, 0xFF, 0xCF, 0x8B, 0xFE, - 0xE8, 0x84, 0x4F, 0x84, 0x24, 0x0F, 0x1D, 0xFB, 0xDA, 0xFE, - 0x0E, 0x16, 0x10, 0x03, 0x15, 0xE6, 0xE3, 0xF8, 0xFF, 0xD8, - 0x4B, 0xC8, 0xE5, 0xF4, 0x26, 0x03, 0xDB, 0x2A, 0xFD, 0x05, - 0xE1, 0xEF, 0x0B, 0xFC, 0x20, 0xFB, 0x31, 0x11, 0x1C, 0x03, - 0x15, 0xE1, 0xD6, 0x0B, 0xDC, 0xF5, 0x12, 0xED, 0xEA, 0x28, - 0x20, 0xE5, 0x21, 0xDC, 0xE7, 0xDF, 0x05, 0xDE, 0xF4, 0xFF, - 0x1F, 0xEF, 0x4A, 0xE6, 0x15, 0x0A, 0x07, 0x06, 0xF7, 0xE6, - 0xEE, 0xEC, 0x00, 0xF0, 0x03, 0xFF, 0xBB, 0x0D, 0xFB, 0x35, - 0xE3, 0xF5, 0xE6, 0xEA, 0x26, 0x00, 0x0E, 0x10, 0xFB, 0xDA, - 0x1B, 0xD1, 0xEF, 0x09, 0x02, 0x03, 0x16, 0x1F, 0x06, 0xDC, - 0xF8, 0x25, 0x17, 0xE9, 0xEA, 0x0F, 0xD5, 0x15, 0x0B, 0xE3, - 0x04, 0x20, 0xF5, 0x09, 0xE9, 0x1A, 0xE8, 0x0F, 0xEB, 0xE4, - 0xE9, 0x36, 0x03, 0xF5, 0xFF, 0x42, 0xFD, 0xE7, 0xFA, 0xF7, - 0xD2, 0x19, 0xCA, 0xE8, 0x22, 0x00, 0xEE, 0xDB, 0x00, 0xFE, - 0x18, 0x19, 0x14, 0x0C, 0x0A, 0xD0, 0x14, 0x21, 0x2E, 0xFD, - 0x36, 0xED, 0xAE, 0x1B, 0x00, 0x15, 0xF4, 0x13, 0xDC, 0x12, - 0xCB, 0x0A, 0xD4, 0xDD, 0x01, 0xCB, 0xED, 0xC2, 0xE5, 0xF2, - 0xD7, 0x02, 0xEF, 0xDB, 0x1D, 0x2F, 0xE2, 0x20, 0x3A, 0xE4, - 0x25, 0x1B, 0x14, 0x18, 0xF5, 0x04, 0x06, 0x18, 0x0D, 0x39, - 0xFC, 0x06, 0xF9, 0x0A, 0x20, 0xE1, 0xF7, 0x2E, 0xFB, 0xE3, - 0xF2, 0x21, 0xF9, 0xD3, 0x04, 0x07, 0xF9, 0x0B, 0xFC, 0xFA, - 0x27, 0x05, 0xF8, 0x2A, 0xFA, 0x0B, 0xFB, 0xEF, 0xB9, 0x08, - 0xFE, 0x0C, 0x14, 0x05, 0xE2, 0xFA, 0xFD, 0xC9, 0x0C, 0xF4, - 0x38, 0xCD, 0xFA, 0xD6, 0xE4, 0x05, 0x05, 0x1E, 0xF8, 0x3B, - 0x2E, 0x0E, 0x16, 0x07, 0x2C, 0x10, 0xF3, 0x1B, 0xF1, 0x00, - 0x08, 0xF0, 0xC7, 0x14, 0xD7, 0xDD, 0x06, 0xC2, 0xF3, 0xFD, - 0x10, 0x05, 0x18, 0x24, 0xE6, 0xDD, 0x0A, 0xDC, 0xDB, 0xEE, - 0xFE, 0xF6, 0xF9, 0x19, 0x40, 0x0B, 0x2B, 0x37, 0x28, 0xC7, - 0xFD, 0xF7, 0x07, 0xD5, 0x0C, 0x0C, 0x01, 0xDC, 0x2B, 0xD8, - 0xFD, 0x0C, 0xD1, 0xFC, 0x12, 0xE8, 0x02, 0xDC, 0x05, 0xDA, - 0xEB, 0x00, 0x1C, 0xDC, 0xFF, 0x07, 0xF8, 0x0F, 0xC8, 0x13, - 0x06, 0x08, 0x03, 0xEC, 0x11, 0xE8, 0xFD, 0xFD, 0xFF, 0x0D, - 0xF2, 0xD8, 0xF7, 0xFF, 0xFB, 0x11, 0xF4, 0xE2, 0xE9, 0x07, - 0xE7, 0xF6, 0xE9, 0x53, 0x13, 0x33, 0xEE, 0x1C, 0x15, 0x13, - 0x00, 0x24, 0xFC, 0xEA, 0x09, 0x15, 0xEC, 0x28, 0xF5, 0x1F, - 0xDB, 0xE3, 0xFC, 0x02, 0xF9, 0x0C, 0x0D, 0x26, 0x05, 0xF6, - 0x04, 0x02, 0xE4, 0x2F, 0x02, 0xF1, 0xE9, 0xE6, 0xEC, 0x03, - 0xEA, 0x16, 0xFA, 0x09, 0x13, 0xF6, 0x29, 0xE7, 0x13, 0xFB, - 0xF9, 0xDD, 0x03, 0xF7, 0xD4, 0x0B, 0xE7, 0xF2, 0x24, 0x2C, - 0x24, 0x35, 0x02, 0xFE, 0x21, 0xE9, 0x20, 0x01, 0x2A, 0x10, - 0x01, 0x1F, 0x03, 0x28, 0x2D, 0x20, 0xF8, 0x10, 0x0A, 0x09, - 0xF5, 0x32, 0xD5, 0xF6, 0xE4, 0x1F, 0xF8, 0xF4, 0xD8, 0xF4, - 0xD8, 0x0A, 0x07, 0x16, 0x0A, 0xFD, 0x14, 0xF8, 0x22, 0xDC, - 0x03, 0xDD, 0xFA, 0xEB, 0xD3, 0xE4, 0x0D, 0x04, 0xF6, 0x1D, - 0x1E, 0xDF, 0xF6, 0x28, 0x25, 0x17, 0x0B, 0xCF, 0xF1, 0x14, - 0xD9, 0x17, 0xEB, 0x34, 0xF7, 0xEC, 0xCE, 0x20, 0x1E, 0xD5, - 0x20, 0x07, 0xEB, 0xE8, 0x13, 0x04, 0x3D, 0x07, 0xF7, 0xF8, - 0xFE, 0xF6, 0xEA, 0xE9, 0xEE, 0xD7, 0xEE, 0xFC, 0xEA, 0xFA, - 0xFB, 0xDA, 0x33, 0x0F, 0xED, 0x0B, 0x2B, 0x00, 0x1A, 0xED, - 0x12, 0xF4, 0x0D, 0x15, 0x14, 0xFB, 0xF0, 0xF4, 0x0F, 0x0C, - 0xEC, 0x27, 0x11, 0x13, 0xF0, 0x0E, 0x2D, 0xE5, 0x00, 0xD2, - 0x0F, 0xD5, 0xF5, 0xFA, 0xF3, 0x03, 0x00, 0xDB, 0x17, 0xDD, - 0x2C, 0xE8, 0xFE, 0xE7, 0x46, 0xF6, 0xEF, 0xFD, 0x1F, 0xFF, - 0x0F, 0xEF, 0xE7, 0xEE, 0x18, 0x02, 0x27, 0x2B, 0xFC, 0x2D, - 0xF6, 0x13, 0xFC, 0xFD, 0xBB, 0xF8, 0xEE, 0xDD, 0x12, 0x0D, - 0x01, 0x22, 0x2F, 0xF0, 0xF1, 0x1B, 0x0C, 0x09, 0xE7, 0x33, - 0xE5, 0xFF, 0xFA, 0xFC, 0x1E, 0x15, 0x08, 0xF2, 0xDA, 0xE3, - 0xF4, 0xEA, 0xEF, 0x29, 0x3A, 0x02, 0x0B, 0x1E, 0xF4, 0x46, - 0xC5, 0x1C, 0xBD, 0xFC, 0xE5, 0x05, 0x0E, 0x24, 0xF9, 0xDE, - 0xD6, 0x1B, 0x05, 0xFF, 0xD3, 0xF3, 0xF2, 0x0D, 0xF0, 0x03, - 0xF5, 0x19, 0xFE, 0xDB, 0x0B, 0x00, 0x02, 0xC5, 0x12, 0x04, - 0xED, 0x1A, 0xF0, 0x12, 0x1C, 0x28, 0x1F, 0xEF, 0xDD, 0xCB, - 0xFC, 0x02, 0xF2, 0xED, 0xD1, 0xEC, 0xE5, 0xCC, 0xFE, 0xF6, - 0x03, 0xEE, 0xDF, 0x3F, 0x0F, 0xFD, 0x04, 0x05, 0x32, 0x11, - 0x1C, 0xF2, 0xF0, 0x1E, 0x07, 0xEF, 0x07, 0x1E, 0x17, 0x15, - 0x04, 0x01, 0x03, 0xF7, 0xFA, 0x02, 0xD9, 0xEB, 0x19, 0xCD, - 0xEA, 0x2B, 0x22, 0xFD, 0xD7, 0x08, 0xF0, 0xF4, 0xF4, 0xF1, - 0x44, 0x09, 0xE5, 0x0B, 0xFE, 0xEE, 0x1F, 0x1A, 0xED, 0xFF, - 0xFB, 0x07, 0xFD, 0xF6, 0x1E, 0x1D, 0x02, 0xFF, 0xDA, 0x01, - 0x1E, 0xEE, 0x04, 0xD2, 0xDF, 0xDA, 0x0D, 0xFC, 0xFA, 0xF9, - 0xFE, 0x12, 0x0B, 0x42, 0x26, 0x0E, 0x00, 0xD9, 0xEF, 0x17, - 0x02, 0xD3, 0x1B, 0x03, 0xEB, 0xDE, 0x0C, 0x11, 0xFF, 0x0E, - 0x1D, 0xCD, 0xF9, 0xEF, 0x12, 0x0E, 0x0F, 0x03, 0xF7, 0x21, - 0x16, 0x1F, 0x11, 0xD9, 0x02, 0x01, 0xE4, 0x0D, 0xDB, 0x2D, - 0xD6, 0x16, 0xE0, 0xEE, 0x1D, 0xF7, 0xFA, 0xE8, 0x10, 0xF3, - 0x39, 0xF0, 0xEA, 0xEC, 0x2D, 0xCE, 0x22, 0xCE, 0x2C, 0xF8, - 0x1F, 0xEA, 0xFC, 0xD9, 0x28, 0x14, 0xFC, 0x22, 0x15, 0xE4, - 0xCF, 0x19, 0xFD, 0xE0, 0xEC, 0xEE, 0xFC, 0xEE, 0x0F, 0xE4, - 0x03, 0xF8, 0xDF, 0xF3, 0x12, 0xF3, 0xF1, 0xED, 0xEB, 0x14, - 0xD4, 0x4E, 0x0B, 0x25, 0xC8, 0x14, 0x01, 0x10, 0xFA, 0x18, - 0x12, 0x13, 0x0A, 0xE0, 0xED, 0xD7, 0x01, 0xD5, 0xF6, 0xDD, - 0xBC, 0x0C, 0xD9, 0xFC, 0xE1, 0x07, 0x06, 0xEE, 0xBD, 0x1F, - 0xEC, 0x1A, 0x22, 0x04, 0xFC, 0x18, 0xF2, 0xEA, 0x01, 0x0B, - 0xF6, 0xFA, 0x13, 0x26, 0x09, 0x07, 0xEC, 0x0B, 0x08, 0x0F, - 0xFE, 0x0E, 0xD2, 0x15, 0xB3, 0xE0, 0xD8, 0x34, 0xE3, 0xEC, - 0xF6, 0x21, 0xEB, 0x13, 0x01, 0xF3, 0x0B, 0x02, 0x07, 0xF7, - 0x0D, 0xF6, 0x2F, 0x22, 0xFE, 0x21, 0x1F, 0xE7, 0xFA, 0xFF, - 0x0F, 0x03, 0xFD, 0xE5, 0xE3, 0x0F, 0xF5, 0x08, 0xF6, 0xFF, - 0x02, 0x30, 0xE0, 0x21, 0xEC, 0x21, 0x3A, 0xF6, 0x1F, 0xF4, - 0x01, 0xCC, 0x0D, 0xD7, 0x1B, 0x24, 0x1F, 0x0F, 0x0D, 0xFB, - 0xFC, 0x16, 0x13, 0x1C, 0xE0, 0xEC, 0xED, 0xE9, 0x07, 0xE0, - 0xFC, 0xF1, 0xDB, 0x07, 0x23, 0xF9, 0x10, 0x08, 0xE4, 0xF7, - 0xF4, 0xEC, 0xCD, 0xE0, 0xF9, 0xCD, 0xF3, 0x13, 0x02, 0x05, - 0x0C, 0xF8, 0xFA, 0xFF, 0x14, 0xE3, 0x01, 0xEA, 0xFB, 0x04, - 0x2C, 0xF5, 0xF3, 0x10, 0x19, 0xE7, 0x03, 0xDC, 0x2A, 0xFB, - 0x06, 0x0B, 0x05, 0x3D, 0xE8, 0xD4, 0x2F, 0xFD, 0xDE, 0x14, - 0x19, 0xD5, 0xEE, 0xFA, 0x0D, 0x06, 0x0B, 0x41, 0x1F, 0xDA, - 0x0E, 0x1C, 0xF5, 0xEF, 0x36, 0x0A, 0x1E, 0x0F, 0x07, 0x0D, - 0x19, 0x03, 0xDA, 0xE2, 0x12, 0x1C, 0xEA, 0xF7, 0x13, 0xCE, - 0x27, 0x18, 0xD2, 0x04, 0xD5, 0xFB, 0xFD, 0xD7, 0xDF, 0xEB, - 0x1B, 0xFC, 0xFD, 0x16, 0xEB, 0x1B, 0xF1, 0xDD, 0x34, 0xD7, - 0x3D, 0x00, 0x24, 0x04, 0x19, 0xF5, 0x0E, 0x14, 0x1F, 0x06, - 0xE4, 0xEF, 0xCF, 0x17, 0xE2, 0x0D, 0x17, 0x06, 0xF7, 0x0A, - 0x21, 0xAA, 0xC5, 0xB8, 0x1B, 0x6C, 0xEB, 0x28, 0x70, 0x4A, - 0x9A, 0x80, 0x17, 0xDD, 0x39, 0xB2, 0xDA, 0x07, 0x9E, 0xC3, - 0xD2, 0x6C, 0xF1, 0x0F, 0x42, 0xB7, 0x48, 0xC4, 0x1A, 0x01, - 0xAD, 0x83, 0x05, 0x4D, 0x8A, 0x4D, 0x56, 0xBC, 0x10, 0x38, - 0x11, 0xD8, 0x6A, 0x34, 0x02, 0xF4, 0x8F, 0x86, 0x64, 0x70, - 0x92, 0xB7, 0xD5, 0xF5, 0xAD, 0x9B, 0x0A, 0x76, 0x8B, 0x42, - 0x39, 0xA0, 0x3B, 0x5F, 0xBA, 0x46, 0x27, 0xF3, 0x4C, 0xC7, - 0x7F, 0x78, 0xB5, 0xE3, 0xC2, 0x95, 0x67, 0x32, 0x3C, 0x28, - 0x88, 0x2A, 0xEE, 0x4F, 0x9E, 0xC2, 0xEC, 0xF5, 0xD7, 0xE2, - 0xA1, 0x4D, 0x9C, 0xB1, 0xC3, 0x64, 0x21, 0xD2, 0x19, 0xD8, - 0xA6, 0x33, 0x95, 0xC0, 0xD8, 0x07, 0x82, 0xC7, 0xB3, 0xC4, - 0x25, 0xCC, 0x24, 0xE8, 0xB7, 0xD2, 0xBA, 0x6F, 0x2B, 0x79, - 0x08, 0xF0, 0xF0, 0x47, 0x65, 0xEF, 0x46, 0x65, 0x46, 0xB9, - 0xD7, 0x0E, 0xC5, 0x52, 0x5C, 0x75, 0x5B, 0xDB, 0xA8, 0x39, - 0x99, 0x4A, 0xA8, 0x47, 0x08, 0xC9, 0xA8, 0x9F, 0x40, 0x1A, - 0x67, 0xFB, 0x46, 0x48, 0xB3, 0x82, 0x11, 0xF2, 0x66, 0xA2, - 0xF6, 0xBB, 0xCC, 0xC2, 0x08, 0xFA, 0xAF, 0x1F, 0x36, 0x10, - 0x9C, 0xF5, 0x5F, 0x6D, 0x54, 0x27, 0xB9, 0x80, 0x88, 0xF8, - 0x50, 0x5F, 0x90, 0x05, 0xC1, 0x94, 0xCA, 0xED, 0xAE, 0x59, - 0xE8, 0x76, 0x1A, 0x16, 0xDA, 0x88, 0xAA, 0x4D, 0xEA, 0xD5, - 0xB6, 0xD3, 0xA1, 0x13, 0x5C, 0xA2, 0x1A, 0x46, 0x47, 0xFC, - 0xB5, 0x4A, 0x47, 0x04, 0xD4, 0xEF, 0xBF, 0xBF, 0x61, 0xAC, - 0x91, 0x05, 0x59, 0xF6, 0x91, 0x3D, 0x98, 0x90, 0xEB, 0x1E, - 0x9A, 0x9D, 0x42, 0x9A, 0xD4, 0x10, 0x21, 0x61, 0x12, 0x66, - 0xE4, 0xDB, 0xC6, 0x06, 0x52, 0x77, 0x91, 0xA7, 0x01, 0x09, - 0x94, 0x92, 0x5D, 0xB5, 0x3C, 0x29, 0xA5, 0x4D, 0xEE, 0xBD, - 0xA6, 0xC8, 0xC7, 0x81, 0x8B, 0x93, 0x64, 0x6C, 0xD6, 0xA8, - 0xAC, 0x18, 0x3C, 0x5B, 0x48, 0x69, 0x77, 0xA9, 0x2E, 0x65, - 0xA2, 0xE6, 0x26, 0x73, 0xF7, 0x8A, 0x9E, 0x31, 0x56, 0xD6, - 0xE6, 0x2F, 0xCD, 0xDD, 0xBF, 0xF2, 0x31, 0xC6, 0x87, 0x2F, - 0xE6, 0x2C, 0x68, 0x4F, 0x79, 0xE4, 0xC2, 0x0A, 0x48, 0xFC, - 0x4D, 0xF4, 0xF8, 0x40, 0x85, 0x9C, 0xE1, 0x4C, 0x47, 0x4D, - 0x16, 0x88, 0xB5, 0xCA, 0x51, 0xBB, 0x6B, 0x12, 0x50, 0x37, - 0x6E, 0xBA, 0x06, 0x10, 0x0E, 0x5A, 0x9F, 0x9C, 0xB5, 0x0B, - 0x32, 0x81, 0x96, 0x1F, 0xC1, 0x24, 0xE8, 0x85, 0x6E, 0x3F, - 0xB9, 0xD8, 0xE4, 0x69, 0x30, 0x1A, 0xF3, 0x12, 0x98, 0x32, - 0xF2, 0xB8, 0x5F, 0xA1, 0xB4, 0x71, 0x0B, 0x19, 0x09, 0x22, - 0xD5, 0x84, 0x1A, 0x49, 0xE7, 0x10, 0x07, 0xDF, 0x68, 0x8D, - 0xFB, 0x02, 0xB0, 0x9E, 0xF4, 0x06, 0x36, 0x8C, 0x81, 0x70, - 0xD6, 0x5D, 0x31, 0x98, 0x5E, 0xC2, 0xF4, 0x5B, 0xDC, 0xA3, - 0x38, 0x7F, 0x82, 0x58, 0x48, 0x50, 0x51, 0x24, 0x2C, 0x80, - 0xE0, 0x1A, 0xAA, 0x8C, 0xDC, 0x4F, 0xD0, 0x21, 0x14, 0x6A, - 0xBD, 0x2C, 0x5D, 0x51, 0xFA, 0x94, 0x18, 0x89, 0x5C, 0x69, - 0xD9, 0xB5, 0x23, 0xCB, 0x00, 0x1C, 0x67, 0x27, 0x58, 0x62, - 0xE3, 0xB3, 0xD5, 0x6A, 0x57, 0xE8, 0x6C, 0x18, 0x60, 0xCA, - 0x20, 0x14, 0x3E, 0xA2, 0x76, 0xA6, 0xBC, 0xE9, 0x83, 0x3A, - 0x20, 0x2E, 0x61, 0x5E, 0xAB, 0x20, 0x1F, 0x0A, 0x32, 0x35, - 0x8E, 0x3B, 0x30, 0x4C, 0xEA, 0x74, 0xB8, 0x72, 0xC5, 0x95, - 0xD9, 0x4A, 0x36, 0xA0, 0x0D, 0xA1, 0x91, 0x64, 0x89, 0x21, - 0x73, 0xC8, 0x8D, 0x08, 0x0F, 0x12, 0xED, 0x85, 0x81, 0xAE, - 0xA1, 0xB8, 0x8B, 0xBF, 0x12, 0xDA, 0x30, 0xBB, 0x68, 0xA7, - 0xFA, 0xB7, 0xA8, 0x68, 0xC5, 0x97, 0xA2, 0xAD, 0x02, 0x01, - 0xE8, 0x11, 0x16, 0x51, 0xF9, 0x3A, 0x39, 0xE4, 0x56, 0x43, - 0x5D, 0xC9, 0xA7, 0x01, 0xB2, 0x14, 0x78, 0x85, 0x0B, 0x75, - 0x1D, 0x9A, 0x68, 0x0A, 0x9C, 0x77, 0x4A, 0xC0, 0xDD, 0xE4, - 0xB4, 0xDE, 0x46, 0x41, 0x8E, 0x00, 0x91, 0xF4, 0xC6, 0xDA, - 0xB9, 0xA1, 0x15, 0x64, 0xBC, 0x5A, 0x57, 0x82, 0xDA, 0xF3, - 0xB8, 0xEE, 0xDE, 0x69, 0x25, 0x30, 0x84, 0xE8, 0xFF, 0x5E, - 0xF2, 0x26, 0xF0, 0x41, 0x02, 0xE9, 0xAA, 0xA7, 0xA1, 0xA8, - 0x88, 0x6A, 0xC8, 0x6D, 0x06, 0x3E, 0x86, 0x6B, 0xA9, 0x39, - 0x28, 0x40, 0x55, 0xE4, 0xA9, 0x11, 0xDF, 0xE5, 0xB9, 0x98, - 0x2D, 0xF2, 0x36, 0x5E, 0xAC, 0x58, 0x54, 0x3A, 0x7C, 0xEA, - 0x77, 0x97, 0x00, 0x66, 0xD2, 0x9B, 0x53, 0x73, 0x4C, 0xC1, - 0x1F, 0xAC, 0xEE, 0x90, 0x6B, 0xC8, 0xE0, 0xBC, 0x9E, 0x7C, - 0xC1, 0x88, 0x1C, 0x90, 0x12, 0x55, 0xE5, 0x17, 0x14, 0xC0, - 0xBF, 0x2C, 0x31, 0xCC, 0x74, 0xEF, 0x50, 0xF3, 0xAA, 0xE4, - 0x91, 0x15, 0xE6, 0x68, 0x2A, 0x86, 0xE4, 0x39, 0x73, 0x11, - 0x93, 0x46, 0x41, 0x22, 0x4B, 0xDB, 0xA7, 0x84, 0x91, 0x6F, - 0x68, 0x8C, 0x05, 0x08, 0x69, 0xE3, 0x4F, 0x95, 0x5F, 0x3A, - 0x1A, 0xDA, 0x34, 0x4C, 0x44, 0x75, 0x1B, 0x5C, 0x09, 0xEB, - 0x2B, 0x6E, 0x9F, 0x18, 0x18, 0x2C, 0x3C, 0x87, 0x7C, 0xA8, - 0xEA, 0x7F, 0x4A, 0xB9, 0xB6, 0x6E, 0x67, 0x49, 0xCA, 0xA1, - 0x00, 0x77, 0xA6, 0x33, 0xE5, 0x2C, 0xC6, 0xED, 0x66, 0xF4, - 0x4E, 0xF4, 0x1F, 0xEB, 0xFD, 0x62, 0x5C, 0xAF, 0x10, 0x3D, - 0x8E, 0x2B, 0xAE, 0xF9, 0x46, 0xB6, 0xF6, 0x98, 0x35, 0x77, - 0xD0, 0x9C, 0x0A, 0xA9, 0x2C, 0xD7, 0x6F, 0x46, 0x42, 0x45, - 0x8B, 0xDF, 0xF7, 0x0A, 0x2C, 0xE6, 0x41, 0xC3, 0xEA, 0xAC, - 0x06, 0x30, 0xDA, 0xC9, 0xE7, 0x22, 0x29, 0x0B, 0x2C, 0x70, - 0x49, 0x5B, 0x05, 0x29, 0x48, 0x14, 0x32, 0xE6, 0x75, 0x6E, - 0x81, 0x35, 0xE4, 0xA0, 0xE2, 0x4C, 0x1E, 0x53, 0xB7, 0x36, - 0x19, 0xC1, 0xEF, 0x44, 0xE1, 0x2A, 0x49, 0xC8, 0x0B, 0xC0, - 0x43, 0xF6, 0x77, 0x54, 0xD6, 0x80, 0xE0, 0xE5, 0x23, 0x64, - 0x4A, 0xF0, 0x18, 0xBF, 0x91, 0x14, 0x71, 0x9A, 0x03, 0x77, - 0xF5, 0x52, 0x4E, 0xA0, 0xDC, 0xAB, 0x64, 0x7C, 0xD0, 0xE5, - 0x1D, 0x92, 0x4A, 0xDB, 0xE8, 0xD3, 0xF4, 0x01, 0xE0, 0xE6, - 0x1B, 0x77, 0x8D, 0x6B, 0x8F, 0xD2, 0x93, 0x0A, 0xE3, 0x5D, - 0x60, 0x1C, 0x19, 0xD5, 0xA8, 0x9B, 0xDE, 0x0F, 0x2C, 0xB2, - 0xF5, 0x2B, 0x3C, 0x1E, 0x50, 0x42, 0xB4, 0x54, 0xC9, 0x28, - 0xE4, 0x2F, 0x3D, 0xD0, 0x6B, 0x24, 0x13, 0x1B, 0xED, 0x85, - 0xA2, 0x0C, 0x95, 0x50, 0xD8, 0x5F, 0x73, 0x96, 0xA1, 0x64, - 0xEF, 0xA6, 0xE8, 0x65, 0x55, 0xF8, 0xA4, 0xF9, 0x54, 0x24, - 0x76, 0x05, 0xD7, 0xE5, 0x35, 0x98, 0xCD, 0x34, 0xE1, 0xF0, - 0x36, 0x27, 0x8C, 0x16, 0x1B, 0xB6, 0xE2, 0x73, 0xDA, 0x57, - 0xDD, 0x11, 0xE1, 0x15, 0x46, 0xD1, 0xC7, 0xA3, 0x2C, 0x9D, - 0xE2, 0xE5, 0xED, 0xAA, 0xB5, 0x70, 0xC5, 0xDD, 0x99, 0x77, - 0x0E, 0x50, 0x28, 0xF2, 0xBD, 0xF1, 0xEB, 0x16, 0xAA, 0xB4, - 0x99, 0xE8, 0x42, 0xAE, 0x81, 0x96, 0x99, 0x40, 0x0E, 0xF1, - 0x30, 0xA8, 0x5C, 0x65, 0x2C, 0x75, 0x21, 0xCA, 0xCC, 0x0E, - 0x95, 0x61, 0x04, 0x04, 0xD4, 0x43, 0x11, 0x7D, 0x8E, 0x21, - 0x84, 0x7A, 0x5B, 0xF7, 0x1D, 0xEA, 0xB6, 0xC8, 0x54, 0x02, - 0xE8, 0x95, 0x26, 0xC3, 0x51, 0xC2, 0x65, 0x14, 0xAB, 0xA9, - 0xBF, 0x43, 0x7E, 0x0E, 0x57, 0x68, 0xFC, 0x4D, 0xDA, 0x08, - 0xD4, 0x73, 0x38, 0x7C, 0x0A, 0xF4, 0x92, 0xA4, 0xD4, 0x6D, - 0x8D, 0xB8, 0xB7, 0xE8, 0xD2, 0x7D, 0x35, 0x4E, 0x44, 0xE2, - 0x84, 0xE0, 0xF0, 0x3D, 0xD0, 0x31, 0xB8, 0xED, 0xD4, 0x75, - 0x8C, 0x98, 0xED, 0x30, 0xBE, 0xD4, 0xDB, 0xA6, 0x02, 0x2C, - 0xEB, 0x9E, 0x6B, 0x83, 0xBE, 0x71, 0x25, 0x9A, 0x8C, 0xDC, - 0x5F, 0x86, 0x09, 0x33, 0x74, 0x32, 0x25, 0xD8, 0xA3, 0x29, - 0x21, 0x6A, 0xE6, 0x68, 0xDD, 0x82, 0x96, 0x87, 0x62, 0xE6, - 0x83, 0xFB, 0x85, 0xD9, 0x00, 0xC8, 0x32, 0x8B, 0xA8, 0x33, - 0x86, 0x2C, 0xE0, 0xDF, 0x1F, 0x76, 0x7D, 0x5C, 0xB1, 0x92, - 0xE3, 0x84, 0xDB, 0x73, 0xEC, 0x3D, 0x49, 0xEB, 0xD8, 0x62, - 0x4A, 0xEE, 0x2D, 0xA1, 0x13, 0xCA, 0x65, 0x7E, 0xBA, 0xAD, - 0x61, 0xEE, 0xA2, 0x8E, 0x23, 0x6E, 0xA7, 0x97, 0x75, 0x93, - 0x62, 0xBF, 0x40, 0x3E, 0x01, 0xE8, 0xE7, 0x40, 0x19, 0xEC, - 0x3F, 0xD2, 0xCE, 0x16, 0x5C, 0xB3, 0x08, 0x29, 0x48, 0xCE, - 0x42, 0x81, 0x59, 0x7A, 0x67, 0xB2, 0x03, 0xEB, 0xBC, 0x1E, - 0x45, 0x64, 0x8B, 0xED, 0xD0, 0xA5, 0x5C, 0x2D, 0xEA, 0xEA, - 0xB5, 0x2A, 0xF2, 0x39, 0x1A, 0x2C, 0xB4, 0x35, 0x4E, 0xC2, - 0xBB, 0x98, 0x66, 0x12, 0x8A, 0xC1, 0xE1, 0x26, 0xFE, 0x3C, - 0x48, 0x1E, 0x40, 0xE3, 0x58, 0x39, 0xFD, 0x33, 0x1B, 0xE9, - 0x91, 0x70, 0x60, 0xD0, 0x22, 0xD0, 0xD6, 0x7D, 0x20, 0x59, - 0x08, 0x84, 0x3B, 0x98, 0x99, 0xB5, 0x5C, 0x44, 0x19, 0xE8, - 0xA5, 0x99, 0x15, 0x61, 0x98, 0xE2, 0x4E, 0x62, 0x59, 0x97, - 0xF9, 0x61, 0x6B, 0xF0, 0x57, 0x89, 0x9F, 0xBD, 0x33, 0xBB, - 0xA9, 0x56, 0xB8, 0x5D, 0x3D, 0x6A, 0x10, 0x35, 0x41, 0xEE, - 0x40, 0xAC, 0xF2, 0xAA, 0x34, 0x6A, 0x09, 0xA0, 0x35, 0x83, - 0xD2, 0xAB, 0x24, 0xA1, 0x97, 0x70, 0xCE, 0xA1, 0xEE, 0x2F, - 0x0D, 0x5D, 0xC9, 0x3E, 0x8B, 0xF6, 0x25, 0xA9, 0xB5, 0xF8, - 0x2C, 0xE0, 0x69, 0x43, 0x08, 0x64, 0x19, 0xC5, 0x23, 0x20, - 0xEC, 0xD8, 0x04, 0x00, 0xA8, 0x86, 0x61, 0x00, 0x1F, 0x6E, - 0x5C, 0x9E, 0xDA, 0x61, 0x68, 0x87, 0x5F, 0xB1, 0x22, 0x49, - 0x7B, 0x17, 0x67, 0x7E, 0x51, 0x4A, 0xE1, 0x05, 0x1B, 0x31, - 0x39, 0xDD, 0x75, 0x42, 0x4C, 0xE1, 0x10, 0xBB, 0xB8, 0x08, - 0xA8, 0x0C, 0x90, 0xC3, 0x59, 0x90, 0xE2, 0x99, 0x83, 0x65, - 0xBC, 0x5D, 0xC4, 0x90, 0x87, 0x8B, 0xE4, 0xF3, 0x32, 0x39, - 0x9D, 0x46, 0xFF, 0x24, 0x60, 0x1F, 0x32, 0x49, 0xA9, 0x57, - 0x97, 0xF7, 0x8C, 0x59, 0x3E, 0x70, 0x09, 0x93, 0x4A, 0x0C, - 0xFC, 0x32, 0x51, 0x86, 0x41, 0x65, 0x04, 0x4D, 0xF7, 0x02, - 0xB2, 0x6A, 0xB1, 0xAA, 0x18, 0x6B, 0xA2, 0x05, 0xE9, 0xD7, - 0x59, 0xC2, 0x93, 0x51, 0x57, 0xC8, 0x42, 0x9A, 0x74, 0xBA, - 0x98, 0x51, 0x9E, 0xB9, 0xA7, 0x41, 0x81, 0x71, 0x54, 0x45, - 0x51, 0xBE, 0xC5, 0x72, 0x02, 0xEB, 0xA8, 0x97, 0x5B, 0x4E, - 0x25, 0xD0, 0x40, 0xD1, 0x45, 0x7D, 0x30, 0xBF, 0x44, 0xBE, - 0x1C, 0xE1, 0x4C, 0x9C, 0xDA, 0xA3, 0x54, 0xEC, 0xFF, 0x46, - 0x26, 0xE9, 0x97, 0x63, 0x82, 0x4F, 0xA6, 0x9A, 0xA0, 0xF3, - 0x89, 0x83, 0x8E, 0x49, 0xAE, 0x21, 0xF4, 0x5C, 0x6E, 0x0D, - 0x89, 0x08, 0xCA, 0x34, 0xCC, 0xC2, 0xC3, 0x47, 0x8C, 0xDC, - 0xC5, 0x9D, 0xA4, 0xAF, 0xA2, 0x0A, 0x75, 0x3A, 0x72, 0x8A, - 0x1D, 0xA0, 0x3A, 0xDA, 0x5B, 0x0F, 0x1A, 0xDC, 0x70, 0x21, - 0xC8, 0xE3, 0x3C, 0xD5, 0xCF, 0x48, 0x74, 0x49, 0xF9, 0x6E, - 0x8D, 0xD6, 0x9D, 0x8A, 0x9A, 0x32, 0x6B, 0xE0, 0x77, 0xA6, - 0x84, 0x54, 0xF5, 0xA3, 0x11, 0x55, 0xB7, 0xA0, 0xA8, 0xF3, - 0xBC, 0xED, 0xEC, 0x6F, 0xB8, 0xAF, 0xA3, 0xE4, 0xDC, 0x13, - 0xA4, 0x76, 0x63, 0x83, 0x92, 0xC4, 0xC6, 0x22, 0x20, 0x37, - 0x58, 0xA3, 0xAC, 0x63, 0x66, 0x88, 0x3B, 0xD8, 0xBA, 0xA4, - 0x06, 0x26, 0xBE, 0xA6, 0x23, 0x9E, 0xC0, 0xD1, 0x61, 0x5D, - 0xCF, 0x64, 0x34, 0x04, 0x4D, 0x05, 0x9C, 0xD2, 0x03, 0xE8, - 0xC8, 0x0B, 0x14, 0xBE, 0x47, 0x45, 0x1E, 0x1B, 0x04, 0x94, - 0xDA, 0xAD, 0x72, 0xCA, 0x1B, 0xE2, 0xB3, 0xC5, 0xA1, 0x69, - 0x45, 0x07, 0xED, 0x2E, 0xF9, 0x1A, 0xC3, 0x3C, 0xC7, 0xB5, - 0x1D, 0xD9, 0x85, 0x27, 0xB8, 0xD4, 0x91, 0x03, 0xD2, 0x35, - 0xF3, 0x5F, 0x5D, 0x3F, 0x3E, 0x56, 0x25, 0xBB, 0x37, 0x0C, - 0xDC, 0x48, 0x1D, 0xCF, 0x82, 0xFD, 0x24, 0xD0, 0xBF, 0xCA, - 0x69, 0x91, 0xC5, 0x8C, 0x7D, 0x7B, 0x78, 0x31, 0xBA, 0xC3, - 0x9F, 0x7C, 0x6E, 0x7D, 0x39, 0xF3, 0xEE, 0x46, 0x9C, 0x81, - 0xE5, 0xAA, 0xA8, 0xD7, 0x02, 0x17, 0x27, 0x94, 0xF8, 0xF1, - 0x54, 0x0A, 0xA2, 0x47, 0x3C, 0xE7, 0xA6, 0xA5, 0x00, 0x31, - 0x81, 0xA1, 0xE3, 0x86, 0xEF, 0x56, 0xE3, 0x36, 0x2C, 0x1F, - 0x86, 0xED, 0xD3, 0x6D, 0x05, 0xBA, 0x36, 0xF1, 0xF0, 0x2E, - 0x84, 0x9A, 0xFA, 0xA7, 0x09, 0x59, 0x14, 0x2B, 0x0A, 0xFC, - 0xC0, 0x16, 0x3E, 0xAA, 0x13, 0xAF, 0x25, 0x02, 0x4A, 0x97, - 0xD0, 0xAD, 0x7E, 0x2D, 0xC2, 0x4A, 0xFD, 0x1F, 0x2B, 0x4D, - 0x46, 0x60, 0x42, 0xB1, 0xAE, 0x12, 0x32, 0x5E, 0x23, 0x19, - 0x47, 0x4B, 0x23, 0x7C, 0x1A, 0xA2, 0xC6, 0x4F, 0x03, 0xBE, - 0x47, 0x95, 0x97, 0x86, 0xFF, 0x0E, 0xCC, 0x40, 0xB0, 0xCA, - 0x45, 0xE5, 0x14, 0x93, 0xA1, 0xD0, 0xC1, 0x37, 0xEE, 0x1E, - 0x13, 0x69, 0xB9, 0x8D, 0xE1, 0x86, 0xCC, 0xDD, 0x0D, 0xC2, - 0xED, 0xD3, 0x59, 0x13, 0x9D, 0xB5, 0xD0, 0x50, 0x68, 0x1A, - 0xA5, 0xA6 + 0x30, 0x82, 0x10, 0x1A, 0x02, 0x01, 0x00, 0x30, 0x07, 0x06, + 0x05, 0x2B, 0xCE, 0x0F, 0x03, 0x0E, 0x04, 0x82, 0x09, 0x05, + 0x04, 0x82, 0x09, 0x01, 0x5A, 0x1E, 0xC3, 0xF0, 0x77, 0xC2, + 0xE6, 0xC4, 0x3F, 0x1B, 0xC2, 0x19, 0x04, 0x22, 0xDC, 0x41, + 0xDF, 0x43, 0xB2, 0x87, 0xE0, 0x0F, 0x8D, 0xF3, 0x73, 0xBF, + 0xF1, 0x01, 0xFF, 0xFC, 0x05, 0x17, 0x4A, 0x40, 0x84, 0x62, + 0x20, 0xC0, 0x6F, 0x73, 0xE0, 0x1F, 0xFC, 0x1D, 0x0B, 0xFE, + 0x09, 0x44, 0x0E, 0x7B, 0xC1, 0x0F, 0xFC, 0x2F, 0x08, 0x5F, + 0x0F, 0x83, 0xFF, 0x83, 0xDF, 0x20, 0x8D, 0xE0, 0x70, 0x3F, + 0x17, 0xB7, 0xBF, 0x8B, 0xC1, 0x07, 0x43, 0xE1, 0x77, 0xC4, + 0x00, 0xC7, 0xF1, 0x7C, 0x5F, 0xE8, 0x01, 0xE1, 0x10, 0x40, + 0x08, 0xC2, 0x22, 0xFF, 0x85, 0xF9, 0x3C, 0x30, 0x8C, 0x1B, + 0x10, 0x82, 0x02, 0x9B, 0xFB, 0xF1, 0x3F, 0xA0, 0x80, 0x01, + 0x0F, 0xFC, 0x4E, 0x00, 0x39, 0x00, 0x3C, 0x40, 0x74, 0xA0, + 0xF7, 0x78, 0x10, 0x0F, 0xC1, 0x08, 0x87, 0xF0, 0x77, 0xDE, + 0x19, 0x01, 0xDF, 0x10, 0x7F, 0xE8, 0xB9, 0xF0, 0x08, 0x5E, + 0xF7, 0x85, 0xD1, 0x83, 0x44, 0xF7, 0xFF, 0xF0, 0x03, 0xC1, + 0xE8, 0xB9, 0xEE, 0x88, 0x3E, 0x10, 0x04, 0x6F, 0x7B, 0xBF, + 0xED, 0xFF, 0xCD, 0xF8, 0x21, 0x08, 0x46, 0x00, 0x77, 0xA2, + 0xFF, 0x80, 0x3E, 0x8F, 0xC0, 0x18, 0x45, 0xDE, 0x80, 0x5E, + 0x08, 0x3C, 0x00, 0x03, 0xE1, 0xFF, 0xF8, 0x5D, 0xF8, 0xFE, + 0xEF, 0x80, 0x2D, 0xF4, 0x04, 0x07, 0xF9, 0xCC, 0xF7, 0xA0, + 0xD0, 0x05, 0xC2, 0x93, 0xC1, 0x07, 0x86, 0x3E, 0x0B, 0xDE, + 0x08, 0x3A, 0x01, 0x80, 0x03, 0x18, 0x04, 0x10, 0xFC, 0x00, + 0x17, 0xF7, 0xD0, 0x0B, 0xE1, 0x1F, 0xC1, 0xF1, 0xEC, 0x5F, + 0x27, 0x00, 0x2F, 0x80, 0x01, 0xCF, 0x7C, 0x5E, 0x88, 0x01, + 0x10, 0x40, 0x12, 0x00, 0x40, 0x0F, 0x48, 0x30, 0x04, 0x24, + 0x08, 0x87, 0xE2, 0x90, 0x07, 0xE8, 0x00, 0x3F, 0x7F, 0x9E, + 0x18, 0x39, 0xCE, 0x8C, 0x44, 0x07, 0x76, 0x32, 0x74, 0xA0, + 0x2F, 0xC0, 0x2E, 0x88, 0x41, 0x18, 0x84, 0x11, 0x7B, 0xC3, + 0xE7, 0x87, 0xEE, 0x13, 0x9C, 0x08, 0x81, 0xFF, 0x78, 0x3F, + 0x00, 0x7D, 0xF0, 0x03, 0xFF, 0x18, 0xBA, 0x2E, 0x03, 0x9D, + 0x20, 0xB6, 0x5C, 0xF8, 0x01, 0x37, 0xFC, 0x00, 0x78, 0x40, + 0xFF, 0x3A, 0x2F, 0x88, 0xE3, 0xF7, 0x83, 0xC1, 0x8C, 0x1F, + 0x08, 0x00, 0x01, 0x07, 0xA0, 0x07, 0x42, 0x20, 0x0C, 0x1C, + 0x16, 0xC0, 0x31, 0x10, 0x5F, 0xD8, 0x3C, 0x30, 0x8B, 0xBC, + 0x09, 0x41, 0xE2, 0x7B, 0xDF, 0x17, 0xBE, 0x2D, 0x88, 0x04, + 0x09, 0x06, 0x1D, 0x8F, 0xE0, 0xF9, 0x3C, 0x60, 0x83, 0x9E, + 0xFF, 0xFC, 0x3F, 0x73, 0x9D, 0x18, 0xCA, 0x1E, 0xEC, 0x02, + 0xFF, 0xFD, 0xDF, 0xFC, 0x5A, 0x00, 0x00, 0x30, 0xFC, 0x21, + 0x07, 0xC3, 0xDF, 0x98, 0xA2, 0x27, 0x7D, 0xFF, 0x0B, 0xE2, + 0xF0, 0x83, 0xE0, 0x83, 0xC2, 0xEF, 0xBA, 0x92, 0x74, 0x05, + 0x0E, 0x87, 0xCC, 0x80, 0x20, 0x08, 0x79, 0xEF, 0x08, 0x07, + 0xE8, 0x01, 0xD0, 0xEF, 0x9E, 0x0F, 0xFC, 0x4F, 0x08, 0xA1, + 0x30, 0x87, 0xFD, 0x70, 0x3A, 0xE8, 0x91, 0xBE, 0xF8, 0x20, + 0x08, 0xB8, 0x1F, 0x7C, 0x83, 0xE1, 0x04, 0x00, 0x74, 0xBE, + 0x10, 0x80, 0x10, 0x84, 0x46, 0xFF, 0x81, 0xE0, 0x10, 0x60, + 0x07, 0x41, 0xF0, 0x03, 0xBD, 0x00, 0xC7, 0xDD, 0xF7, 0xA0, + 0xF8, 0x32, 0x2F, 0x87, 0x41, 0xF7, 0x82, 0x3D, 0x73, 0xC0, + 0xD9, 0x7F, 0xDF, 0x83, 0xE3, 0x17, 0x3A, 0x20, 0x88, 0x23, + 0x07, 0x3A, 0x20, 0x74, 0x9E, 0xF7, 0x3F, 0xF1, 0x80, 0x83, + 0xEF, 0xC0, 0x51, 0xEF, 0xC1, 0x08, 0x76, 0x0D, 0x0F, 0x84, + 0xF9, 0x76, 0x01, 0x08, 0x9D, 0xC8, 0x85, 0xE1, 0x74, 0x40, + 0x37, 0x84, 0x02, 0x7F, 0x61, 0xEF, 0x83, 0xCF, 0x87, 0xDF, + 0x0E, 0xBF, 0xCF, 0xFC, 0x7C, 0x09, 0x3E, 0x11, 0x84, 0x3F, + 0x29, 0x3E, 0x5F, 0x87, 0xBE, 0x10, 0x3B, 0xF1, 0x8B, 0xFE, + 0x19, 0x82, 0x40, 0x78, 0x9F, 0xFF, 0xFA, 0x31, 0x7F, 0x60, + 0x00, 0x8A, 0x0F, 0x00, 0x18, 0x01, 0x83, 0xA2, 0x0F, 0xC4, + 0xF9, 0x3B, 0xCD, 0x08, 0x64, 0xE0, 0x84, 0x1F, 0x0C, 0x3C, + 0x0F, 0x3E, 0x30, 0x84, 0x5D, 0x08, 0x3E, 0x0D, 0x07, 0xC3, + 0x20, 0x7D, 0xED, 0x83, 0xC5, 0x11, 0x3A, 0x0E, 0x88, 0x1A, + 0xE0, 0xBC, 0x2E, 0x03, 0xE0, 0x08, 0x06, 0x10, 0x08, 0x7A, + 0xF7, 0xF4, 0x0F, 0x03, 0x7E, 0x20, 0x01, 0xE0, 0x17, 0x7D, + 0xD8, 0x87, 0xE2, 0x88, 0x80, 0xF7, 0x7A, 0x1D, 0x08, 0xA0, + 0xE1, 0x78, 0x0F, 0x90, 0x21, 0x10, 0x85, 0xE0, 0x04, 0x83, + 0xE0, 0x05, 0xD0, 0x08, 0x5E, 0x00, 0x41, 0xFF, 0x7F, 0x80, + 0x4E, 0xFE, 0x11, 0x0F, 0xE6, 0x00, 0x3F, 0xE0, 0x0F, 0xE0, + 0xE8, 0x84, 0x5F, 0x88, 0x65, 0xE8, 0xC0, 0x00, 0xFC, 0x19, + 0x16, 0x40, 0x51, 0x87, 0xC0, 0x30, 0x3D, 0xE0, 0x70, 0xBE, + 0x08, 0x87, 0xE2, 0x90, 0xBE, 0x3F, 0x43, 0xCE, 0x94, 0x1E, + 0x29, 0x42, 0x00, 0x00, 0x3F, 0x30, 0x07, 0xFF, 0x04, 0x61, + 0xE8, 0x03, 0xCF, 0xF7, 0xBA, 0x08, 0x40, 0x2F, 0x77, 0xE2, + 0x18, 0x41, 0xF0, 0x08, 0x1D, 0xEF, 0xC2, 0x2E, 0x80, 0x03, + 0xF9, 0x7A, 0x0F, 0x1C, 0x5F, 0x00, 0x00, 0x20, 0x10, 0x20, + 0xF8, 0x02, 0x5F, 0x80, 0x44, 0xE0, 0x38, 0x4E, 0xFC, 0x20, + 0xF8, 0x02, 0x31, 0xFC, 0x5D, 0xEF, 0xC9, 0xFF, 0x0C, 0x03, + 0xF8, 0x3D, 0xB2, 0xF3, 0x9F, 0x20, 0x48, 0x0F, 0x04, 0x3F, + 0xFF, 0xF9, 0xF0, 0x70, 0x82, 0x08, 0xBC, 0x12, 0x74, 0x1F, + 0x07, 0x01, 0xE1, 0x04, 0x82, 0xF8, 0x77, 0xF1, 0x78, 0x81, + 0x07, 0x40, 0x21, 0xFC, 0xBD, 0x1F, 0xFE, 0x2E, 0x78, 0x60, + 0x17, 0xFF, 0xD1, 0x74, 0x62, 0xF7, 0x41, 0xF0, 0xFB, 0xC0, + 0x07, 0xC2, 0x31, 0x6C, 0x1F, 0xF8, 0x7F, 0xDF, 0x03, 0x62, + 0x27, 0xC2, 0x02, 0x7F, 0x82, 0x00, 0xBA, 0x6F, 0x7C, 0x80, + 0xE0, 0x01, 0xED, 0x9B, 0xDD, 0x19, 0x41, 0xFD, 0x8C, 0x5F, + 0x0E, 0xFE, 0x60, 0x88, 0x7F, 0xF8, 0x44, 0x41, 0xF8, 0x5F, + 0xD7, 0xBE, 0x12, 0xF4, 0x7E, 0xC8, 0xCA, 0x2C, 0xFC, 0x9D, + 0xEF, 0xBA, 0x3E, 0x88, 0xA3, 0xE7, 0x04, 0x30, 0x83, 0xD9, + 0x10, 0x84, 0x0F, 0x87, 0x9E, 0x10, 0x7B, 0xDF, 0xFC, 0x22, + 0xE0, 0x7A, 0x31, 0x78, 0x20, 0xD7, 0x48, 0x10, 0x08, 0x7E, + 0xF0, 0x7A, 0x12, 0x04, 0x24, 0x17, 0xC9, 0xEF, 0xFB, 0xBE, + 0x0E, 0xC3, 0xC0, 0x87, 0x9F, 0xFF, 0x42, 0x2E, 0x04, 0x3D, + 0x0F, 0xC5, 0xFF, 0x08, 0x81, 0x21, 0x48, 0x40, 0x10, 0x9B, + 0x0F, 0xC2, 0x10, 0x97, 0xBF, 0x30, 0x40, 0x1F, 0x88, 0x1D, + 0x17, 0x8C, 0x01, 0x00, 0x41, 0x08, 0x7C, 0x4F, 0xF3, 0xBF, + 0x07, 0x80, 0x02, 0x0F, 0xE0, 0xFF, 0x47, 0xBF, 0x84, 0x5F, + 0x01, 0x00, 0x0F, 0x74, 0x1E, 0xF0, 0x01, 0x80, 0x07, 0xA1, + 0xF7, 0x83, 0xFF, 0x81, 0x3F, 0x10, 0x88, 0x0F, 0xFC, 0x3E, + 0xFF, 0xBF, 0xB0, 0x90, 0x3B, 0xF1, 0x08, 0x20, 0xF7, 0xA0, + 0xF9, 0x47, 0xD0, 0xF8, 0x81, 0x1F, 0xFC, 0x00, 0xFC, 0x1C, + 0x1E, 0xC9, 0xDF, 0x98, 0x61, 0xD8, 0xBB, 0xF1, 0xF4, 0x82, + 0x00, 0xB7, 0xD0, 0xFF, 0xDB, 0x08, 0x81, 0xE0, 0x08, 0xC0, + 0xE0, 0x7F, 0xE0, 0xEC, 0x23, 0x00, 0x33, 0xF0, 0xF7, 0xFE, + 0xF8, 0xC7, 0xEF, 0x84, 0x41, 0x00, 0x49, 0xE0, 0x00, 0x5F, + 0xF6, 0xFC, 0x4E, 0x6C, 0x00, 0xF0, 0x00, 0x1F, 0x9B, 0xDF, + 0x10, 0x3C, 0x01, 0x00, 0xFF, 0x1E, 0xF5, 0xFF, 0x03, 0xC0, + 0xF0, 0x7D, 0xFE, 0x63, 0xE1, 0x08, 0xFD, 0xD1, 0x88, 0x60, + 0xF8, 0xBA, 0x51, 0x07, 0xBF, 0x18, 0x43, 0xD0, 0x83, 0xC1, + 0xF9, 0x85, 0xE0, 0x7C, 0x04, 0xFF, 0xC6, 0x01, 0x84, 0x05, + 0xFF, 0x3C, 0x30, 0x74, 0x1F, 0x01, 0x00, 0x22, 0x8F, 0xE1, + 0xF7, 0xC3, 0xDF, 0x7C, 0xDE, 0xC8, 0x46, 0x30, 0x87, 0xE5, + 0x00, 0xBB, 0xF0, 0x97, 0xC3, 0xE6, 0xBC, 0x20, 0x7F, 0xDE, + 0x17, 0x40, 0x1F, 0x03, 0xFB, 0xF7, 0xFC, 0x42, 0x87, 0x66, + 0xF8, 0xC8, 0x10, 0x0F, 0xFC, 0xF6, 0x02, 0x2F, 0xE0, 0x00, + 0xE7, 0x38, 0x13, 0x74, 0x7F, 0x27, 0x0E, 0x5C, 0xE8, 0x60, + 0x10, 0x83, 0xEE, 0x13, 0x9D, 0xF8, 0x42, 0x3F, 0x8C, 0x02, + 0x26, 0xFF, 0xF0, 0x80, 0x00, 0x10, 0x7A, 0x3F, 0xFB, 0xDB, + 0x08, 0x45, 0xF2, 0x08, 0x23, 0xC8, 0x3D, 0xED, 0x07, 0xBD, + 0xF0, 0x46, 0x40, 0x0B, 0x21, 0x18, 0xC1, 0xE0, 0x78, 0x5F, + 0x18, 0xB8, 0x31, 0x74, 0x20, 0x08, 0x07, 0xDF, 0xFC, 0x9C, + 0xFF, 0x06, 0x4E, 0x84, 0x7C, 0x0F, 0xFB, 0xB1, 0x04, 0x26, + 0xC9, 0x38, 0x0D, 0x7C, 0x5B, 0x17, 0xFE, 0x11, 0x80, 0x9F, + 0x07, 0x83, 0xFE, 0xFC, 0x82, 0x00, 0x43, 0xFF, 0xF0, 0x22, + 0xF8, 0x7B, 0xD1, 0x78, 0xA0, 0xF8, 0x87, 0xC0, 0x13, 0x67, + 0xF0, 0x00, 0x02, 0x1B, 0x3E, 0x10, 0x47, 0xE0, 0x07, 0xDE, + 0x17, 0x76, 0x30, 0x7B, 0xDD, 0x07, 0x7F, 0xF1, 0xF7, 0x9F, + 0xF7, 0xFE, 0x00, 0x13, 0xBC, 0x00, 0x01, 0xFE, 0xF4, 0x7D, + 0x38, 0xBC, 0x32, 0x83, 0xE3, 0x20, 0xBD, 0xE2, 0x7C, 0x22, + 0x00, 0x7C, 0x12, 0xF8, 0x42, 0xF0, 0x48, 0x4F, 0x78, 0x02, + 0x21, 0x7F, 0xD0, 0x73, 0xC4, 0x20, 0xBD, 0xE0, 0x00, 0x01, + 0x17, 0xC1, 0xC1, 0xFC, 0x43, 0xF7, 0xFC, 0x0E, 0x7B, 0xBC, + 0x10, 0x00, 0x21, 0x77, 0xDF, 0xF0, 0x12, 0xF7, 0xE0, 0xE5, + 0xE7, 0x12, 0xE5, 0x2C, 0xC2, 0x11, 0xD4, 0x03, 0xEE, 0x09, + 0x07, 0xFA, 0xCE, 0xC5, 0x0B, 0x0D, 0x1D, 0xF5, 0x39, 0xF5, + 0xD0, 0x17, 0xEC, 0xFF, 0xEC, 0xFA, 0xE9, 0xDF, 0x40, 0x0F, + 0x02, 0x11, 0xF2, 0x1A, 0x0D, 0xE2, 0xEA, 0x0F, 0xF5, 0x0E, + 0xFF, 0x02, 0xFC, 0x0E, 0xF6, 0xDE, 0x2F, 0x12, 0x2D, 0xEA, + 0xFF, 0x1F, 0xD5, 0xFB, 0x1D, 0x0D, 0x12, 0xB2, 0x08, 0x1F, + 0x08, 0x07, 0xEC, 0x1C, 0x15, 0xFD, 0xFA, 0x02, 0xF0, 0xFE, + 0x0D, 0xEC, 0xFF, 0xD1, 0xF3, 0x02, 0x0A, 0xEC, 0xF7, 0xE6, + 0x06, 0x0B, 0x4E, 0x2D, 0xFB, 0x17, 0x35, 0xEF, 0xD1, 0x0C, + 0xEC, 0x1C, 0x25, 0x01, 0x0A, 0xF4, 0x16, 0x22, 0xEA, 0x00, + 0x13, 0x05, 0x0F, 0xED, 0x0F, 0xFC, 0x02, 0x02, 0x31, 0xE2, + 0xEE, 0x16, 0x2C, 0xF0, 0x3F, 0x08, 0x01, 0xE9, 0x00, 0x29, + 0x0B, 0x13, 0x17, 0xE8, 0xE6, 0xDE, 0xE9, 0x1F, 0x09, 0xF6, + 0x0B, 0x0B, 0x20, 0xF2, 0xF8, 0x26, 0xFC, 0xFA, 0xE4, 0x16, + 0xFB, 0xF0, 0x05, 0xE9, 0x00, 0xEF, 0xE5, 0x0E, 0xF3, 0x0D, + 0x0E, 0xC7, 0x0E, 0x14, 0xEF, 0x03, 0xDC, 0x0B, 0x0F, 0xF2, + 0x38, 0xEF, 0xED, 0x13, 0x1D, 0x0E, 0x24, 0x0B, 0xE1, 0xC1, + 0xC4, 0xE1, 0x14, 0x05, 0x2E, 0xDA, 0x1C, 0x10, 0x10, 0xFC, + 0xF3, 0xF9, 0xFA, 0xFA, 0x02, 0x0D, 0xE7, 0xFE, 0xF3, 0x02, + 0xE9, 0x08, 0xFD, 0xD4, 0x41, 0x26, 0x2E, 0xE2, 0xD3, 0x24, + 0xFF, 0x00, 0x09, 0x23, 0xEC, 0xE8, 0x05, 0xEF, 0xE7, 0x02, + 0x13, 0x00, 0x12, 0x0E, 0xD4, 0xD6, 0x13, 0x31, 0xF9, 0x15, + 0x15, 0xC8, 0x01, 0x17, 0x2C, 0x27, 0x16, 0xD1, 0x07, 0x3F, + 0xF5, 0xEF, 0x0E, 0x00, 0xD0, 0x2B, 0x13, 0xE2, 0xF5, 0x0E, + 0x4C, 0xDF, 0x03, 0x07, 0xE8, 0xEA, 0x0D, 0x25, 0x01, 0xF0, + 0xFA, 0x0A, 0xFA, 0xDE, 0x01, 0xFB, 0x27, 0xFC, 0xEE, 0xEF, + 0xCB, 0x12, 0x1D, 0xE0, 0x00, 0xF8, 0xF0, 0xFA, 0xFF, 0xFE, + 0xFB, 0x0E, 0xD7, 0xD7, 0xD9, 0x01, 0x13, 0xE9, 0xED, 0xD9, + 0x18, 0xEF, 0xF9, 0xED, 0x0A, 0x06, 0xFB, 0xE5, 0x17, 0xD8, + 0xE8, 0x08, 0xFA, 0x1D, 0x0A, 0xFF, 0x22, 0x06, 0xF2, 0x1A, + 0x0A, 0xFD, 0xE4, 0xF3, 0xED, 0xF8, 0x18, 0xF3, 0x10, 0x0A, + 0x00, 0xE0, 0xF6, 0x12, 0xF2, 0xFC, 0x20, 0x28, 0xF7, 0x0C, + 0xFA, 0x18, 0x09, 0x01, 0xFB, 0xDE, 0x27, 0xF7, 0x33, 0xFA, + 0x0B, 0x2F, 0x1C, 0x24, 0x1B, 0xDD, 0x0D, 0x04, 0x14, 0xFC, + 0xFA, 0x22, 0xF1, 0x09, 0x2B, 0x06, 0x01, 0x0A, 0x15, 0x0D, + 0xCE, 0x0B, 0x22, 0xF9, 0x0D, 0x35, 0x14, 0xF7, 0xFC, 0x07, + 0xE4, 0xE4, 0xE3, 0x16, 0x0B, 0x20, 0xC1, 0x01, 0xEA, 0x17, + 0x21, 0xE0, 0x02, 0x12, 0xE9, 0x0B, 0x01, 0xF8, 0xED, 0x27, + 0xE9, 0xDF, 0x0B, 0xCC, 0x04, 0x21, 0x13, 0x0D, 0x20, 0x07, + 0x0F, 0x10, 0x13, 0x19, 0x24, 0x04, 0xFC, 0x01, 0xFC, 0xBF, + 0xC1, 0x0A, 0x2B, 0xFD, 0xF5, 0xF4, 0xFE, 0xEC, 0xFB, 0xF8, + 0x26, 0x03, 0xE0, 0xFE, 0x17, 0xFA, 0xDA, 0x19, 0x0C, 0xFD, + 0x05, 0x2D, 0xFA, 0xF0, 0x0D, 0x04, 0x11, 0xFB, 0xEC, 0x00, + 0xEA, 0x06, 0x06, 0xD6, 0xD0, 0xFB, 0xCF, 0xDF, 0x03, 0xFB, + 0x01, 0xD1, 0xEE, 0x14, 0xE6, 0xF8, 0x0C, 0x0F, 0xEC, 0x22, + 0x09, 0xC8, 0xD8, 0x2A, 0xFC, 0x04, 0x05, 0x17, 0x19, 0x05, + 0xDA, 0x27, 0x0E, 0xE1, 0xE2, 0x0B, 0x2D, 0xE8, 0xD8, 0xE5, + 0xE0, 0xF6, 0xEE, 0x1C, 0xC8, 0xE5, 0x17, 0xFD, 0x0C, 0x0D, + 0xF5, 0xEE, 0xE8, 0x1B, 0x0D, 0xFB, 0x09, 0xF0, 0xE9, 0x0A, + 0x2F, 0xDA, 0x05, 0xE5, 0xFE, 0x12, 0xEE, 0x0C, 0xFB, 0x29, + 0xF8, 0xE5, 0xEA, 0x1C, 0xF4, 0xFF, 0x0C, 0xFB, 0x1E, 0xD5, + 0x03, 0xF9, 0xFC, 0xF9, 0x21, 0xFC, 0xD4, 0xF8, 0x18, 0x04, + 0xE3, 0xF5, 0xE1, 0x14, 0xF8, 0x17, 0x26, 0xEA, 0x15, 0x00, + 0xEA, 0xF0, 0x03, 0xF7, 0x01, 0xE4, 0x4A, 0xFD, 0xF5, 0xE8, + 0x18, 0x29, 0xF8, 0x0E, 0xFD, 0xF2, 0x12, 0x0A, 0xE5, 0x06, + 0x34, 0x07, 0x14, 0xF7, 0xE9, 0xE1, 0x1B, 0xF0, 0xE4, 0x26, + 0x18, 0x09, 0x01, 0x0B, 0xE9, 0xE3, 0x0D, 0xD1, 0xF3, 0x27, + 0x10, 0xF5, 0x05, 0xFA, 0x15, 0xCB, 0xDB, 0x04, 0xF7, 0xF9, + 0x22, 0x11, 0x1F, 0x1F, 0x00, 0x0B, 0x0F, 0x0C, 0x03, 0xF9, + 0xF6, 0x0C, 0xDD, 0xFB, 0xFD, 0xDB, 0x1F, 0xF9, 0x09, 0xF5, + 0x1A, 0x14, 0xFB, 0x06, 0x17, 0xF3, 0x23, 0x10, 0xFF, 0x07, + 0xE8, 0xF4, 0x02, 0x01, 0xDF, 0x17, 0x22, 0xFB, 0xD5, 0x1A, + 0xE0, 0xF2, 0x02, 0xFB, 0xEF, 0xDD, 0xE8, 0x25, 0xEE, 0xED, + 0xCB, 0x09, 0x0E, 0xEF, 0x11, 0x0C, 0xBD, 0xDD, 0x1A, 0xF5, + 0x0A, 0xD5, 0x03, 0x1F, 0x1E, 0x1E, 0xD1, 0xF6, 0x0C, 0xE8, + 0xED, 0x0D, 0x13, 0xE8, 0x29, 0xF5, 0x0A, 0x2D, 0x04, 0xF3, + 0xF6, 0x15, 0xFB, 0xD8, 0xFC, 0xC7, 0xEA, 0x0A, 0x15, 0xE7, + 0xF2, 0x3D, 0x05, 0x1A, 0xF1, 0xFC, 0x14, 0x02, 0xDD, 0x26, + 0xF0, 0xEE, 0x02, 0x02, 0x08, 0x14, 0xED, 0x02, 0xD7, 0x0A, + 0x0F, 0x00, 0xFA, 0xFA, 0x0A, 0x05, 0xF9, 0x11, 0x0C, 0x1B, + 0x06, 0x0B, 0x2C, 0xDA, 0x13, 0x12, 0x0C, 0x0B, 0x29, 0xDD, + 0xF8, 0xD1, 0xF3, 0xFE, 0x23, 0x0D, 0xEB, 0xED, 0xF0, 0x0F, + 0x43, 0xC6, 0xD1, 0x01, 0xDB, 0x01, 0xE7, 0x13, 0xF2, 0xD9, + 0xF4, 0x0A, 0x0A, 0x04, 0xE6, 0x11, 0x36, 0x0B, 0xE0, 0x18, + 0xDE, 0xC4, 0x18, 0x05, 0x1A, 0xF4, 0xDC, 0xF6, 0x1B, 0xF8, + 0xFD, 0x02, 0x30, 0x1A, 0x1A, 0x0E, 0xEC, 0x07, 0x1B, 0xE8, + 0x30, 0x10, 0xF9, 0xE4, 0x05, 0x02, 0x05, 0x03, 0xEC, 0x07, + 0x0E, 0xFE, 0x0C, 0xEF, 0x05, 0xD6, 0xD1, 0x02, 0x18, 0xE0, + 0xE1, 0xCC, 0x12, 0xF6, 0xF6, 0xF3, 0x0D, 0x27, 0x0F, 0x37, + 0x3A, 0x1A, 0x0B, 0x1C, 0xC8, 0xDC, 0x06, 0x29, 0x04, 0x01, + 0xFC, 0x05, 0x1A, 0x23, 0xFD, 0xEF, 0x18, 0x36, 0x0E, 0x1D, + 0x06, 0xF2, 0xFC, 0x0D, 0x15, 0x1F, 0x2B, 0xD6, 0xE0, 0x18, + 0x10, 0xF4, 0x0C, 0x0B, 0x23, 0x15, 0x11, 0x05, 0xF1, 0x28, + 0xFA, 0xF2, 0x05, 0xEA, 0x13, 0xE0, 0xFB, 0x07, 0x0C, 0xF8, + 0x12, 0x29, 0xEE, 0x19, 0xD6, 0xE7, 0x15, 0xCD, 0xFF, 0x03, + 0x40, 0xEB, 0xF5, 0x1E, 0x0E, 0xE7, 0xE7, 0xF1, 0xFA, 0x23, + 0xF8, 0x18, 0x06, 0x10, 0xEF, 0x16, 0x05, 0x01, 0xEB, 0x21, + 0x08, 0xFF, 0xF9, 0xDA, 0xEE, 0x01, 0xF8, 0xE4, 0x10, 0xFC, + 0xDD, 0x19, 0xFE, 0xFA, 0xF2, 0xE0, 0x0E, 0x42, 0xFD, 0xDC, + 0x1B, 0xF2, 0xE2, 0xEF, 0x33, 0x0C, 0x0F, 0xDE, 0x03, 0xF6, + 0x1C, 0xDF, 0xD7, 0xD9, 0xF4, 0x08, 0xDD, 0xE8, 0xDB, 0xEE, + 0x1F, 0xF2, 0x26, 0xF3, 0x02, 0xF3, 0x2E, 0x07, 0x09, 0xFD, + 0xE8, 0x10, 0x03, 0x0B, 0xCC, 0x0A, 0xFB, 0x3D, 0xF9, 0xF1, + 0x04, 0xF0, 0x15, 0xFB, 0x13, 0xEF, 0xFC, 0xBB, 0x0D, 0xDC, + 0xE9, 0xE8, 0x01, 0xFD, 0xDB, 0x10, 0x08, 0x14, 0x08, 0xDB, + 0x14, 0xF9, 0x16, 0x1A, 0xEA, 0x22, 0xF6, 0xF3, 0x32, 0xEE, + 0x10, 0xF8, 0x06, 0x04, 0x05, 0xE6, 0xFF, 0x38, 0x0E, 0xF7, + 0x2E, 0xEB, 0xE0, 0xF6, 0x19, 0xEE, 0xD8, 0x1A, 0x26, 0x01, + 0x1A, 0x00, 0xF3, 0x0C, 0x1B, 0x30, 0x18, 0xF0, 0x1A, 0xF4, + 0xF8, 0x3D, 0xE9, 0xEF, 0xE4, 0xE9, 0x05, 0xC7, 0x06, 0xF5, + 0xFF, 0x11, 0x38, 0xF4, 0xF8, 0xEF, 0xE3, 0x19, 0x05, 0xD6, + 0xDE, 0xF9, 0xDD, 0xF0, 0x0D, 0x09, 0x0F, 0x0C, 0x1D, 0x81, + 0x82, 0x07, 0x01, 0x0A, 0x34, 0x51, 0x9B, 0x39, 0xF7, 0xA3, + 0x68, 0xBF, 0x74, 0x68, 0x56, 0x19, 0x2C, 0x01, 0x5F, 0xE1, + 0x67, 0x4B, 0x2C, 0x45, 0x3B, 0x10, 0xFD, 0x76, 0xB9, 0xF0, + 0x52, 0x58, 0x11, 0x89, 0xB3, 0xB4, 0x30, 0xD1, 0x85, 0x4C, + 0xC1, 0x27, 0xC0, 0xA1, 0x8D, 0x54, 0x09, 0xFC, 0xF5, 0xD4, + 0x6A, 0xDE, 0x2D, 0x18, 0x88, 0x00, 0x57, 0x2D, 0x9C, 0x3B, + 0x25, 0xAA, 0xC9, 0xFA, 0xA4, 0xE7, 0xC6, 0x38, 0xEC, 0xE2, + 0x86, 0x1F, 0xD0, 0x18, 0x5F, 0x20, 0xCF, 0xE3, 0xAA, 0x4C, + 0x9F, 0x68, 0x69, 0xE5, 0x10, 0x43, 0xD7, 0xA3, 0x28, 0x12, + 0x1E, 0xA2, 0xA6, 0xD1, 0xE1, 0x1D, 0x30, 0xAD, 0xF6, 0xDF, + 0x82, 0x63, 0x88, 0xBA, 0x73, 0xD3, 0x8B, 0xAE, 0x50, 0x68, + 0x26, 0x81, 0x1A, 0x2D, 0x1F, 0x29, 0x98, 0x25, 0x9E, 0xE0, + 0x71, 0x8D, 0x62, 0x35, 0xAD, 0x91, 0x7A, 0x85, 0x2F, 0x31, + 0xBD, 0x2D, 0x78, 0xD4, 0x26, 0x60, 0xBA, 0xA0, 0x5A, 0xE3, + 0xB0, 0xDB, 0x5A, 0xF7, 0x4F, 0x4E, 0xAB, 0x44, 0x2E, 0x4B, + 0xF8, 0x69, 0xB6, 0x53, 0x19, 0x49, 0xA4, 0x9F, 0x5B, 0x5E, + 0x2B, 0x59, 0x25, 0x15, 0xB2, 0x12, 0xED, 0x06, 0x92, 0x47, + 0x46, 0x35, 0xB1, 0xA6, 0x15, 0xF9, 0x6E, 0x1D, 0x75, 0x7F, + 0xA0, 0x1F, 0x55, 0x44, 0xCD, 0x9A, 0x1F, 0x0C, 0x1E, 0x90, + 0x59, 0x40, 0x9A, 0x55, 0x09, 0xE7, 0x41, 0x87, 0x98, 0x7C, + 0x0A, 0xE2, 0xA9, 0xB4, 0x8C, 0xE2, 0x0E, 0x3A, 0x28, 0x88, + 0x58, 0xF1, 0x91, 0x73, 0x02, 0x01, 0x6C, 0xE9, 0xF3, 0x0B, + 0x40, 0x0A, 0xD8, 0x91, 0x63, 0xF6, 0xA4, 0x5F, 0x82, 0x76, + 0x18, 0xB4, 0x2C, 0xC8, 0xF2, 0x3A, 0xAE, 0x77, 0x19, 0x30, + 0x16, 0x54, 0x4E, 0x82, 0x7F, 0x37, 0xF4, 0xC8, 0x01, 0x3D, + 0x65, 0xF8, 0xA8, 0x9D, 0x44, 0x93, 0x62, 0x85, 0x04, 0xAB, + 0xB0, 0x95, 0x34, 0xA7, 0xF5, 0x64, 0x1A, 0xD5, 0x2D, 0x91, + 0x45, 0x71, 0xE1, 0x26, 0xF5, 0xC8, 0xC7, 0x7F, 0x6E, 0xC5, + 0xB6, 0xE7, 0x9B, 0x41, 0x10, 0x44, 0x76, 0x9A, 0x7A, 0xCE, + 0x66, 0x84, 0x5E, 0xC6, 0x76, 0xBC, 0xC1, 0xDA, 0x63, 0x52, + 0x04, 0x1A, 0xC7, 0x51, 0x12, 0x86, 0xBD, 0xF3, 0xF3, 0xCF, + 0xEA, 0xD8, 0x5B, 0x6D, 0x70, 0xD9, 0x82, 0x59, 0x48, 0x21, + 0x58, 0x1E, 0xA8, 0xC9, 0xE1, 0x77, 0x28, 0x9A, 0x6C, 0x17, + 0x76, 0xDA, 0x55, 0x16, 0x82, 0xB3, 0xB0, 0x69, 0xE3, 0xAF, + 0x56, 0x15, 0x28, 0xC2, 0x6A, 0x15, 0xCF, 0x28, 0x5E, 0xBA, + 0x87, 0xDC, 0x13, 0x0D, 0x32, 0xA2, 0x80, 0x97, 0x9A, 0x84, + 0xFF, 0x5B, 0x2D, 0x63, 0x15, 0x58, 0x55, 0xB3, 0x7D, 0x46, + 0xD6, 0xFA, 0x02, 0x06, 0x9D, 0x98, 0xEA, 0x6E, 0x95, 0x37, + 0xE5, 0x39, 0x0D, 0x42, 0xBF, 0xC8, 0xF0, 0xDC, 0x5C, 0x12, + 0xB0, 0xC9, 0xF3, 0xE4, 0xA3, 0xE1, 0x76, 0x98, 0x0D, 0x17, + 0xF5, 0x0D, 0xBF, 0x7C, 0x1D, 0x89, 0x64, 0x04, 0x8C, 0x37, + 0x64, 0x9D, 0x43, 0x71, 0x94, 0x54, 0x16, 0x5A, 0xD2, 0x3B, + 0xD7, 0x8E, 0x4A, 0xAA, 0x5C, 0xB5, 0xE8, 0x05, 0x9B, 0xA5, + 0xB5, 0x95, 0xC5, 0x6D, 0xF2, 0xEB, 0x08, 0xCE, 0x4C, 0x86, + 0x53, 0xA7, 0xC3, 0x44, 0x40, 0x4D, 0x64, 0x4B, 0xE7, 0xF5, + 0x6C, 0x62, 0x31, 0x35, 0xC3, 0x12, 0x15, 0x2D, 0x9A, 0x88, + 0xE9, 0x24, 0x19, 0x6B, 0xC1, 0xCF, 0x0D, 0xB8, 0x15, 0x44, + 0x04, 0xC9, 0x28, 0x75, 0xCE, 0xC0, 0x26, 0x19, 0xDB, 0xC6, + 0x40, 0xF1, 0x80, 0x74, 0xE0, 0x62, 0x3E, 0x77, 0x86, 0xC1, + 0x32, 0x12, 0xC0, 0x44, 0x17, 0x49, 0x7A, 0xDA, 0x46, 0xE2, + 0xF8, 0x70, 0xC5, 0x59, 0x76, 0xBE, 0xDB, 0xBA, 0x4F, 0x1D, + 0x21, 0x42, 0x5E, 0x5B, 0xED, 0x5A, 0xFA, 0x44, 0x44, 0x66, + 0x8D, 0x5C, 0xA0, 0x22, 0xE2, 0xD7, 0x7D, 0x6E, 0xAD, 0x72, + 0x41, 0xF3, 0xE1, 0x28, 0xD9, 0x6A, 0x5A, 0xFA, 0x10, 0xAA, + 0x1C, 0xC3, 0x98, 0x64, 0x44, 0x35, 0x06, 0x21, 0x6C, 0x5C, + 0x8C, 0x24, 0x6C, 0x39, 0xC8, 0x06, 0xE4, 0x6C, 0x41, 0x59, + 0x0A, 0x8A, 0x8B, 0x73, 0xB7, 0x9C, 0x87, 0x74, 0xFD, 0xD0, + 0x88, 0xA6, 0x2C, 0x41, 0xD5, 0xC7, 0xC6, 0x55, 0x59, 0xEA, + 0xBB, 0x07, 0x83, 0x54, 0xDC, 0x8E, 0x4D, 0xB5, 0x5A, 0xA9, + 0x24, 0x73, 0x01, 0x62, 0x33, 0x78, 0x56, 0x46, 0x70, 0x97, + 0xF6, 0xC5, 0xA9, 0x9D, 0xA3, 0xB7, 0x5D, 0x4A, 0x71, 0xB3, + 0xB6, 0xA3, 0x64, 0xA8, 0xF5, 0x24, 0x77, 0x62, 0x19, 0x2F, + 0xA7, 0xD0, 0x3B, 0x50, 0x24, 0x28, 0x3E, 0x20, 0xF6, 0xA5, + 0x05, 0x8D, 0x40, 0x41, 0x27, 0x79, 0x13, 0xBB, 0x93, 0x48, + 0x76, 0x2E, 0x8C, 0xBC, 0xB7, 0xC6, 0xDC, 0x8A, 0xAD, 0xBD, + 0xB4, 0x82, 0x5D, 0x5C, 0xBE, 0x8A, 0x3C, 0x0D, 0x59, 0x81, + 0x82, 0x2E, 0x01, 0xFD, 0xFE, 0xCA, 0x3E, 0x4D, 0x9D, 0x6A, + 0xD5, 0x93, 0xB5, 0x84, 0x22, 0xFF, 0x08, 0x61, 0xF7, 0x80, + 0xAF, 0xDB, 0x7B, 0xBE, 0xD0, 0xB8, 0x68, 0xB6, 0x90, 0x4C, + 0xA9, 0xC4, 0x66, 0x35, 0x41, 0xA3, 0xA4, 0x0D, 0x94, 0x68, + 0x44, 0x0B, 0x91, 0x39, 0xA9, 0x05, 0xF8, 0xE6, 0xD9, 0x22, + 0xF0, 0x30, 0xDE, 0xE3, 0x18, 0xD9, 0xC5, 0x0F, 0xB5, 0x91, + 0x10, 0x52, 0xEB, 0x20, 0xED, 0x94, 0x2C, 0xC8, 0x6B, 0x0D, + 0xA1, 0x44, 0x63, 0x78, 0xFF, 0xD6, 0xAF, 0x8E, 0xE6, 0x01, + 0xD6, 0xB0, 0xF7, 0x8D, 0x67, 0x24, 0x99, 0x0E, 0x91, 0x48, + 0xA6, 0x0F, 0xB7, 0x24, 0xA4, 0x63, 0x34, 0x8B, 0x90, 0x3E, + 0xAB, 0x6A, 0xD7, 0x84, 0xB6, 0x29, 0xCF, 0xA6, 0x48, 0xF6, + 0xF1, 0xFF, 0x06, 0x9C, 0x27, 0xF4, 0x71, 0x67, 0xCF, 0xAB, + 0xD6, 0x6F, 0xC4, 0x63, 0x70, 0xA3, 0x2E, 0x66, 0x15, 0x3A, + 0x3F, 0xB8, 0x52, 0x6F, 0x9D, 0x83, 0x71, 0x22, 0x08, 0xE9, + 0xDC, 0xCE, 0xB0, 0xB9, 0x71, 0x30, 0x96, 0x8F, 0xB5, 0x8F, + 0x90, 0xBB, 0x62, 0xD2, 0xDE, 0xA7, 0xB3, 0x2E, 0x2D, 0x45, + 0xDA, 0x15, 0x6E, 0x43, 0x39, 0x6A, 0xB1, 0x65, 0xA7, 0x7D, + 0x48, 0xFA, 0xEB, 0xC6, 0x7A, 0x22, 0x16, 0x9B, 0xF9, 0xBB, + 0x15, 0x0E, 0xC6, 0x2A, 0x24, 0xDA, 0x5E, 0x24, 0xCB, 0xC6, + 0x28, 0x5D, 0x80, 0x04, 0x41, 0x15, 0x17, 0xCE, 0xB9, 0xB1, + 0x66, 0x17, 0x28, 0x91, 0x38, 0x26, 0x94, 0xAE, 0x54, 0x11, + 0xD9, 0xEC, 0x49, 0xFC, 0x5C, 0x7A, 0x13, 0xC7, 0x33, 0xBB, + 0x80, 0xC2, 0x64, 0x49, 0xC4, 0xFD, 0x69, 0xE9, 0x3B, 0xE4, + 0x20, 0x1F, 0x16, 0x1C, 0x1D, 0x44, 0xB9, 0x28, 0x03, 0x07, + 0x21, 0xC1, 0x07, 0xC9, 0x9E, 0x67, 0x43, 0x95, 0x1D, 0xBC, + 0x47, 0x9D, 0x84, 0xE2, 0x75, 0x8A, 0x4C, 0x96, 0xBC, 0x4C, + 0x33, 0x62, 0x9E, 0x81, 0x22, 0x84, 0x85, 0xE7, 0x70, 0x46, + 0x7B, 0xB7, 0xBE, 0xE0, 0xC5, 0x26, 0x01, 0x3D, 0x22, 0x3D, + 0xA7, 0x22, 0x80, 0x7A, 0xBF, 0xD5, 0x7D, 0x49, 0x0E, 0x2A, + 0x39, 0x79, 0xA9, 0x57, 0xE7, 0xFE, 0x30, 0x3E, 0x10, 0xE6, + 0x66, 0x16, 0x2E, 0xA3, 0x95, 0xA9, 0xD5, 0xBD, 0xAE, 0x33, + 0x70, 0xB6, 0x42, 0x20, 0x1F, 0x4E, 0xC5, 0x21, 0x26, 0x3C, + 0x14, 0x5B, 0xC1, 0x2C, 0x06, 0xA9, 0x59, 0xAB, 0x1A, 0x5D, + 0xDE, 0x67, 0x42, 0xBA, 0x73, 0x61, 0x4B, 0x16, 0x00, 0x29, + 0x3A, 0x4A, 0xBD, 0xE7, 0x2A, 0x92, 0x36, 0xD9, 0xA9, 0x18, + 0x0C, 0x3E, 0x0C, 0x50, 0x2B, 0xF6, 0x48, 0xDB, 0x2A, 0x0B, + 0x4E, 0x15, 0x7A, 0x6D, 0xA5, 0x0C, 0x54, 0xB6, 0x56, 0x9A, + 0xEF, 0x18, 0x48, 0x5B, 0x4C, 0x7C, 0xF2, 0x02, 0xDA, 0x81, + 0xB7, 0x90, 0xEE, 0xD5, 0x51, 0xA5, 0x25, 0x73, 0x4A, 0x83, + 0x5A, 0xE2, 0xCB, 0xEE, 0xAC, 0xD2, 0xE0, 0x84, 0x0E, 0x80, + 0xB2, 0x4C, 0xF1, 0x2F, 0x37, 0x99, 0xAD, 0xA4, 0x37, 0xEC, + 0xD0, 0xB1, 0x9C, 0xD8, 0xFD, 0x7E, 0x9A, 0x15, 0xB9, 0x47, + 0xEC, 0x2A, 0x32, 0x0E, 0x90, 0x63, 0xB7, 0xC0, 0x1F, 0x6C, + 0x48, 0x85, 0x41, 0x5E, 0xCE, 0x22, 0x68, 0xAD, 0x7D, 0xEA, + 0x9B, 0x99, 0x3D, 0x9B, 0xD6, 0xAC, 0x23, 0x20, 0x00, 0x54, + 0x7E, 0x72, 0x63, 0x66, 0x55, 0x2D, 0xCC, 0x27, 0x79, 0xE4, + 0x58, 0x61, 0xC0, 0xDE, 0x6A, 0xD8, 0x3B, 0x41, 0xD1, 0xA1, + 0x11, 0xAE, 0x21, 0x4A, 0xB3, 0x87, 0xDC, 0x45, 0xA2, 0x4D, + 0xC0, 0xE7, 0x28, 0xCF, 0x20, 0x89, 0xBA, 0xE8, 0xE3, 0x47, + 0x68, 0x84, 0x89, 0x95, 0x2B, 0xFA, 0x14, 0x5A, 0xB9, 0x2E, + 0x7C, 0xEE, 0x09, 0x6D, 0x8C, 0x02, 0xB5, 0xDC, 0xCF, 0x94, + 0xE4, 0xE8, 0xB0, 0x6E, 0xC4, 0x2A, 0x47, 0x26, 0x10, 0xC3, + 0xB3, 0xD6, 0xAE, 0x38, 0xAF, 0x22, 0x57, 0x26, 0x31, 0x7A, + 0xF7, 0x0D, 0x29, 0x5B, 0x40, 0xF9, 0x38, 0xA1, 0xCF, 0x95, + 0xD9, 0x71, 0xAC, 0x42, 0x74, 0x4D, 0x5E, 0xAD, 0x80, 0x36, + 0xAF, 0xA6, 0x63, 0xE2, 0x38, 0x81, 0x09, 0x2C, 0x50, 0x98, + 0x60, 0xE2, 0x19, 0x30, 0x72, 0x48, 0x88, 0xE1, 0x59, 0x6F, + 0x28, 0x13, 0xA6, 0x56, 0x90, 0x53, 0x51, 0xE8, 0x4B, 0x31, + 0xFC, 0x67, 0x14, 0x62, 0x2D, 0x9F, 0xBA, 0xED, 0x52, 0x0A, + 0x9A, 0x20, 0x8B, 0xAB, 0xF4, 0xA1, 0x9D, 0xB4, 0xE1, 0xDE, + 0x65, 0x1B, 0x6F, 0x97, 0x9E, 0x58, 0xEC, 0xB3, 0xEF, 0x1E, + 0x40, 0xAD, 0x22, 0x11, 0x89, 0x1D, 0xE2, 0x6D, 0xB8, 0x0C, + 0xAA, 0x82, 0x95, 0xE9, 0xDB, 0x94, 0x6E, 0xDA, 0x66, 0xBB, + 0x43, 0x89, 0x99, 0x36, 0x06, 0xB6, 0x60, 0xD3, 0x64, 0x56, + 0x32, 0x72, 0xE4, 0xEF, 0x2B, 0xF8, 0x83, 0x9E, 0x22, 0x88, + 0xEA, 0xC4, 0xAD, 0x49, 0x2C, 0x39, 0xF1, 0x65, 0x90, 0xF8, + 0x3A, 0x3A, 0x6F, 0x67, 0xFC, 0xE0, 0x40, 0x6F, 0x9A, 0xA1, + 0x84, 0x6F, 0x07, 0x1C, 0x04, 0x31, 0x52, 0xF6, 0x59, 0x9B, + 0xC1, 0x27, 0xD8, 0x6B, 0xA0, 0x94, 0xD8, 0x47, 0x9C, 0x80, + 0xB1, 0xCA, 0xC3, 0xC8, 0x8E, 0x9F, 0x62, 0x2E, 0x30, 0x1A, + 0x13, 0x60, 0x8B, 0xF0, 0x0C, 0x60, 0x29, 0x0F, 0x7A, 0xA1, + 0x0D, 0xFE, 0x60, 0x34, 0x14, 0x12, 0xA8, 0x51, 0x09, 0xE7, + 0x7E, 0x4C, 0x71, 0x87, 0x96, 0x81, 0x70, 0x7F, 0xDB, 0x6D, + 0x21, 0xBC, 0x80, 0x76, 0x00, 0x27, 0x56, 0x95, 0xF5, 0xA1, + 0x94, 0xF2, 0xC9, 0x95, 0x27, 0x26, 0x41, 0x67, 0xEE, 0x49, + 0x09, 0x89, 0xE0, 0xFF, 0x96, 0x22, 0xE1, 0x38, 0x05, 0xBE, + 0x89, 0xF0, 0xFE, 0x2F, 0x63, 0x2C, 0xC0, 0x43, 0x54, 0x9D, + 0x0B, 0x7E, 0xB7, 0xED, 0x66, 0x42, 0x45, 0x96, 0xC3, 0x5F, + 0x6D, 0x3A, 0x11, 0xF8, 0x56, 0x33, 0x8A, 0xE9, 0x48, 0x27, + 0x2B, 0x10, 0xEF, 0x7E, 0x82, 0x75, 0x70, 0xC5, 0x67, 0x0E, + 0x77, 0x9C, 0xBC, 0xD4, 0x58, 0xC2, 0x84, 0x11, 0xDC, 0xA3, + 0x90, 0x77, 0x43, 0x81, 0x77, 0xFC, 0x33, 0x18, 0xEB, 0x9F, + 0xEC, 0x18, 0x05, 0x83, 0x56, 0xBF, 0x2B, 0x51, 0x2A, 0x04, + 0xE6, 0x14, 0xA0, 0xE9, 0x89, 0x57, 0xD4, 0xFF, 0x63, 0xFA, + 0x62, 0x40, 0x37, 0x60, 0x1A, 0xE7, 0x67, 0x2F, 0x0A, 0x37, + 0x25, 0x93, 0xF2, 0x90, 0xC8, 0xA1, 0x3B, 0x2A, 0x0A, 0x4B, + 0xE9, 0x1A, 0x8D, 0xBD, 0x61, 0x5B, 0xF9, 0xD5, 0xDD, 0x0B, + 0x91, 0xCC, 0x79, 0xEB, 0xD2, 0x4A, 0xA6, 0x79, 0x06, 0x84, + 0xE6, 0x0A, 0xAB, 0xA5, 0x3E, 0x8E, 0xC7, 0xE4, 0x72, 0x51, + 0xCA, 0x90, 0x62, 0x07, 0x61, 0xDC, 0x2B, 0x18, 0x72, 0xE6, + 0x15, 0x54, 0x6F, 0x82, 0x29, 0x49, 0x5D, 0x0D, 0xE5, 0x4B, + 0xDC, 0x75, 0xB2, 0x56, 0x7B, 0x4B, 0x62, 0x8E, 0x04, 0x16, + 0xF6, 0x16, 0x55, 0x16, 0x10, 0xBD, 0x69, 0x81, 0x08, 0x00, + 0x79, 0xCB, 0x23, 0x02, 0x4A, 0x87, 0x34, 0x2B, 0x49, 0xC2, + 0x0B, 0xEC, 0x31, 0xC2, 0x0D, 0x65, 0x12, 0x55, 0xE8, 0x70, + 0x58, 0xD3, 0x08, 0xF9, 0x3E, 0x72, 0xA6, 0x79, 0x05, 0xA6, + 0x0A, 0x92, 0x4C, 0xE5, 0xAB, 0xB1, 0x2A, 0x76, 0x3B, 0xBD, + 0xDF, 0x25, 0xF4, 0x93, 0x8B, 0x74, 0x3D, 0x4D, 0x8A, 0x67, + 0x64, 0x2B, 0x7B, 0x84, 0xAD, 0x1A, 0xDD, 0x27, 0xF7, 0x8A, + 0x9E, 0x26, 0x22, 0x55, 0xDC, 0x43, 0x75, 0xAC, 0xAE, 0x61, + 0xD5, 0x15, 0xCF, 0xA0, 0x70, 0xAA, 0xE2, 0xB7, 0xA8, 0xA2, + 0x21, 0xC0, 0xBF, 0x28, 0xFD, 0xCA, 0x84, 0x79, 0x95, 0xB8, + 0x84, 0xB4, 0x05, 0xB9, 0xA0, 0x61, 0xFC, 0x32, 0x76, 0x68, + 0xED, 0x3C, 0x59, 0xBE, 0x90, 0x8A, 0xE7, 0x6C, 0x73, 0x71, + 0xC8, 0xD0, 0xC7, 0xE0, 0x6F, 0x4E, 0x04, 0x6E, 0x0B, 0x85, + 0x8C, 0x8F, 0x5C, 0x76, 0x83, 0x9A, 0xE9, 0x99, 0xC8, 0x16, + 0x02, 0x50, 0x03, 0xF4, 0x1E, 0x60, 0x38, 0x19, 0x0A, 0xC8, + 0xCF, 0x4E, 0xB9, 0x2D, 0x09, 0x5B, 0xDA, 0x6C, 0xEC, 0xA9, + 0x46, 0x8C, 0x1C, 0xA1, 0x1F, 0xDF, 0x38, 0x62, 0x52, 0xFE, + 0xC1, 0xFE, 0xD6, 0x03, 0x1F, 0xF5, 0x34, 0xF8, 0x15, 0x03, + 0x66, 0xB0, 0x2D, 0xF6, 0x64, 0xB3, 0x6B, 0x23, 0xA7, 0x92, + 0xDB, 0x71, 0xE3, 0xA4, 0xAB, 0x7A, 0x78, 0xCB, 0x08, 0x65, + 0x58, 0x13, 0x6F, 0x3D, 0x78, 0x92, 0xC4, 0x54, 0x16, 0x58, + 0x38, 0x27, 0xE6, 0x0F, 0xDA, 0x30 }; #define sizeof_bench_falcon_level5_key (sizeof(bench_falcon_level5_key)) diff --git a/wolfssl/internal.h b/wolfssl/internal.h index c4582e03b2..6eaefa8939 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1776,9 +1776,9 @@ enum Misc { /* These values for falcon match what OQS has defined. */ FALCON_LEVEL1_SA_MAJOR = 0xFE, - FALCON_LEVEL1_SA_MINOR = 0xAE, + FALCON_LEVEL1_SA_MINOR = 0xD7, FALCON_LEVEL5_SA_MAJOR = 0xFE, - FALCON_LEVEL5_SA_MINOR = 0xB1, + FALCON_LEVEL5_SA_MINOR = 0xDA, /* these values for MLDSA (Dilithium) correspond to what is proposed in the * IETF. */ diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 4755cbfb87..112f5e89cc 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -1037,7 +1037,7 @@ enum SNICbReturn { /* Maximum master key length (SECRET_LEN) */ #define WOLFSSL_MAX_MASTER_KEY_LENGTH 48 /* Maximum number of groups that can be set */ -#ifdef HAVE_PQC +#ifdef WOLFSSL_HAVE_MLKEM #define WOLFSSL_MAX_GROUP_COUNT 36 #else #define WOLFSSL_MAX_GROUP_COUNT 10 @@ -4767,7 +4767,7 @@ enum { WOLFSSL_FFDHE_8192 = 260, WOLFSSL_FFDHE_END = 511, -#ifdef HAVE_PQC +#ifdef WOLFSSL_HAVE_MLKEM #ifdef WOLFSSL_MLKEM_KYBER /* Old code points to keep compatibility with Kyber Round 3. @@ -4817,7 +4817,7 @@ enum { WOLFSSL_X25519MLKEM512 = 12214, WOLFSSL_X448MLKEM768 = 12215, #endif /* WOLFSSL_NO_ML_KEM */ -#endif /* HAVE_PQC */ +#endif /* WOLFSSL_HAVE_MLKEM */ WOLF_ENUM_DUMMY_LAST_ELEMENT(SSL_H) }; diff --git a/wolfssl/wolfcrypt/cryptocb.h b/wolfssl/wolfcrypt/cryptocb.h index 710b522b9e..a9fb827e59 100644 --- a/wolfssl/wolfcrypt/cryptocb.h +++ b/wolfssl/wolfcrypt/cryptocb.h @@ -78,12 +78,7 @@ #include #endif #ifdef WOLFSSL_HAVE_MLKEM - #include -#ifdef WOLFSSL_WC_MLKEM #include -#elif defined(HAVE_LIBOQS) - #include -#endif #endif #if defined(HAVE_DILITHIUM) #include diff --git a/wolfssl/wolfcrypt/dilithium.h b/wolfssl/wolfcrypt/dilithium.h index 71ae96ce68..defd1c8a6a 100644 --- a/wolfssl/wolfcrypt/dilithium.h +++ b/wolfssl/wolfcrypt/dilithium.h @@ -37,11 +37,6 @@ #if defined(HAVE_DILITHIUM) -#ifdef HAVE_LIBOQS -#include -#include -#endif - #if defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) && \ defined(WOLFSSL_DILITHIUM_NO_SIGN) && \ !defined(WOLFSSL_DILITHIUM_NO_VERIFY) && \ @@ -73,12 +68,10 @@ #define WOLFSSL_DILITHIUM_CHECK_KEY #endif -#ifdef WOLFSSL_WC_DILITHIUM - #include +#include #ifndef WOLFSSL_DILITHIUM_VERIFY_ONLY #include #endif -#endif #if defined(WC_DILITHIUM_CACHE_PRIV_VECTORS) && \ !defined(WC_DILITHIUM_CACHE_MATRIX_A) @@ -95,8 +88,6 @@ /* Macros Definitions */ -#ifdef WOLFSSL_WC_DILITHIUM - #ifndef WOLFSSL_DILITHIUM_ALIGNMENT #if defined(__arch64__) #define WOLFSSL_DILITHIUM_ALIGNMENT 8 @@ -589,100 +580,6 @@ #endif -#elif defined(HAVE_LIBOQS) - -#define DILITHIUM_LEVEL2_KEY_SIZE OQS_SIG_ml_dsa_44_ipd_length_secret_key -#define DILITHIUM_LEVEL2_SIG_SIZE OQS_SIG_ml_dsa_44_ipd_length_signature -#define DILITHIUM_LEVEL2_PUB_KEY_SIZE OQS_SIG_ml_dsa_44_ipd_length_public_key -#define DILITHIUM_LEVEL2_PRV_KEY_SIZE \ - (DILITHIUM_LEVEL2_PUB_KEY_SIZE+DILITHIUM_LEVEL2_KEY_SIZE) -/* Buffer sizes large enough to store exported DER encoded keys */ -#define DILITHIUM_LEVEL2_PUB_KEY_DER_SIZE 1334 -#define DILITHIUM_LEVEL2_PRV_KEY_DER_SIZE 2588 -#define DILITHIUM_LEVEL2_BOTH_KEY_DER_SIZE 3904 -/* PEM size with the header "-----BEGIN PRIVATE KEY-----" and - * the footer "-----END PRIVATE KEY-----" */ -#define DILITHIUM_LEVEL2_BOTH_KEY_PEM_SIZE 5344 - -#define DILITHIUM_LEVEL3_KEY_SIZE OQS_SIG_ml_dsa_65_ipd_length_secret_key -#define DILITHIUM_LEVEL3_SIG_SIZE OQS_SIG_ml_dsa_65_ipd_length_signature -#define DILITHIUM_LEVEL3_PUB_KEY_SIZE OQS_SIG_ml_dsa_65_ipd_length_public_key -#define DILITHIUM_LEVEL3_PRV_KEY_SIZE \ - (DILITHIUM_LEVEL3_PUB_KEY_SIZE+DILITHIUM_LEVEL3_KEY_SIZE) -/* Buffer sizes large enough to store exported DER encoded keys */ -#define DILITHIUM_LEVEL3_PUB_KEY_DER_SIZE 1974 -#define DILITHIUM_LEVEL3_PRV_KEY_DER_SIZE 4060 -#define DILITHIUM_LEVEL3_BOTH_KEY_DER_SIZE 6016 -/* PEM size with the header "-----BEGIN PRIVATE KEY-----" and - * the footer "-----END PRIVATE KEY-----" */ -#define DILITHIUM_LEVEL3_BOTH_KEY_PEM_SIZE 8204 - -#define DILITHIUM_LEVEL5_KEY_SIZE OQS_SIG_ml_dsa_87_ipd_length_secret_key -#define DILITHIUM_LEVEL5_SIG_SIZE OQS_SIG_ml_dsa_87_ipd_length_signature -#define DILITHIUM_LEVEL5_PUB_KEY_SIZE OQS_SIG_ml_dsa_87_ipd_length_public_key -#define DILITHIUM_LEVEL5_PRV_KEY_SIZE \ - (DILITHIUM_LEVEL5_PUB_KEY_SIZE+DILITHIUM_LEVEL5_KEY_SIZE) -/* Buffer sizes large enough to store exported DER encoded keys */ -#define DILITHIUM_LEVEL5_PUB_KEY_DER_SIZE 2614 -#define DILITHIUM_LEVEL5_PRV_KEY_DER_SIZE 4924 -#define DILITHIUM_LEVEL5_BOTH_KEY_DER_SIZE 7520 -/* PEM size with the header "-----BEGIN ML_DSA_LEVEL5 PRIVATE KEY-----" and - * the footer "-----END ML_DSA_LEVEL5 PRIVATE KEY-----" */ -#define DILITHIUM_LEVEL5_BOTH_KEY_PEM_SIZE 10267 - -#define ML_DSA_LEVEL2_KEY_SIZE OQS_SIG_ml_dsa_44_ipd_length_secret_key -#define ML_DSA_LEVEL2_SIG_SIZE OQS_SIG_ml_dsa_44_ipd_length_signature -#define ML_DSA_LEVEL2_PUB_KEY_SIZE OQS_SIG_ml_dsa_44_ipd_length_public_key -#define ML_DSA_LEVEL2_PRV_KEY_SIZE \ - (ML_DSA_LEVEL2_PUB_KEY_SIZE+ML_DSA_LEVEL2_KEY_SIZE) -/* Buffer sizes large enough to store exported DER encoded keys */ -#define ML_DSA_LEVEL2_PUB_KEY_DER_SIZE DILITHIUM_LEVEL2_PUB_KEY_DER_SIZE -#define ML_DSA_LEVEL2_PRV_KEY_DER_SIZE DILITHIUM_LEVEL2_PRV_KEY_DER_SIZE -#define ML_DSA_LEVEL2_BOTH_KEY_DER_SIZE DILITHIUM_LEVEL2_BOTH_KEY_DER_SIZE -/* PEM size with the header "-----BEGIN PRIVATE KEY-----" and - * the footer "-----END PRIVATE KEY-----" */ -#define ML_DSA_LEVEL2_BOTH_KEY_PEM_SIZE DILITHIUM_LEVEL2_BOTH_KEY_PEM_SIZE - -#define ML_DSA_LEVEL3_KEY_SIZE OQS_SIG_ml_dsa_65_ipd_length_secret_key -#define ML_DSA_LEVEL3_SIG_SIZE OQS_SIG_ml_dsa_65_ipd_length_signature -#define ML_DSA_LEVEL3_PUB_KEY_SIZE OQS_SIG_ml_dsa_65_ipd_length_public_key -#define ML_DSA_LEVEL3_PRV_KEY_SIZE \ - (ML_DSA_LEVEL3_PUB_KEY_SIZE+ML_DSA_LEVEL3_KEY_SIZE) -/* Buffer sizes large enough to store exported DER encoded keys */ -#define ML_DSA_LEVEL3_PUB_KEY_DER_SIZE DILITHIUM_LEVEL3_PUB_KEY_DER_SIZE -#define ML_DSA_LEVEL3_PRV_KEY_DER_SIZE DILITHIUM_LEVEL3_PRV_KEY_DER_SIZE -#define ML_DSA_LEVEL3_BOTH_KEY_DER_SIZE DILITHIUM_LEVEL3_BOTH_KEY_DER_SIZE -/* PEM size with the header "-----BEGIN PRIVATE KEY-----" and - * the footer "-----END PRIVATE KEY-----" */ -#define ML_DSA_LEVEL3_BOTH_KEY_PEM_SIZE DILITHIUM_LEVEL3_BOTH_KEY_PEM_SIZE - -#define ML_DSA_LEVEL5_KEY_SIZE OQS_SIG_ml_dsa_87_ipd_length_secret_key -#define ML_DSA_LEVEL5_SIG_SIZE OQS_SIG_ml_dsa_87_ipd_length_signature -#define ML_DSA_LEVEL5_PUB_KEY_SIZE OQS_SIG_ml_dsa_87_ipd_length_public_key -#define ML_DSA_LEVEL5_PRV_KEY_SIZE \ - (ML_DSA_LEVEL5_PUB_KEY_SIZE+ML_DSA_LEVEL5_KEY_SIZE) -/* Buffer sizes large enough to store exported DER encoded keys */ -#define ML_DSA_LEVEL5_PUB_KEY_DER_SIZE DILITHIUM_LEVEL5_PUB_KEY_DER_SIZE -#define ML_DSA_LEVEL5_PRV_KEY_DER_SIZE DILITHIUM_LEVEL5_PRV_KEY_DER_SIZE -#define ML_DSA_LEVEL5_BOTH_KEY_DER_SIZE DILITHIUM_LEVEL5_BOTH_KEY_DER_SIZE -/* PEM size with the header "-----BEGIN ML_DSA_LEVEL5 PRIVATE KEY-----" and - * the footer "-----END ML_DSA_LEVEL5 PRIVATE KEY-----" */ -#define ML_DSA_LEVEL5_BOTH_KEY_PEM_SIZE DILITHIUM_LEVEL5_BOTH_KEY_PEM_SIZE - -#define DILITHIUM_MAX_KEY_SIZE DILITHIUM_LEVEL5_KEY_SIZE -#define DILITHIUM_MAX_SIG_SIZE DILITHIUM_LEVEL5_SIG_SIZE -#define DILITHIUM_MAX_PUB_KEY_SIZE DILITHIUM_LEVEL5_PUB_KEY_SIZE -#define DILITHIUM_MAX_PRV_KEY_SIZE DILITHIUM_LEVEL5_PRV_KEY_SIZE -/* Buffer sizes large enough to store exported DER encoded keys */ -#define DILITHIUM_MAX_PUB_KEY_DER_SIZE DILITHIUM_LEVEL5_PUB_KEY_DER_SIZE -#define DILITHIUM_MAX_PRV_KEY_DER_SIZE DILITHIUM_LEVEL5_PRV_KEY_DER_SIZE -#define DILITHIUM_MAX_BOTH_KEY_DER_SIZE DILITHIUM_LEVEL5_BOTH_KEY_DER_SIZE -/* PEM size with the header "-----BEGIN ML_DSA_LEVEL5 PRIVATE KEY-----" and - * the footer "-----END ML_DSA_LEVEL5 PRIVATE KEY-----" */ -#define DILITHIUM_MAX_BOTH_KEY_PEM_SIZE DILITHIUM_LEVEL5_BOTH_KEY_PEM_SIZE - -#endif /* HAVE_LIBOQS */ - #ifdef WOLF_PRIVATE_KEY_ID #define DILITHIUM_MAX_ID_LEN 32 @@ -691,7 +588,6 @@ /* Structs */ -#ifdef WOLFSSL_WC_DILITHIUM typedef struct wc_dilithium_params { byte level; byte k; @@ -714,7 +610,6 @@ typedef struct wc_dilithium_params { word16 pkSz; word16 sigSz; } wc_dilithium_params; -#endif struct dilithium_key { byte pubKeySet; @@ -753,7 +648,6 @@ struct dilithium_key { const byte* k; #endif -#ifdef WOLFSSL_WC_DILITHIUM const wc_dilithium_params* params; wc_Shake shake; #ifndef WC_DILITHIUM_FIXED_ARRAY @@ -801,7 +695,6 @@ struct dilithium_key { byte block[DILITHIUM_GEN_C_BLOCK_BYTES]; #endif /* WOLFSSL_DILITHIUM_VERIFY_NO_MALLOC && * WOLFSSL_DILITHIUM_VERIFY_SMALL_MEM */ -#endif /* WOLFSSL_WC_DILITHIUM */ }; #ifndef WC_DILITHIUMKEY_TYPE_DEFINED diff --git a/wolfssl/wolfcrypt/ext_mlkem.h b/wolfssl/wolfcrypt/ext_mlkem.h deleted file mode 100644 index 02ac3bd2d7..0000000000 --- a/wolfssl/wolfcrypt/ext_mlkem.h +++ /dev/null @@ -1,74 +0,0 @@ -/* ext_mlkem.h - * - * Copyright (C) 2006-2026 wolfSSL Inc. - * - * This file is part of wolfSSL. - * - * wolfSSL is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * wolfSSL is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA - */ - -#ifndef EXT_KYBER_H -#define EXT_KYBER_H - -#ifdef WOLF_CRYPTO_CB - #include -#endif - -#ifdef WOLFSSL_HAVE_MLKEM -#include - -#if !defined(HAVE_LIBOQS) -#error "This code requires liboqs" -#endif - -#if defined(WOLFSSL_WC_MLKEM) -#error "This code is incompatible with wolfCrypt's implementation of Kyber." -#endif - -#if defined (HAVE_LIBOQS) - #include - - #ifndef WOLFSSL_NO_ML_KEM - #define EXT_KYBER_MAX_PRIV_SZ OQS_KEM_ml_kem_1024_length_secret_key - #define EXT_KYBER_MAX_PUB_SZ OQS_KEM_ml_kem_1024_length_public_key - #elif defined(WOLFSSL_MLKEM_KYBER) - #define EXT_KYBER_MAX_PRIV_SZ OQS_KEM_kyber_1024_length_secret_key - #define EXT_KYBER_MAX_PUB_SZ OQS_KEM_kyber_1024_length_public_key - #endif -#endif - -struct KyberKey { - /* Type of key: KYBER_LEVEL1 - * KYBER_LEVEL3 - * KYBER_LEVEL5 - * - * Note we don't save the variant (SHAKE vs AES) as that is decided at - * configuration time. */ - int type; - -#ifdef WOLF_CRYPTO_CB - void* devCtx; - int devId; -#endif - - byte priv[EXT_KYBER_MAX_PRIV_SZ]; - byte pub[EXT_KYBER_MAX_PUB_SZ]; -}; - -#if defined (HAVE_LIBOQS) -WOLFSSL_LOCAL int ext_mlkem_enabled(int id); -#endif -#endif /* WOLFSSL_HAVE_MLKEM */ -#endif /* EXT_KYBER_H */ diff --git a/wolfssl/wolfcrypt/falcon.h b/wolfssl/wolfcrypt/falcon.h index 06ded4d6c1..7e0a27a954 100644 --- a/wolfssl/wolfcrypt/falcon.h +++ b/wolfssl/wolfcrypt/falcon.h @@ -35,12 +35,14 @@ #include #endif -#if defined(HAVE_PQC) && defined(HAVE_FALCON) +#if defined(HAVE_FALCON) + +#ifndef HAVE_LIBOQS +#error "HAVE_FALCON requires HAVE_LIBOQS." +#endif -#ifdef HAVE_LIBOQS #include #include -#endif #ifdef __cplusplus extern "C" { @@ -48,7 +50,6 @@ /* Macros Definitions */ -#ifdef HAVE_LIBOQS #define FALCON_LEVEL1_KEY_SIZE OQS_SIG_falcon_512_length_secret_key #define FALCON_LEVEL1_SIG_SIZE OQS_SIG_falcon_512_length_signature #define FALCON_LEVEL1_PUB_KEY_SIZE OQS_SIG_falcon_512_length_public_key @@ -58,7 +59,6 @@ #define FALCON_LEVEL5_SIG_SIZE OQS_SIG_falcon_1024_length_signature #define FALCON_LEVEL5_PUB_KEY_SIZE OQS_SIG_falcon_1024_length_public_key #define FALCON_LEVEL5_PRV_KEY_SIZE (FALCON_LEVEL5_PUB_KEY_SIZE+FALCON_LEVEL5_KEY_SIZE) -#endif #define FALCON_MAX_KEY_SIZE FALCON_LEVEL5_KEY_SIZE #define FALCON_MAX_SIG_SIZE FALCON_LEVEL5_SIG_SIZE @@ -176,5 +176,5 @@ WOLFSSL_API int wc_Falcon_PublicKeyToDer(falcon_key* key, byte* output, } /* extern "C" */ #endif -#endif /* HAVE_PQC && HAVE_FALCON */ +#endif /* HAVE_FALCON */ #endif /* WOLF_CRYPT_FALCON_H */ diff --git a/wolfssl/wolfcrypt/include.am b/wolfssl/wolfcrypt/include.am index 7f07389a07..0e123c2be5 100644 --- a/wolfssl/wolfcrypt/include.am +++ b/wolfssl/wolfcrypt/include.am @@ -77,9 +77,7 @@ nobase_include_HEADERS+= \ wolfssl/wolfcrypt/siphash.h \ wolfssl/wolfcrypt/cpuid.h \ wolfssl/wolfcrypt/cryptocb.h \ - wolfssl/wolfcrypt/mlkem.h \ wolfssl/wolfcrypt/wc_mlkem.h \ - wolfssl/wolfcrypt/ext_mlkem.h \ wolfssl/wolfcrypt/sm2.h \ wolfssl/wolfcrypt/sm3.h \ wolfssl/wolfcrypt/sm4.h \ diff --git a/wolfssl/wolfcrypt/mlkem.h b/wolfssl/wolfcrypt/mlkem.h deleted file mode 100644 index 4c185482b8..0000000000 --- a/wolfssl/wolfcrypt/mlkem.h +++ /dev/null @@ -1,390 +0,0 @@ -/* mlkem.h - * - * Copyright (C) 2006-2026 wolfSSL Inc. - * - * This file is part of wolfSSL. - * - * wolfSSL is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * wolfSSL is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA - */ - -/*! - \file wolfssl/wolfcrypt/mlkem.h - */ - -#ifndef WOLF_CRYPT_MLKEM_H -#define WOLF_CRYPT_MLKEM_H - -#include -#include - -#ifdef WOLFSSL_HAVE_MLKEM - -/* Number of co-efficients in polynomial. */ -#define MLKEM_N 256 - -/* Define algorithm type when not excluded. */ -#ifndef WOLFSSL_NO_ML_KEM - #if !defined(WOLFSSL_NO_ML_KEM_512) - #define WOLFSSL_WC_ML_KEM_512 - #endif - #if !defined(WOLFSSL_NO_ML_KEM_768) - #define WOLFSSL_WC_ML_KEM_768 - #endif - #if !defined(WOLFSSL_NO_ML_KEM_1024) - #define WOLFSSL_WC_ML_KEM_1024 - #endif - - #if !defined(WOLFSSL_WC_ML_KEM_512) && !defined(WOLFSSL_WC_ML_KEM_768) && \ - !defined(WOLFSSL_WC_ML_KEM_1024) - #error "No ML-KEM key size chosen." - #endif -#endif - -#ifdef WOLFSSL_MLKEM_KYBER - #ifndef WOLFSSL_NO_KYBER512 - #define WOLFSSL_KYBER512 - #define WOLFSSL_WC_ML_KEM_512 - #endif - #ifndef WOLFSSL_NO_KYBER768 - #define WOLFSSL_KYBER768 - #define WOLFSSL_WC_ML_KEM_768 - #endif - #ifndef WOLFSSL_NO_KYBER1024 - #define WOLFSSL_KYBER1024 - #define WOLFSSL_WC_ML_KEM_1024 - #endif - - #if !defined(WOLFSSL_KYBER512) && !defined(WOLFSSL_KYBER768) && \ - !defined(WOLFSSL_KYBER1024) - #error "No Kyber key size chosen." - #endif -#endif - -/* Size of a polynomial vector based on dimensions. */ -#define MLKEM_POLY_VEC_SZ(k) ((k) * WC_ML_KEM_POLY_SIZE) -/* Size of a compressed polynomial based on bits per coefficient. */ -#define MLKEM_POLY_COMPRESSED_SZ(b) ((b) * (MLKEM_N / 8)) -/* Size of a compressed vector polynomial based on dimensions and bits per - * coefficient. */ -#define MLKEM_POLY_VEC_COMPRESSED_SZ(k, b) ((k) * ((b) * (MLKEM_N / 8))) - -#ifdef WOLFSSL_WC_ML_KEM_512 -#define WC_ML_KEM_512_K 2 -/* Size of a polynomial vector. */ -#define WC_ML_KEM_512_POLY_VEC_SZ MLKEM_POLY_VEC_SZ(WC_ML_KEM_512_K) -/* Size of a compressed polynomial based on bits per coefficient. */ -#define WC_ML_KEM_512_POLY_COMPRESSED_SZ MLKEM_POLY_COMPRESSED_SZ(4) -/* Size of a compressed vector polynomial based on dimensions and bits per - * coefficient. */ -#define WC_ML_KEM_512_POLY_VEC_COMPRESSED_SZ \ - MLKEM_POLY_VEC_COMPRESSED_SZ(WC_ML_KEM_512_K, 10) - -/* Public key size. */ -#define WC_ML_KEM_512_PUBLIC_KEY_SIZE \ - (WC_ML_KEM_512_POLY_VEC_SZ + WC_ML_KEM_SYM_SZ) -/* Private key size. */ -#define WC_ML_KEM_512_PRIVATE_KEY_SIZE \ - (WC_ML_KEM_512_POLY_VEC_SZ + WC_ML_KEM_512_PUBLIC_KEY_SIZE + \ - 2 * WC_ML_KEM_SYM_SZ) -/* Cipher text size. */ -#define WC_ML_KEM_512_CIPHER_TEXT_SIZE \ - (WC_ML_KEM_512_POLY_VEC_COMPRESSED_SZ + WC_ML_KEM_512_POLY_COMPRESSED_SZ) -#endif - -#ifdef WOLFSSL_WC_ML_KEM_768 -#define WC_ML_KEM_768_K 3 - -/* Size of a polynomial vector. */ -#define WC_ML_KEM_768_POLY_VEC_SZ MLKEM_POLY_VEC_SZ(WC_ML_KEM_768_K) -/* Size of a compressed polynomial based on bits per coefficient. */ -#define WC_ML_KEM_768_POLY_COMPRESSED_SZ MLKEM_POLY_COMPRESSED_SZ(4) -/* Size of a compressed vector polynomial based on dimensions and bits per - * coefficient. */ -#define WC_ML_KEM_768_POLY_VEC_COMPRESSED_SZ \ - MLKEM_POLY_VEC_COMPRESSED_SZ(WC_ML_KEM_768_K, 10) - -/* Public key size. */ -#define WC_ML_KEM_768_PUBLIC_KEY_SIZE \ - (WC_ML_KEM_768_POLY_VEC_SZ + WC_ML_KEM_SYM_SZ) -/* Private key size. */ -#define WC_ML_KEM_768_PRIVATE_KEY_SIZE \ - (WC_ML_KEM_768_POLY_VEC_SZ + WC_ML_KEM_768_PUBLIC_KEY_SIZE + \ - 2 * WC_ML_KEM_SYM_SZ) -/* Cipher text size. */ -#define WC_ML_KEM_768_CIPHER_TEXT_SIZE \ - (WC_ML_KEM_768_POLY_VEC_COMPRESSED_SZ + WC_ML_KEM_768_POLY_COMPRESSED_SZ) -#endif - -#ifdef WOLFSSL_WC_ML_KEM_1024 -#define WC_ML_KEM_1024_K 4 - -/* Size of a polynomial vector. */ -#define WC_ML_KEM_1024_POLY_VEC_SZ MLKEM_POLY_VEC_SZ(WC_ML_KEM_1024_K) -/* Size of a compressed polynomial based on bits per coefficient. */ -#define WC_ML_KEM_1024_POLY_COMPRESSED_SZ MLKEM_POLY_COMPRESSED_SZ(5) -/* Size of a compressed vector polynomial based on dimensions and bits per - * coefficient. */ -#define WC_ML_KEM_1024_POLY_VEC_COMPRESSED_SZ \ - MLKEM_POLY_VEC_COMPRESSED_SZ(WC_ML_KEM_1024_K, 11) - -/* Public key size. */ -#define WC_ML_KEM_1024_PUBLIC_KEY_SIZE \ - (WC_ML_KEM_1024_POLY_VEC_SZ + WC_ML_KEM_SYM_SZ) -/* Private key size. */ -#define WC_ML_KEM_1024_PRIVATE_KEY_SIZE \ - (WC_ML_KEM_1024_POLY_VEC_SZ + WC_ML_KEM_1024_PUBLIC_KEY_SIZE + \ - 2 * WC_ML_KEM_SYM_SZ) -/* Cipher text size. */ -#define WC_ML_KEM_1024_CIPHER_TEXT_SIZE \ - (WC_ML_KEM_1024_POLY_VEC_COMPRESSED_SZ + WC_ML_KEM_1024_POLY_COMPRESSED_SZ) -#endif - -#ifndef WC_ML_KEM_MAX_K -#ifdef WOLFSSL_WC_ML_KEM_1024 -#define WC_ML_KEM_MAX_K WC_ML_KEM_1024_K -#define WC_ML_KEM_MAX_PRIVATE_KEY_SIZE WC_ML_KEM_1024_PRIVATE_KEY_SIZE -#define WC_ML_KEM_MAX_PUBLIC_KEY_SIZE WC_ML_KEM_1024_PUBLIC_KEY_SIZE -#define WC_ML_KEM_MAX_CIPHER_TEXT_SIZE WC_ML_KEM_1024_CIPHER_TEXT_SIZE -#elif defined(WOLFSSL_WC_ML_KEM_768) -#define WC_ML_KEM_MAX_K WC_ML_KEM_768_K -#define WC_ML_KEM_MAX_PRIVATE_KEY_SIZE WC_ML_KEM_768_PRIVATE_KEY_SIZE -#define WC_ML_KEM_MAX_PUBLIC_KEY_SIZE WC_ML_KEM_768_PUBLIC_KEY_SIZE -#define WC_ML_KEM_MAX_CIPHER_TEXT_SIZE WC_ML_KEM_768_CIPHER_TEXT_SIZE -#elif defined(WOLFSSL_WC_ML_KEM_512) -#define WC_ML_KEM_MAX_K WC_ML_KEM_512_K -#define WC_ML_KEM_MAX_PRIVATE_KEY_SIZE WC_ML_KEM_512_PRIVATE_KEY_SIZE -#define WC_ML_KEM_MAX_PUBLIC_KEY_SIZE WC_ML_KEM_512_PUBLIC_KEY_SIZE -#define WC_ML_KEM_MAX_CIPHER_TEXT_SIZE WC_ML_KEM_512_CIPHER_TEXT_SIZE -#endif -#endif /* WC_ML_KEM_MAX_K */ - -#define KYBER_N MLKEM_N - -/* Size of a polynomial vector based on dimensions. */ -#define KYBER_POLY_VEC_SZ(k) ((k) * KYBER_POLY_SIZE) -/* Size of a compressed polynomial based on bits per coefficient. */ -#define KYBER_POLY_COMPRESSED_SZ(b) ((b) * (KYBER_N / 8)) -/* Size of a compressed vector polynomial based on dimensions and bits per - * coefficient. */ -#define KYBER_POLY_VEC_COMPRESSED_SZ(k, b) ((k) * ((b) * (KYBER_N / 8))) - - -/* Kyber-512 parameters */ -/* Number of polynomials in a vector and vectors in a matrix. */ -#define KYBER512_K 2 - -/* Size of a polynomial vector. */ -#define KYBER512_POLY_VEC_SZ KYBER_POLY_VEC_SZ(KYBER512_K) -/* Size of a compressed polynomial based on bits per coefficient. */ -#define KYBER512_POLY_COMPRESSED_SZ KYBER_POLY_COMPRESSED_SZ(4) -/* Size of a compressed vector polynomial based on dimensions and bits per - * coefficient. */ -#define KYBER512_POLY_VEC_COMPRESSED_SZ \ - KYBER_POLY_VEC_COMPRESSED_SZ(KYBER512_K, 10) - -/* Public key size. */ -#define KYBER512_PUBLIC_KEY_SIZE \ - (KYBER512_POLY_VEC_SZ + KYBER_SYM_SZ) -/* Private key size. */ -#define KYBER512_PRIVATE_KEY_SIZE \ - (KYBER512_POLY_VEC_SZ + KYBER512_PUBLIC_KEY_SIZE + 2 * KYBER_SYM_SZ) -/* Cipher text size. */ -#define KYBER512_CIPHER_TEXT_SIZE \ - (KYBER512_POLY_VEC_COMPRESSED_SZ + KYBER512_POLY_COMPRESSED_SZ) - -/* Kyber-768 parameters */ -/* Number of polynomials in a vector and vectors in a matrix. */ -#define KYBER768_K 3 - -/* Size of a polynomial vector. */ -#define KYBER768_POLY_VEC_SZ KYBER_POLY_VEC_SZ(KYBER768_K) -/* Size of a compressed polynomial based on bits per coefficient. */ -#define KYBER768_POLY_COMPRESSED_SZ KYBER_POLY_COMPRESSED_SZ(4) -/* Size of a compressed vector polynomial based on dimensions and bits per - * coefficient. */ -#define KYBER768_POLY_VEC_COMPRESSED_SZ \ - KYBER_POLY_VEC_COMPRESSED_SZ(KYBER768_K, 10) - -/* Public key size. */ -#define KYBER768_PUBLIC_KEY_SIZE \ - (KYBER768_POLY_VEC_SZ + KYBER_SYM_SZ) -/* Private key size. */ -#define KYBER768_PRIVATE_KEY_SIZE \ - (KYBER768_POLY_VEC_SZ + KYBER768_PUBLIC_KEY_SIZE + 2 * KYBER_SYM_SZ) -/* Cipher text size. */ -#define KYBER768_CIPHER_TEXT_SIZE \ - (KYBER768_POLY_VEC_COMPRESSED_SZ + KYBER768_POLY_COMPRESSED_SZ) - -/* Kyber-1024 parameters */ -/* Number of polynomials in a vector and vectors in a matrix. */ -#define KYBER1024_K 4 - -/* Size of a polynomial vector. */ -#define KYBER1024_POLY_VEC_SZ KYBER_POLY_VEC_SZ(KYBER1024_K) -/* Size of a compressed polynomial based on bits per coefficient. */ -#define KYBER1024_POLY_COMPRESSED_SZ KYBER_POLY_COMPRESSED_SZ(5) -/* Size of a compressed vector polynomial based on dimensions and bits per - * coefficient. */ -#define KYBER1024_POLY_VEC_COMPRESSED_SZ \ - KYBER_POLY_VEC_COMPRESSED_SZ(KYBER1024_K, 11) - -/* Public key size. */ -#define KYBER1024_PUBLIC_KEY_SIZE \ - (KYBER1024_POLY_VEC_SZ + KYBER_SYM_SZ) -/* Private key size. */ -#define KYBER1024_PRIVATE_KEY_SIZE \ - (KYBER1024_POLY_VEC_SZ + KYBER1024_PUBLIC_KEY_SIZE + 2 * KYBER_SYM_SZ) -/* Cipher text size. */ -#define KYBER1024_CIPHER_TEXT_SIZE \ - (KYBER1024_POLY_VEC_COMPRESSED_SZ + KYBER1024_POLY_COMPRESSED_SZ) - - -/* Maximum dimensions and sizes of supported key types. */ -#ifdef WOLFSSL_KYBER1024 -#define KYBER_MAX_K KYBER1024_K -#define KYBER_MAX_PRIVATE_KEY_SIZE KYBER1024_PRIVATE_KEY_SIZE -#define KYBER_MAX_PUBLIC_KEY_SIZE KYBER1024_PUBLIC_KEY_SIZE -#define KYBER_MAX_CIPHER_TEXT_SIZE KYBER1024_CIPHER_TEXT_SIZE -#elif defined(WOLFSSL_KYBER768) -#define KYBER_MAX_K KYBER768_K -#define KYBER_MAX_PRIVATE_KEY_SIZE KYBER768_PRIVATE_KEY_SIZE -#define KYBER_MAX_PUBLIC_KEY_SIZE KYBER768_PUBLIC_KEY_SIZE -#define KYBER_MAX_CIPHER_TEXT_SIZE KYBER768_CIPHER_TEXT_SIZE -#elif defined(WOLFSSL_KYBER512) -#define KYBER_MAX_K KYBER512_K -#define KYBER_MAX_PRIVATE_KEY_SIZE KYBER512_PRIVATE_KEY_SIZE -#define KYBER_MAX_PUBLIC_KEY_SIZE KYBER512_PUBLIC_KEY_SIZE -#define KYBER_MAX_CIPHER_TEXT_SIZE KYBER512_CIPHER_TEXT_SIZE -#endif - -#define KYBER_SYM_SZ WC_ML_KEM_SYM_SZ -#define KYBER_SS_SZ WC_ML_KEM_SS_SZ -#define KYBER_MAKEKEY_RAND_SZ WC_ML_KEM_MAKEKEY_RAND_SZ -#define KYBER_ENC_RAND_SZ WC_ML_KEM_ENC_RAND_SZ -#define KYBER_POLY_SIZE WC_ML_KEM_POLY_SIZE - - -enum { - /* Types of Kyber keys. */ - WC_ML_KEM_512 = 0, - WC_ML_KEM_768 = 1, - WC_ML_KEM_1024 = 2, - - MLKEM_KYBER = 0x10, - KYBER512 = 0 | MLKEM_KYBER, - KYBER768 = 1 | MLKEM_KYBER, - KYBER1024 = 2 | MLKEM_KYBER, - - KYBER_LEVEL1 = KYBER512, - KYBER_LEVEL3 = KYBER768, - KYBER_LEVEL5 = KYBER1024, - - /* Symmetric data size. */ - WC_ML_KEM_SYM_SZ = 32, - /* Shared secret size. */ - WC_ML_KEM_SS_SZ = 32, - /* Size of random required for making a key. */ - WC_ML_KEM_MAKEKEY_RAND_SZ = 2 * WC_ML_KEM_SYM_SZ, - /* Size of random required for encapsulation. */ - WC_ML_KEM_ENC_RAND_SZ = WC_ML_KEM_SYM_SZ, - - /* Encoded polynomial size. */ - WC_ML_KEM_POLY_SIZE = 384 -}; - -#ifdef WOLF_PRIVATE_KEY_ID - #define MLKEM_MAX_ID_LEN 32 - #define MLKEM_MAX_LABEL_LEN 32 -#endif - -/* Different structures for different implementations. */ -typedef struct MlKemKey MlKemKey; - - -#ifdef __cplusplus - extern "C" { -#endif - -WOLFSSL_API MlKemKey* wc_MlKemKey_New(int type, void* heap, int devId); -WOLFSSL_API int wc_MlKemKey_Delete(MlKemKey* key, MlKemKey** key_p); - -WOLFSSL_API int wc_MlKemKey_Init(MlKemKey* key, int type, void* heap, - int devId); -WOLFSSL_API int wc_MlKemKey_Free(MlKemKey* key); -#if defined(WOLF_PRIVATE_KEY_ID) && defined(WOLFSSL_WC_MLKEM) -WOLFSSL_API int wc_MlKemKey_Init_Id(MlKemKey* key, int type, - const unsigned char* id, int len, void* heap, int devId); -WOLFSSL_API int wc_MlKemKey_Init_Label(MlKemKey* key, int type, - const char* label, void* heap, int devId); -#endif - -WOLFSSL_API int wc_MlKemKey_MakeKey(MlKemKey* key, WC_RNG* rng); -WOLFSSL_API int wc_MlKemKey_MakeKeyWithRandom(MlKemKey* key, - const unsigned char* rand, int len); - -WOLFSSL_API int wc_MlKemKey_CipherTextSize(MlKemKey* key, word32* len); -WOLFSSL_API int wc_MlKemKey_SharedSecretSize(MlKemKey* key, word32* len); - -WOLFSSL_API int wc_MlKemKey_Encapsulate(MlKemKey* key, unsigned char* ct, - unsigned char* ss, WC_RNG* rng); -WOLFSSL_API int wc_MlKemKey_EncapsulateWithRandom(MlKemKey* key, - unsigned char* ct, unsigned char* ss, const unsigned char* rand, int len); -WOLFSSL_API int wc_MlKemKey_Decapsulate(MlKemKey* key, unsigned char* ss, - const unsigned char* ct, word32 len); - -WOLFSSL_API int wc_MlKemKey_DecodePrivateKey(MlKemKey* key, - const unsigned char* in, word32 len); -WOLFSSL_API int wc_MlKemKey_DecodePublicKey(MlKemKey* key, - const unsigned char* in, word32 len); - -WOLFSSL_API int wc_MlKemKey_PrivateKeySize(MlKemKey* key, word32* len); -WOLFSSL_API int wc_MlKemKey_PublicKeySize(MlKemKey* key, word32* len); -WOLFSSL_API int wc_MlKemKey_EncodePrivateKey(MlKemKey* key, unsigned char* out, - word32 len); -WOLFSSL_API int wc_MlKemKey_EncodePublicKey(MlKemKey* key, unsigned char* out, - word32 len); - - -#define KyberKey MlKemKey - -#define wc_KyberKey_Init(type, key, heap, devId) \ - wc_MlKemKey_Init(key, type, heap, devId) -#define wc_KyberKey_Free wc_MlKemKey_Free -#if defined(WOLF_PRIVATE_KEY_ID) && defined(WOLFSSL_WC_MLKEM) -#define wc_KyberKey_Init_Id wc_MlKemKey_Init_Id -#define wc_KyberKey_Init_Label wc_MlKemKey_Init_Label -#endif -#define wc_KyberKey_MakeKey wc_MlKemKey_MakeKey -#define wc_KyberKey_MakeKeyWithRandom wc_MlKemKey_MakeKeyWithRandom -#define wc_KyberKey_CipherTextSize wc_MlKemKey_CipherTextSize -#define wc_KyberKey_SharedSecretSize wc_MlKemKey_SharedSecretSize -#define wc_KyberKey_Encapsulate wc_MlKemKey_Encapsulate -#define wc_KyberKey_EncapsulateWithRandom wc_MlKemKey_EncapsulateWithRandom -#define wc_KyberKey_Decapsulate wc_MlKemKey_Decapsulate -#define wc_KyberKey_DecodePrivateKey wc_MlKemKey_DecodePrivateKey -#define wc_KyberKey_DecodePublicKey wc_MlKemKey_DecodePublicKey -#define wc_KyberKey_PrivateKeySize wc_MlKemKey_PrivateKeySize -#define wc_KyberKey_PublicKeySize wc_MlKemKey_PublicKeySize -#define wc_KyberKey_EncodePrivateKey wc_MlKemKey_EncodePrivateKey -#define wc_KyberKey_EncodePublicKey wc_MlKemKey_EncodePublicKey - - -#ifdef __cplusplus - } /* extern "C" */ -#endif - -#endif /* WOLFSSL_HAVE_MLKEM */ - -#endif /* WOLF_CRYPT_MLKEM_H */ diff --git a/wolfssl/wolfcrypt/oid_sum.h b/wolfssl/wolfcrypt/oid_sum.h index a85b6fb7c5..f0d4a2fe30 100644 --- a/wolfssl/wolfcrypt/oid_sum.h +++ b/wolfssl/wolfcrypt/oid_sum.h @@ -180,10 +180,10 @@ enum Key_Sum { X448k = 255, /* 1.3.101.111 */ /* 0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x03,0x01 */ DHk = 647, /* 1.2.840.113549.1.3.1 */ - /* 0x2b,0xce,0x0f,0x03,0x06 */ - FALCON_LEVEL1k = 273, /* 1.3.9999.3.6 */ - /* 0x2b,0xce,0x0f,0x03,0x09 */ - FALCON_LEVEL5k = 276, /* 1.3.9999.3.9 */ + /* 0x2b,0xce,0x0f,0x03,0x0b */ + FALCON_LEVEL1k = 278, /* 1.3.9999.3.11 */ + /* 0x2b,0xce,0x0f,0x03,0x0e */ + FALCON_LEVEL5k = 281, /* 1.3.9999.3.14 */ /* 0x2b,0x06,0x01,0x04,0x01,0x02,0x82,0x0b,0x0c,0x04,0x04 */ DILITHIUM_LEVEL2k = 218, /* 1.3.6.1.4.1.2.267.12.4.4 */ /* 0x2b,0x06,0x01,0x04,0x01,0x02,0x82,0x0b,0x0c,0x06,0x05 */ @@ -233,10 +233,10 @@ enum Key_Sum { X448k = 0x7f9065d4, /* 1.3.101.111 */ /* 0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x03,0x01 */ DHk = 0x7ab67423, /* 1.2.840.113549.1.3.1 */ - /* 0x2b,0xce,0x0f,0x03,0x06 */ - FALCON_LEVEL1k = 0x7c0f312d, /* 1.3.9999.3.6 */ - /* 0x2b,0xce,0x0f,0x03,0x09 */ - FALCON_LEVEL5k = 0x7c0f3122, /* 1.3.9999.3.9 */ + /* 0x2b,0xce,0x0f,0x03,0x0b */ + FALCON_LEVEL1k = 0x7c0f3120, /* 1.3.9999.3.11 */ + /* 0x2b,0xce,0x0f,0x03,0x0e */ + FALCON_LEVEL5k = 0x7c0f3125, /* 1.3.9999.3.14 */ /* 0x2b,0x06,0x01,0x04,0x01,0x02,0x82,0x0b,0x0c,0x04,0x04 */ DILITHIUM_LEVEL2k = 0x707800d9, /* 1.3.6.1.4.1.2.267.12.4.4 */ /* 0x2b,0x06,0x01,0x04,0x01,0x02,0x82,0x0b,0x0c,0x06,0x05 */ @@ -1564,10 +1564,10 @@ enum Ctc_SigType { CTC_ED25519 = 256, /* 1.3.101.112 */ /* 0x2b,0x65,0x71 */ CTC_ED448 = 257, /* 1.3.101.113 */ - /* 0x2b,0xce,0x0f,0x03,0x06 */ - CTC_FALCON_LEVEL1 = 273, /* 1.3.9999.3.6 */ - /* 0x2b,0xce,0x0f,0x03,0x09 */ - CTC_FALCON_LEVEL5 = 276, /* 1.3.9999.3.9 */ + /* 0x2b,0xce,0x0f,0x03,0x0b */ + CTC_FALCON_LEVEL1 = 278, /* 1.3.9999.3.11 */ + /* 0x2b,0xce,0x0f,0x03,0x0e */ + CTC_FALCON_LEVEL5 = 281, /* 1.3.9999.3.14 */ /* 0x2b,0x06,0x01,0x04,0x01,0x02,0x82,0x0b,0x0c,0x04,0x04 */ CTC_DILITHIUM_LEVEL2 = 218, /* 1.3.6.1.4.1.2.267.12.4.4 */ /* 0x2b,0x06,0x01,0x04,0x01,0x02,0x82,0x0b,0x0c,0x06,0x05 */ @@ -1645,10 +1645,10 @@ enum Ctc_SigType { CTC_ED25519 = 0x7f8f65d4, /* 1.3.101.112 */ /* 0x2b,0x65,0x71 */ CTC_ED448 = 0x7f8e65d4, /* 1.3.101.113 */ - /* 0x2b,0xce,0x0f,0x03,0x06 */ - CTC_FALCON_LEVEL1 = 0x7c0f312d, /* 1.3.9999.3.6 */ - /* 0x2b,0xce,0x0f,0x03,0x09 */ - CTC_FALCON_LEVEL5 = 0x7c0f3122, /* 1.3.9999.3.9 */ + /* 0x2b,0xce,0x0f,0x03,0x0b */ + CTC_FALCON_LEVEL1 = 0x7c0f3120, /* 1.3.9999.3.11 */ + /* 0x2b,0xce,0x0f,0x03,0x0e */ + CTC_FALCON_LEVEL5 = 0x7c0f3125, /* 1.3.9999.3.14 */ /* 0x2b,0x06,0x01,0x04,0x01,0x02,0x82,0x0b,0x0c,0x04,0x04 */ CTC_DILITHIUM_LEVEL2 = 0x707800d9, /* 1.3.6.1.4.1.2.267.12.4.4 */ /* 0x2b,0x06,0x01,0x04,0x01,0x02,0x82,0x0b,0x0c,0x06,0x05 */ @@ -1698,7 +1698,7 @@ enum PKCS7_TYPES { FIRMWARE_PKG_DATA = 685, /* 1.2.840.113549.1.9.16.1.16 */ /* 0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x09,0x10,0x01,0x17 */ AUTH_ENVELOPED_DATA = 692, /* 1.2.840.113549.1.9.16.1.23 */ - /* 0x60,0x86,0x48,0x01,0x65,0x02,0x01,0x02,0x4E,0x02 */ + /* 0x60,0x86,0x48,0x01,0x65,0x02,0x01,0x02,0x4e,0x02 */ ENCRYPTED_KEY_PACKAGE = 489 /* 2.16.840.1.101.2.1.2.78.2 */ #else /* 0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07 */ @@ -1721,8 +1721,8 @@ enum PKCS7_TYPES { FIRMWARE_PKG_DATA = 0x70a68a32, /* 1.2.840.113549.1.9.16.1.16 */ /* 0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x09,0x10,0x01,0x17 */ AUTH_ENVELOPED_DATA = 0x70a18a32, /* 1.2.840.113549.1.9.16.1.23 */ - /* 0x60,0x86,0x48,0x01,0x65,0x02,0x01,0x02,0x4E,0x02 */ - ENCRYPTED_KEY_PACKAGE = 0x034986B4 /* 2.16.840.1.101.2.1.2.78.2 */ + /* 0x60,0x86,0x48,0x01,0x65,0x02,0x01,0x02,0x4e,0x02 */ + ENCRYPTED_KEY_PACKAGE = 0x034986b4 /* 2.16.840.1.101.2.1.2.78.2 */ #endif }; diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 32fa66fb62..b03e353fb6 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -933,7 +933,6 @@ #ifdef CONFIG_ESP_WOLFSSL_ENABLE_MLKEM /* Kyber typically needs a minimum 10K stack */ #define WOLFSSL_HAVE_MLKEM - #define WOLFSSL_WC_MLKEM #define WOLFSSL_SHA3 #if defined(CONFIG_IDF_TARGET_ESP8266) /* With limited RAM, we'll disable some of the Kyber sizes: */ @@ -4574,30 +4573,14 @@ extern void uITRON4_free(void *p) ; #endif #endif -#ifdef WOLFSSL_HAVE_MLKEM -#define HAVE_PQC -#endif - -/* Enable Post-Quantum Cryptography if we have liboqs from the OpenQuantumSafe - * group */ -#ifdef HAVE_LIBOQS -#define HAVE_PQC -#define HAVE_FALCON -#ifndef HAVE_DILITHIUM - #define HAVE_DILITHIUM -#endif -#ifndef WOLFSSL_NO_SPHINCS - #define HAVE_SPHINCS -#endif -#ifndef WOLFSSL_HAVE_MLKEM - #define WOLFSSL_HAVE_MLKEM - #define WOLFSSL_KYBER512 - #define WOLFSSL_KYBER768 - #define WOLFSSL_KYBER1024 - #define WOLFSSL_WC_ML_KEM_512 - #define WOLFSSL_WC_ML_KEM_768 - #define WOLFSSL_WC_ML_KEM_1024 +/* Falcon is the only algorithm we still pull from liboqs, so the two options + * go together: Falcon cannot be built without liboqs, and enabling liboqs + * without Falcon leaves nothing for it to do. */ +#if defined(HAVE_LIBOQS) && !defined(HAVE_FALCON) +#error "HAVE_LIBOQS without HAVE_FALCON has no effect; enable Falcon or drop liboqs." #endif +#if defined(HAVE_FALCON) && !defined(HAVE_LIBOQS) +#error "HAVE_FALCON requires HAVE_LIBOQS (enable liboqs via --with-liboqs)." #endif #if (defined(HAVE_LIBOQS) || \ @@ -4609,26 +4592,22 @@ extern void uITRON4_free(void *p) ; #error Experimental settings without WOLFSSL_EXPERIMENTAL_SETTINGS #endif -#if defined(HAVE_PQC) && !defined(HAVE_LIBOQS) && !defined(WOLFSSL_HAVE_MLKEM) -#error Please do not define HAVE_PQC yourself. -#endif - /* If no malloc then make sure the valid Dilithium settings are used */ #if defined(HAVE_DILITHIUM) && defined(WOLFSSL_NO_MALLOC) #undef WOLFSSL_DILITHIUM_VERIFY_NO_MALLOC #define WOLFSSL_DILITHIUM_VERIFY_NO_MALLOC #endif -#if defined(HAVE_PQC) && defined(WOLFSSL_HAVE_MLKEM) && \ +#if defined(WOLFSSL_HAVE_MLKEM) && \ defined(WOLFSSL_DTLS13) && !defined(WOLFSSL_DTLS_CH_FRAG) #define WOLFSSL_DTLS_CH_FRAG -#warning "WOLFSSL_DTLS_CH_FRAG is enabled to support PQC in DTLS 1.3" +#warning "WOLFSSL_DTLS_CH_FRAG is enabled to support ML-KEM in DTLS 1.3" #endif #if !defined(WOLFSSL_DTLS13) && defined(WOLFSSL_DTLS_CH_FRAG) #error "WOLFSSL_DTLS_CH_FRAG only works with DTLS 1.3" #endif -#if defined(HAVE_PQC) && defined(WOLFSSL_HAVE_MLKEM) && \ +#if defined(WOLFSSL_HAVE_MLKEM) && \ !defined(WOLFSSL_NO_ML_KEM) && !defined(WOLFSSL_PQC_HYBRIDS) && \ defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE) && !defined(WOLFCRYPT_ONLY) #error "Neither PQ/T hybrid combinations nor ML-KEM as standalone TLS key " \ @@ -4717,7 +4696,7 @@ extern void uITRON4_free(void *p) ; #if defined(WOLFSSL_SHA3) && \ ((defined(HAVE_FIPS) && FIPS_VERSION_LE(5,2)) || \ (defined(HAVE_SELFTEST) && \ - !defined(WOLFSSL_HAVE_MLKEM) && !defined(WOLFSSL_WC_DILITHIUM))) + !defined(WOLFSSL_HAVE_MLKEM) && !defined(HAVE_DILITHIUM))) #undef WOLFSSL_NO_SHAKE128 #define WOLFSSL_NO_SHAKE128 #undef WOLFSSL_NO_SHAKE256 diff --git a/wolfssl/wolfcrypt/sphincs.h b/wolfssl/wolfcrypt/sphincs.h index a14252278e..a070baf664 100644 --- a/wolfssl/wolfcrypt/sphincs.h +++ b/wolfssl/wolfcrypt/sphincs.h @@ -37,7 +37,7 @@ #include -#if defined(HAVE_PQC) && defined(HAVE_SPHINCS) +#if defined(HAVE_SPHINCS) #ifdef HAVE_LIBOQS #include @@ -163,5 +163,5 @@ WOLFSSL_API int wc_Sphincs_PublicKeyToDer(sphincs_key* key, byte* output, } /* extern "C" */ #endif -#endif /* HAVE_PQC && HAVE_SPHINCS */ +#endif /* HAVE_SPHINCS */ #endif /* WOLF_CRYPT_SPHINCS_H */ diff --git a/wolfssl/wolfcrypt/types.h b/wolfssl/wolfcrypt/types.h index b06969971b..b6c8049e48 100644 --- a/wolfssl/wolfcrypt/types.h +++ b/wolfssl/wolfcrypt/types.h @@ -1581,11 +1581,9 @@ enum wc_PkType { enum wc_PqcKemType { WC_PQC_KEM_TYPE_NONE = 0, #define _WC_PQC_KEM_TYPE_MAX WC_PQC_KEM_TYPE_NONE - #if defined(WOLFSSL_HAVE_MLKEM) WC_PQC_KEM_TYPE_KYBER = 1, #undef _WC_PQC_KEM_TYPE_MAX #define _WC_PQC_KEM_TYPE_MAX WC_PQC_KEM_TYPE_KYBER - #endif WC_PQC_KEM_TYPE_MAX = _WC_PQC_KEM_TYPE_MAX }; #endif diff --git a/wolfssl/wolfcrypt/wc_mlkem.h b/wolfssl/wolfcrypt/wc_mlkem.h index 5735acdd98..b8a0efa1d9 100644 --- a/wolfssl/wolfcrypt/wc_mlkem.h +++ b/wolfssl/wolfcrypt/wc_mlkem.h @@ -21,8 +21,7 @@ /*! \file wolfssl/wolfcrypt/wc_mlkem.h -*/ - + */ #ifndef WOLF_CRYPT_WC_MLKEM_H #define WOLF_CRYPT_WC_MLKEM_H @@ -30,10 +29,13 @@ #include #include #include -#include #ifdef WOLFSSL_HAVE_MLKEM +#ifdef __cplusplus + extern "C" { +#endif + #ifdef WOLFSSL_KYBER_NO_MAKE_KEY #define WOLFSSL_MLKEM_NO_MAKE_KEY #endif @@ -44,10 +46,292 @@ #define WOLFSSL_MLKEM_NO_DECAPSULATE #endif -#define MLKEM_NOINLINE WC_NO_INLINE +#define MLKEM_NOINLINE WC_NO_INLINE + +/* SHAKE128 rate. */ +#define XOF_BLOCK_SIZE 168 + +/* Modulus of co-efficients of polynomial. */ +#define MLKEM_Q 3329 + +/* Number of co-efficients in polynomial. */ +#define MLKEM_N 256 + +/* Define algorithm type when not excluded. */ +#ifndef WOLFSSL_NO_ML_KEM + #if !defined(WOLFSSL_NO_ML_KEM_512) + #define WOLFSSL_WC_ML_KEM_512 + #endif + #if !defined(WOLFSSL_NO_ML_KEM_768) + #define WOLFSSL_WC_ML_KEM_768 + #endif + #if !defined(WOLFSSL_NO_ML_KEM_1024) + #define WOLFSSL_WC_ML_KEM_1024 + #endif + + #if !defined(WOLFSSL_WC_ML_KEM_512) && !defined(WOLFSSL_WC_ML_KEM_768) && \ + !defined(WOLFSSL_WC_ML_KEM_1024) + #error "No ML-KEM key size chosen." + #endif +#endif + +#ifdef WOLFSSL_MLKEM_KYBER + #ifndef WOLFSSL_NO_KYBER512 + #define WOLFSSL_KYBER512 + #define WOLFSSL_WC_ML_KEM_512 + #endif + #ifndef WOLFSSL_NO_KYBER768 + #define WOLFSSL_KYBER768 + #define WOLFSSL_WC_ML_KEM_768 + #endif + #ifndef WOLFSSL_NO_KYBER1024 + #define WOLFSSL_KYBER1024 + #define WOLFSSL_WC_ML_KEM_1024 + #endif + + #if !defined(WOLFSSL_KYBER512) && !defined(WOLFSSL_KYBER768) && \ + !defined(WOLFSSL_KYBER1024) + #error "No Kyber key size chosen." + #endif +#endif + +/* Size of a polynomial vector based on dimensions. */ +#define MLKEM_POLY_VEC_SZ(k) ((k) * WC_ML_KEM_POLY_SIZE) +/* Size of a compressed polynomial based on bits per coefficient. */ +#define MLKEM_POLY_COMPRESSED_SZ(b) ((b) * (MLKEM_N / 8)) +/* Size of a compressed vector polynomial based on dimensions and bits per + * coefficient. */ +#define MLKEM_POLY_VEC_COMPRESSED_SZ(k, b) ((k) * ((b) * (MLKEM_N / 8))) + +#ifdef WOLFSSL_WC_ML_KEM_512 +#define WC_ML_KEM_512_K 2 +/* Number of bits of random to create noise from. */ +#define WC_ML_KEM_512_ETA1 MLKEM_CBD_ETA3 +/* Size of a polynomial vector. */ +#define WC_ML_KEM_512_POLY_VEC_SZ MLKEM_POLY_VEC_SZ(WC_ML_KEM_512_K) +/* Size of a compressed polynomial based on bits per coefficient. */ +#define WC_ML_KEM_512_POLY_COMPRESSED_SZ MLKEM_POLY_COMPRESSED_SZ(4) +/* Size of a compressed vector polynomial based on dimensions and bits per + * coefficient. */ +#define WC_ML_KEM_512_POLY_VEC_COMPRESSED_SZ \ + MLKEM_POLY_VEC_COMPRESSED_SZ(WC_ML_KEM_512_K, 10) + +/* Public key size. */ +#define WC_ML_KEM_512_PUBLIC_KEY_SIZE \ + (WC_ML_KEM_512_POLY_VEC_SZ + WC_ML_KEM_SYM_SZ) +/* Private key size. */ +#define WC_ML_KEM_512_PRIVATE_KEY_SIZE \ + (WC_ML_KEM_512_POLY_VEC_SZ + WC_ML_KEM_512_PUBLIC_KEY_SIZE + \ + 2 * WC_ML_KEM_SYM_SZ) +/* Cipher text size. */ +#define WC_ML_KEM_512_CIPHER_TEXT_SIZE \ + (WC_ML_KEM_512_POLY_VEC_COMPRESSED_SZ + WC_ML_KEM_512_POLY_COMPRESSED_SZ) +#endif + +#ifdef WOLFSSL_WC_ML_KEM_768 +#define WC_ML_KEM_768_K 3 +/* Number of bits of random to create noise from. */ +#define WC_ML_KEM_768_ETA1 MLKEM_CBD_ETA2 + +/* Size of a polynomial vector. */ +#define WC_ML_KEM_768_POLY_VEC_SZ MLKEM_POLY_VEC_SZ(WC_ML_KEM_768_K) +/* Size of a compressed polynomial based on bits per coefficient. */ +#define WC_ML_KEM_768_POLY_COMPRESSED_SZ MLKEM_POLY_COMPRESSED_SZ(4) +/* Size of a compressed vector polynomial based on dimensions and bits per + * coefficient. */ +#define WC_ML_KEM_768_POLY_VEC_COMPRESSED_SZ \ + MLKEM_POLY_VEC_COMPRESSED_SZ(WC_ML_KEM_768_K, 10) + +/* Public key size. */ +#define WC_ML_KEM_768_PUBLIC_KEY_SIZE \ + (WC_ML_KEM_768_POLY_VEC_SZ + WC_ML_KEM_SYM_SZ) +/* Private key size. */ +#define WC_ML_KEM_768_PRIVATE_KEY_SIZE \ + (WC_ML_KEM_768_POLY_VEC_SZ + WC_ML_KEM_768_PUBLIC_KEY_SIZE + \ + 2 * WC_ML_KEM_SYM_SZ) +/* Cipher text size. */ +#define WC_ML_KEM_768_CIPHER_TEXT_SIZE \ + (WC_ML_KEM_768_POLY_VEC_COMPRESSED_SZ + WC_ML_KEM_768_POLY_COMPRESSED_SZ) +#endif + +#ifdef WOLFSSL_WC_ML_KEM_1024 +#define WC_ML_KEM_1024_K 4 +/* Number of bits of random to create noise from. */ +#define WC_ML_KEM_1024_ETA1 MLKEM_CBD_ETA2 + +/* Size of a polynomial vector. */ +#define WC_ML_KEM_1024_POLY_VEC_SZ MLKEM_POLY_VEC_SZ(WC_ML_KEM_1024_K) +/* Size of a compressed polynomial based on bits per coefficient. */ +#define WC_ML_KEM_1024_POLY_COMPRESSED_SZ MLKEM_POLY_COMPRESSED_SZ(5) +/* Size of a compressed vector polynomial based on dimensions and bits per + * coefficient. */ +#define WC_ML_KEM_1024_POLY_VEC_COMPRESSED_SZ \ + MLKEM_POLY_VEC_COMPRESSED_SZ(WC_ML_KEM_1024_K, 11) + +/* Public key size. */ +#define WC_ML_KEM_1024_PUBLIC_KEY_SIZE \ + (WC_ML_KEM_1024_POLY_VEC_SZ + WC_ML_KEM_SYM_SZ) +/* Private key size. */ +#define WC_ML_KEM_1024_PRIVATE_KEY_SIZE \ + (WC_ML_KEM_1024_POLY_VEC_SZ + WC_ML_KEM_1024_PUBLIC_KEY_SIZE + \ + 2 * WC_ML_KEM_SYM_SZ) +/* Cipher text size. */ +#define WC_ML_KEM_1024_CIPHER_TEXT_SIZE \ + (WC_ML_KEM_1024_POLY_VEC_COMPRESSED_SZ + WC_ML_KEM_1024_POLY_COMPRESSED_SZ) +#endif + +#ifndef WC_ML_KEM_MAX_K +#ifdef WOLFSSL_WC_ML_KEM_1024 +#define WC_ML_KEM_MAX_K WC_ML_KEM_1024_K +#define WC_ML_KEM_MAX_PRIVATE_KEY_SIZE WC_ML_KEM_1024_PRIVATE_KEY_SIZE +#define WC_ML_KEM_MAX_PUBLIC_KEY_SIZE WC_ML_KEM_1024_PUBLIC_KEY_SIZE +#define WC_ML_KEM_MAX_CIPHER_TEXT_SIZE WC_ML_KEM_1024_CIPHER_TEXT_SIZE +#elif defined(WOLFSSL_WC_ML_KEM_768) +#define WC_ML_KEM_MAX_K WC_ML_KEM_768_K +#define WC_ML_KEM_MAX_PRIVATE_KEY_SIZE WC_ML_KEM_768_PRIVATE_KEY_SIZE +#define WC_ML_KEM_MAX_PUBLIC_KEY_SIZE WC_ML_KEM_768_PUBLIC_KEY_SIZE +#define WC_ML_KEM_MAX_CIPHER_TEXT_SIZE WC_ML_KEM_768_CIPHER_TEXT_SIZE +#elif defined(WOLFSSL_WC_ML_KEM_512) +#define WC_ML_KEM_MAX_K WC_ML_KEM_512_K +#define WC_ML_KEM_MAX_PRIVATE_KEY_SIZE WC_ML_KEM_512_PRIVATE_KEY_SIZE +#define WC_ML_KEM_MAX_PUBLIC_KEY_SIZE WC_ML_KEM_512_PUBLIC_KEY_SIZE +#define WC_ML_KEM_MAX_CIPHER_TEXT_SIZE WC_ML_KEM_512_CIPHER_TEXT_SIZE +#endif +#endif /* WC_ML_KEM_MAX_K */ + +#define KYBER_N MLKEM_N + +/* Size of a polynomial vector based on dimensions. */ +#define KYBER_POLY_VEC_SZ(k) ((k) * KYBER_POLY_SIZE) +/* Size of a compressed polynomial based on bits per coefficient. */ +#define KYBER_POLY_COMPRESSED_SZ(b) ((b) * (KYBER_N / 8)) +/* Size of a compressed vector polynomial based on dimensions and bits per + * coefficient. */ +#define KYBER_POLY_VEC_COMPRESSED_SZ(k, b) ((k) * ((b) * (KYBER_N / 8))) + + +/* Kyber-512 parameters */ +/* Number of polynomials in a vector and vectors in a matrix. */ +#define KYBER512_K 2 + +/* Size of a polynomial vector. */ +#define KYBER512_POLY_VEC_SZ KYBER_POLY_VEC_SZ(KYBER512_K) +/* Size of a compressed polynomial based on bits per coefficient. */ +#define KYBER512_POLY_COMPRESSED_SZ KYBER_POLY_COMPRESSED_SZ(4) +/* Size of a compressed vector polynomial based on dimensions and bits per + * coefficient. */ +#define KYBER512_POLY_VEC_COMPRESSED_SZ \ + KYBER_POLY_VEC_COMPRESSED_SZ(KYBER512_K, 10) + +/* Public key size. */ +#define KYBER512_PUBLIC_KEY_SIZE \ + (KYBER512_POLY_VEC_SZ + KYBER_SYM_SZ) +/* Private key size. */ +#define KYBER512_PRIVATE_KEY_SIZE \ + (KYBER512_POLY_VEC_SZ + KYBER512_PUBLIC_KEY_SIZE + 2 * KYBER_SYM_SZ) +/* Cipher text size. */ +#define KYBER512_CIPHER_TEXT_SIZE \ + (KYBER512_POLY_VEC_COMPRESSED_SZ + KYBER512_POLY_COMPRESSED_SZ) + +/* Kyber-768 parameters */ +/* Number of polynomials in a vector and vectors in a matrix. */ +#define KYBER768_K 3 + +/* Size of a polynomial vector. */ +#define KYBER768_POLY_VEC_SZ KYBER_POLY_VEC_SZ(KYBER768_K) +/* Size of a compressed polynomial based on bits per coefficient. */ +#define KYBER768_POLY_COMPRESSED_SZ KYBER_POLY_COMPRESSED_SZ(4) +/* Size of a compressed vector polynomial based on dimensions and bits per + * coefficient. */ +#define KYBER768_POLY_VEC_COMPRESSED_SZ \ + KYBER_POLY_VEC_COMPRESSED_SZ(KYBER768_K, 10) + +/* Public key size. */ +#define KYBER768_PUBLIC_KEY_SIZE \ + (KYBER768_POLY_VEC_SZ + KYBER_SYM_SZ) +/* Private key size. */ +#define KYBER768_PRIVATE_KEY_SIZE \ + (KYBER768_POLY_VEC_SZ + KYBER768_PUBLIC_KEY_SIZE + 2 * KYBER_SYM_SZ) +/* Cipher text size. */ +#define KYBER768_CIPHER_TEXT_SIZE \ + (KYBER768_POLY_VEC_COMPRESSED_SZ + KYBER768_POLY_COMPRESSED_SZ) + +/* Kyber-1024 parameters */ +/* Number of polynomials in a vector and vectors in a matrix. */ +#define KYBER1024_K 4 + +/* Size of a polynomial vector. */ +#define KYBER1024_POLY_VEC_SZ KYBER_POLY_VEC_SZ(KYBER1024_K) +/* Size of a compressed polynomial based on bits per coefficient. */ +#define KYBER1024_POLY_COMPRESSED_SZ KYBER_POLY_COMPRESSED_SZ(5) +/* Size of a compressed vector polynomial based on dimensions and bits per + * coefficient. */ +#define KYBER1024_POLY_VEC_COMPRESSED_SZ \ + KYBER_POLY_VEC_COMPRESSED_SZ(KYBER1024_K, 11) + +/* Public key size. */ +#define KYBER1024_PUBLIC_KEY_SIZE \ + (KYBER1024_POLY_VEC_SZ + KYBER_SYM_SZ) +/* Private key size. */ +#define KYBER1024_PRIVATE_KEY_SIZE \ + (KYBER1024_POLY_VEC_SZ + KYBER1024_PUBLIC_KEY_SIZE + 2 * KYBER_SYM_SZ) +/* Cipher text size. */ +#define KYBER1024_CIPHER_TEXT_SIZE \ + (KYBER1024_POLY_VEC_COMPRESSED_SZ + KYBER1024_POLY_COMPRESSED_SZ) + + +/* Maximum dimensions and sizes of supported key types. */ +#ifdef WOLFSSL_KYBER1024 +#define KYBER_MAX_K KYBER1024_K +#define KYBER_MAX_PRIVATE_KEY_SIZE KYBER1024_PRIVATE_KEY_SIZE +#define KYBER_MAX_PUBLIC_KEY_SIZE KYBER1024_PUBLIC_KEY_SIZE +#define KYBER_MAX_CIPHER_TEXT_SIZE KYBER1024_CIPHER_TEXT_SIZE +#elif defined(WOLFSSL_KYBER768) +#define KYBER_MAX_K KYBER768_K +#define KYBER_MAX_PRIVATE_KEY_SIZE KYBER768_PRIVATE_KEY_SIZE +#define KYBER_MAX_PUBLIC_KEY_SIZE KYBER768_PUBLIC_KEY_SIZE +#define KYBER_MAX_CIPHER_TEXT_SIZE KYBER768_CIPHER_TEXT_SIZE +#elif defined(WOLFSSL_KYBER512) +#define KYBER_MAX_K KYBER512_K +#define KYBER_MAX_PRIVATE_KEY_SIZE KYBER512_PRIVATE_KEY_SIZE +#define KYBER_MAX_PUBLIC_KEY_SIZE KYBER512_PUBLIC_KEY_SIZE +#define KYBER_MAX_CIPHER_TEXT_SIZE KYBER512_CIPHER_TEXT_SIZE +#endif + +#define KYBER_SYM_SZ WC_ML_KEM_SYM_SZ +#define KYBER_SS_SZ WC_ML_KEM_SS_SZ +#define KYBER_MAKEKEY_RAND_SZ WC_ML_KEM_MAKEKEY_RAND_SZ +#define KYBER_ENC_RAND_SZ WC_ML_KEM_ENC_RAND_SZ +#define KYBER_POLY_SIZE WC_ML_KEM_POLY_SIZE + enum { - /* Flags of Kyber keys. */ + WC_ML_KEM_512 = 0, + WC_ML_KEM_768 = 1, + WC_ML_KEM_1024 = 2, + + MLKEM_KYBER = 0x10, + KYBER512 = 0 | MLKEM_KYBER, + KYBER768 = 1 | MLKEM_KYBER, + KYBER1024 = 2 | MLKEM_KYBER, + + KYBER_LEVEL1 = KYBER512, + KYBER_LEVEL3 = KYBER768, + KYBER_LEVEL5 = KYBER1024, + + /* Symmetric data size. */ + WC_ML_KEM_SYM_SZ = 32, + /* Shared secret size. */ + WC_ML_KEM_SS_SZ = 32, + /* Size of random required for making a key. */ + WC_ML_KEM_MAKEKEY_RAND_SZ = 2 * WC_ML_KEM_SYM_SZ, + /* Size of random required for encapsulation. */ + WC_ML_KEM_ENC_RAND_SZ = WC_ML_KEM_SYM_SZ, + + /* Encoded polynomial size. */ + WC_ML_KEM_POLY_SIZE = 384, + + /* Flags of ML-KEM keys. */ MLKEM_FLAG_PRIV_SET = 0x0001, MLKEM_FLAG_PUB_SET = 0x0002, MLKEM_FLAG_BOTH_SET = 0x0003, @@ -66,33 +350,10 @@ enum { MLKEM_COMP_11BITS = 11 }; - -/* SHAKE128 rate. */ -#define XOF_BLOCK_SIZE 168 - -/* Modulus of co-efficients of polynomial. */ -#define MLKEM_Q 3329 - - -/* Kyber-512 parameters */ -#ifdef WOLFSSL_WC_ML_KEM_512 -/* Number of bits of random to create noise from. */ -#define WC_ML_KEM_512_ETA1 MLKEM_CBD_ETA3 -#endif /* WOLFSSL_WC_ML_KEM_512 */ - -/* Kyber-768 parameters */ -#ifdef WOLFSSL_WC_ML_KEM_768 -/* Number of bits of random to create noise from. */ -#define WC_ML_KEM_768_ETA1 MLKEM_CBD_ETA2 -#endif /* WOLFSSL_WC_ML_KEM_768 */ - -/* Kyber-1024 parameters */ -#ifdef WOLFSSL_WC_ML_KEM_1024 -/* Number of bits of random to create noise from. */ -#define WC_ML_KEM_1024_ETA1 MLKEM_CBD_ETA2 -#endif /* WOLFSSL_KYBER1024 */ - - +#ifdef WOLF_PRIVATE_KEY_ID + #define MLKEM_MAX_ID_LEN 32 + #define MLKEM_MAX_LABEL_LEN 32 +#endif /* The data type of the hash function. */ #define MLKEM_HASH_T wc_Sha3 @@ -101,7 +362,7 @@ enum { #define MLKEM_PRF_T wc_Shake /* ML-KEM key. */ -struct MlKemKey { +typedef struct MlKemKey { /* Type of key: WC_ML_KEM_512, WC_ML_KEM_768, WC_ML_KEM_1024 */ int type; #ifdef WOLFSSL_MLKEM_DYNAMIC_KEYS @@ -157,12 +418,73 @@ struct MlKemKey { sword16* a; #endif #endif -}; +} MlKemKey; -#ifdef __cplusplus - extern "C" { + +WOLFSSL_API MlKemKey* wc_MlKemKey_New(int type, void* heap, int devId); +WOLFSSL_API int wc_MlKemKey_Delete(MlKemKey* key, MlKemKey** key_p); + +WOLFSSL_API int wc_MlKemKey_Init(MlKemKey* key, int type, void* heap, + int devId); +WOLFSSL_API int wc_MlKemKey_Free(MlKemKey* key); +#ifdef WOLF_PRIVATE_KEY_ID +WOLFSSL_API int wc_MlKemKey_Init_Id(MlKemKey* key, int type, + const unsigned char* id, int len, void* heap, int devId); +WOLFSSL_API int wc_MlKemKey_Init_Label(MlKemKey* key, int type, + const char* label, void* heap, int devId); #endif +WOLFSSL_API int wc_MlKemKey_MakeKey(MlKemKey* key, WC_RNG* rng); +WOLFSSL_API int wc_MlKemKey_MakeKeyWithRandom(MlKemKey* key, + const unsigned char* rand, int len); + +WOLFSSL_API int wc_MlKemKey_CipherTextSize(MlKemKey* key, word32* len); +WOLFSSL_API int wc_MlKemKey_SharedSecretSize(MlKemKey* key, word32* len); + +WOLFSSL_API int wc_MlKemKey_Encapsulate(MlKemKey* key, unsigned char* ct, + unsigned char* ss, WC_RNG* rng); +WOLFSSL_API int wc_MlKemKey_EncapsulateWithRandom(MlKemKey* key, + unsigned char* ct, unsigned char* ss, const unsigned char* rand, int len); +WOLFSSL_API int wc_MlKemKey_Decapsulate(MlKemKey* key, unsigned char* ss, + const unsigned char* ct, word32 len); + +WOLFSSL_API int wc_MlKemKey_DecodePrivateKey(MlKemKey* key, + const unsigned char* in, word32 len); +WOLFSSL_API int wc_MlKemKey_DecodePublicKey(MlKemKey* key, + const unsigned char* in, word32 len); + +WOLFSSL_API int wc_MlKemKey_PrivateKeySize(MlKemKey* key, word32* len); +WOLFSSL_API int wc_MlKemKey_PublicKeySize(MlKemKey* key, word32* len); +WOLFSSL_API int wc_MlKemKey_EncodePrivateKey(MlKemKey* key, unsigned char* out, + word32 len); +WOLFSSL_API int wc_MlKemKey_EncodePublicKey(MlKemKey* key, unsigned char* out, + word32 len); + + +#define KyberKey MlKemKey + +#define wc_KyberKey_Init(type, key, heap, devId) \ + wc_MlKemKey_Init(key, type, heap, devId) +#define wc_KyberKey_Free wc_MlKemKey_Free +#ifdef WOLF_PRIVATE_KEY_ID +#define wc_KyberKey_Init_Id wc_MlKemKey_Init_Id +#define wc_KyberKey_Init_Label wc_MlKemKey_Init_Label +#endif +#define wc_KyberKey_MakeKey wc_MlKemKey_MakeKey +#define wc_KyberKey_MakeKeyWithRandom wc_MlKemKey_MakeKeyWithRandom +#define wc_KyberKey_CipherTextSize wc_MlKemKey_CipherTextSize +#define wc_KyberKey_SharedSecretSize wc_MlKemKey_SharedSecretSize +#define wc_KyberKey_Encapsulate wc_MlKemKey_Encapsulate +#define wc_KyberKey_EncapsulateWithRandom wc_MlKemKey_EncapsulateWithRandom +#define wc_KyberKey_Decapsulate wc_MlKemKey_Decapsulate +#define wc_KyberKey_DecodePrivateKey wc_MlKemKey_DecodePrivateKey +#define wc_KyberKey_DecodePublicKey wc_MlKemKey_DecodePublicKey +#define wc_KyberKey_PrivateKeySize wc_MlKemKey_PrivateKeySize +#define wc_KyberKey_PublicKeySize wc_MlKemKey_PublicKeySize +#define wc_KyberKey_EncodePrivateKey wc_MlKemKey_EncodePrivateKey +#define wc_KyberKey_EncodePublicKey wc_MlKemKey_EncodePublicKey + + WOLFSSL_LOCAL void mlkem_init(void); diff --git a/wrapper/CSharp/user_settings.h b/wrapper/CSharp/user_settings.h index 1dae86d2e0..37b911c522 100644 --- a/wrapper/CSharp/user_settings.h +++ b/wrapper/CSharp/user_settings.h @@ -89,12 +89,10 @@ /* Enable ML-KEM, ML-DSA */ #define HAVE_MLKEM -#define WOLFSSL_WC_MLKEM #define WOLFSSL_HAVE_MLKEM /* Required for PQC with DTLS 1.3 (auto-enabled in settings.h, explicit for clarity) */ #define WOLFSSL_DTLS_CH_FRAG #define HAVE_DILITHIUM -#define WOLFSSL_WC_DILITHIUM #define WOLFSSL_SHAKE128 #define WOLFSSL_SHAKE256 diff --git a/wrapper/CSharp/wolfssl.vcxproj b/wrapper/CSharp/wolfssl.vcxproj index a01d55d5a4..6bb50d9da0 100644 --- a/wrapper/CSharp/wolfssl.vcxproj +++ b/wrapper/CSharp/wolfssl.vcxproj @@ -308,7 +308,6 @@ - diff --git a/wrapper/rust/wolfssl-wolfcrypt/headers.h b/wrapper/rust/wolfssl-wolfcrypt/headers.h index 6db82daa5e..719c2f01f0 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/headers.h +++ b/wrapper/rust/wolfssl-wolfcrypt/headers.h @@ -20,5 +20,5 @@ #include "wolfssl/wolfcrypt/aes.h" #include "wolfssl/wolfcrypt/pwdbased.h" #include "wolfssl/wolfcrypt/dilithium.h" -#include "wolfssl/wolfcrypt/mlkem.h" +#include "wolfssl/wolfcrypt/wc_mlkem.h" #include "wolfssl/wolfcrypt/wc_lms.h" diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index 35b8a76565..9b5ca2097c 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -78,7 +78,6 @@ if(CONFIG_WOLFSSL) zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/ed25519.c) zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/ed448.c) zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/error.c) - zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/ext_mlkem.c) zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/falcon.c) zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/fe_448.c) zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/fe_low_mem.c) diff --git a/zephyr/user_settings.h b/zephyr/user_settings.h index 29aea487c8..13c689da6d 100644 --- a/zephyr/user_settings.h +++ b/zephyr/user_settings.h @@ -352,7 +352,6 @@ extern "C" { /* PQC ML-KEM */ #if defined(CONFIG_WOLFSSL_MLKEM) #define WOLFSSL_HAVE_MLKEM - #define WOLFSSL_WC_MLKEM #define WOLFSSL_MLKEM_NO_LARGE_CODE #define WOLFSSL_MLKEM_SMALL #define WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM From 9393d62591540ffdcd3c312d366b5377c2f5f79f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Mon, 20 Apr 2026 15:12:16 +0200 Subject: [PATCH 165/167] Replace liboqs SPHINCS+ with SLH-DSA in certificate layer Replace the liboqs-based pre-standardization SPHINCS+ implementation with the native FIPS 205 SLH-DSA implementation across the certificate / ASN.1 / X.509 layers, and add SLH-DSA-rooted test certificates plus TLS 1.3 .conf scenarios that exercise the new verification path. All liboqs SPHINCS+ code is removed. This enables SLH-DSA for certificate chain authentication: CA certificates signed with SLH-DSA, certificate signature verification against an SLH-DSA root. TLS 1.3 entity authentication via CertificateVerify with SLH-DSA will be added in a follow-up PR. Follows RFC 9909 (X.509 Algorithm Identifiers for SLH-DSA) and NIST FIPS 205. Supports both SHAKE and SHA-2 parameter families across all twelve standardized variants. DER codec: - New PrivateKeyDecode, PublicKeyDecode, KeyToDer, PrivateKeyToDer, PublicKeyToDer with RFC 9909 encoding (bare OCTET STRING containing 4*n raw bytes = SK.seed || SK.prf || PK.seed || PK.root, no nested wrapper). OID auto-detection across all twelve SHAKE / SHA-2 variants. - PublicKeyDecode raw-bytes fast path mirrors wc_Falcon_PublicKeyDecode and wc_Dilithium_PublicKeyDecode so callers (notably wolfssl_x509_make_der and ConfirmSignature, which pass the raw BIT STRING contents stashed by StoreKey) decode correctly. Honours the caller's *inOutIdx start offset. - Error paths in Private/PublicKeyDecode preserve params/flags/ inOutIdx and only ForceZero the buffer half each helper actually writes; skip the wipe entirely on BAD_LENGTH_E (no bytes touched). - ImportPublic uses |= on flags so a Private-then-Public import sequence retains FLAG_PRIVATE. OID dispatch: - 12 standardized NIST OIDs (6 SHAKE + 6 SHA-2) per RFC 9909. The pre-standardization OID-collision mechanism is removed since NIST OIDs do not collide. - wc_SlhDsaOidToParam / wc_SlhDsaOidToCertType return NOT_COMPILED_IN (rather than -1) for recognised SLH-DSA OIDs whose parameter set isn't built; wc_IsSlhDsaOid recognises both. The x509 dispatch surfaces this as a precise diagnostic instead of the generic "No public key found". - wc_GetKeyOID picks a placeholder parameter from whatever variant is compiled in and #errors at compile time if none is. - asn_orig.c EncodeCert / EncodeCertReq accept SHA-2 SLH-DSA keyTypes alongside SHAKE. Tests and fixtures: - Test cert chain in certs/slhdsa/: SLH-DSA-SHAKE-128s and SLH-DSA-SHA2-128s self-signed roots that sign reused ML-DSA-44 entity keys (server + client), plus the gen script (gen-slhdsa-mldsa-certs.sh, OpenSSL >= 3.5). - New TLS 1.3 .conf scenarios under tests/suites.c dispatch: test-tls13-slhdsa-shake.conf, test-tls13-slhdsa-sha2.conf, and a wrong-CA negative test test-tls13-slhdsa-fail.conf. - DER round-trip and on-disk decode tests; bench_slhdsa_*_key.der fixtures regenerated with wolfSSL's own encoder so the codec is pinned to RFC 9909. - New unit test test_wc_slhdsa_x509_i2d_roundtrip exercises the raw PublicKeyDecode entry point that wolfssl_x509_make_der relies on. - test_wc_slhdsa_check_key now tests both Public-then-Private and Private-then-Public import orderings. Build / ABI: - DYNAMIC_TYPE_SPHINCS = 98 kept as RESERVED with a tombstone comment for ABI stability; new code should use DYNAMIC_TYPE_SLHDSA (107). - All build system / IDE project files updated; SPHINCS+ sources, headers, and test data removed. - Dead bench_slhdsa_*_key arrays removed from gencertbuf.pl and certs_test.h; the .der files on disk drive the decode tests. --- .wolfssl_known_macro_extras | 2 - .../template/components/wolfssl/component.mk | 2 +- .../components/wolfssl/component.mk | 2 +- .../components/wolfssl/component.mk | 2 +- .../components/wolfssl/component.mk | 2 +- .../components/wolfssl/component.mk | 2 +- IDE/INTIME-RTOS/Makefile | 20 +- IDE/INTIME-RTOS/libwolfssl.vcxproj | 3 +- IDE/INTIME-RTOS/wolfssl-lib.vcxproj | 2 +- .../wolfssl.X/nbproject/configurations.xml | 2 +- .../e2studio/SK-S7G2/wolfssl_lib/.project | 10 +- .../wolfssl-FIPS.xcodeproj/project.pbxproj | 8 +- IDE/XCODE/wolfssl.xcodeproj/project.pbxproj | 8 +- INSTALL | 8 +- certs/include.am | 2 +- certs/slhdsa/bench_slhdsa_sha2_128f_key.der | Bin 0 -> 84 bytes certs/slhdsa/bench_slhdsa_sha2_128s_key.der | Bin 0 -> 84 bytes certs/slhdsa/bench_slhdsa_sha2_192f_key.der | Bin 0 -> 116 bytes certs/slhdsa/bench_slhdsa_sha2_192s_key.der | Bin 0 -> 116 bytes certs/slhdsa/bench_slhdsa_sha2_256f_key.der | Bin 0 -> 150 bytes certs/slhdsa/bench_slhdsa_sha2_256s_key.der | Bin 0 -> 150 bytes certs/slhdsa/bench_slhdsa_shake128f_key.der | Bin 0 -> 84 bytes certs/slhdsa/bench_slhdsa_shake128s_key.der | Bin 0 -> 84 bytes certs/slhdsa/bench_slhdsa_shake192f_key.der | Bin 0 -> 116 bytes certs/slhdsa/bench_slhdsa_shake192s_key.der | Bin 0 -> 116 bytes certs/slhdsa/bench_slhdsa_shake256f_key.der | Bin 0 -> 150 bytes certs/slhdsa/bench_slhdsa_shake256s_key.der | Bin 0 -> 150 bytes certs/slhdsa/client-mldsa44-priv.pem | 57 + certs/slhdsa/client-mldsa44-sha2.der | Bin 0 -> 9745 bytes certs/slhdsa/client-mldsa44-sha2.pem | 1402 ++++++++++++ certs/slhdsa/client-mldsa44-shake.der | Bin 0 -> 9747 bytes certs/slhdsa/client-mldsa44-shake.pem | 1402 ++++++++++++ certs/slhdsa/gen-slhdsa-mldsa-certs.sh | 168 ++ certs/slhdsa/include.am | 36 + certs/slhdsa/root-slhdsa-sha2-128s-priv.der | Bin 0 -> 84 bytes certs/slhdsa/root-slhdsa-sha2-128s-priv.pem | 4 + certs/slhdsa/root-slhdsa-sha2-128s.der | Bin 0 -> 8435 bytes certs/slhdsa/root-slhdsa-sha2-128s.pem | 644 ++++++ certs/slhdsa/root-slhdsa-shake-128s-priv.der | Bin 0 -> 84 bytes certs/slhdsa/root-slhdsa-shake-128s-priv.pem | 4 + certs/slhdsa/root-slhdsa-shake-128s.der | Bin 0 -> 8437 bytes certs/slhdsa/root-slhdsa-shake-128s.pem | 644 ++++++ certs/slhdsa/server-mldsa44-priv.pem | 56 + certs/slhdsa/server-mldsa44-sha2.der | Bin 0 -> 9766 bytes certs/slhdsa/server-mldsa44-sha2.pem | 1404 ++++++++++++ certs/slhdsa/server-mldsa44-shake.der | Bin 0 -> 9768 bytes certs/slhdsa/server-mldsa44-shake.pem | 1404 ++++++++++++ .../sphincs/bench_sphincs_fast_level1_key.der | Bin 115 -> 0 bytes .../sphincs/bench_sphincs_fast_level3_key.der | Bin 166 -> 0 bytes .../sphincs/bench_sphincs_fast_level5_key.der | Bin 214 -> 0 bytes .../bench_sphincs_small_level1_key.der | Bin 115 -> 0 bytes .../bench_sphincs_small_level3_key.der | Bin 166 -> 0 bytes .../bench_sphincs_small_level5_key.der | Bin 214 -> 0 bytes certs/sphincs/include.am | 11 - cmake/functions.cmake | 8 - doc/dox_comments/header_files/asn.h | 2 +- gencertbuf.pl | 32 - rpm/spec.in | 2 - scripts/asn1_oid_sum.pl | 63 +- src/include.am | 1 - src/ssl.c | 3 - src/x509.c | 103 +- tests/api/test_slhdsa.c | 1898 ++++++++++++++--- tests/api/test_slhdsa.h | 14 +- tests/include.am | 3 + tests/suites.c | 44 + tests/test-tls13-slhdsa-fail.conf | 18 + tests/test-tls13-slhdsa-sha2.conf | 40 + tests/test-tls13-slhdsa-shake.conf | 35 + wolfcrypt/benchmark/benchmark.c | 245 +-- wolfcrypt/benchmark/benchmark.h | 5 +- wolfcrypt/src/asn.c | 1597 +++++++------- wolfcrypt/src/asn_orig.c | 126 +- wolfcrypt/src/sphincs.c | 1057 --------- wolfcrypt/src/wc_slhdsa.c | 455 +++- wolfcrypt/test/test.c | 32 +- wolfssl-VS2022.vcxproj | 2 +- wolfssl.vcproj | 8 +- wolfssl.vcxproj | 2 +- wolfssl/certs_test.h | 142 -- wolfssl/wolfcrypt/asn.h | 47 +- wolfssl/wolfcrypt/asn_public.h | 24 +- wolfssl/wolfcrypt/include.am | 1 - wolfssl/wolfcrypt/oid_sum.h | 144 +- wolfssl/wolfcrypt/settings.h | 4 +- wolfssl/wolfcrypt/sphincs.h | 167 -- wolfssl/wolfcrypt/types.h | 8 +- wolfssl/wolfcrypt/wc_slhdsa.h | 34 +- wrapper/CSharp/wolfssl.vcxproj | 2 +- zephyr/CMakeLists.txt | 2 +- 90 files changed, 10755 insertions(+), 2926 deletions(-) create mode 100644 certs/slhdsa/bench_slhdsa_sha2_128f_key.der create mode 100644 certs/slhdsa/bench_slhdsa_sha2_128s_key.der create mode 100644 certs/slhdsa/bench_slhdsa_sha2_192f_key.der create mode 100644 certs/slhdsa/bench_slhdsa_sha2_192s_key.der create mode 100644 certs/slhdsa/bench_slhdsa_sha2_256f_key.der create mode 100644 certs/slhdsa/bench_slhdsa_sha2_256s_key.der create mode 100644 certs/slhdsa/bench_slhdsa_shake128f_key.der create mode 100644 certs/slhdsa/bench_slhdsa_shake128s_key.der create mode 100644 certs/slhdsa/bench_slhdsa_shake192f_key.der create mode 100644 certs/slhdsa/bench_slhdsa_shake192s_key.der create mode 100644 certs/slhdsa/bench_slhdsa_shake256f_key.der create mode 100644 certs/slhdsa/bench_slhdsa_shake256s_key.der create mode 100644 certs/slhdsa/client-mldsa44-priv.pem create mode 100644 certs/slhdsa/client-mldsa44-sha2.der create mode 100644 certs/slhdsa/client-mldsa44-sha2.pem create mode 100644 certs/slhdsa/client-mldsa44-shake.der create mode 100644 certs/slhdsa/client-mldsa44-shake.pem create mode 100755 certs/slhdsa/gen-slhdsa-mldsa-certs.sh create mode 100644 certs/slhdsa/include.am create mode 100644 certs/slhdsa/root-slhdsa-sha2-128s-priv.der create mode 100644 certs/slhdsa/root-slhdsa-sha2-128s-priv.pem create mode 100644 certs/slhdsa/root-slhdsa-sha2-128s.der create mode 100644 certs/slhdsa/root-slhdsa-sha2-128s.pem create mode 100644 certs/slhdsa/root-slhdsa-shake-128s-priv.der create mode 100644 certs/slhdsa/root-slhdsa-shake-128s-priv.pem create mode 100644 certs/slhdsa/root-slhdsa-shake-128s.der create mode 100644 certs/slhdsa/root-slhdsa-shake-128s.pem create mode 100644 certs/slhdsa/server-mldsa44-priv.pem create mode 100644 certs/slhdsa/server-mldsa44-sha2.der create mode 100644 certs/slhdsa/server-mldsa44-sha2.pem create mode 100644 certs/slhdsa/server-mldsa44-shake.der create mode 100644 certs/slhdsa/server-mldsa44-shake.pem delete mode 100644 certs/sphincs/bench_sphincs_fast_level1_key.der delete mode 100644 certs/sphincs/bench_sphincs_fast_level3_key.der delete mode 100644 certs/sphincs/bench_sphincs_fast_level5_key.der delete mode 100644 certs/sphincs/bench_sphincs_small_level1_key.der delete mode 100644 certs/sphincs/bench_sphincs_small_level3_key.der delete mode 100644 certs/sphincs/bench_sphincs_small_level5_key.der delete mode 100644 certs/sphincs/include.am create mode 100644 tests/test-tls13-slhdsa-fail.conf create mode 100644 tests/test-tls13-slhdsa-sha2.conf create mode 100644 tests/test-tls13-slhdsa-shake.conf delete mode 100644 wolfcrypt/src/sphincs.c delete mode 100644 wolfssl/wolfcrypt/sphincs.h diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 5f3ba17498..43e09fcc2c 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -299,7 +299,6 @@ HAVE_PKCS7_RSA_RAW_SIGN_CALLBACK HAVE_POCO_LIB HAVE_RTP_SYS HAVE_SECURE_GETENV -HAVE_SPHINCS HAVE_STACK_SIZE_VERBOSE_LOG HAVE_THREADX HAVE_TM_TYPE @@ -852,7 +851,6 @@ WOLFSSL_NO_SERVER_GROUPS_EXT WOLFSSL_NO_SESSION_STATS WOLFSSL_NO_SIGALG WOLFSSL_NO_SOCKADDR_UN -WOLFSSL_NO_SPHINCS WOLFSSL_NO_STRICT_CIPHER_SUITE WOLFSSL_NO_TICKET_EXPIRE WOLFSSL_NO_TRUSTED_CERTS_VERIFY diff --git a/IDE/Espressif/ESP-IDF/examples/template/components/wolfssl/component.mk b/IDE/Espressif/ESP-IDF/examples/template/components/wolfssl/component.mk index 3b85dfa9e0..35b3462cdb 100644 --- a/IDE/Espressif/ESP-IDF/examples/template/components/wolfssl/component.mk +++ b/IDE/Espressif/ESP-IDF/examples/template/components/wolfssl/component.mk @@ -244,7 +244,6 @@ COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/siphash.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/sm2.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/sm3.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/sm4.o -COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/sphincs.o # COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/sp_arm32.o # COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/sp_arm64.o # COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/sp_armthumb.o @@ -270,6 +269,7 @@ COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wc_mlkem_poly.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wc_lms.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wc_pkcs11.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wc_port.o +COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wc_slhdsa.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wc_xmss.o # COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wolfcrypt_first.o # autogen exclusion # COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wolfcrypt_last.o # autogen exclusion diff --git a/IDE/Espressif/ESP-IDF/examples/wolfssl_benchmark/components/wolfssl/component.mk b/IDE/Espressif/ESP-IDF/examples/wolfssl_benchmark/components/wolfssl/component.mk index 15939e4e58..9afc520b3f 100644 --- a/IDE/Espressif/ESP-IDF/examples/wolfssl_benchmark/components/wolfssl/component.mk +++ b/IDE/Espressif/ESP-IDF/examples/wolfssl_benchmark/components/wolfssl/component.mk @@ -244,7 +244,6 @@ COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/siphash.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/sm2.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/sm3.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/sm4.o -COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/sphincs.o # COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/sp_arm32.o # COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/sp_arm64.o # COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/sp_armthumb.o @@ -270,6 +269,7 @@ COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wc_mlkem_poly.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wc_lms.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wc_pkcs11.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wc_port.o +COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wc_slhdsa.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wc_xmss.o # COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wolfcrypt_first.o # autogen exclusion # COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wolfcrypt_last.o # autogen exclusion diff --git a/IDE/Espressif/ESP-IDF/examples/wolfssl_client/components/wolfssl/component.mk b/IDE/Espressif/ESP-IDF/examples/wolfssl_client/components/wolfssl/component.mk index 3b85dfa9e0..35b3462cdb 100644 --- a/IDE/Espressif/ESP-IDF/examples/wolfssl_client/components/wolfssl/component.mk +++ b/IDE/Espressif/ESP-IDF/examples/wolfssl_client/components/wolfssl/component.mk @@ -244,7 +244,6 @@ COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/siphash.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/sm2.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/sm3.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/sm4.o -COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/sphincs.o # COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/sp_arm32.o # COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/sp_arm64.o # COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/sp_armthumb.o @@ -270,6 +269,7 @@ COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wc_mlkem_poly.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wc_lms.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wc_pkcs11.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wc_port.o +COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wc_slhdsa.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wc_xmss.o # COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wolfcrypt_first.o # autogen exclusion # COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wolfcrypt_last.o # autogen exclusion diff --git a/IDE/Espressif/ESP-IDF/examples/wolfssl_server/components/wolfssl/component.mk b/IDE/Espressif/ESP-IDF/examples/wolfssl_server/components/wolfssl/component.mk index 3b85dfa9e0..35b3462cdb 100644 --- a/IDE/Espressif/ESP-IDF/examples/wolfssl_server/components/wolfssl/component.mk +++ b/IDE/Espressif/ESP-IDF/examples/wolfssl_server/components/wolfssl/component.mk @@ -244,7 +244,6 @@ COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/siphash.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/sm2.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/sm3.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/sm4.o -COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/sphincs.o # COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/sp_arm32.o # COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/sp_arm64.o # COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/sp_armthumb.o @@ -270,6 +269,7 @@ COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wc_mlkem_poly.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wc_lms.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wc_pkcs11.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wc_port.o +COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wc_slhdsa.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wc_xmss.o # COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wolfcrypt_first.o # autogen exclusion # COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wolfcrypt_last.o # autogen exclusion diff --git a/IDE/Espressif/ESP-IDF/examples/wolfssl_test/components/wolfssl/component.mk b/IDE/Espressif/ESP-IDF/examples/wolfssl_test/components/wolfssl/component.mk index 76cbea8e6a..341883c3fb 100644 --- a/IDE/Espressif/ESP-IDF/examples/wolfssl_test/components/wolfssl/component.mk +++ b/IDE/Espressif/ESP-IDF/examples/wolfssl_test/components/wolfssl/component.mk @@ -244,7 +244,6 @@ COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/siphash.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/sm2.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/sm3.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/sm4.o -COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/sphincs.o # COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/sp_arm32.o # COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/sp_arm64.o # COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/sp_armthumb.o @@ -270,6 +269,7 @@ COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wc_mlkem_poly.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wc_lms.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wc_pkcs11.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wc_port.o +COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wc_slhdsa.o COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wc_xmss.o # COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wolfcrypt_first.o # autogen exclusion # COMPONENT_OBJS += $(WOLFSSL_ROOT)/wolfcrypt/src/wolfcrypt_last.o # autogen exclusion diff --git a/IDE/INTIME-RTOS/Makefile b/IDE/INTIME-RTOS/Makefile index 3ec9ae7199..1157b93fce 100644 --- a/IDE/INTIME-RTOS/Makefile +++ b/IDE/INTIME-RTOS/Makefile @@ -3,14 +3,14 @@ SWENGENV := $(RMX_SRC_BASE)/tools/swenghg # # makefile -- defines the macros, directives and rules necessary to build the -# wolfSSL library. +# wolfSSL library. # # NOTES: # 1. This makefile is a "wrapper" makefile for the Visual Studio 80 -# INtime package project. The makefile provides RCS and component +# INtime package project. The makefile provides RCS and component # release support not provided by the project's native visual Studio # makefile. -# +# # 2. The SWENG environment assumes makefile execution from a Windows NT # environment. # @@ -33,7 +33,7 @@ SWENGENV := $(RMX_SRC_BASE)/tools/swenghg # components. # # 6. A SWENG makefile executes standard MKS and MSVC tools. Other tool -# sets require additional macro and rule definition. +# sets require additional macro and rule definition. # # Default macros and directives. @@ -157,11 +157,11 @@ MAKEFILE := makefile ASM := C := CPP := -RCFILE := +RCFILE := -SRCS := +SRCS := OBJ := -CFGS := +CFGS := DEBRIS := $(LOGFILE) release* debug* *.sdf *.user *.aps *.bak *~ @@ -319,7 +319,6 @@ INCL_TARGS := wolfssl/callbacks.h \ wolfssl/wolfcrypt/sm4.h \ wolfssl/wolfcrypt/sp.h \ wolfssl/wolfcrypt/sp_int.h \ - wolfssl/wolfcrypt/sphincs.h \ wolfssl/wolfcrypt/srp.h \ wolfssl/wolfcrypt/tfm.h \ wolfssl/wolfcrypt/types.h \ @@ -329,6 +328,7 @@ INCL_TARGS := wolfssl/callbacks.h \ wolfssl/wolfcrypt/wc_lms.h \ wolfssl/wolfcrypt/wc_pkcs11.h \ wolfssl/wolfcrypt/wc_port.h \ + wolfssl/wolfcrypt/wc_slhdsa.h \ wolfssl/wolfcrypt/wc_xmss.h \ wolfssl/wolfcrypt/wolfevent.h \ wolfssl/wolfcrypt/wolfmath.h \ @@ -404,7 +404,7 @@ INCL_TARGS := wolfssl/callbacks.h \ # # NOTES: # 1. These files must always be included after the macro definitions and -# before the component-specific rules. +# before the component-specific rules. .INCLUDE:$(SWENGENV)/rules.wnt .INCLUDE:$(SWENGENV)/intimerules.wnt @@ -495,7 +495,7 @@ done # environment variables in a sub-shell before invoking the makefile. # # 2. Path vectors are converted to Microsoft-style pathname slashes -# via 'redmond.ksh' before passing them as environment variables to +# via 'redmond.ksh' before passing them as environment variables to # Microsoft tools. SOLUTIONFILE = wolfssl-lib.sln diff --git a/IDE/INTIME-RTOS/libwolfssl.vcxproj b/IDE/INTIME-RTOS/libwolfssl.vcxproj index 87ab3de8f4..03aa6f973e 100644 --- a/IDE/INTIME-RTOS/libwolfssl.vcxproj +++ b/IDE/INTIME-RTOS/libwolfssl.vcxproj @@ -81,7 +81,6 @@ - @@ -93,6 +92,7 @@ + @@ -164,6 +164,7 @@ + diff --git a/IDE/INTIME-RTOS/wolfssl-lib.vcxproj b/IDE/INTIME-RTOS/wolfssl-lib.vcxproj index 5b4226af94..9564c6ae66 100644 --- a/IDE/INTIME-RTOS/wolfssl-lib.vcxproj +++ b/IDE/INTIME-RTOS/wolfssl-lib.vcxproj @@ -106,7 +106,6 @@ - @@ -188,6 +187,7 @@ + diff --git a/IDE/MPLABX16/wolfssl.X/nbproject/configurations.xml b/IDE/MPLABX16/wolfssl.X/nbproject/configurations.xml index bd423ae2c1..9ae37688b7 100644 --- a/IDE/MPLABX16/wolfssl.X/nbproject/configurations.xml +++ b/IDE/MPLABX16/wolfssl.X/nbproject/configurations.xml @@ -81,12 +81,12 @@ ../../../wolfcrypt/src/sp_c32.c ../../../wolfcrypt/src/sp_c64.c ../../../wolfcrypt/src/sp_int.c - ../../../wolfcrypt/src/sphincs.c ../../../wolfcrypt/src/srp.c ../../../wolfcrypt/src/tfm.c ../../../wolfcrypt/src/wc_encrypt.c ../../../wolfcrypt/src/wc_pkcs11.c ../../../wolfcrypt/src/wc_port.c + ../../../wolfcrypt/src/wc_slhdsa.c ../../../wolfcrypt/src/wolfevent.c ../../../wolfcrypt/src/wolfmath.c diff --git a/IDE/Renesas/e2studio/SK-S7G2/wolfssl_lib/.project b/IDE/Renesas/e2studio/SK-S7G2/wolfssl_lib/.project index a7ff640024..3d015b4705 100644 --- a/IDE/Renesas/e2studio/SK-S7G2/wolfssl_lib/.project +++ b/IDE/Renesas/e2studio/SK-S7G2/wolfssl_lib/.project @@ -440,11 +440,6 @@ 1 PARENT-5-PROJECT_LOC/wolfcrypt/src/sp_x86_64.c - - src/wolfcrypt/sphincs.c - 1 - PARENT-5-PROJECT_LOC/wolfcrypt/src/sphincs.c - src/wolfcrypt/srp.c 1 @@ -495,6 +490,11 @@ 1 PARENT-5-PROJECT_LOC/wolfcrypt/src/wc_port.c + + src/wolfcrypt/wc_slhdsa.c + 1 + PARENT-5-PROJECT_LOC/wolfcrypt/src/wc_slhdsa.c + src/wolfcrypt/wc_xmss.c 1 diff --git a/IDE/XCODE/wolfssl-FIPS.xcodeproj/project.pbxproj b/IDE/XCODE/wolfssl-FIPS.xcodeproj/project.pbxproj index 0115d35159..ab2f56cfdb 100644 --- a/IDE/XCODE/wolfssl-FIPS.xcodeproj/project.pbxproj +++ b/IDE/XCODE/wolfssl-FIPS.xcodeproj/project.pbxproj @@ -126,6 +126,7 @@ 700F0CF62A2FC11300755BA7 /* ed448.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0CD22A2FC0D500755BA7 /* ed448.h */; }; 700F0CF72A2FC11300755BA7 /* ed25519.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0CE12A2FC0D500755BA7 /* ed25519.h */; }; 700F0CF92A2FC11300755BA7 /* falcon.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0CDD2A2FC0D500755BA7 /* falcon.h */; }; + 700F0D9A2A2FC11300755BA7 /* wc_slhdsa.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0D992A2FC0D500755BA7 /* wc_slhdsa.h */; }; 700F0CFA2A2FC11300755BA7 /* fe_448.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0CDE2A2FC0D500755BA7 /* fe_448.h */; }; 700F0CFB2A2FC11300755BA7 /* fe_operations.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0CC72A2FC0D400755BA7 /* fe_operations.h */; }; 700F0CFC2A2FC11300755BA7 /* fips.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0CCF2A2FC0D500755BA7 /* fips.h */; }; @@ -144,7 +145,6 @@ 700F0D092A2FC11300755BA7 /* siphash.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0CD42A2FC0D500755BA7 /* siphash.h */; }; 700F0D0A2A2FC11300755BA7 /* sp_int.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0CDF2A2FC0D500755BA7 /* sp_int.h */; }; 700F0D0B2A2FC11300755BA7 /* sp.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0CD12A2FC0D500755BA7 /* sp.h */; }; - 700F0D0C2A2FC11300755BA7 /* sphincs.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0CEC2A2FC0D500755BA7 /* sphincs.h */; }; 700F0D0D2A2FC11300755BA7 /* srp.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0CDC2A2FC0D500755BA7 /* srp.h */; }; 700F0D0F2A2FC11300755BA7 /* wc_pkcs11.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0CE82A2FC0D500755BA7 /* wc_pkcs11.h */; }; 700F0D102A2FC11300755BA7 /* wolfevent.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0CD62A2FC0D500755BA7 /* wolfevent.h */; }; @@ -284,6 +284,7 @@ 700F0CF62A2FC11300755BA7 /* ed448.h in CopyFiles */, 700F0CF72A2FC11300755BA7 /* ed25519.h in CopyFiles */, 700F0CF92A2FC11300755BA7 /* falcon.h in CopyFiles */, + 700F0D9A2A2FC11300755BA7 /* wc_slhdsa.h in CopyFiles */, 700F0CFA2A2FC11300755BA7 /* fe_448.h in CopyFiles */, 700F0CFB2A2FC11300755BA7 /* fe_operations.h in CopyFiles */, 700F0CFC2A2FC11300755BA7 /* fips.h in CopyFiles */, @@ -302,7 +303,6 @@ 700F0D092A2FC11300755BA7 /* siphash.h in CopyFiles */, 700F0D0A2A2FC11300755BA7 /* sp_int.h in CopyFiles */, 700F0D0B2A2FC11300755BA7 /* sp.h in CopyFiles */, - 700F0D0C2A2FC11300755BA7 /* sphincs.h in CopyFiles */, 700F0D0D2A2FC11300755BA7 /* srp.h in CopyFiles */, 700F0D0F2A2FC11300755BA7 /* wc_pkcs11.h in CopyFiles */, 700F0D102A2FC11300755BA7 /* wolfevent.h in CopyFiles */, @@ -575,6 +575,7 @@ 700F0CDB2A2FC0D500755BA7 /* eccsi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eccsi.h; path = ../../wolfssl/wolfcrypt/eccsi.h; sourceTree = ""; }; 700F0CDC2A2FC0D500755BA7 /* srp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = srp.h; path = ../../wolfssl/wolfcrypt/srp.h; sourceTree = ""; }; 700F0CDD2A2FC0D500755BA7 /* falcon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = falcon.h; path = ../../wolfssl/wolfcrypt/falcon.h; sourceTree = ""; }; + 700F0D992A2FC0D500755BA7 /* wc_slhdsa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wc_slhdsa.h; path = ../../wolfssl/wolfcrypt/wc_slhdsa.h; sourceTree = ""; }; 700F0CDE2A2FC0D500755BA7 /* fe_448.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fe_448.h; path = ../../wolfssl/wolfcrypt/fe_448.h; sourceTree = ""; }; 700F0CDF2A2FC0D500755BA7 /* sp_int.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sp_int.h; path = ../../wolfssl/wolfcrypt/sp_int.h; sourceTree = ""; }; 700F0CE02A2FC0D500755BA7 /* cryptocb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cryptocb.h; path = ../../wolfssl/wolfcrypt/cryptocb.h; sourceTree = ""; }; @@ -587,7 +588,6 @@ 700F0CE82A2FC0D500755BA7 /* wc_pkcs11.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wc_pkcs11.h; path = ../../wolfssl/wolfcrypt/wc_pkcs11.h; sourceTree = ""; }; 700F0CEA2A2FC0D500755BA7 /* rc2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = rc2.h; path = ../../wolfssl/wolfcrypt/rc2.h; sourceTree = ""; }; 700F0CEB2A2FC0D500755BA7 /* wolfmath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wolfmath.h; path = ../../wolfssl/wolfcrypt/wolfmath.h; sourceTree = ""; }; - 700F0CEC2A2FC0D500755BA7 /* sphincs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sphincs.h; path = ../../wolfssl/wolfcrypt/sphincs.h; sourceTree = ""; }; 9D2E31D6291CE2190082B941 /* dtls13.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dtls13.c; path = ../../src/dtls13.c; sourceTree = ""; }; 9D2E31D9291CE2370082B941 /* dtls.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dtls.c; path = ../../src/dtls.c; sourceTree = ""; }; 9D2E31DC291CE2740082B941 /* quic.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = quic.c; path = ../../src/quic.c; sourceTree = ""; }; @@ -638,6 +638,7 @@ 700F0CD22A2FC0D500755BA7 /* ed448.h */, 700F0CE12A2FC0D500755BA7 /* ed25519.h */, 700F0CDD2A2FC0D500755BA7 /* falcon.h */, + 700F0D992A2FC0D500755BA7 /* wc_slhdsa.h */, 700F0CDE2A2FC0D500755BA7 /* fe_448.h */, 700F0CC72A2FC0D400755BA7 /* fe_operations.h */, 700F0CCF2A2FC0D500755BA7 /* fips.h */, @@ -656,7 +657,6 @@ 700F0CD42A2FC0D500755BA7 /* siphash.h */, 700F0CDF2A2FC0D500755BA7 /* sp_int.h */, 700F0CD12A2FC0D500755BA7 /* sp.h */, - 700F0CEC2A2FC0D500755BA7 /* sphincs.h */, 700F0CDC2A2FC0D500755BA7 /* srp.h */, 700F0CE82A2FC0D500755BA7 /* wc_pkcs11.h */, 700F0CD62A2FC0D500755BA7 /* wolfevent.h */, diff --git a/IDE/XCODE/wolfssl.xcodeproj/project.pbxproj b/IDE/XCODE/wolfssl.xcodeproj/project.pbxproj index 2481d83d16..972f46d1cd 100644 --- a/IDE/XCODE/wolfssl.xcodeproj/project.pbxproj +++ b/IDE/XCODE/wolfssl.xcodeproj/project.pbxproj @@ -257,6 +257,7 @@ 700F0C0E2A2FBC5100755BA7 /* ed448.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0BF82A2FBC1600755BA7 /* ed448.h */; }; 700F0C0F2A2FBC5100755BA7 /* ed25519.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0BF42A2FBC1600755BA7 /* ed25519.h */; }; 700F0C112A2FBC5100755BA7 /* falcon.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0C022A2FBC1600755BA7 /* falcon.h */; }; + 700F0C9A2A2FBC5100755BA7 /* wc_slhdsa.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0C992A2FBC1600755BA7 /* wc_slhdsa.h */; }; 700F0C122A2FBC5100755BA7 /* fe_448.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0BEB2A2FBC1500755BA7 /* fe_448.h */; }; 700F0C132A2FBC5100755BA7 /* fe_operations.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0BF62A2FBC1600755BA7 /* fe_operations.h */; }; 700F0C142A2FBC5100755BA7 /* fips.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0C002A2FBC1600755BA7 /* fips.h */; }; @@ -274,7 +275,6 @@ 700F0C202A2FBC5100755BA7 /* siphash.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0BFE2A2FBC1600755BA7 /* siphash.h */; }; 700F0C212A2FBC5100755BA7 /* sp_int.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0BE82A2FBC1500755BA7 /* sp_int.h */; }; 700F0C222A2FBC5100755BA7 /* sp.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0BE92A2FBC1500755BA7 /* sp.h */; }; - 700F0C232A2FBC5100755BA7 /* sphincs.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0BE22A2FBC1500755BA7 /* sphincs.h */; }; 700F0C242A2FBC5100755BA7 /* srp.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0BF32A2FBC1600755BA7 /* srp.h */; }; 700F0C262A2FBC5100755BA7 /* wc_pkcs11.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0BF52A2FBC1600755BA7 /* wc_pkcs11.h */; }; 700F0C272A2FBC5100755BA7 /* wolfevent.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 700F0BE62A2FBC1500755BA7 /* wolfevent.h */; }; @@ -621,6 +621,7 @@ 700F0C0E2A2FBC5100755BA7 /* ed448.h in CopyFiles */, 700F0C0F2A2FBC5100755BA7 /* ed25519.h in CopyFiles */, 700F0C112A2FBC5100755BA7 /* falcon.h in CopyFiles */, + 700F0C9A2A2FBC5100755BA7 /* wc_slhdsa.h in CopyFiles */, 700F0C122A2FBC5100755BA7 /* fe_448.h in CopyFiles */, 700F0C132A2FBC5100755BA7 /* fe_operations.h in CopyFiles */, 700F0C142A2FBC5100755BA7 /* fips.h in CopyFiles */, @@ -638,7 +639,6 @@ 700F0C202A2FBC5100755BA7 /* siphash.h in CopyFiles */, 700F0C212A2FBC5100755BA7 /* sp_int.h in CopyFiles */, 700F0C222A2FBC5100755BA7 /* sp.h in CopyFiles */, - 700F0C232A2FBC5100755BA7 /* sphincs.h in CopyFiles */, 700F0C242A2FBC5100755BA7 /* srp.h in CopyFiles */, 700F0C262A2FBC5100755BA7 /* wc_pkcs11.h in CopyFiles */, 700F0C272A2FBC5100755BA7 /* wolfevent.h in CopyFiles */, @@ -971,7 +971,6 @@ 6AC8513B272CB04F00F2B32A /* kdf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = kdf.h; path = ../../wolfssl/wolfcrypt/kdf.h; sourceTree = ""; }; 700F0BE02A2FBC1500755BA7 /* rc2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = rc2.h; path = ../../wolfssl/wolfcrypt/rc2.h; sourceTree = ""; }; 700F0BE12A2FBC1500755BA7 /* hpke.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = hpke.h; path = ../../wolfssl/wolfcrypt/hpke.h; sourceTree = ""; }; - 700F0BE22A2FBC1500755BA7 /* sphincs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sphincs.h; path = ../../wolfssl/wolfcrypt/sphincs.h; sourceTree = ""; }; 700F0BE32A2FBC1500755BA7 /* curve448.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = curve448.h; path = ../../wolfssl/wolfcrypt/curve448.h; sourceTree = ""; }; 700F0BE52A2FBC1500755BA7 /* curve25519.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = curve25519.h; path = ../../wolfssl/wolfcrypt/curve25519.h; sourceTree = ""; }; 700F0BE62A2FBC1500755BA7 /* wolfevent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wolfevent.h; path = ../../wolfssl/wolfcrypt/wolfevent.h; sourceTree = ""; }; @@ -1001,6 +1000,7 @@ 700F0C002A2FBC1600755BA7 /* fips.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fips.h; path = ../../wolfssl/wolfcrypt/fips.h; sourceTree = ""; }; 700F0C012A2FBC1600755BA7 /* ge_operations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ge_operations.h; path = ../../wolfssl/wolfcrypt/ge_operations.h; sourceTree = ""; }; 700F0C022A2FBC1600755BA7 /* falcon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = falcon.h; path = ../../wolfssl/wolfcrypt/falcon.h; sourceTree = ""; }; + 700F0C992A2FBC1600755BA7 /* wc_slhdsa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wc_slhdsa.h; path = ../../wolfssl/wolfcrypt/wc_slhdsa.h; sourceTree = ""; }; 700F0C032A2FBC1600755BA7 /* async.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = async.h; path = ../../wolfssl/wolfcrypt/async.h; sourceTree = ""; }; 700F0C292A2FBCAD00755BA7 /* quic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = quic.h; path = ../../wolfssl/quic.h; sourceTree = ""; }; 700F0C2A2A2FBCAD00755BA7 /* sniffer_error.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sniffer_error.h; path = ../../wolfssl/sniffer_error.h; sourceTree = ""; }; @@ -1148,6 +1148,7 @@ 700F0BF82A2FBC1600755BA7 /* ed448.h */, 700F0BF42A2FBC1600755BA7 /* ed25519.h */, 700F0C022A2FBC1600755BA7 /* falcon.h */, + 700F0C992A2FBC1600755BA7 /* wc_slhdsa.h */, 700F0BEB2A2FBC1500755BA7 /* fe_448.h */, 700F0BF62A2FBC1600755BA7 /* fe_operations.h */, 700F0C002A2FBC1600755BA7 /* fips.h */, @@ -1165,7 +1166,6 @@ 700F0BFE2A2FBC1600755BA7 /* siphash.h */, 700F0BE82A2FBC1500755BA7 /* sp_int.h */, 700F0BE92A2FBC1500755BA7 /* sp.h */, - 700F0BE22A2FBC1500755BA7 /* sphincs.h */, 700F0BF32A2FBC1600755BA7 /* srp.h */, 700F0BF52A2FBC1600755BA7 /* wc_pkcs11.h */, 700F0BE62A2FBC1500755BA7 /* wolfevent.h */, diff --git a/INSTALL b/INSTALL index 43ba022e6e..058b5a1edf 100644 --- a/INSTALL +++ b/INSTALL @@ -252,17 +252,15 @@ The following NIST Competition winning algorithms are supported by the native wolfSSL implementation: - - ML-KEM (CRYSTALS-KYBER) (key encapsulation mechanism) - - ML-DSA (CRYSTALS-Dilithium) (signature scheme) + - ML-KEM (FIPS 203, CRYSTALS-KYBER) (key encapsulation mechanism) + - ML-DSA (FIPS 204, CRYSTALS-Dilithium) (signature scheme) + - SLH-DSA (FIPS 205, SPHINCS+) (signature scheme) Falcon (signature scheme) is still provided through liboqs integration. To enable it, pass both --with-liboqs and --enable-falcon to configure (CMake: -DWOLFSSL_OQS=yes -DWOLFSSL_FALCON=yes). Passing --with-liboqs without --enable-falcon (or vice versa) is now an error. - SPHINCS+ is in the middle of being replaced with native SLH-DSA; see - PR #10261. Until that lands, SPHINCS+ continues to build via liboqs. - The following NIST Competition Round 3 finalist algorithms were supported, but have been removed after 5.3.3 - SABER (KEM) diff --git a/certs/include.am b/certs/include.am index b19881d31f..840af3dc30 100644 --- a/certs/include.am +++ b/certs/include.am @@ -159,7 +159,7 @@ include certs/intermediate/include.am include certs/falcon/include.am include certs/rsapss/include.am include certs/dilithium/include.am -include certs/sphincs/include.am +include certs/slhdsa/include.am include certs/rpk/include.am include certs/acert/include.am include certs/mldsa/include.am diff --git a/certs/slhdsa/bench_slhdsa_sha2_128f_key.der b/certs/slhdsa/bench_slhdsa_sha2_128f_key.der new file mode 100644 index 0000000000000000000000000000000000000000..2b58abddcf219f5f7546f2a0e2a2a8ed6c7f4ea3 GIT binary patch literal 84 zcmXpAVq#=4;AZ1YX!Br9WoBU(WpOA(14U?{7!7b;ysDmOp?Cbj#-~S~`6g=u0CcG! Ak^lez literal 0 HcmV?d00001 diff --git a/certs/slhdsa/bench_slhdsa_sha2_128s_key.der b/certs/slhdsa/bench_slhdsa_sha2_128s_key.der new file mode 100644 index 0000000000000000000000000000000000000000..92e8e9bc102a895f30dd7d1ee1b17a80d5dc3b2b GIT binary patch literal 84 zcmXpAVq#=4;AZ1YX!Br9WoBU(VR1-A14(Eg84cKHKbZ6Wf5zdz+EZt#Zm?Pi00>te AYybcN literal 0 HcmV?d00001 diff --git a/certs/slhdsa/bench_slhdsa_sha2_192f_key.der b/certs/slhdsa/bench_slhdsa_sha2_192f_key.der new file mode 100644 index 0000000000000000000000000000000000000000..f9351012db243fa430765954c130c48d0a9033ff GIT binary patch literal 116 zcmXpgVq#=4;AZ1YX!Br9WoBU(XGxfd15CmJCgT95xBoNGntqG*d?WYlwTE?2Pn%ug J^)pIq9{`y@IR^j$ literal 0 HcmV?d00001 diff --git a/certs/slhdsa/bench_slhdsa_sha2_192s_key.der b/certs/slhdsa/bench_slhdsa_sha2_192s_key.der new file mode 100644 index 0000000000000000000000000000000000000000..6791ea070c1dbf749aef71607c213c862107f122 GIT binary patch literal 116 zcmXpgVq#=4;AZ1YX!Br9WoBU(V@YVl0h(}tW*k7fdlF0Jw`XkEjkmw@Zd>$7dh+Dj I$Oosz0eHtV_y7O^ literal 0 HcmV?d00001 diff --git a/certs/slhdsa/bench_slhdsa_sha2_256f_key.der b/certs/slhdsa/bench_slhdsa_sha2_256f_key.der new file mode 100644 index 0000000000000000000000000000000000000000..772f575dabe8a4fa81cf5586180b82750428850c GIT binary patch literal 150 zcmXqLoXo_?V8G4Bnb79Jn99t;EXmT?u#o`RL;!3i0Djrjc5M+n+Pt8sdfJJX%k2t( T&QU8(2@0OAd9&7iOUW_-ZD&{N literal 0 HcmV?d00001 diff --git a/certs/slhdsa/bench_slhdsa_sha2_256s_key.der b/certs/slhdsa/bench_slhdsa_sha2_256s_key.der new file mode 100644 index 0000000000000000000000000000000000000000..4144e443e8ad976173ba2f6134e68c386a2a50a6 GIT binary patch literal 150 zcmXqLoXo_?V8G4Bnb79Jn99t;EWy&)u#f;)L;x%%0Op%>?hEeL*vZ!X(^b literal 0 HcmV?d00001 diff --git a/certs/slhdsa/bench_slhdsa_shake256f_key.der b/certs/slhdsa/bench_slhdsa_shake256f_key.der new file mode 100644 index 0000000000000000000000000000000000000000..264c2393a75ab1f2fc173f68dd2715bc6b35fc21 GIT binary patch literal 150 zcmXqLoXo_?V8G4Bnb79Jn99t;EYH%|5J&(75dgsifPYV&-czZGM}uFVclo7XeA8_6 Tf)^itWvTUi^;W#KeCJ^RAlNmF literal 0 HcmV?d00001 diff --git a/certs/slhdsa/bench_slhdsa_shake256s_key.der b/certs/slhdsa/bench_slhdsa_shake256s_key.der new file mode 100644 index 0000000000000000000000000000000000000000..712c6b9b34b13676583331eb2fd8adb762411c83 GIT binary patch literal 150 zcmXqLoXo_?V8G4Bnb79Jn99t;EXUH=;79;C5dh8vfTbK~`S%G<;ws-79_t^R%W1Xk Tu*@I+d9nM_3obme`?eVX1H3HY literal 0 HcmV?d00001 diff --git a/certs/slhdsa/client-mldsa44-priv.pem b/certs/slhdsa/client-mldsa44-priv.pem new file mode 100644 index 0000000000..607aa7e779 --- /dev/null +++ b/certs/slhdsa/client-mldsa44-priv.pem @@ -0,0 +1,57 @@ +-----BEGIN PRIVATE KEY----- +MIIKPgIBADALBglghkgBZQMEAxEEggoqMIIKJgQgB5k2MNHvdz51ebw/tXj6ECZ3 +eScZNPdog84ItrvpBhgEggoAnXtmhZqzy98ZxarirCp5r/H94riNkdr1joa0kTwV +KhLGmElj7VDLeQ1YQ/IAjjVfJS88y6vZBIUgHV5ViJRkN0/TZIm+4svclsximVbe +JozeMBhm+dkb8c8yxXhIAgSyOxY96ahsgQaf9Gl3foY0pd2xSSDgLxcr3GL5k14X +UThKgghIBiQISGCStFETBSgauI2JtCiQqGQMgUTjxomEFg5EAkALly3ZSJIBFWRC +OGgaJ44TE1IAMQLEAiYUQk0QKJAgMTIBwWALAWyAAGxjJlACgEVKpkAcsiUIIWIk +SU4hh0gbSAIchmQEopDasIkUGU5JJgUYyQCapIXcpEhBIoECNXBjJorUEGEgRIij +omACooEZtHCcFoSBAkEitZHSCFESNEHTuBEIITJCRGUASGmSRhIilGHCtnDimI3T +JgmEIgoJuQ1MsGQDJC4BloSZBBGbyBGjEpAMFgqMICyUCEYEtg1gsIjcBCKaRkIh +Qk1JRikkJ2ITJQUKhAVKEEakBoAcNIIapUwZlokkJmEQRozBGEgcGW0EmI2LRgIC +kA1cEmVKFHICwWUbIU1cOG0DQYykJg6JooBKQCYcmWmBEjDDQCEiRmEiQ3ICRyYQ +oQmBIgbDIi5kMhIBsgFZlkUENQjDto0UMGwMlQyjSIBjQFAAICbcICQBRnHhQFHC +Eg3EEEAMQyQCMyYCyAQaIwjgFoqasC0TQAhDIjJEOG3RRJDUhglIggDimGgSsZEJ +kG3JMIXAhICcxkzhEJHYljDatmjIxmXjBlBcFBECREmbomhaMpBSgEUAJjACRkzU +yEmcuJDEIIoMFQ0JN44SRkUIIyUhoRGAkGWTRnLhKG1EllGBEoAERkqLEG0TRlFT +NkrhpkXgIgFIpgASkXAjs0ACqGXbQgbgBmrjlmFIlGVDImncIoWbhIlZGGRDsCCL +qClYMCQKF44RQS0kuCWJFCAUQZEjoiQhFyERsQQDhEwLI2JQhmVUIkJCgoAIpVHZ +BjEjAJEQqU3iBGZENjCLskmYxnAZpIxapg1jAC6blHCKIC1iJixCJmwSEy7bGAgR +IS6KsHEBwSzjRGLjlCgLOHBAFGViwEGhBiGCokSUsCwhEI0UlnESFAURJwQSl2XE +Am5YxGzAEHCEwEWZElKAqIjTuCgBF3ADwxCIGApTkkBTxiCTwIGkkJCTkgUiiAjI +AGTwGc/fNxkyya8KPEqPnLO0SilcbdKBED+fTSMYZe4Dp+sUmcCrbC6tMaAVf/0S +wwuGjR0PGY4s3cHO8nXCP//DvH1cQFCB1ZLJ3IlWAARkZiepwEPNXdbmx4So8ALa +o/LXJ6xSMLOVUzQxHwbydLpYUs+5C9E5PmD+2VVy+9lcLZ5fXZXj+CVtFHAk+BUE +JBQVq6UzyeD9nLM9V+/04ochm9QnPm57I55WfGfSOepStb1t2gDHHgrubRb7mjSu +i4V7aZqY1hUmGU8JveAGeZMsnqqHPMarygeYqbRjkHgTKNxi8wQE1VWKkfuL3B1q +UxbeGYjnlvyxtRHnkU5ixqS4qwh/dQZFC1RjeH0KhGSWo51Ec/YWdEY1EKKcvlvA +4V7EqCSr4cJZUhbYybY+WK37yDZlfvGOT5HI4vOn0yirYiGWljHvoa/pLjb+Cevx +jfr7WDmjzkXkH92MJKnXM4D1uwURUsu8swkULgrdROQvhYROCdoLIHhhKrlnnITg +67uV0DFdg5EVvyf1HiXJxUioqoz86mB6zZeSqwfHngtUvEHcf/eJchLuhRiGG+BE +4U97dT0n94LuOPdh48ml21n/IA18uNIs7IhdxAMIZ7RyO1zGFqsaa3KZh4CnNVq5 +kU5cesaUGNLll3zVkV1XVun/WmT5yP8qWrrODc9nCbEtY8VyeMdPwcAjQq/yuC95 +t/ddpbrVD6ib8q9dcpKGzhBS090VFWWoOMKYJ0dOsd4Fi9k21w/1M25MnEl9jgd5 +dxSK6juGxK/5TI9DJr+kaPSz59IDxIUc1QoYVVH+sVuOee0Hh3261AmYk8upTzHO +4qs68m06608sGmvy/4H69DS+tU4a6vIQez6Wz2c32K7wPQOo5pMdWbwaBrQcDWjy +vidYGmaSyjdjZypZYr1A1enZSklpjEz0ZYU0zDfQXj5linNrMtL6bFSUtyB1bkrJ ++HLI3NoJyuOUm/jr6DK+u0FotgGN6Z/Tf/2R4ivATvlCW6LsyDUPNtnRiGWiKupQ +mRlQMSQQe1ZnpKXK46XJd7TRityk/8ru2Fg+baXUszkVossCnP6TZhjY0s6yjU0o +YsR7OeIqAm44Wcw12pmywZMktmOo/jeRMngR+ZVyLdFRQBOQ+qc9XfrOwT3Uq7dL +jNHZRcZ+DMa83RH6UoNZLaeorj+4WKKEFAV3+bn+BdFK+eh9Hri0OfyAHbI4jcRj +wOkVX/72gbI94BPs0HUdA7hr3BO2CbGC5AISGMseLc7u8sSkmhumUcP9c8HFhee7 +ROdhngADChjkYoZF2PpbcUaGDjqJbbLXDtdlPswW5Zwt8g5EZBT9qS+26HiiVKNF +XrAUAveh4BZY2cNYWuZypwqfM/jVGFQegFQeUWlTYFfw+caXS1uY5hrBtGHtPcfo +FNaSSXxGHjogtiCzJeD4OerJfcs4mAOVmplprtQMHlA0bYVqMy+MA2qkGv2sijQI +6Yi2oLmWp0E3f+fC0a/lYGgG/nCBgLT+922I7MaQOAQ0JBu4V4ZA0hnsoTYR/yI0 +jDE/Y6FPzmdzXHhdhcjYQFpA34g98230m7Ypvwfd2VEnppeyb2HvHKkBUivQEuRA +puolgLqAYYeljX5xCWj7xggvmCznqzC03jm2cf8ykGFl+cQWftrEBXcL8fngwH0U +V29IuurgxZNgFOP4amey3FboN39ZY1x30uOnc1OcjfSs6QeKHL6nTR9gNp8znfQt +T2HdM0AfbhCf9x/wlYlijAT3ZOBm0EtKeZZwVtsH2q8A0VTsB6wJJZFG0U+/UOnm +VHORx/tnM+sBG9xFWtyjljVscZum5ytllS2ugQooMfAqngHigy/gpGXKkkoPMkW1 +5hkkRCsr6mRGsknQL+JkDR/u5CkEmYCLfHo6TNQY1Pc7DEQ5PQ8Q1B9Hf7Hf0sHX +HR/3KTZUS45Vm8sI9TEP1AxeGFl+6u9a0g3GlF2DvVWpL/6FgtmpkUD2zPmIunIJ +Np+hxXzqk9SuSKoukZMvG2Y+hw7doB4ZjSXfvzmC33p8fJWyvScrPXbvBTj8ijhG +bdWqOWupyvWf/YHCT6WMEpCjA+b9eWpIaWzDeDCdeaaBp/Tpz06dWAEQ7SwnLlyq +yNBX7wWl55+NB6fXSAV7cBes49RKCZLEjoQDdFphYQ4aDB+MTtlslkKskwvUFGzY +Jw6buXcN1d2CCPWJ20SGjbIsqAZfvExzJ/4yJjwzg9oYyQ== +-----END PRIVATE KEY----- diff --git a/certs/slhdsa/client-mldsa44-sha2.der b/certs/slhdsa/client-mldsa44-sha2.der new file mode 100644 index 0000000000000000000000000000000000000000..bdcf1fbd60e11394bdec9be84d386e6d3ce97c01 GIT binary patch literal 9745 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 MNf+u3<~Zm90DRbP-T(jq literal 0 HcmV?d00001 diff --git a/certs/slhdsa/client-mldsa44-sha2.pem b/certs/slhdsa/client-mldsa44-sha2.pem new file mode 100644 index 0000000000..85407c7fe3 --- /dev/null +++ b/certs/slhdsa/client-mldsa44-sha2.pem @@ -0,0 +1,1402 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 2 (0x2) + Signature Algorithm: SLH-DSA-SHA2-128s + Issuer: C=US, ST=Montana, L=Bozeman, O=wolfSSL_SLH-DSA, OU=Root-SLH-DSA-sha2, CN=www.wolfssl.com, emailAddress=info@wolfssl.com + Validity + Not Before: Apr 28 08:10:05 2026 GMT + Not After : Jan 22 08:10:05 2029 GMT + Subject: C=US, ST=Montana, L=Bozeman, O=wolfSSL_SLH-DSA, OU=Client-mldsa44-sha2, CN=www.wolfssl.com, emailAddress=info@wolfssl.com, UID=wolfSSL + Subject Public Key Info: + Public Key Algorithm: ML-DSA-44 + ML-DSA-44 Public-Key: + pub: + 9d:7b:66:85:9a:b3:cb:df:19:c5:aa:e2:ac:2a:79: + af:f1:fd:e2:b8:8d:91:da:f5:8e:86:b4:91:3c:15: + 2a:12:61:89:56:b2:dc:76:13:f4:35:1a:72:dc:a1: + 14:f6:95:76:25:a3:93:69:23:db:80:f9:13:55:9d: + 52:ed:df:83:77:46:19:f9:55:46:91:36:11:23:6a: + b4:17:40:f8:32:a8:86:d7:07:99:fd:ee:28:bd:39: + fc:6d:00:ee:59:b0:c6:c2:0b:60:ce:3b:6b:8f:08: + ff:8b:da:31:c3:b6:64:e3:7f:7d:df:51:ed:d1:c1: + b9:ec:23:ce:b9:ff:04:67:4e:93:bb:fd:6b:2b:e9: + d4:ca:22:b1:af:a4:6c:e0:cc:52:5c:0c:ef:0c:ea: + 4c:8c:a2:22:9f:c2:34:41:26:c4:01:42:64:a1:1c: + fd:19:6a:df:7d:ac:a3:9e:30:46:82:39:07:a2:2a: + c3:d4:f0:55:10:4b:e9:f0:d5:af:12:15:33:01:97: + bf:53:6a:51:27:1a:1e:3f:da:2f:5b:57:aa:02:11: + 4b:ee:0c:27:ca:f5:7b:8a:fd:ac:b2:2f:35:b4:2a: + 3d:bb:cc:a1:16:77:48:c3:45:24:01:33:25:9c:7b: + 65:e8:2b:48:4e:3c:bd:26:cc:e8:11:8f:5d:aa:2d: + cc:c4:22:61:b1:e0:9f:b8:cf:86:67:bd:a1:9c:6c: + fe:94:0b:e6:14:57:64:e0:76:c5:59:88:58:f1:a2: + 15:da:0a:7a:c8:f8:83:44:9b:f7:0d:68:fd:35:dc: + 46:82:17:e3:b0:24:23:3d:21:43:11:c3:5e:0c:54: + e5:67:e1:04:63:45:b4:bb:44:21:96:6c:24:bc:3a: + 4e:c4:0f:b4:b6:29:ef:f7:f9:0c:70:e0:a6:43:92: + 55:05:0b:24:e2:52:a8:9f:5d:90:50:38:99:33:76: + 71:39:10:2d:e9:ce:4a:99:51:21:c2:81:cd:54:6b: + f1:04:2a:04:ae:93:11:d5:d4:dc:96:c8:f5:84:3f: + c1:23:17:47:0c:7e:b5:01:a4:4d:3a:cb:c2:28:ce: + 6c:26:35:55:c0:f4:a9:7b:30:4f:20:e8:84:4b:8f: + c1:7d:51:52:34:96:11:3d:6a:34:52:03:3c:e1:27: + 3e:f0:3e:0c:b4:41:a5:06:93:51:e4:a6:e3:3d:fb: + f0:ad:f8:73:0b:3d:64:dd:00:d8:ba:09:bd:84:90: + 7e:b4:f3:84:a9:88:84:9f:f1:37:3b:ea:29:c8:21: + 8f:a6:9a:1a:70:14:34:5d:6f:e0:f3:6f:4d:ff:43: + 61:53:1b:d6:47:e5:9b:41:d8:ec:ef:7e:94:a6:4c: + 64:5a:1a:45:c2:64:17:57:cb:1e:e2:54:9c:5a:08: + 5b:85:4c:41:22:3d:be:3d:13:aa:56:a7:fb:90:29: + ad:4d:74:a6:48:ee:db:22:57:03:82:77:73:f2:00: + 36:d1:34:6c:ae:e6:a8:b5:30:b8:7a:78:a6:6b:c6: + ae:82:1c:44:f4:60:4d:dc:fd:bc:9b:a5:9e:92:55: + 55:f4:7d:7e:bf:4d:f2:cf:15:b3:4e:c8:94:3b:a4: + 54:9d:0c:b0:92:f0:77:49:af:aa:22:4d:0f:48:ac: + f9:4a:d7:b1:d2:fb:be:39:35:7b:14:43:7d:73:ad: + 8a:31:97:eb:0e:24:d2:9a:78:8d:9f:74:51:41:51: + aa:4f:c4:cd:dd:7d:c4:f7:e5:70:8c:01:18:7b:96: + dc:d7:a4:ce:dc:61:62:0c:5f:b9:5c:93:2a:4c:83: + c7:e2:2f:bf:e2:14:95:89:a8:70:21:29:8a:64:0a: + c4:eb:2f:1b:e3:34:fa:5e:95:1b:50:ed:35:1e:ba: + 11:f2:ff:98:f9:38:83:17:89:b8:d4:96:95:4e:33: + c6:90:a1:b4:e1:e3:d4:81:33:b7:2c:fc:05:52:90: + b7:4a:c1:4c:66:87:90:38:b1:0a:15:bf:d1:1c:c4: + 80:a0:68:d1:7b:69:37:16:e2:88:a8:5c:99:fc:20: + a6:a9:d4:67:2f:63:fa:67:1e:71:d9:ea:75:7c:28: + c7:53:2c:3d:54:83:f6:0b:4d:01:89:26:24:ce:73: + 1b:4d:b9:7a:a9:4a:77:f3:5a:8b:39:d6:07:49:d6: + f8:64:a0:07:b4:04:4c:cf:50:13:be:39:2b:f3:56: + 68:e4:ad:65:3b:3d:d1:57:bd:d6:bc:30:6a:e9:92: + a3:09:5e:11:bd:d4:56:91:91:da:5e:1a:e9:fd:fd: + d9:bd:60:fc:36:42:42:78:e2:8c:60:d6:be:ac:77: + 8f:6e:73:23:fe:0d:5a:1c:f2:47:47:69:92:63:64: + 35:3e:2d:af:d6:11:ce:62:83:97:d1:d3:07:da:85: + e7:3a:db:a2:ef:52:e8:ee:47:8e:01:2b:b0:93:d2: + bc:3f:b9:6a:da:15:e4:2c:46:a9:14:08:0d:a3:71: + ee:0d:ab:48:ff:e0:d3:af:2c:23:45:47:e0:3f:8e: + 05:ea:44:ed:78:9a:11:ec:5a:76:72:b9:82:3f:36: + bc:74:21:42:22:c5:2c:49:ad:1b:f4:8f:c4:26:79: + a1:e7:2f:e7:a7:d3:db:bc:70:2d:b4:b1:7e:c9:55: + 4f:de:a5:55:f8:ca:48:b8:6d:cd:59:ef:5d:89:f7: + 6b:d0:06:0c:0e:4e:7f:a9:ea:d4:82:5b:e4:35:74: + b7:84:b4:2c:20:1b:f2:46:6a:21:f5:88:d6:3e:04: + 3e:5d:54:58:4a:ac:0c:fe:ff:af:6f:aa:98:92:c9: + c7:05:9b:dc:40:38:bd:ed:cd:50:1f:51:17:39:b5: + ad:f1:5a:b3:c2:ee:e5:b3:ba:27:10:f0:03:92:72: + 5c:09:20:00:ca:f0:8e:30:c1:c7:dc:a4:14:8b:98: + 28:0d:00:d2:cb:c0:57:11:1b:25:f0:7e:54:a8:a9: + b7:b7:6b:34:0a:1f:3b:67:a1:5b:5a:74:ee:64:1e: + fe:2c:ae:a8:00:ff:1d:fb:d8:26:d9:84:90:b1:bf: + 3e:d2:19:25:a6:56:63:fd:c7:9c:b7:c8:7e:72:5c: + 67:71:48:cc:b4:c0:24:44:30:d2:64:a9:a4:ad:63: + 2a:e5:7e:e7:12:ac:61:92:59:26:e6:6b:f9:b7:93: + 0a:48:61:43:77:a7:ce:7b:83:6a:9a:39:e9:e7:0d: + a2:4d:63:65:20:ac:24:ea:54:7b:30:4b:2a:68:47: + d7:17:c6:13:84:19:d6:67:9c:05:5c:72:f9:32:63: + 35:87:aa:7b:4d:f6:47:53:d6:73:82:a3:2b:32:a3: + 8e:31:26:15:9c:13:61:8d:94:b2:da:69:fd:14:41: + a5:67:f4:66:1f:8d:14:76:d2:07:8f:4b:8a:73:c6: + 08:41:c0:ed:95:98:98:43:f3:c1:3a:20:8a:14:25: + fa:57:03:e6:cb:e8:3c:a6:d6:1a:e7:d7:06:ec:dc: + f9:a9:13:27:09:3f:85 + X509v3 extensions: + X509v3 Subject Key Identifier: + 06:BA:09:60:1C:F1:80:5D:2F:50:EF:88:EB:58:18:F9:47:2C:0D:6C + X509v3 Authority Key Identifier: + BD:80:23:3A:06:DD:38:57:EE:6B:C2:94:7B:EA:BF:43:57:3A:B0:8C + X509v3 Basic Constraints: critical + CA:FALSE + X509v3 Key Usage: critical + Digital Signature, Key Encipherment, Key Agreement + X509v3 Extended Key Usage: + TLS Web Client Authentication + Signature Algorithm: SLH-DSA-SHA2-128s + Signature Value: + 5a:fa:bd:47:54:b0:1c:e5:b6:e9:3c:94:59:20:00:6d:46:cf: + 4b:30:1e:e5:30:c9:94:0c:f5:05:e3:04:cc:f3:a5:b5:8f:92: + b2:26:91:e6:21:fe:cf:d9:e4:a4:83:51:d3:e1:09:53:c1:f7: + 9b:58:ae:99:46:3b:04:3b:21:be:d1:c9:8d:49:15:08:d3:81: + b7:46:c2:5f:d0:0b:cc:7b:56:69:8d:91:61:2e:a5:d2:ca:63: + 6a:b3:1d:cc:94:aa:b6:28:94:08:4c:17:56:1b:f1:d7:00:94: + 8c:14:f2:c2:18:06:e2:71:00:14:e1:7e:bd:7e:71:23:8a:35: + bc:78:0b:7b:4a:c5:78:1a:32:b9:65:d4:cc:5d:c7:a8:6c:10: + 2a:49:ce:50:e2:8d:ac:62:33:dc:01:84:4f:6c:a0:34:70:e1: + 7c:c7:07:b7:65:a9:c3:84:54:52:7d:f0:c4:1f:ad:6a:14:3d: + e9:27:0e:88:19:be:f5:81:37:b8:f1:32:d7:18:15:2a:c9:86: + 18:8e:8a:45:78:ce:b4:94:05:bf:e4:ef:31:4f:18:f6:26:3c: + c1:39:5d:08:d1:bf:3c:d8:fd:68:fc:11:15:86:96:84:35:85: + de:0c:47:a1:5c:b6:a3:d5:e9:50:d2:0a:bf:2a:6c:03:23:94: + b3:51:5c:61:f6:1e:a6:6f:ab:b1:4d:a8:7e:28:e0:5b:49:8c: + de:32:37:09:50:e0:ff:45:0c:77:4e:c4:22:e0:39:45:c6:3c: + 03:1a:1e:34:28:9e:8c:aa:78:45:99:3a:fc:57:43:e2:a9:57: + 57:2c:25:7c:86:31:48:16:b1:10:41:cb:23:0d:26:80:4b:d8: + de:ab:c8:d4:8a:bb:c2:45:57:91:75:be:30:b5:c9:b4:82:18: + 83:d8:dc:33:d1:38:06:c3:2b:c6:02:76:26:07:a6:b4:cb:78: + af:68:e3:a8:1d:6a:ed:72:1d:aa:92:42:db:52:dd:ff:81:07: + 29:35:9e:c3:7d:34:a9:8b:1a:05:e3:51:5d:5b:79:9a:9c:41: + 58:b5:50:c9:21:a9:d1:29:e6:20:a8:da:0c:2e:0d:06:f7:ec: + 84:e3:7e:eb:00:38:f1:25:a8:9a:b7:1d:5a:08:bf:02:9f:66: + 8f:6f:07:d1:f6:8c:80:aa:92:9a:ef:e7:f1:62:4c:3d:f3:99: + f2:c1:ce:e3:96:f5:e3:11:8c:d7:ce:53:2e:1e:17:4a:9d:b2: + 24:a2:fc:4c:9d:cc:95:ab:cb:c8:10:c4:c9:55:26:31:21:28: + d7:1c:a1:46:18:95:c7:32:cf:51:6d:2f:34:7b:05:ee:7e:04: + 5a:a4:50:28:24:73:52:86:5f:f0:c0:c8:50:9e:0d:3d:75:23: + 93:ea:aa:f7:ba:7c:d8:6b:e2:01:41:e7:b1:5e:38:58:f3:1c: + 6c:c9:60:16:57:fd:51:0c:3e:c1:e0:75:10:74:03:3b:93:f4: + bd:6b:c4:c0:1d:ca:d9:42:fd:fa:45:61:e5:e8:42:72:3f:72: + fb:dd:53:e1:0f:6c:c5:f5:df:c9:bd:74:91:46:54:33:3d:43: + 0b:9e:26:f6:27:6a:49:a6:ee:32:96:f2:1a:c8:32:61:77:9e: + e6:cc:f5:54:0f:c2:3f:4a:9e:56:66:54:aa:4f:6d:54:8c:9f: + 99:e4:41:10:cf:a3:2b:38:53:9a:23:a3:eb:e1:e9:29:40:5b: + 81:ce:4f:b6:32:9f:f5:f2:b2:6a:45:be:be:4d:3d:25:68:b8: + 84:69:b1:77:49:69:ac:09:e9:65:e3:22:79:32:62:c8:2e:21: + 60:f0:19:50:73:ff:53:fe:64:28:0b:5b:7e:33:b7:8c:f1:82: + 25:00:23:e6:eb:a3:ca:fe:b9:45:b7:a4:82:4e:5c:6f:0d:6a: + 42:1d:68:9e:ff:53:d2:0d:fa:6a:c5:f5:88:ef:5b:48:7a:00: + 9f:d8:e8:fc:d3:51:42:53:dd:3a:0c:02:d6:88:c2:4c:df:ea: + 0a:78:5b:48:e8:ae:d1:46:af:40:37:f3:6b:2c:8d:75:37:58: + a9:c1:88:f2:41:a8:a1:85:c8:4c:7a:20:cf:b7:74:2e:ac:f5: + 3d:7c:d3:97:2c:8c:e3:4a:c1:2f:27:aa:4f:3a:59:03:e7:d5: + 87:62:48:58:8d:d6:61:16:7c:d8:29:0f:41:0b:8d:c9:e0:e5: + d0:19:fa:3f:d5:43:1b:43:54:ef:9b:16:d9:bd:0e:16:cf:4c: + 98:8c:66:ec:42:24:ef:38:21:75:07:e2:bd:b5:aa:45:39:b6: + cf:71:24:75:88:d3:95:a4:9c:ce:17:8d:f1:40:37:d0:5d:97: + a2:30:f4:a9:d6:b4:ba:a2:81:ad:a1:e3:16:35:de:b3:fc:c2: + f6:40:cb:f5:d3:64:30:f8:cd:42:b3:49:b8:2b:6d:b3:c1:4c: + 13:73:33:48:4a:52:98:93:44:5c:5f:5f:63:39:e4:0a:41:15: + c9:73:30:43:48:5d:3b:eb:f0:9e:87:e4:b4:07:81:da:0b:12: + 1f:b6:15:42:87:a3:12:df:7d:18:93:23:fc:98:cd:8d:9f:4b: + ab:99:ac:7c:87:64:56:1d:5d:bf:d2:fe:38:89:42:8b:47:82: + 44:17:cd:c2:63:43:68:10:8f:73:a2:b0:10:e1:0f:8d:9b:b5: + fc:70:d8:2c:3a:ab:4e:7f:31:17:c1:7b:b9:82:89:22:a6:b2: + 22:ad:a3:2f:4b:f6:b7:fe:f7:33:29:8d:66:77:f1:30:8e:59: + 67:01:51:85:61:23:75:8e:4c:b6:fd:40:23:68:98:ee:df:c9: + 8e:e7:89:2e:d5:c5:ec:de:ef:69:bf:04:66:75:69:fb:7f:a8: + fe:4e:89:2c:9b:f5:35:97:b9:94:d4:e6:89:33:05:2e:1a:ed: + 22:da:3d:c0:27:fd:cf:d3:1f:22:c3:a0:56:32:b1:40:86:13: + a8:6a:13:50:40:64:81:52:b1:5a:04:4b:e8:13:84:54:b2:79: + 3b:46:dc:06:7d:90:03:54:8c:4b:d6:c6:ec:c1:42:9b:1b:e1: + 56:37:c4:40:7a:51:c6:69:d9:09:2c:31:c0:47:50:3d:19:3b: + 04:8a:4b:07:64:e1:c5:ee:af:1d:30:03:52:ac:5e:b9:ad:b7: + 1f:90:5a:b0:f2:5d:53:4a:e3:b8:35:e5:8d:bc:f2:ff:50:9f: + 26:2d:c9:c7:a1:45:05:3b:87:d7:83:11:f9:e6:d8:32:14:f4: + 2f:77:08:55:fb:e3:b3:d7:27:17:fd:60:9d:d9:e4:c4:d3:cb: + db:80:d9:41:5a:62:ce:18:45:22:d7:8d:6a:2c:6a:84:c3:a8: + bb:65:d7:ac:01:3a:ea:da:40:23:a4:5e:47:21:af:dd:98:ae: + d7:f8:e2:bc:ac:1c:0c:61:37:d2:68:c1:c6:e6:e1:d0:68:30: + f0:a8:46:27:e6:8b:3a:56:22:f0:bc:e7:6e:64:bd:b9:26:3a: + 00:6e:f1:99:56:3c:d1:aa:28:1d:35:69:62:b1:c7:1f:ca:bf: + 49:f3:46:45:9b:80:a2:e2:ca:5f:ce:7a:7e:b1:33:8f:3e:c6: + 26:2e:c4:df:23:32:8b:3e:fd:18:7e:d8:6f:43:93:2f:cc:3d: + 3b:59:a2:77:8b:54:27:ce:5e:f3:03:1c:22:0d:d2:84:67:26: + 11:60:62:75:22:af:c0:18:a1:36:82:31:96:05:7f:37:d4:b0: + 1c:43:d8:fa:97:92:7c:6d:a7:7d:79:9b:59:df:12:d3:58:ce: + f5:bc:33:9d:e5:64:de:79:bf:31:80:2d:a7:27:69:69:88:b0: + b4:23:16:5f:d0:a7:2f:ff:1c:c4:20:fd:26:59:e3:e2:49:34: + 06:f9:6c:3a:7d:0b:ec:18:3f:8f:6e:a5:be:3c:eb:7f:88:60: + f8:99:14:ee:94:0d:bb:f6:40:29:97:f8:ac:16:a5:2a:87:4d: + 15:0d:9d:2c:2c:14:03:45:cc:0f:bd:f6:37:e6:f6:a2:94:da: + dc:e4:17:d6:82:10:c6:e5:ff:4b:29:d4:0f:db:5f:74:27:bc: + 75:f5:f3:75:49:15:37:e5:4b:05:8f:27:d8:94:c3:f8:1d:5c: + c2:ee:51:16:ff:df:96:3a:91:07:a3:17:e4:f0:89:6b:58:b1: + 23:6c:71:d4:5a:09:a9:8a:fe:2e:55:bc:b6:9f:a5:04:64:a5: + 11:c9:f9:1c:6a:de:ab:e2:2f:1e:72:87:5f:b6:ed:8c:93:49: + ba:9d:12:96:ad:22:56:f9:09:13:af:8c:ed:d7:9a:52:31:3a: + 6a:86:18:00:ec:a7:4a:40:12:ff:97:c6:79:5c:34:72:4e:d5: + 09:ea:2d:a1:8c:59:ae:92:cc:5f:ca:d8:b4:22:e0:cd:71:b7: + d7:bf:25:ca:65:3e:50:e9:4d:ad:8f:34:92:a5:91:be:79:53: + 59:ea:26:2b:1d:5f:19:65:cc:7e:d0:23:2c:9a:56:77:3f:b5: + e3:e0:d6:13:0c:81:90:bb:85:de:de:fe:56:f4:ca:0a:ce:c4: + 95:a9:62:af:e4:ef:0b:8d:1f:95:2f:ef:91:9b:5b:7a:35:9d: + 32:c0:ad:26:b1:c6:54:99:ac:c0:ba:fe:1a:82:99:fa:13:ad: + 08:24:ae:61:a5:f6:07:b2:89:74:f8:e3:82:e8:4f:51:19:60: + 75:31:1a:39:15:ef:fd:cd:15:2f:10:50:be:1b:1d:67:3c:73: + c2:6c:56:4b:3f:02:c4:ab:5e:25:6b:f1:22:e9:09:dc:99:f2: + 65:23:81:ad:40:28:42:4c:bd:c7:ce:a9:20:71:65:9d:c3:59: + c3:0a:44:f0:6f:be:05:a5:a0:2a:30:42:37:b8:c8:7f:fe:ef: + 27:5b:01:ed:7c:77:86:8c:97:3e:0b:a4:46:c7:dd:6f:ec:64: + 8b:43:db:c3:ff:7a:f1:1e:00:3b:0e:c0:79:c1:de:cd:a3:e3: + 82:c2:46:d7:e2:30:75:23:6f:6a:b6:da:11:44:e0:8b:87:9c: + 7e:14:dd:58:59:f8:15:bf:a0:37:cd:ba:88:a8:36:84:4e:86: + 30:ea:3c:49:0e:3c:44:08:f4:53:b0:c1:ad:2d:8c:bf:72:91: + cd:af:0e:2e:36:90:8c:fb:5c:c8:a4:61:7f:21:49:d7:c0:bd: + 67:fc:f6:e1:f3:f0:ba:ad:b9:1a:1c:4c:11:7c:ae:74:8b:95: + d1:b1:7e:c2:46:2d:0d:b6:bd:2f:84:a3:c3:4b:e9:d0:d9:79: + b7:ca:7d:a5:6e:ff:e5:78:36:b1:71:86:f6:0c:93:d9:f7:b8: + 66:bc:2a:ba:23:d2:a9:c8:1f:64:f1:18:9d:8e:91:6a:f5:a1: + 79:c6:54:bb:67:21:04:e9:17:06:78:28:dd:ee:56:d0:95:30: + 34:de:5c:a2:3e:da:5a:05:73:60:72:db:1d:5f:27:e4:ad:ea: + fb:24:91:e1:ce:0d:28:d9:5a:fa:b9:fc:de:85:29:22:f9:6c: + 58:79:d0:c7:42:5a:f9:1d:82:d3:1d:6f:cd:8c:7d:5c:91:91: + 1e:35:7c:86:65:9a:2f:31:9c:00:f6:9e:d5:85:99:3a:f1:6c: + 28:ee:7a:23:2c:78:27:20:36:b8:b8:dd:d8:14:3a:d3:ff:7e: + a3:30:f6:1b:07:f5:74:e0:f2:f8:e4:fb:a2:4e:1b:be:58:8e: + 82:c5:07:84:4a:9e:e3:54:e8:79:c4:88:43:87:03:cd:c2:a9: + 73:64:a4:9a:dd:72:1b:8b:05:80:30:5e:cd:f5:9b:30:79:b3: + 6d:4c:dd:19:f1:84:d0:72:bf:56:a0:42:00:77:17:40:f7:c4: + 8e:20:60:70:6d:fe:31:d3:41:ef:22:cf:dd:3e:31:e4:62:ad: + 47:85:4a:11:36:9b:84:96:8f:dd:10:ea:78:e0:fd:c7:8c:50: + 5c:b8:78:6a:bf:f4:9f:9e:b4:2e:ba:25:12:70:e4:fe:d1:8b: + 9c:9a:1b:97:45:f3:6b:8c:fc:cb:59:2d:85:08:93:61:50:69: + 6e:55:4c:57:7e:64:4f:90:7f:a7:1c:52:8b:fa:c1:33:83:d8: + 81:96:72:88:fa:fb:0a:e2:73:38:9f:a1:8a:47:36:48:28:dc: + e8:4e:69:0d:a9:68:1a:f1:ef:84:57:97:07:58:70:10:b4:1e: + 28:8f:d9:4e:97:fe:0c:d5:95:cc:14:1a:dc:8d:d2:e9:a9:ab: + bf:3a:8d:52:0b:f5:5b:47:8a:e6:3f:e5:ee:3c:62:99:1b:eb: + 0e:d1:16:60:9c:4c:d5:f7:23:f5:22:c8:09:c6:f1:79:fc:4d: + 29:17:a2:07:b9:7b:82:59:d7:96:4f:0d:fb:0e:cb:03:12:cf: + a0:9b:c2:d1:7a:31:9b:0c:e0:08:4f:c4:d4:53:8f:f2:cd:24: + e5:8d:06:20:e0:ac:bb:ef:41:a9:98:b8:07:c8:96:63:d3:5c: + e5:5b:ea:56:21:42:fd:29:fd:b0:68:61:1f:d2:e2:b8:dd:b1: + 4c:3c:4a:9c:0a:97:a8:25:5f:e4:45:d6:32:a4:b8:df:f4:d2: + 67:36:e0:4c:5d:19:fb:6a:84:62:21:81:9f:50:31:f6:a5:3b: + 54:6b:0e:a1:2e:00:4f:7b:a9:ce:93:06:e8:64:d5:a6:9d:41: + 9b:ee:f7:c2:63:cb:af:fc:0f:79:2b:ec:5b:5c:03:a1:bc:b0: + 6f:83:f6:8f:02:89:d8:68:a2:43:b6:7d:cf:74:11:0f:ea:eb: + c1:bd:62:42:3d:35:da:cc:99:5d:b4:f8:44:e1:ab:27:4b:80: + 7d:c9:16:b5:cd:80:b9:11:73:d9:8a:81:37:be:94:32:8a:94: + ce:a6:16:34:60:58:d3:d2:95:24:7b:ce:b5:ca:52:4c:a9:cc: + 3d:9d:68:66:c2:b4:2f:59:1e:20:fd:55:11:e2:6e:38:9b:40: + 09:44:06:05:61:5c:3c:49:63:a2:7f:58:4c:43:da:90:13:7e: + e2:25:5a:3b:df:88:4c:e0:21:eb:46:8e:2b:71:19:28:68:bc: + 8c:cf:33:e8:dd:15:9c:d5:96:4d:22:f7:6a:aa:42:12:56:a7: + 75:92:0c:a3:5a:95:d3:aa:7c:28:dc:13:0d:1c:e7:10:5e:69: + cd:c2:01:c5:92:40:5c:4b:0a:30:d1:11:57:ee:67:21:d3:0e: + b4:8a:47:b6:71:a8:47:25:1d:1b:eb:49:f1:cc:f7:2a:f7:8f: + d9:b9:43:80:a2:c6:b7:dd:c2:31:a3:fe:e9:e6:0f:22:da:cb: + c8:e2:7d:9b:4b:e5:7a:69:42:f9:44:c3:03:8e:d8:21:96:25: + 8b:90:8a:77:77:22:1e:cb:61:5b:c6:52:d7:03:8c:69:1f:0d: + c1:4b:ce:9a:6f:20:f6:b4:7d:96:01:c7:70:34:04:b5:8d:7a: + a0:3a:68:aa:61:50:52:45:3a:cd:be:57:1d:76:be:e1:60:5f: + 8c:82:4c:fc:58:41:c2:60:a5:57:67:e3:66:c1:a6:55:4f:34: + 9c:34:a1:92:6f:3c:8e:3d:16:f3:af:a4:5d:12:fc:92:34:3e: + 8e:ec:89:4b:54:67:18:1a:08:56:4f:a6:86:f0:8d:a3:13:df: + 2f:cb:82:f0:85:92:3c:48:14:54:82:fb:09:dc:95:12:ab:49: + df:f5:d8:13:07:df:3d:eb:1e:9d:da:e9:48:be:e5:48:41:59: + 69:44:f7:78:df:bd:14:be:1e:3d:72:fe:12:5e:aa:18:a0:a3: + 64:ba:ef:86:81:d3:a9:01:77:8b:5e:c7:6a:67:e9:6b:ed:af: + 43:38:42:e4:5f:1d:e1:a6:4e:3a:8f:64:f1:e3:62:c7:dd:99: + 9a:13:5b:12:ad:16:c6:22:27:de:9e:4a:e9:4d:ad:6d:2b:dc: + a7:aa:00:69:d4:f0:50:8a:69:d7:a1:e6:55:99:e2:bf:4a:94: + 9f:1a:e8:0f:d5:ac:8e:d8:14:bf:6b:3f:d6:50:e1:0c:e0:21: + f5:1c:23:35:67:d6:70:b0:ae:08:68:57:b5:b2:8e:3d:a1:3e: + 72:49:9e:3c:7c:ed:8a:be:dd:2c:cd:63:16:af:99:1a:44:aa: + df:57:1b:fb:aa:15:a3:02:02:16:b9:17:63:61:91:f1:4a:f9: + df:22:2a:70:0f:51:68:83:75:c9:b8:52:ea:48:0a:d1:3b:b9: + c1:bc:2a:8a:f0:29:01:f0:28:92:cf:32:9a:4d:d3:0e:4b:da: + 29:5c:30:25:c2:96:8d:ee:28:61:9a:b5:8b:da:bf:1e:9c:01: + c5:45:75:64:52:d7:cb:de:46:27:ac:36:be:f7:14:ef:40:f8: + 08:0a:e8:69:3d:37:b2:04:86:08:2c:16:78:74:98:89:f9:04: + ea:32:ba:e4:5c:4a:31:84:cd:b8:6f:53:4b:bc:87:e4:df:e2: + ce:11:53:75:93:16:a6:57:2d:36:bb:78:e2:89:bc:9e:9b:0b: + 87:b4:c3:29:53:3b:e3:da:c0:e7:01:8e:39:e0:5a:5f:64:ba: + d3:fb:5a:37:5b:af:b0:bc:b2:66:5b:4b:c6:65:a2:5e:fc:39: + 61:74:76:1f:8e:5f:55:c4:3c:43:54:de:d3:3a:c6:fa:8d:a0: + 99:28:44:3a:2c:cb:ce:46:d0:ef:40:d1:cf:67:8b:a2:ea:e4: + b9:cd:7a:14:22:82:0d:82:ce:4e:5d:de:8e:3b:06:bc:fc:5e: + 74:e6:e6:0f:cc:96:24:68:39:3c:29:98:68:ed:26:b6:d9:ef: + 3c:1c:a7:e4:da:7e:51:57:11:21:75:f2:71:fd:0c:b5:18:3a: + 32:73:39:42:4e:c4:76:bd:de:6d:a0:35:bc:b9:c4:24:99:1b: + 23:70:f1:31:ab:f7:53:95:e1:59:c2:6b:ac:45:94:1b:fb:64: + 6d:f2:ea:2a:1c:f5:ff:b2:9d:f8:a1:e1:ba:f8:33:6a:4a:15: + 43:ce:1c:f6:a8:a0:0f:b1:ac:7d:18:10:b3:3d:5f:bb:a7:29: + d7:c2:c8:05:be:41:09:ab:68:3f:5e:9c:d1:95:21:76:4a:0a: + 9b:f3:0e:18:9d:93:c1:58:6a:e0:f2:be:72:8f:f6:b5:f3:ae: + 20:60:f9:8b:57:56:57:d0:46:53:99:5e:64:a9:9f:c5:27:d1: + ac:1f:01:85:e1:36:cb:69:5e:aa:3d:86:12:7c:7d:bc:77:7a: + 94:dd:16:a3:26:4a:10:c4:8e:93:22:42:89:3e:8a:67:f4:82: + 20:de:7b:2b:1a:9e:33:d4:70:18:01:3d:b0:5c:9a:a3:9d:0b: + 73:90:c4:b0:33:72:bc:14:9e:ae:0e:c1:42:f4:e1:40:b7:04: + 5c:5b:16:bd:39:c5:74:4e:59:ba:d2:8c:e0:ad:09:da:61:43: + 6b:a4:91:49:e2:a4:50:d4:ef:14:2f:be:ad:ef:cd:32:b0:05: + e7:94:19:d2:9b:fc:2b:c9:21:33:4f:92:6b:d7:f2:82:86:ba: + 56:3f:e2:fa:a6:63:6f:81:de:5a:14:b5:83:52:a8:2b:3b:3d: + 22:27:53:4c:f2:55:cd:88:d7:16:11:4c:b5:d5:78:d7:28:0c: + d1:ea:cb:ec:31:e2:35:8c:ec:08:04:e7:8b:cc:0c:a2:25:9b: + 7c:4c:16:52:2a:48:cc:05:dc:2e:11:42:c1:21:a2:8f:e9:be: + 47:d1:84:d3:69:08:0d:09:a8:e0:09:4a:c1:1a:fd:9d:fc:f5: + bf:03:9e:d1:68:66:3c:0f:f7:5e:00:b8:0d:6d:34:5f:b0:75: + 2d:5b:65:8d:2e:b3:d8:8f:e0:0f:1c:0f:35:62:0a:0c:56:8f: + fc:94:53:1f:ad:10:7d:d6:18:a2:19:f6:79:17:a7:66:37:0f: + 0d:c3:0b:ba:39:b6:0d:30:fa:81:9e:18:0e:c6:c4:8b:4d:a6: + de:7d:00:29:7e:ff:a8:76:4d:d3:4a:10:19:db:b6:26:b7:96: + c7:5c:6a:5c:77:7c:0d:17:eb:22:50:8e:d7:c8:e0:39:05:3d: + 75:aa:0b:a3:0f:39:2d:87:32:3e:c4:14:db:c7:d7:52:9e:89: + b3:4d:03:cf:35:94:33:bd:e2:fa:38:58:ef:1d:a9:56:e4:77: + b6:3e:b7:da:ff:59:cd:aa:ce:a8:77:f8:77:fc:f5:2f:67:e6: + 37:8f:90:69:3c:11:d6:e8:e1:5e:1a:89:ce:6d:2e:18:90:6e: + be:08:22:93:46:4f:06:44:2d:55:53:cc:38:d4:b9:74:57:77: + 67:19:30:29:c6:01:97:c1:b8:f7:89:0d:a0:0f:0a:58:3b:04: + ac:6a:1e:0d:23:57:00:25:d8:4e:14:9e:42:16:d6:b2:0f:23: + 41:fc:ff:30:55:06:55:52:9a:e3:f8:2e:a2:86:a8:5a:69:68: + f2:60:1d:8b:1b:05:1f:3a:b7:69:fd:0b:d4:09:f9:2f:b0:89: + 75:83:bd:50:df:d5:09:ea:96:13:1e:db:51:55:73:62:79:d1: + 1d:9e:f3:05:50:b9:b7:c7:ae:95:ee:7b:4c:8f:d9:d1:a2:3d: + ec:ff:87:5c:f7:e9:b3:61:36:5f:42:6b:53:d3:17:84:ad:52: + fa:a1:a4:45:40:ba:57:f4:b4:da:77:82:85:c2:90:0c:85:ee: + 1a:ab:10:1c:eb:5b:07:54:98:95:a2:a2:3a:26:07:53:e0:85: + 1f:26:3d:b4:9a:16:0a:7d:a8:c5:8e:a4:20:76:cc:34:45:fa: + c3:ec:5d:90:3c:d1:d5:bd:d5:1f:6d:79:84:07:90:65:ba:03: + 3e:33:52:18:d4:f3:df:fe:e4:5e:33:2b:e0:c8:59:ab:aa:93: + af:e9:5c:4d:3f:87:1b:ab:bc:98:81:dd:e7:24:46:d3:83:1e: + 7b:75:b2:71:06:66:d2:7f:4a:d7:1e:9b:c6:fd:b8:29:a2:1f: + fb:fe:0d:0d:77:0a:1f:43:1b:0b:dc:0e:2f:73:d2:b0:1b:20: + bd:c2:c3:55:f5:eb:ee:19:4e:a0:a3:a2:df:19:41:f5:bc:2c: + dc:36:88:92:79:fc:c1:51:88:3d:2a:92:55:58:87:d3:f9:3c: + aa:54:ec:bd:fd:05:a2:0f:cb:bc:ef:b7:ed:88:55:5b:96:ed: + 33:0a:c7:5c:76:85:a4:98:6e:ed:53:ee:4c:91:63:25:99:e9: + ed:8c:74:70:85:61:47:99:ae:d9:c3:22:3b:bd:76:9c:c6:ff: + 86:8f:2c:3e:e2:e3:08:01:12:79:ea:01:5e:89:e6:a0:09:e7: + 50:21:c1:4a:af:9a:96:17:fb:d2:91:e9:8d:8e:a1:29:33:f5: + ec:25:c1:14:dd:82:c4:61:69:7d:8d:5c:07:ca:b9:8d:45:bc: + 1b:d5:d9:36:d9:79:7f:d5:ec:d8:44:d6:65:a6:b5:29:a3:08: + b1:8d:40:71:d0:c3:a7:a0:a8:01:d7:5e:b4:b1:ad:43:a0:33: + 6c:6b:e0:e0:ae:41:a7:82:23:89:e5:e4:0a:84:f4:a8:f1:88: + cd:65:ba:5a:67:26:df:cc:1d:6d:9f:8d:f9:66:5b:41:03:26: + d9:10:06:0c:38:05:de:30:06:15:25:32:6f:7f:45:b6:da:a5: + 2d:ee:33:d2:0a:f6:4e:1c:ec:e7:cb:85:b2:02:5d:2c:b9:9e: + f0:0e:38:da:59:ca:27:59:8d:68:38:90:6f:d2:21:ec:f5:53: + 56:ed:68:4e:fa:46:25:13:19:35:df:b3:81:88:e6:41:1b:2a: + f5:c3:8c:f1:b3:10:cb:da:d5:39:d2:4e:72:cf:4e:b1:55:7a: + 21:85:4b:8c:8c:76:d6:8b:c1:d9:62:2c:22:5a:9f:b0:e1:5a: + 77:38:78:1c:72:8c:fe:37:0b:ef:02:31:fe:7a:d2:4d:60:cc: + e2:6d:37:38:38:a5:61:f3:c0:13:c6:ed:d2:d6:24:70:bc:00: + 83:b5:07:e8:4e:31:34:a2:69:5c:ae:85:f9:2f:78:92:cf:52: + f1:21:f3:e6:cc:f9:60:9c:32:80:13:47:a0:5a:7c:49:f8:da: + 40:99:52:e4:f6:8d:be:d1:ae:ca:a3:a1:7c:39:65:53:91:85: + 2a:6f:b4:4b:7d:44:cd:6b:a9:41:c6:4e:60:47:3a:5d:6c:f4: + b6:6c:71:f8:0a:16:ad:ef:47:1b:32:b1:93:37:a4:fa:c6:ad: + f2:be:c2:b1:35:dc:89:75:17:db:a9:2e:a0:0e:6b:06:1f:e3: + 70:b4:cd:b3:b3:e9:0f:47:43:b9:23:c4:49:b4:9c:79:31:d8: + c9:ed:f2:db:c9:0f:df:a5:ef:bc:8f:34:4e:bc:39:46:8c:46: + 54:97:e2:66:0a:7b:de:fd:ba:8e:9b:74:92:5f:2d:21:47:db: + d7:48:9d:f8:6c:f3:29:13:f0:38:0f:05:35:0f:12:c6:ee:6e: + 07:56:9a:5a:d9:7c:65:bd:6e:42:5d:cb:02:27:ca:79:c5:b9: + 46:be:0c:99:aa:ee:dc:e0:20:3e:6f:8f:61:cc:3c:26:bc:cb: + 17:b2:ac:30:94:df:c7:62:4e:9e:cc:7c:39:c5:ce:c9:51:67: + 30:d1:a9:9c:0f:0f:b4:d3:2d:fb:68:b8:9a:58:e9:5e:12:d8: + 18:e8:af:77:25:e2:b9:d6:ff:7a:37:92:00:0b:82:b0:f5:35: + dd:41:48:d1:db:70:69:c5:80:d1:55:92:86:1c:86:62:8d:b2: + 55:df:54:58:ed:42:21:12:b6:35:37:43:f9:c4:fa:d2:b2:b6: + 15:13:12:07:3a:64:50:82:19:f7:7b:f3:b3:18:34:ce:b7:88: + 09:51:62:68:1b:e7:02:d9:6d:5b:b7:91:75:1f:18:f7:25:1c: + 6d:ab:ae:a7:66:1e:03:79:82:3d:3f:c1:23:86:a8:16:26:bf: + fe:25:0f:db:7f:34:3d:e4:45:db:13:e9:17:2c:58:2c:94:ec: + c8:4e:f8:57:1c:08:19:c3:fa:6b:d3:a5:e8:b3:1d:4c:7f:dd: + e7:ae:2b:d4:a9:af:f3:19:dd:e4:f8:56:f9:eb:86:37:8a:0f: + be:05:e1:89:9f:e5:a4:af:ae:eb:35:47:7e:27:a3:1a:fb:fa: + 8c:e2:9f:56:3a:4a:f4:d2:5d:04:09:c9:13:88:cc:db:dc:ba: + 7f:c0:1f:d6:a4:9d:f2:2a:a7:49:bf:69:39:26:f7:9a:c8:5e: + 13:bc:07:0d:d2:3d:8c:1c:84:8d:59:db:80:10:36:a2:a6:15: + 54:4d:05:e1:9f:be:65:95:8d:0d:91:d6:c8:20:4a:22:1a:1e: + ae:bf:ec:45:e6:69:00:0a:00:fa:13:1c:62:11:79:d5:7c:9b: + 97:26:b9:47:46:e3:0a:c3:49:f2:74:29:9a:51:88:18:68:a0: + d1:f0:93:2f:18:1b:7b:89:11:eb:7e:7f:90:54:60:b9:c7:1c: + 6b:09:09:ed:0b:7e:8a:ba:b7:4a:b7:c1:d3:03:4d:15:54:96: + 42:47:9a:76:1c:ea:89:99:05:de:d1:8b:26:0e:22:42:e3:37: + 06:19:7f:f9:40:45:c5:1e:63:81:b9:3d:9b:b6:b3:9e:46:e1: + 40:4e:59:e4:4a:d0:ff:65:76:43:a8:bd:95:25:a6:1c:d9:c8: + 0a:d4:88:1d:dd:a8:62:0b:05:36:a2:66:48:0e:39:23:b6:34: + eb:d3:a2:fb:82:e0:f7:1f:25:6b:d3:ca:45:91:5a:e4:10:13: + 31:59:a1:91:58:8b:ac:5e:c2:ee:a6:46:d2:07:be:de:bc:dc: + b1:88:78:8d:8a:9e:fd:73:4f:33:bf:10:fb:b4:ad:ba:03:07: + 41:26:cd:59:1d:ca:24:f1:fe:4c:d0:34:9f:0f:bb:85:e6:3f: + 8b:ad:a2:6d:a3:28:ce:c3:9b:03:c4:c4:5f:7a:77:e7:77:f8: + b1:d2:6d:92:13:58:75:fc:34:f4:6a:13:59:15:45:cc:eb:a0: + 05:af:e7:20:ed:58:e3:88:10:69:bf:ce:94:71:a9:be:81:77: + 98:4c:f5:64:99:23:23:c9:a5:0f:7c:23:e8:fc:21:d6:76:4c: + 3b:f9:3e:bd:28:e0:57:19:20:4f:8f:65:d5:1f:9c:0b:1b:37: + 6f:7e:87:4c:c9:10:95:a7:21:a2:30:7e:1e:36:0a:4f:ac:07: + 83:5d:e5:a6:4e:2e:8a:97:2e:56:00:65:cb:00:bb:98:cc:ed: + cb:00:a9:f2:72:1d:1a:34:8d:fe:41:e4:ac:be:99:0c:5f:01: + 70:c8:9c:40:99:d5:73:46:d1:6b:68:f3:e9:a2:c7:1b:00:e2: + b0:5b:c6:15:25:33:d9:79:a6:21:83:f8:04:f9:5b:53:68:15: + 2b:1c:a6:53:b5:ed:ff:40:dd:cd:72:85:53:95:ed:7d:70:4c: + 68:56:6a:5e:b4:3a:a7:3e:31:15:46:5f:75:85:d9:b8:ba:6c: + ce:dc:5f:9c:e0:b1:b5:19:3f:9b:5c:cd:c7:fd:09:28:0d:05: + a4:a6:86:88:c2:af:b2:41:a6:92:3c:b4:18:80:cd:87:7e:b7: + 32:8e:b6:a9:8f:38:f7:48:a2:80:9b:fe:b3:16:2d:1a:23:91: + 54:6d:72:ff:32:f8:10:de:2b:ff:73:5f:a4:2c:33:c7:8f:3c: + b1:7b:0d:05:c8:48:cc:27:b8:85:ba:b7:2b:8d:81:51:9e:08: + cb:bc:81:88:45:56:88:3a:d6:b5:29:11:b4:c7:d7:ee:e0:da: + 52:43:b2:03:11:93:94:85:ad:1c:58:f7:53:7a:d4:79:0a:ba: + 86:c8:24:7b:fd:74:86:ed:a3:ca:ad:5f:f2:2d:23:6a:6d:c3: + b8:26:70:64:30:a0:aa:d4:e6:86:7f:0b:88:88:50:cd:a2:fd: + fd:b7:ed:6a:83:da:eb:ff:5f:63:c5:a8:51:67:d8:06:75:9d: + 20:cc:e2:46:11:b9:87:a3:81:2f:2f:3b:bb:db:1f:45:a7:21: + 0d:28:f1:6f:a0:c7:db:84:1a:00:ce:9f:6f:34:b0:fa:52:79: + d1:da:38:70:3b:67:ab:e5:dd:30:81:c7:6f:b5:c5:25:e4:53: + 10:36:80:5f:e8:a8:0f:30:fb:49:35:77:1f:e3:49:89:1a:e9: + ff:4e:19:da:c8:f4:8d:33:eb:9e:7b:e0:b7:91:46:c0:1a:99: + 3e:8b:5c:ed:5c:47:b1:27:d5:8d:e0:82:15:e9:62:b8:d5:7f: + 4f:cc:16:73:d2:f5:b7:6c:3d:74:8d:a8:44:f9:a4:73:b5:9a: + b8:27:29:cb:11:16:02:5f:f9:8c:d8:4c:56:b0:b0:f4:3b:09: + 68:60:70:ee:b0:a7:49:ed:55:28:ed:c8:bc:77:5f:75:07:2b: + ad:44:1d:6e:a7:d0:79:1d:d5:6e:db:f6:90:d6:70:10:80:3d: + 90:0a:cf:ed:bb:28:d0:45:ff:88:00:8e:e7:64:86:89:c4:1d: + 0f:a2:bb:36:2f:34:a9:50:de:d1:6b:4f:1c:7b:5f:37:54:a3: + 7b:da:a3:5f:29:d8:76:f9:8d:a4:1f:0b:d1:73:83:0b:8d:4d: + f5:c4:a9:79:1a:67:ba:72:b8:ac:47:a4:bc:86:27:83:9a:98: + 8e:e5:b8:90:28:ea:c5:f7:68:b5:12:f5:a5:73:64:82:85:85: + 03:71:14:c9:e5:cd:43:56:16:2e:78:12:7b:d1:c0:fa:8c:79: + 8b:0c:79:f2:c6:6a:3e:fe:56:e4:0c:de:2d:1f:e9:fe:ea:0a: + d9:ed:97:d1:8f:ec:ba:6e:02:0f:74:28:eb:ca:f7:ec:13:97: + 06:e7:ed:29:40:3d:d9:f7:83:1f:a1:59:e1:18:ac:4d:39:4b: + 26:84:a0:96:8b:01:ac:ac:87:76:ba:52:fe:57:24:19:f4:6e: + ee:8d:0d:d7:4a:c0:15:93:f6:b8:c5:d8:08:37:ec:28:cc:3a: + 6b:52:2d:b5:7c:4f:c0:b6:b5:c8:65:92:ee:ed:ff:3f:29:b1: + c4:96:0c:37:26:7a:cb:20:e7:57:8e:14:d9:8b:e2:e9:d1:5b: + 43:44:f9:a9:a2:bf:af:11:2f:cd:21:db:77:21:6d:3a:61:e2: + 49:ce:6e:0b:12:82:ba:4d:a4:c7:c6:12:20:31:c3:21:d3:ac: + a8:d0:72:04:f4:46:1f:7b:a9:e6:43:ba:b0:a4:9a:51:b8:91: + ff:0f:8c:76:fc:4b:89:c7:07:31:f0:b4:ea:21:2d:63:67:83: + 24:86:34:ce:95:47:5a:61:d6:a1:ab:eb:af:98:7d:82:a2:1b: + 03:6f:3f:28:cb:74:74:4d:16:3c:96:ca:da:99:16:7d:ac:76: + 66:a7:a5:8b:45:eb:da:e3:3d:e1:bc:e2:92:22:e6:46:7a:6c: + c4:4a:2f:60:ee:27:6e:4b:6c:b3:de:c2:b3:1b:6c:49:e8:5d: + a6:4d:bb:f8:2f:25:fc:de:15:4e:b6:34:06:be:c2:bb:19:9f: + a8:01:82:a6:71:cd:f8:15:6f:77:da:db:55:f7:87:8a:96:52: + 87:87:ee:1e:50:99:4f:25:27:57:0a:ba:cd:86:16:bd:e3:48: + 7b:06:48:be:d4:23:91:16:49:a8:2e:b1:4c:bb:da:4b:37:1f: + 10:5f:e3:4c:03:58:89:08:1d:ae:8b:22:f0:10:f0:3b:77:92: + 5d:7c:7f:35:be:44:2c:81:4e:75:fc:72:25:90:e3:52:f8:75: + 78:63:3c:09:65:c7:82:46:7d:8c:7f:8a:d6:4a:09:53:e6:ee: + 6d:7b:08:47:e3:01:5d:f7:ff:c2:f3:3e:4e:19:ef:81:61:49: + 6d:85:f4:36:1c:74:91:b2:71:4e:af:1f:1f:77:49:b7:27:63: + eb:8c:67:e5:94:12:93:2c:83:9d:e6:41:ed:ed:ad:05:57:9f: + 01:df:2e:60:a1:8b:a6:29:44:69:f7:f8:f5:22:46:36:76:cb: + e1:f1:65:74:92:7f:5f:01:af:aa:2b:a8:26:ed:d3:0b:3f:b3: + a1:3d:67:71:fe:e0:f8:3e:66:37:c5:19:53:aa:66:67:51:88: + 6b:81:41:48:dd:8c:2f:43:a7:f3:e7:15:72:92:cd:a9:7a:30: + cc:4c:84:9a:1d:2f:a3:af:bd:05:ff:24:48:72:b3:a6:0a:c2: + c6:48:73:dd:46:3f:bb:46:85:5c:61:70:f1:f9:d0:df:bd:48: + 4e:31:65:e0:b1:67:64:87:e6:97:f2:fc:5b:ea:1f:65:a9:37: + a2:2b:db:e5:a4:3e:4e:7f:f9:94:60:7a:66:de:42:41:d4:29: + a9:ee:cb:d9:a8:f9:ee:10:b7:a8:15:f5:54:d0:74:8e:f9:4b: + 0d:53:aa:5e:6d:12:ec:48:8d:42:9b:ef:63:30:00:05:f4:35: + f8:8e:a8:dd:ca:71:e0:31:6e:cc:d7:ba:82:f0:b3:e7:86:f7: + d7:93:f6:e2:66:81:a4:d0:cc:8e:75:22:a8:2f:91:cf:ba:0a: + c1:a4:0e:28:b5:fd:0c:1c:8a:b1:80:62:49:9d:c6:fa:81:4f: + b2:74:8f:fd:41:3f:40:42:52:25:93:b1:1f:ba:1b:49:03:f9: + 1f:af:fe:f0:c6:77:55:c2:23:e4:e7:fb:cb:be:da:c2:ac:3d: + 81:a7:05:2a:61:c5:34:d6:32:37:22:e9:06:4e:35:fc:85:a0: + 7f:1d:81:11:14:95:e7:b8:39:8c:a1:3a:f6:6f:4d:4d:e1:8e: + 8c:6e:38:a6:83:07:1f:39:31:65:6f:aa:3c:a7:9f:a5:42:fa: + 67:a2:09:d1:5a:04:c5:69:2d:90:79:36:25:e2:03:cf:51:ff: + bc:d1:7c:f5:95:b6:6e:33:e7:47:34:49:a0:d4:ac:78:f3:30: + 5f:78:96:94:98:d2:1f:2b:fe:b4:da:30:a7:3f:ef:94:6b:f5: + 1a:12:09:0f:e5:27:ff:f5:0a:7e:25:ba:6a:bd:36:f7:1f:fc: + c9:c7:84:19:d0:f0:5e:be:91:4f:16:87:47:56:fa:79:ef:0a: + 3d:be:99:2e:9d:bd:65:d4:99:c4:e5:09:25:bd:9c:f6:f8:08: + ea:7e:58:8b:21:b2:0c:a0:f7:99:2a:8d:21:41:3c:23:b3:ae: + fc:bf:eb:81:fc:f3:55:18:c4:96:ac:a3:7c:5f:be:b1:03:7d: + 5a:81:db:dc:fe:42:c9:8b:d5:04:0c:61:87:8c:57:f0:16:d4: + 47:ce:21:ed:69:1e:d8:c4:30:52:8d:6a:ff:84:13:30:fd:73: + 5b:b7:40:df:d1:93:09:4c:2f:a9:ea:01:8f:c2:79:e9:cd:31: + 56:67:de:82:ea:46:fd:91:05:ab:a8:7b:e9:41:03:bc:93:86: + ee:3b:35:27:a5:1a:50:ea:7d:78:6e:9f:eb:a2:ae:ff:59:7d: + ad:26:9c:fc:82:ce:9f:7e:d1:b5:fc:b3:1a:79:64:49:0a:4f: + 5c:66:e7:66:2f:19:dd:8b:d8:19:0b:df:98:6f:8c:d6:c3:e9: + fa:07:b4:7f:98:17:09:dc:61:25:3f:11:3a:5d:16:cb:8a:cf: + a7:7e:4c:5d:c7:39:f5:8c:21:31:41:9f:3a:a3:db:f6:be:02: + be:98:23:dd:39:7c:1f:8b:c7:79:dc:44:17:79:6e:28:48:9f: + ae:46:4d:d1:e7:d4:f3:5f:39:a0:df:27:a3:ec:b6:4b:08:6b: + 63:43:e7:82:f0:5e:41:1b:c3:76:75:54:6b:26:bf:64:a9:0a: + 89:6d:80:3d:f6:9a:ef:99:e2:ae:d0:c6:e9:de:ab:16:6c:30: + 95:df:c6:42:ed:c3:e0:4f:4b:ea:72:a1:0b:8f:2b:b1:16:a2: + 4d:f5:0d:ca:a9:9a:dd:07:43:39:70:56:e2:5f:99:55:7c:24: + ab:1b:63:9e:cf:0a:40:90:13:4c:9e:38:ae:f1:07:9c:4b:ff: + 56:36:44:31:bf:69:7b:ca:d4:b0:4b:ea:0a:a9:0f:dd:d1:a0: + 86:61:02:f1:ea:23:e3:d6:97:b7:76:50:45:a9:44:ca:cd:78: + f4:65:a5:1b:f2:c1:2b:52:cd:de:40:9b:41:f3:e2:ff:26:d7: + db:f7:b4:d4:92:d1:3d:38:a0:04:ee:bf:ea:b9:f2:df:7d:f8: + 4d:3b:33:6f:a2:1d:d2:c4:f9:aa:c4:22:7e:32:ce:f8:95:82: + ac:6c:89:34:6b:3c:a0:af:93:92:57:7d:b8:85:65:22:25:4b: + 94:56:f5:dd:b5:6b:67:ed:28:30:10:af:cc:1a:b5:1d:2d:a9: + 68:69:a4:46:33:de:a2:82:f0:0f:0c:a5:8c:e1:9e:0b:c5:ad: + 39:fe:ec:ef:7a:8a:78:34:2f:75:b1:92:c8:40:9d:45:95:27: + 8f:5c:0a:80:69:96:88:bc:f5:f3:f4:83:bf:c3:69:4b:8d:2c: + 02:52:19:0d:9b:4d:00:d5:d3:7d:44:08:b6:d3:fd:68:f4:da: + 32:71:5a:ab:aa:ef:d1:c5:54:2c:06:74:c1:0e:5b:b0:ef:48: + ef:98:ed:9d:97:ac:b0:c9:a0:1a:c9:56:52:d4:be:22:62:df: + 63:99:7b:b6:24:64:da:3a:1e:7e:63:7b:ab:27:4a:e1:a1:ff: + 55:8f:91:78:74:ee:51:a0:2b:2f:f8:b6:67:0c:16:dd:7c:ff: + 37:86:5e:87:bd:1c:3b:3a:19:5f:ad:7d:0a:12:f7:ca:09:2e: + 3e:d8:23:f3:e5:2c:96:51:9e:e7:67:ff:fc:2f:6f:cf:cf:e0: + 01:b4:cc:c3:2b:94:55:7b:e1:35:a6:04:89:d0:aa:8d:74:e9: + 86:17:46:d9:77:27:38:fe:c8:5b:08:56:b6:93:36:c6:e2:23: + 55:b8:fb:74:de:4e:f6:da:57:c0:3d:7c:58:41:44:32:31:de: + 75:83:b0:78:be:d7:10:27:77:20:22:bc:72:df:0f:c3:01:69: + 87:18:02:51:d0:7d:e2:b3:e5:e2:08:ca:84:18:1a:43:90:9a: + cf:22:93:48:f4:03:52:d4:5d:02:4a:b9:d3:71:1b:1a:91:fd: + 92:b1:c4:a0:8c:bf:70:25:20:85:6c:ac:9d:7b:17:fe:0c:21: + e5:16:2a:44:22:89:ed:04:63:c1:28:a9:1e:05:cb:ef:90:8e: + cb:be:04:f5:a7:d8:04:a0:c0:d3:2e:34:ca:90:c5:be:1e:fa: + 10:a8:7d:2b:59:ac:0c:20:e8:0c:58:08:dc:d7:d9:86:16:22: + bd:2a:88:e0:51:fd:aa:59:b5:d8:a6:ad:1c:10:ff:15:2b:fa: + e0:aa:f7:55:44:21:ab:50:2d:27:2e:ba:b4:c4:4a:8d:ae:53: + 58:c5:ab:1b:d8:ad:63:5b:fb:41:c2:a4:69:f3:24:c1:da:d5: + 43:1c:36:5d:32:c1:d9:67:98:87:bb:b1:9a:06:45:61:7f:92: + 15:df:02:03:9e:6b:43:81:90:a9:78:60:6b:2f:f4:1a:61:2f: + a2:fc:40:5e:03:70:50:90:fc:83:11:d7:dd:1e:e7:74:48:ab: + 4e:aa:8d:e1:85:7a:6d:d2:24:ed:97:d3:45:87:d1:44:44:aa: + ed:69:f5:e3:3a:89:32:4d:4d:35:f6:25:03:1e:c1:8f:49:39: + d7:d0:5e:37:8f:3a:70:17:01:61:25:90:d8:5c:6b:b1:22:d9: + 4c:f4:77:36:e8:3d:96:e6:61:14:79:b8:4c:17:e4:9d:2c:8a: + 89:3f:db:8d:a3:3d:7e:93:2d:5f:78:67:30:ac:75:97:21:3c: + e9:49:cf:56:3b:44:87:a2:6f:e8:34:a0:de:fc:54:a8:3a:26: + 41:b8:fe:80:53:6d:29:64:09:1f:6f:e9:ac:ff:70:8f:06:ef: + 48:a2:07:1f:8c:d9:86:2c:84:f4:a7:01:66:d1:2f:f2:47:92: + a1:e6:de:a7:28:70:4f:bd:d6:d8:b4:ed:17:ab:4e:18:4f:e2: + 4a:62:d0:7f:30:9c:40:2e +-----BEGIN CERTIFICATE----- +MIImDTCCB0egAwIBAgIBAjALBglghkgBZQMEAxQwgaIxCzAJBgNVBAYTAlVTMRAw +DgYDVQQIDAdNb250YW5hMRAwDgYDVQQHDAdCb3plbWFuMRgwFgYDVQQKDA93b2xm +U1NMX1NMSC1EU0ExGjAYBgNVBAsMEVJvb3QtU0xILURTQS1zaGEyMRgwFgYDVQQD +DA93d3cud29sZnNzbC5jb20xHzAdBgkqhkiG9w0BCQEWEGluZm9Ad29sZnNzbC5j +b20wHhcNMjYwNDI4MDgxMDA1WhcNMjkwMTIyMDgxMDA1WjCBvTELMAkGA1UEBhMC +VVMxEDAOBgNVBAgMB01vbnRhbmExEDAOBgNVBAcMB0JvemVtYW4xGDAWBgNVBAoM +D3dvbGZTU0xfU0xILURTQTEcMBoGA1UECwwTQ2xpZW50LW1sZHNhNDQtc2hhMjEY +MBYGA1UEAwwPd3d3LndvbGZzc2wuY29tMR8wHQYJKoZIhvcNAQkBFhBpbmZvQHdv +bGZzc2wuY29tMRcwFQYKCZImiZPyLGQBAQwHd29sZlNTTDCCBTIwCwYJYIZIAWUD +BAMRA4IFIQCde2aFmrPL3xnFquKsKnmv8f3iuI2R2vWOhrSRPBUqEmGJVrLcdhP0 +NRpy3KEU9pV2JaOTaSPbgPkTVZ1S7d+Dd0YZ+VVGkTYRI2q0F0D4MqiG1weZ/e4o +vTn8bQDuWbDGwgtgzjtrjwj/i9oxw7Zk439931Ht0cG57CPOuf8EZ06Tu/1rK+nU +yiKxr6Rs4MxSXAzvDOpMjKIin8I0QSbEAUJkoRz9GWrffayjnjBGgjkHoirD1PBV +EEvp8NWvEhUzAZe/U2pRJxoeP9ovW1eqAhFL7gwnyvV7iv2ssi81tCo9u8yhFndI +w0UkATMlnHtl6CtITjy9JszoEY9dqi3MxCJhseCfuM+GZ72hnGz+lAvmFFdk4HbF +WYhY8aIV2gp6yPiDRJv3DWj9NdxGghfjsCQjPSFDEcNeDFTlZ+EEY0W0u0Qhlmwk +vDpOxA+0tinv9/kMcOCmQ5JVBQsk4lKon12QUDiZM3ZxORAt6c5KmVEhwoHNVGvx +BCoErpMR1dTclsj1hD/BIxdHDH61AaRNOsvCKM5sJjVVwPSpezBPIOiES4/BfVFS +NJYRPWo0UgM84Sc+8D4MtEGlBpNR5KbjPfvwrfhzCz1k3QDYugm9hJB+tPOEqYiE +n/E3O+opyCGPppoacBQ0XW/g829N/0NhUxvWR+WbQdjs736UpkxkWhpFwmQXV8se +4lScWghbhUxBIj2+PROqVqf7kCmtTXSmSO7bIlcDgndz8gA20TRsruaotTC4enim +a8aughxE9GBN3P28m6WeklVV9H1+v03yzxWzTsiUO6RUnQywkvB3Sa+qIk0PSKz5 +Stex0vu+OTV7FEN9c62KMZfrDiTSmniNn3RRQVGqT8TN3X3E9+VwjAEYe5bc16TO +3GFiDF+5XJMqTIPH4i+/4hSViahwISmKZArE6y8b4zT6XpUbUO01HroR8v+Y+TiD +F4m41JaVTjPGkKG04ePUgTO3LPwFUpC3SsFMZoeQOLEKFb/RHMSAoGjRe2k3FuKI +qFyZ/CCmqdRnL2P6Zx5x2ep1fCjHUyw9VIP2C00BiSYkznMbTbl6qUp381qLOdYH +Sdb4ZKAHtARMz1ATvjkr81Zo5K1lOz3RV73WvDBq6ZKjCV4RvdRWkZHaXhrp/f3Z +vWD8NkJCeOKMYNa+rHePbnMj/g1aHPJHR2mSY2Q1Pi2v1hHOYoOX0dMH2oXnOtui +71Lo7keOASuwk9K8P7lq2hXkLEapFAgNo3HuDatI/+DTrywjRUfgP44F6kTteJoR +7Fp2crmCPza8dCFCIsUsSa0b9I/EJnmh5y/np9PbvHAttLF+yVVP3qVV+MpIuG3N +We9difdr0AYMDk5/qerUglvkNXS3hLQsIBvyRmoh9YjWPgQ+XVRYSqwM/v+vb6qY +ksnHBZvcQDi97c1QH1EXObWt8Vqzwu7ls7onEPADknJcCSAAyvCOMMHH3KQUi5go +DQDSy8BXERsl8H5UqKm3t2s0Ch87Z6FbWnTuZB7+LK6oAP8d+9gm2YSQsb8+0hkl +plZj/cect8h+clxncUjMtMAkRDDSZKmkrWMq5X7nEqxhklkm5mv5t5MKSGFDd6fO +e4Nqmjnp5w2iTWNlIKwk6lR7MEsqaEfXF8YThBnWZ5wFXHL5MmM1h6p7TfZHU9Zz +gqMrMqOOMSYVnBNhjZSy2mn9FEGlZ/RmH40UdtIHj0uKc8YIQcDtlZiYQ/PBOiCK +FCX6VwPmy+g8ptYa59cG7Nz5qRMnCT+Fo3UwczAdBgNVHQ4EFgQUBroJYBzxgF0v +UO+I61gY+UcsDWwwHwYDVR0jBBgwFoAUvYAjOgbdOFfua8KUe+q/Q1c6sIwwDAYD +VR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCA6gwEwYDVR0lBAwwCgYIKwYBBQUHAwIw +CwYJYIZIAWUDBAMUA4IesQBa+r1HVLAc5bbpPJRZIABtRs9LMB7lMMmUDPUF4wTM +86W1j5KyJpHmIf7P2eSkg1HT4QlTwfebWK6ZRjsEOyG+0cmNSRUI04G3RsJf0AvM +e1ZpjZFhLqXSymNqsx3MlKq2KJQITBdWG/HXAJSMFPLCGAbicQAU4X69fnEjijW8 +eAt7SsV4GjK5ZdTMXceobBAqSc5Q4o2sYjPcAYRPbKA0cOF8xwe3ZanDhFRSffDE +H61qFD3pJw6IGb71gTe48TLXGBUqyYYYjopFeM60lAW/5O8xTxj2JjzBOV0I0b88 +2P1o/BEVhpaENYXeDEehXLaj1elQ0gq/KmwDI5SzUVxh9h6mb6uxTah+KOBbSYze +MjcJUOD/RQx3TsQi4DlFxjwDGh40KJ6MqnhFmTr8V0PiqVdXLCV8hjFIFrEQQcsj +DSaAS9jeq8jUirvCRVeRdb4wtcm0ghiD2Nwz0TgGwyvGAnYmB6a0y3ivaOOoHWrt +ch2qkkLbUt3/gQcpNZ7DfTSpixoF41FdW3manEFYtVDJIanRKeYgqNoMLg0G9+yE +437rADjxJaiatx1aCL8Cn2aPbwfR9oyAqpKa7+fxYkw985nywc7jlvXjEYzXzlMu +HhdKnbIkovxMncyVq8vIEMTJVSYxISjXHKFGGJXHMs9RbS80ewXufgRapFAoJHNS +hl/wwMhQng09dSOT6qr3unzYa+IBQeexXjhY8xxsyWAWV/1RDD7B4HUQdAM7k/S9 +a8TAHcrZQv36RWHl6EJyP3L73VPhD2zF9d/JvXSRRlQzPUMLnib2J2pJpu4ylvIa +yDJhd57mzPVUD8I/Sp5WZlSqT21UjJ+Z5EEQz6MrOFOaI6Pr4ekpQFuBzk+2Mp/1 +8rJqRb6+TT0laLiEabF3SWmsCell4yJ5MmLILiFg8BlQc/9T/mQoC1t+M7eM8YIl +ACPm66PK/rlFt6SCTlxvDWpCHWie/1PSDfpqxfWI71tIegCf2Oj801FCU906DALW +iMJM3+oKeFtI6K7RRq9AN/NrLI11N1ipwYjyQaihhchMeiDPt3QurPU9fNOXLIzj +SsEvJ6pPOlkD59WHYkhYjdZhFnzYKQ9BC43J4OXQGfo/1UMbQ1TvmxbZvQ4Wz0yY +jGbsQiTvOCF1B+K9tapFObbPcSR1iNOVpJzOF43xQDfQXZeiMPSp1rS6ooGtoeMW +Nd6z/ML2QMv102Qw+M1Cs0m4K22zwUwTczNISlKYk0RcX19jOeQKQRXJczBDSF07 +6/Ceh+S0B4HaCxIfthVCh6MS330YkyP8mM2Nn0urmax8h2RWHV2/0v44iUKLR4JE +F83CY0NoEI9zorAQ4Q+Nm7X8cNgsOqtOfzEXwXu5gokiprIiraMvS/a3/vczKY1m +d/EwjllnAVGFYSN1jky2/UAjaJju38mO54ku1cXs3u9pvwRmdWn7f6j+Toksm/U1 +l7mU1OaJMwUuGu0i2j3AJ/3P0x8iw6BWMrFAhhOoahNQQGSBUrFaBEvoE4RUsnk7 +RtwGfZADVIxL1sbswUKbG+FWN8RAelHGadkJLDHAR1A9GTsEiksHZOHF7q8dMANS +rF65rbcfkFqw8l1TSuO4NeWNvPL/UJ8mLcnHoUUFO4fXgxH55tgyFPQvdwhV++Oz +1ycX/WCd2eTE08vbgNlBWmLOGEUi141qLGqEw6i7ZdesATrq2kAjpF5HIa/dmK7X ++OK8rBwMYTfSaMHG5uHQaDDwqEYn5os6ViLwvOduZL25JjoAbvGZVjzRqigdNWli +sccfyr9J80ZFm4Ci4spfznp+sTOPPsYmLsTfIzKLPv0YfthvQ5MvzD07WaJ3i1Qn +zl7zAxwiDdKEZyYRYGJ1Iq/AGKE2gjGWBX831LAcQ9j6l5J8bad9eZtZ3xLTWM71 +vDOd5WTeeb8xgC2nJ2lpiLC0IxZf0Kcv/xzEIP0mWePiSTQG+Ww6fQvsGD+PbqW+ +POt/iGD4mRTulA279kApl/isFqUqh00VDZ0sLBQDRcwPvfY35vailNrc5BfWghDG +5f9LKdQP2190J7x19fN1SRU35UsFjyfYlMP4HVzC7lEW/9+WOpEHoxfk8IlrWLEj +bHHUWgmpiv4uVby2n6UEZKURyfkcat6r4i8ecodftu2Mk0m6nRKWrSJW+QkTr4zt +15pSMTpqhhgA7KdKQBL/l8Z5XDRyTtUJ6i2hjFmuksxfyti0IuDNcbfXvyXKZT5Q +6U2tjzSSpZG+eVNZ6iYrHV8ZZcx+0CMsmlZ3P7Xj4NYTDIGQu4Xe3v5W9MoKzsSV +qWKv5O8LjR+VL++Rm1t6NZ0ywK0mscZUmazAuv4agpn6E60IJK5hpfYHsol0+OOC +6E9RGWB1MRo5Fe/9zRUvEFC+Gx1nPHPCbFZLPwLEq14la/Ei6QncmfJlI4GtQChC +TL3HzqkgcWWdw1nDCkTwb74FpaAqMEI3uMh//u8nWwHtfHeGjJc+C6RGx91v7GSL +Q9vD/3rxHgA7DsB5wd7No+OCwkbX4jB1I29qttoRROCLh5x+FN1YWfgVv6A3zbqI +qDaEToYw6jxJDjxECPRTsMGtLYy/cpHNrw4uNpCM+1zIpGF/IUnXwL1n/Pbh8/C6 +rbkaHEwRfK50i5XRsX7CRi0Ntr0vhKPDS+nQ2Xm3yn2lbv/leDaxcYb2DJPZ97hm +vCq6I9KpyB9k8RidjpFq9aF5xlS7ZyEE6RcGeCjd7lbQlTA03lyiPtpaBXNgctsd +Xyfkrer7JJHhzg0o2Vr6ufzehSki+WxYedDHQlr5HYLTHW/NjH1ckZEeNXyGZZov +MZwA9p7VhZk68Wwo7nojLHgnIDa4uN3YFDrT/36jMPYbB/V04PL45PuiThu+WI6C +xQeESp7jVOh5xIhDhwPNwqlzZKSa3XIbiwWAMF7N9ZswebNtTN0Z8YTQcr9WoEIA +dxdA98SOIGBwbf4x00HvIs/dPjHkYq1HhUoRNpuElo/dEOp44P3HjFBcuHhqv/Sf +nrQuuiUScOT+0YucmhuXRfNrjPzLWS2FCJNhUGluVUxXfmRPkH+nHFKL+sEzg9iB +lnKI+vsK4nM4n6GKRzZIKNzoTmkNqWga8e+EV5cHWHAQtB4oj9lOl/4M1ZXMFBrc +jdLpqau/Oo1SC/VbR4rmP+XuPGKZG+sO0RZgnEzV9yP1IsgJxvF5/E0pF6IHuXuC +WdeWTw37DssDEs+gm8LRejGbDOAIT8TUU4/yzSTljQYg4Ky770GpmLgHyJZj01zl +W+pWIUL9Kf2waGEf0uK43bFMPEqcCpeoJV/kRdYypLjf9NJnNuBMXRn7aoRiIYGf +UDH2pTtUaw6hLgBPe6nOkwboZNWmnUGb7vfCY8uv/A95K+xbXAOhvLBvg/aPAonY +aKJDtn3PdBEP6uvBvWJCPTXazJldtPhE4asnS4B9yRa1zYC5EXPZioE3vpQyipTO +phY0YFjT0pUke861ylJMqcw9nWhmwrQvWR4g/VUR4m44m0AJRAYFYVw8SWOif1hM +Q9qQE37iJVo734hM4CHrRo4rcRkoaLyMzzPo3RWc1ZZNIvdqqkISVqd1kgyjWpXT +qnwo3BMNHOcQXmnNwgHFkkBcSwow0RFX7mch0w60ike2cahHJR0b60nxzPcq94/Z +uUOAosa33cIxo/7p5g8i2svI4n2bS+V6aUL5RMMDjtghliWLkIp3dyIey2FbxlLX +A4xpHw3BS86abyD2tH2WAcdwNAS1jXqgOmiqYVBSRTrNvlcddr7hYF+Mgkz8WEHC +YKVXZ+NmwaZVTzScNKGSbzyOPRbzr6RdEvySND6O7IlLVGcYGghWT6aG8I2jE98v +y4LwhZI8SBRUgvsJ3JUSq0nf9dgTB9896x6d2ulIvuVIQVlpRPd4370Uvh49cv4S +XqoYoKNkuu+GgdOpAXeLXsdqZ+lr7a9DOELkXx3hpk46j2Tx42LH3ZmaE1sSrRbG +IifenkrpTa1tK9ynqgBp1PBQimnXoeZVmeK/SpSfGugP1ayO2BS/az/WUOEM4CH1 +HCM1Z9ZwsK4IaFe1so49oT5ySZ48fO2Kvt0szWMWr5kaRKrfVxv7qhWjAgIWuRdj +YZHxSvnfIipwD1Fog3XJuFLqSArRO7nBvCqK8CkB8CiSzzKaTdMOS9opXDAlwpaN +7ihhmrWL2r8enAHFRXVkUtfL3kYnrDa+9xTvQPgICuhpPTeyBIYILBZ4dJiJ+QTq +MrrkXEoxhM24b1NLvIfk3+LOEVN1kxamVy02u3jiibyemwuHtMMpUzvj2sDnAY45 +4FpfZLrT+1o3W6+wvLJmW0vGZaJe/DlhdHYfjl9VxDxDVN7TOsb6jaCZKEQ6LMvO +RtDvQNHPZ4ui6uS5zXoUIoINgs5OXd6OOwa8/F505uYPzJYkaDk8KZho7Sa22e88 +HKfk2n5RVxEhdfJx/Qy1GDoyczlCTsR2vd5toDW8ucQkmRsjcPExq/dTleFZwmus +RZQb+2Rt8uoqHPX/sp34oeG6+DNqShVDzhz2qKAPsax9GBCzPV+7pynXwsgFvkEJ +q2g/XpzRlSF2Sgqb8w4YnZPBWGrg8r5yj/a1864gYPmLV1ZX0EZTmV5kqZ/FJ9Gs +HwGF4TbLaV6qPYYSfH28d3qU3RajJkoQxI6TIkKJPopn9IIg3nsrGp4z1HAYAT2w +XJqjnQtzkMSwM3K8FJ6uDsFC9OFAtwRcWxa9OcV0Tlm60ozgrQnaYUNrpJFJ4qRQ +1O8UL76t780ysAXnlBnSm/wrySEzT5Jr1/KChrpWP+L6pmNvgd5aFLWDUqgrOz0i +J1NM8lXNiNcWEUy11XjXKAzR6svsMeI1jOwIBOeLzAyiJZt8TBZSKkjMBdwuEULB +IaKP6b5H0YTTaQgNCajgCUrBGv2d/PW/A57RaGY8D/deALgNbTRfsHUtW2WNLrPY +j+APHA81YgoMVo/8lFMfrRB91hiiGfZ5F6dmNw8Nwwu6ObYNMPqBnhgOxsSLTabe +fQApfv+odk3TShAZ27Ymt5bHXGpcd3wNF+siUI7XyOA5BT11qgujDzkthzI+xBTb +x9dSnomzTQPPNZQzveL6OFjvHalW5He2Prfa/1nNqs6od/h3/PUvZ+Y3j5BpPBHW +6OFeGonObS4YkG6+CCKTRk8GRC1VU8w41Ll0V3dnGTApxgGXwbj3iQ2gDwpYOwSs +ah4NI1cAJdhOFJ5CFtayDyNB/P8wVQZVUprj+C6ihqhaaWjyYB2LGwUfOrdp/QvU +CfkvsIl1g71Q39UJ6pYTHttRVXNiedEdnvMFULm3x66V7ntMj9nRoj3s/4dc9+mz +YTZfQmtT0xeErVL6oaRFQLpX9LTad4KFwpAMhe4aqxAc61sHVJiVoqI6JgdT4IUf +Jj20mhYKfajFjqQgdsw0RfrD7F2QPNHVvdUfbXmEB5BlugM+M1IY1PPf/uReMyvg +yFmrqpOv6VxNP4cbq7yYgd3nJEbTgx57dbJxBmbSf0rXHpvG/bgpoh/7/g0Ndwof +QxsL3A4vc9KwGyC9wsNV9evuGU6go6LfGUH1vCzcNoiSefzBUYg9KpJVWIfT+Tyq +VOy9/QWiD8u877ftiFVblu0zCsdcdoWkmG7tU+5MkWMlmentjHRwhWFHma7ZwyI7 +vXacxv+Gjyw+4uMIARJ56gFeieagCedQIcFKr5qWF/vSkemNjqEpM/XsJcEU3YLE +YWl9jVwHyrmNRbwb1dk22Xl/1ezYRNZlprUpowixjUBx0MOnoKgB1160sa1DoDNs +a+DgrkGngiOJ5eQKhPSo8YjNZbpaZybfzB1tn435ZltBAybZEAYMOAXeMAYVJTJv +f0W22qUt7jPSCvZOHOzny4WyAl0suZ7wDjjaWconWY1oOJBv0iHs9VNW7WhO+kYl +Exk137OBiOZBGyr1w4zxsxDL2tU50k5yz06xVXohhUuMjHbWi8HZYiwiWp+w4Vp3 +OHgccoz+NwvvAjH+etJNYMzibTc4OKVh88ATxu3S1iRwvACDtQfoTjE0omlcroX5 +L3iSz1LxIfPmzPlgnDKAE0egWnxJ+NpAmVLk9o2+0a7Ko6F8OWVTkYUqb7RLfUTN +a6lBxk5gRzpdbPS2bHH4Chat70cbMrGTN6T6xq3yvsKxNdyJdRfbqS6gDmsGH+Nw +tM2zs+kPR0O5I8RJtJx5MdjJ7fLbyQ/fpe+8jzROvDlGjEZUl+JmCnve/bqOm3SS +Xy0hR9vXSJ34bPMpE/A4DwU1DxLG7m4HVppa2XxlvW5CXcsCJ8p5xblGvgyZqu7c +4CA+b49hzDwmvMsXsqwwlN/HYk6ezHw5xc7JUWcw0amcDw+00y37aLiaWOleEtgY +6K93JeK51v96N5IAC4Kw9TXdQUjR23BpxYDRVZKGHIZijbJV31RY7UIhErY1N0P5 +xPrSsrYVExIHOmRQghn3e/OzGDTOt4gJUWJoG+cC2W1bt5F1Hxj3JRxtq66nZh4D +eYI9P8EjhqgWJr/+JQ/bfzQ95EXbE+kXLFgslOzITvhXHAgZw/pr06Xosx1Mf93n +rivUqa/zGd3k+Fb564Y3ig++BeGJn+Wkr67rNUd+J6Ma+/qM4p9WOkr00l0ECckT +iMzb3Lp/wB/WpJ3yKqdJv2k5JveayF4TvAcN0j2MHISNWduAEDaiphVUTQXhn75l +lY0NkdbIIEoiGh6uv+xF5mkACgD6ExxiEXnVfJuXJrlHRuMKw0nydCmaUYgYaKDR +8JMvGBt7iRHrfn+QVGC5xxxrCQntC36KurdKt8HTA00VVJZCR5p2HOqJmQXe0Ysm +DiJC4zcGGX/5QEXFHmOBuT2btrOeRuFATlnkStD/ZXZDqL2VJaYc2cgK1Igd3ahi +CwU2omZIDjkjtjTr06L7guD3HyVr08pFkVrkEBMxWaGRWIusXsLupkbSB77evNyx +iHiNip79c08zvxD7tK26AwdBJs1ZHcok8f5M0DSfD7uF5j+LraJtoyjOw5sDxMRf +enfnd/ix0m2SE1h1/DT0ahNZFUXM66AFr+cg7VjjiBBpv86Ucam+gXeYTPVkmSMj +yaUPfCPo/CHWdkw7+T69KOBXGSBPj2XVH5wLGzdvfodMyRCVpyGiMH4eNgpPrAeD +XeWmTi6Kly5WAGXLALuYzO3LAKnych0aNI3+QeSsvpkMXwFwyJxAmdVzRtFraPPp +oscbAOKwW8YVJTPZeaYhg/gE+VtTaBUrHKZTte3/QN3NcoVTle19cExoVmpetDqn +PjEVRl91hdm4umzO3F+c4LG1GT+bXM3H/QkoDQWkpoaIwq+yQaaSPLQYgM2Hfrcy +jrapjzj3SKKAm/6zFi0aI5FUbXL/MvgQ3iv/c1+kLDPHjzyxew0FyEjMJ7iFurcr +jYFRngjLvIGIRVaIOta1KRG0x9fu4NpSQ7IDEZOUha0cWPdTetR5CrqGyCR7/XSG +7aPKrV/yLSNqbcO4JnBkMKCq1OaGfwuIiFDNov39t+1qg9rr/19jxahRZ9gGdZ0g +zOJGEbmHo4EvLzu72x9FpyENKPFvoMfbhBoAzp9vNLD6UnnR2jhwO2er5d0wgcdv +tcUl5FMQNoBf6KgPMPtJNXcf40mJGun/ThnayPSNM+uee+C3kUbAGpk+i1ztXEex +J9WN4IIV6WK41X9PzBZz0vW3bD10jahE+aRztZq4JynLERYCX/mM2ExWsLD0Owlo +YHDusKdJ7VUo7ci8d191ByutRB1up9B5HdVu2/aQ1nAQgD2QCs/tuyjQRf+IAI7n +ZIaJxB0Pors2LzSpUN7Ra08ce183VKN72qNfKdh2+Y2kHwvRc4MLjU31xKl5Gme6 +crisR6S8hieDmpiO5biQKOrF92i1EvWlc2SChYUDcRTJ5c1DVhYueBJ70cD6jHmL +DHnyxmo+/lbkDN4tH+n+6grZ7ZfRj+y6bgIPdCjryvfsE5cG5+0pQD3Z94MfoVnh +GKxNOUsmhKCWiwGsrId2ulL+VyQZ9G7ujQ3XSsAVk/a4xdgIN+wozDprUi21fE/A +trXIZZLu7f8/KbHElgw3JnrLIOdXjhTZi+Lp0VtDRPmpor+vES/NIdt3IW06YeJJ +zm4LEoK6TaTHxhIgMcMh06yo0HIE9EYfe6nmQ7qwpJpRuJH/D4x2/EuJxwcx8LTq +IS1jZ4MkhjTOlUdaYdahq+uvmH2CohsDbz8oy3R0TRY8lsramRZ9rHZmp6WLReva +4z3hvOKSIuZGemzESi9g7iduS2yz3sKzG2xJ6F2mTbv4LyX83hVOtjQGvsK7GZ+o +AYKmcc34FW932ttV94eKllKHh+4eUJlPJSdXCrrNhha940h7Bki+1CORFkmoLrFM +u9pLNx8QX+NMA1iJCB2uiyLwEPA7d5JdfH81vkQsgU51/HIlkONS+HV4YzwJZceC +Rn2Mf4rWSglT5u5tewhH4wFd9//C8z5OGe+BYUlthfQ2HHSRsnFOrx8fd0m3J2Pr +jGfllBKTLIOd5kHt7a0FV58B3y5goYumKURp9/j1IkY2dsvh8WV0kn9fAa+qK6gm +7dMLP7OhPWdx/uD4PmY3xRlTqmZnUYhrgUFI3YwvQ6fz5xVyks2pejDMTISaHS+j +r70F/yRIcrOmCsLGSHPdRj+7RoVcYXDx+dDfvUhOMWXgsWdkh+aX8vxb6h9lqTei +K9vlpD5Of/mUYHpm3kJB1Cmp7svZqPnuELeoFfVU0HSO+UsNU6pebRLsSI1Cm+9j +MAAF9DX4jqjdynHgMW7M17qC8LPnhvfXk/biZoGk0MyOdSKoL5HPugrBpA4otf0M +HIqxgGJJncb6gU+ydI/9QT9AQlIlk7EfuhtJA/kfr/7wxndVwiPk5/vLvtrCrD2B +pwUqYcU01jI3IukGTjX8haB/HYERFJXnuDmMoTr2b01N4Y6MbjimgwcfOTFlb6o8 +p5+lQvpnognRWgTFaS2QeTYl4gPPUf+80Xz1lbZuM+dHNEmg1Kx48zBfeJaUmNIf +K/602jCnP++Ua/UaEgkP5Sf/9Qp+JbpqvTb3H/zJx4QZ0PBevpFPFodHVvp57wo9 +vpkunb1l1JnE5QklvZz2+AjqfliLIbIMoPeZKo0hQTwjs678v+uB/PNVGMSWrKN8 +X76xA31agdvc/kLJi9UEDGGHjFfwFtRHziHtaR7YxDBSjWr/hBMw/XNbt0Df0ZMJ +TC+p6gGPwnnpzTFWZ96C6kb9kQWrqHvpQQO8k4buOzUnpRpQ6n14bp/roq7/WX2t +Jpz8gs6fftG1/LMaeWRJCk9cZudmLxndi9gZC9+Yb4zWw+n6B7R/mBcJ3GElPxE6 +XRbLis+nfkxdxzn1jCExQZ86o9v2vgK+mCPdOXwfi8d53EQXeW4oSJ+uRk3R59Tz +Xzmg3yej7LZLCGtjQ+eC8F5BG8N2dVRrJr9kqQqJbYA99prvmeKu0Mbp3qsWbDCV +38ZC7cPgT0vqcqELjyuxFqJN9Q3KqZrdB0M5cFbiX5lVfCSrG2OezwpAkBNMnjiu +8QecS/9WNkQxv2l7ytSwS+oKqQ/d0aCGYQLx6iPj1pe3dlBFqUTKzXj0ZaUb8sEr +Us3eQJtB8+L/Jtfb97TUktE9OKAE7r/qufLfffhNOzNvoh3SxPmqxCJ+Ms74lYKs +bIk0azygr5OSV324hWUiJUuUVvXdtWtn7SgwEK/MGrUdLaloaaRGM96igvAPDKWM +4Z4Lxa05/uzveop4NC91sZLIQJ1FlSePXAqAaZaIvPXz9IO/w2lLjSwCUhkNm00A +1dN9RAi20/1o9NoycVqrqu/RxVQsBnTBDluw70jvmO2dl6ywyaAayVZS1L4iYt9j +mXu2JGTaOh5+Y3urJ0rhof9Vj5F4dO5RoCsv+LZnDBbdfP83hl6HvRw7OhlfrX0K +EvfKCS4+2CPz5SyWUZ7nZ//8L2/Pz+ABtMzDK5RVe+E1pgSJ0KqNdOmGF0bZdyc4 +/shbCFa2kzbG4iNVuPt03k722lfAPXxYQUQyMd51g7B4vtcQJ3cgIrxy3w/DAWmH +GAJR0H3is+XiCMqEGBpDkJrPIpNI9ANS1F0CSrnTcRsakf2SscSgjL9wJSCFbKyd +exf+DCHlFipEIontBGPBKKkeBcvvkI7LvgT1p9gEoMDTLjTKkMW+HvoQqH0rWawM +IOgMWAjc19mGFiK9KojgUf2qWbXYpq0cEP8VK/rgqvdVRCGrUC0nLrq0xEqNrlNY +xasb2K1jW/tBwqRp8yTB2tVDHDZdMsHZZ5iHu7GaBkVhf5IV3wIDnmtDgZCpeGBr +L/QaYS+i/EBeA3BQkPyDEdfdHud0SKtOqo3hhXpt0iTtl9NFh9FERKrtafXjOoky +TU019iUDHsGPSTnX0F43jzpwFwFhJZDYXGuxItlM9Hc26D2W5mEUebhMF+SdLIqJ +P9uNoz1+ky1feGcwrHWXITzpSc9WO0SHom/oNKDe/FSoOiZBuP6AU20pZAkfb+ms +/3CPBu9IogcfjNmGLIT0pwFm0S/yR5Kh5t6nKHBPvdbYtO0Xq04YT+JKYtB/MJxA +Lg== +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 65:47:75:b4:58:fa:b2:e1:1f:16:b5:5f:25:49:b4:7f:2a:12:60:56 + Signature Algorithm: SLH-DSA-SHA2-128s + Issuer: C=US, ST=Montana, L=Bozeman, O=wolfSSL_SLH-DSA, OU=Root-SLH-DSA-sha2, CN=www.wolfssl.com, emailAddress=info@wolfssl.com + Validity + Not Before: Apr 28 08:10:05 2026 GMT + Not After : Jan 22 08:10:05 2029 GMT + Subject: C=US, ST=Montana, L=Bozeman, O=wolfSSL_SLH-DSA, OU=Root-SLH-DSA-sha2, CN=www.wolfssl.com, emailAddress=info@wolfssl.com + Subject Public Key Info: + Public Key Algorithm: SLH-DSA-SHA2-128s + SLH-DSA-SHA2-128s Public-Key: + pub: + a6:e0:24:a8:4a:18:10:4d:cd:c6:da:23:24:67:de: + 96:95:81:00:a6:ca:ce:43:e4:fd:fc:7b:1a:8c:fa: + eb:7e + X509v3 extensions: + X509v3 Subject Key Identifier: + BD:80:23:3A:06:DD:38:57:EE:6B:C2:94:7B:EA:BF:43:57:3A:B0:8C + X509v3 Authority Key Identifier: + BD:80:23:3A:06:DD:38:57:EE:6B:C2:94:7B:EA:BF:43:57:3A:B0:8C + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + Signature Algorithm: SLH-DSA-SHA2-128s + Signature Value: + 10:3c:70:c5:f5:b1:4f:1c:77:85:34:b9:b3:57:97:62:ef:e7: + 4d:17:67:56:63:74:02:e1:50:5c:5b:dc:56:94:45:d7:f9:6b: + 76:fd:fb:e2:00:16:0b:5a:0f:86:86:7e:1e:0c:4e:7f:d0:95: + cb:d4:8d:09:58:53:4e:e2:9f:0e:11:2e:38:dc:c0:87:ec:6f: + 25:ef:1b:59:81:ab:71:69:51:2e:3c:2f:f6:eb:f2:22:73:62: + e1:a2:68:b3:67:db:2e:05:16:fa:bc:ae:b6:22:cb:c2:0f:fd: + 88:1e:36:43:27:13:de:61:01:0c:ba:5a:df:0a:69:17:45:c2: + 77:b5:df:87:62:b3:16:6e:8e:57:e0:3b:9f:02:80:5d:f0:92: + 76:51:73:2e:7a:25:1c:88:79:dd:0d:55:c5:73:94:b3:76:52: + 39:fb:58:0d:34:fe:74:38:45:fc:99:39:87:c7:fe:4b:2a:7c: + 51:ae:92:ee:5f:28:16:13:04:b5:f0:5f:93:90:74:d0:e0:f4: + 1d:06:af:6b:ad:33:fe:2c:d5:9a:e5:10:32:7f:01:2f:7e:97: + c6:ff:b6:57:97:56:cc:5a:5a:9a:79:de:19:b0:9c:0b:57:bb: + bb:e5:8b:91:2c:cd:19:2d:7c:75:8e:71:4f:c5:c5:88:74:5c: + 5d:27:82:dc:94:58:7d:6e:71:6e:78:c5:f3:0d:3b:85:95:2a: + da:4d:af:34:a9:3c:02:88:cc:45:1d:08:0c:9d:20:39:73:06: + 0a:2d:ba:8a:5d:a9:44:32:24:32:b1:d1:fd:d1:7f:b4:10:56: + 3a:15:12:a5:f6:c1:6f:16:ef:84:5e:86:ab:5b:9b:a7:b4:21: + e3:43:86:1a:50:f8:95:b3:b0:10:56:0e:26:b6:5a:46:75:51: + e2:7a:5a:76:2b:14:4e:57:5d:88:61:27:16:8c:e0:6a:ad:87: + b1:19:89:80:87:aa:6a:59:69:18:fc:e3:5a:78:83:d8:58:3a: + ec:8e:b9:28:2a:22:e6:13:8f:ad:df:4e:4d:9e:99:6b:34:9a: + c5:c1:81:0e:28:1a:16:e5:60:d1:7d:1c:d7:5f:f8:3e:7d:1c: + 7c:2d:18:5f:3a:5c:d2:d2:0b:db:c4:4f:69:57:a7:6d:60:95: + 5e:04:fb:71:31:71:d1:e4:ee:dd:10:34:a5:9b:0c:7b:29:e9: + 4b:85:3a:2f:64:87:93:9a:8f:06:9f:75:8a:c2:b3:a6:0c:ff: + 94:7a:c8:f4:e6:14:31:b1:6f:20:ad:34:5c:3f:1a:67:c7:0e: + 0e:89:00:c5:9f:d6:56:4b:8d:86:dc:64:94:e0:7e:4d:8b:cd: + 43:5f:3b:46:c9:92:f0:a4:0d:df:b9:ab:38:aa:5b:3b:9c:af: + fa:fb:d5:f6:0b:25:96:30:33:28:3d:3f:1e:a6:10:43:58:53: + ae:88:a7:5b:8e:55:66:57:2e:0d:88:a9:5b:d3:71:0a:23:05: + 47:82:ca:e6:0c:c8:d1:f2:99:9f:c9:37:2a:59:99:d4:f0:a5: + 82:18:0b:98:f0:ee:be:0f:11:6f:2a:6a:14:dd:c4:c9:bc:ed: + 80:ac:7c:ca:65:eb:fa:af:b3:29:a7:b2:c3:1c:42:1e:7d:3f: + d3:1a:f0:1b:30:f5:a3:53:8c:13:d3:96:82:01:a8:2e:d2:ae: + ea:f1:50:17:ae:cb:a4:7b:55:72:55:8b:90:28:f0:d9:5b:81: + f4:78:9b:b0:fe:a0:c4:6e:dc:25:fc:94:64:71:12:bf:fc:cd: + 31:50:26:2d:e2:ef:38:05:14:82:b6:62:83:a9:86:cb:df:05: + ef:27:6a:cc:2c:8f:1c:5d:40:13:c1:e3:24:a6:7d:3c:83:1a: + 78:79:7d:63:75:4f:68:b9:9c:75:b9:07:ed:62:16:29:22:c1: + cd:f2:52:02:e9:17:b0:d0:44:13:9c:25:c7:fd:39:df:eb:d5: + 32:5e:bf:c5:47:81:18:83:63:96:89:4c:31:02:8f:c4:e9:7f: + 27:8e:01:3f:44:4e:96:b0:73:ad:56:a7:95:4d:ab:a3:03:e2: + dc:33:65:d2:17:87:e8:07:be:95:17:64:3e:6c:87:cd:3a:e6: + 0a:b8:e6:8b:e2:e9:d9:60:2a:ef:d5:c8:2f:7a:8d:ec:70:16: + 10:a2:1d:12:16:41:a3:c1:07:2f:95:b1:d4:7f:9f:ca:16:ca: + 72:1d:2d:df:3a:6f:93:eb:9e:76:34:3f:dd:a7:47:12:18:5b: + f4:34:2b:73:42:33:15:c8:19:0c:a8:10:d5:d3:04:81:e2:d1: + b4:3f:7e:53:34:d8:db:02:d6:60:b4:24:8c:28:4d:31:51:0b: + 4e:c8:f1:4c:99:98:a7:36:ab:bc:ce:a2:d6:67:f5:b2:64:ec: + 0e:e3:f3:82:46:d3:87:ce:1b:a9:46:d3:dc:1a:27:e2:5f:bf: + 55:33:ca:e0:de:02:84:26:ed:57:58:27:f4:d6:3c:0d:a7:db: + 40:2d:d8:c8:0c:84:47:97:fb:bf:49:8c:d2:1c:80:ff:da:d6: + 3f:93:00:77:f3:31:f0:c8:57:46:5a:9a:15:25:0b:2d:d1:1b: + 5a:eb:ae:09:0e:3e:24:e6:a9:eb:72:be:e4:45:d2:41:db:21: + dd:a7:1b:6e:62:3e:43:d9:62:34:31:62:76:d4:2e:39:48:fd: + 54:9c:51:6a:f7:71:44:88:c0:c3:98:3b:66:e1:8e:0a:9d:e3: + 68:a9:6a:d2:52:80:97:3d:9e:14:c9:bc:36:33:6f:24:9c:7b: + e1:8a:a5:a1:12:44:bf:61:a2:3b:da:18:b9:7f:9f:89:bb:10: + 33:8f:46:18:92:49:5e:10:81:a6:0b:06:19:19:a3:e8:06:c8: + fe:4e:94:20:de:70:36:7b:40:ee:04:ca:fc:fa:81:aa:87:9d: + ad:f3:57:78:0c:34:51:f4:fa:ef:78:58:1e:e9:0f:b9:75:f6: + a5:09:a0:91:7f:80:19:80:17:4b:5c:a9:b9:6d:b6:00:f8:17: + 90:e1:b7:4f:21:33:64:1d:d1:d5:a8:78:a0:98:46:0a:0a:0e: + 72:dc:2a:67:8e:57:44:00:76:2e:79:b9:4e:c7:78:b2:a7:12: + 17:75:44:6c:ce:a6:d7:ae:25:54:6c:5d:eb:3d:92:74:65:26: + f7:6d:23:1a:43:91:ad:2e:20:c8:f4:fa:13:a9:97:ea:7e:a9: + 61:94:81:a7:cd:b3:60:a9:62:4c:ec:8b:91:21:a9:d3:7c:39: + 9f:3f:4c:f8:8f:16:81:3f:23:3a:20:64:7a:10:ce:82:d7:24: + 28:ea:e0:74:6a:ea:62:bd:e3:06:90:1e:92:ca:fa:2d:25:a5: + 70:52:8f:a1:3f:9f:7a:7a:f3:55:4d:4b:8b:1d:1e:ce:d0:61: + 44:68:e5:c2:69:e8:14:2f:5c:90:96:72:8f:7e:39:61:c1:d4: + 3d:36:bf:12:b4:de:31:3e:7e:f4:45:d9:6b:d8:9c:61:06:fe: + 7d:43:ae:e3:c8:f4:3b:0d:7a:5d:b6:35:46:5d:5b:30:e9:9f: + de:49:53:d8:a7:97:61:33:ec:fe:dd:4a:89:c3:db:aa:39:4b: + 01:f8:20:27:a3:0b:12:2f:03:fd:8d:69:5f:90:2a:62:97:93: + a6:d4:12:80:ee:98:47:93:d9:89:7d:46:f3:2d:61:8e:e6:9d: + 7e:7e:42:07:0f:3e:15:08:9b:49:36:98:1c:1e:dc:57:5d:eb: + ab:35:4b:33:eb:2f:fd:a5:6e:92:45:5d:21:df:d4:74:83:02: + a9:3c:bd:88:ed:d7:05:da:b5:2a:56:e1:ae:7c:53:a8:9d:f3: + 24:bf:82:1d:09:20:66:b9:b8:4b:ee:b7:e0:9a:15:e3:99:bc: + e3:93:a4:2e:93:4a:c2:0c:8b:42:ee:29:42:f5:93:e9:b6:73: + 8d:8d:24:4c:78:26:b7:dc:64:c7:94:8e:f3:2f:81:68:91:a5: + 57:ec:c7:b3:7d:73:02:d0:20:18:16:7a:3b:dd:e9:65:08:84: + 6b:40:19:f6:79:71:13:ca:8f:be:8a:ae:c2:a4:67:ae:0e:5b: + a8:55:01:38:5a:0e:0a:51:04:57:12:76:e6:cf:d8:57:25:a7: + 8c:03:da:22:13:dd:90:e1:27:26:e0:d8:dc:9b:5a:6b:3a:0f: + e2:e3:8d:54:73:6e:12:02:72:f4:2b:c3:9b:80:3f:6f:fb:8a: + 9e:fd:bb:e4:d7:c6:14:8a:19:d6:9f:30:bc:00:98:41:92:2b: + bd:a5:8e:ab:93:89:9d:6e:d4:8e:82:17:88:a6:19:2b:8b:a4: + 67:e9:5b:ee:7f:bb:e6:a4:d7:cd:85:7a:c1:2d:15:8b:3d:4e: + 25:71:63:5c:7e:72:b7:bc:e7:8e:a8:ad:d5:a4:2f:d2:56:cf: + b1:29:49:03:9e:d3:b9:ce:35:60:8d:d3:50:97:5f:4e:ac:72: + f4:b0:20:e4:91:75:cc:27:5e:ce:ae:04:77:1b:84:02:fe:0c: + bc:a7:dd:62:3e:55:e9:e7:5b:a3:c8:1d:08:34:18:53:bd:fa: + 05:0c:e9:fc:84:73:0d:4b:9f:56:52:e5:09:e8:46:43:3b:4e: + 59:fa:84:67:d5:c2:94:3d:ea:cb:9d:29:31:4d:91:61:90:f2: + 1f:29:68:dc:34:5f:13:fd:b1:f2:38:72:85:f1:16:1c:7f:05: + e5:b8:32:57:3f:6a:68:ce:e5:58:1a:14:e5:1f:e7:b7:1c:04: + a6:e1:c5:86:c8:78:e3:62:92:fd:ff:9b:f1:e8:60:9c:40:b9: + 1c:1d:7b:52:ad:ee:de:fa:04:bf:0b:bd:d9:34:bf:ef:4a:1b: + f2:0c:72:43:1e:55:24:b1:56:ae:0c:44:99:ef:b5:fb:e5:ee: + c6:20:7c:15:5f:66:c8:32:c3:e0:33:76:00:d3:b0:7e:be:0a: + 28:79:3f:98:51:78:12:73:ae:b3:24:a5:a1:d3:1c:f8:6c:5a: + e7:c0:47:5f:86:a5:67:d5:3b:20:19:49:91:fd:c6:32:0c:96: + e9:df:ea:e1:8e:cf:4a:bd:9f:95:eb:88:2c:3c:f6:34:da:89: + f7:3a:d1:bb:0f:97:f0:38:99:ec:89:b4:b3:92:bf:ed:13:7d: + bc:14:54:16:63:01:f3:60:f0:f6:c4:e0:db:00:dc:c8:5f:13: + 11:82:1d:04:73:a4:f1:8d:d0:8e:7a:4d:1f:9c:0e:8d:dc:fe: + 7d:8f:97:5e:a1:97:c2:73:e7:45:94:19:19:93:f5:4f:fc:25: + 8b:c3:1a:19:a7:1d:91:0a:bf:28:78:41:06:7d:09:d4:95:c5: + d2:8f:47:04:cf:3f:9a:be:72:b0:8a:d0:29:0d:87:b8:22:11: + 2a:c6:c7:27:81:12:6f:9e:18:88:9c:8a:25:04:05:66:b1:ef: + b1:4c:48:f7:f7:53:ec:c8:72:bc:70:25:5e:19:be:3c:d7:f6: + 1a:52:77:05:15:db:ba:99:2a:d6:bd:ce:a1:70:fc:30:40:cc: + bd:4d:e4:36:f0:fc:b9:54:31:48:d3:9c:bb:3b:51:08:a5:e8: + b0:3b:5b:0a:69:91:2c:f7:d4:50:07:4c:a8:2f:7b:43:82:64: + fb:c3:ca:48:5c:b9:f7:f3:bc:d6:21:43:c3:b5:26:61:06:86: + 23:c6:7f:05:d7:0b:c1:e5:7d:5f:5a:c3:09:1a:7c:06:cb:35: + f8:a3:70:13:14:37:b6:98:00:88:24:b0:90:4f:f4:99:99:75: + d5:15:23:7b:5a:09:db:33:30:8b:b9:da:b2:08:7c:ea:39:3c: + 88:96:a8:39:da:1e:22:5a:b3:be:f7:40:58:7a:6d:7b:88:de: + 4c:57:30:f1:38:a5:cc:6a:e7:b3:c4:ef:8a:f1:4d:ca:2c:bf: + 5b:05:02:30:97:10:12:dd:3f:8a:bf:0a:86:4f:57:63:79:bc: + 2c:21:a2:c2:07:26:a4:96:d2:1a:d2:73:86:a9:af:2d:ca:ae: + 6f:07:e7:26:f4:47:65:8e:0e:29:8f:ca:ce:16:cd:90:00:f0: + a6:19:a4:30:b8:d7:8a:da:de:5a:5b:54:91:9a:e1:75:6b:49: + f6:b8:67:0d:02:d2:c4:ec:67:f5:0f:c2:dc:11:c5:65:69:f5: + 1f:44:44:af:1f:91:9c:29:1f:8b:e1:8e:9d:5c:9e:ac:72:fa: + 4b:c9:29:9a:f1:1e:d1:64:6b:8e:22:5a:34:0f:53:47:ce:0b: + e3:07:49:cb:86:de:35:ec:17:e4:d5:df:cb:f4:de:0c:e1:b8: + 93:97:88:9e:f6:0d:b3:fa:f7:4b:a6:52:ef:48:61:c1:43:f2: + 32:f7:af:77:ab:75:c0:6c:08:b6:cd:63:cb:b6:64:e8:01:ed: + e4:62:39:36:38:ab:70:4d:c3:a4:b4:92:be:79:e0:f2:7d:7f: + 06:52:48:bd:ba:c2:56:6d:af:1f:86:b6:7a:eb:e9:b4:fc:8c: + 13:83:fc:25:f8:93:5f:52:c4:bb:4a:08:5a:a0:bf:bd:24:37: + 4b:44:e4:a7:ea:fa:36:49:dd:86:1a:f9:f0:24:1b:ab:c1:1e: + 8c:03:f8:8a:86:99:fd:3d:9d:9f:68:1a:96:47:73:18:22:3b: + 7b:c0:76:02:1d:61:79:73:ac:f9:2c:45:ce:87:53:b5:f5:44: + 8d:73:9b:38:d9:bb:a4:11:fd:f8:0c:16:c6:74:49:f0:e0:18: + 10:c6:d1:2c:2b:5d:c4:17:72:60:e0:7c:d9:48:b3:eb:38:ba: + 4f:e9:82:c2:10:9a:cd:bd:8e:e8:ff:be:f0:57:d8:e5:94:50: + 15:6d:87:42:32:8b:d7:8a:07:22:8e:e2:31:e7:95:9b:22:4f: + 5d:0d:51:02:49:1e:fc:66:51:bb:81:01:96:64:63:d8:57:43: + 66:0d:1f:6c:b4:9a:16:b6:dd:09:c8:6d:0e:c0:79:1f:a6:49: + c8:11:79:d1:18:34:9a:4e:4f:1d:80:1e:47:5b:75:07:a1:74: + fa:52:d2:69:d1:24:d7:2a:cd:72:c6:c8:ec:7d:6b:6b:b6:f9: + e5:5e:9e:d4:24:a0:00:df:ab:b9:6d:57:58:90:18:ac:1c:bd: + af:c1:88:d8:90:5c:82:de:fa:4b:40:51:01:6d:45:c2:83:18: + a3:38:ca:e6:5d:c0:5a:dd:b9:68:0e:0d:c3:c2:f8:6a:8c:ee: + a8:6f:19:c2:d6:78:d6:57:33:7a:fb:c6:0a:db:47:aa:55:89: + 47:a6:20:6f:0b:78:84:69:20:da:b5:6c:1b:d3:2c:d7:db:94: + 38:e0:75:e7:6c:8f:4d:f5:e5:42:16:c6:91:93:6a:41:39:a5: + 77:92:02:49:63:0f:74:c3:b2:55:3f:b1:33:e5:7b:d9:ff:59: + ae:a1:6e:1c:06:bf:76:98:dc:ae:94:39:49:3f:5d:d6:b0:fa: + 06:3e:29:8e:40:62:b8:b7:dc:22:11:50:48:19:41:37:c5:e4: + 34:b8:25:60:98:ed:b9:4a:68:47:a9:e6:2d:d7:e5:ef:35:e7: + 6f:a8:9f:a5:b2:0f:0d:98:fa:9e:ff:fb:c5:57:83:69:98:b0: + 37:06:fb:4c:0d:17:ad:e9:68:2b:c3:42:1c:f6:0c:ac:7f:ca: + 1b:ba:a9:90:b8:f6:e1:a2:2a:45:8d:f5:aa:e5:8b:4a:16:f6: + 0e:3a:38:ee:25:d9:5f:b6:f8:fc:7b:a8:c6:88:e3:ea:f0:1f: + a1:b0:e7:46:e4:b0:59:08:95:02:25:0c:6a:8a:3d:56:3d:c9: + a8:12:dd:47:b4:2d:5a:f6:ae:43:cc:3e:4c:7f:4e:ab:b1:78: + 2a:59:6d:6f:ca:93:21:e4:f6:ad:91:a6:1d:da:a9:16:8f:e6: + 1a:d2:c9:22:13:62:8f:be:28:96:bd:23:59:38:91:75:b5:84: + bc:ae:b9:5f:07:4a:dd:fd:a8:fc:e6:6d:0d:04:e2:76:fe:30: + 0b:e9:9b:60:1c:98:bf:92:80:57:45:ba:53:d2:61:f7:50:51: + d2:ad:9c:03:39:96:39:ee:45:64:04:b3:ca:02:bf:ec:3b:d1: + ab:ec:8d:97:9a:ec:1a:ac:62:99:85:f6:15:c7:d9:b0:2b:f4: + dc:55:f4:19:ac:7e:36:59:70:ee:8c:79:98:89:61:86:25:bd: + b3:38:9e:49:ed:8a:ce:61:1d:d1:13:99:96:74:9e:4f:43:78: + c0:c9:a2:f3:62:92:f8:aa:6b:ca:91:7e:29:d1:80:27:64:68: + e1:0f:9b:fc:fe:64:99:0f:d6:8e:d3:78:d8:ea:fd:e5:0a:55: + 34:8b:f1:b4:d9:1b:a5:bb:30:f9:1a:f4:19:3c:3d:af:ac:5f: + ce:9b:27:08:18:52:6f:b0:aa:02:0d:46:84:73:92:f1:0b:16: + 12:9b:cf:bc:f3:97:bc:c2:9c:18:57:cc:55:63:21:de:f7:32: + c1:3e:fb:88:de:f7:ae:f0:11:10:5b:5f:04:df:9d:3d:19:2f: + 89:cb:72:b4:5b:f2:49:81:76:c2:57:ec:d9:44:ff:b8:8d:19: + 6a:2d:bf:31:47:34:e0:b1:03:32:26:15:e4:d7:44:41:d1:5e: + f9:ba:e2:5f:50:45:44:08:44:7f:9b:09:f4:37:ff:8b:d9:d6: + 55:66:d0:60:b2:8b:94:34:8d:97:dd:73:2f:02:22:be:9a:bd: + d3:57:8c:c3:c6:e1:e1:19:64:f1:6d:3e:41:20:6f:4e:47:bb: + 29:41:bd:a9:8c:ab:01:41:ea:2a:51:c7:f2:9f:ec:ca:9b:1e: + be:e7:f9:3a:5e:66:f8:dd:30:3c:dd:3d:53:61:1e:ad:93:31: + 01:c4:c4:b3:2c:b1:14:a3:68:a2:a2:6a:f9:60:e7:63:19:e4: + 89:19:89:1d:ad:de:85:5d:43:4c:57:61:17:b4:7d:f9:18:93: + 93:c6:88:40:0a:3d:7e:a4:e9:ab:fd:56:c0:2b:5f:35:68:26: + d4:e2:c8:f7:75:08:1c:11:4f:a0:64:a8:15:2d:f2:e9:58:0a: + 31:ec:cb:f8:ba:3b:85:aa:95:93:5e:47:05:27:c4:32:6d:56: + 71:6f:38:8d:db:93:99:57:35:cf:25:83:99:77:d3:7e:93:cd: + a0:04:ae:e5:e9:20:e7:63:b1:ed:69:8c:46:3d:1c:f6:84:bf: + 67:a5:71:60:d5:ec:9f:5b:d9:12:12:9e:0a:b2:85:40:94:34: + 9a:74:6b:25:1e:3b:03:2b:2c:55:7f:51:4a:6a:93:07:dd:e6: + d4:89:fb:1a:95:1d:cd:bb:d1:61:47:6d:8c:09:56:44:b3:52: + c9:ca:df:a1:27:45:77:a1:e3:31:ec:da:b4:ad:15:20:ac:f7: + cc:88:1a:b6:84:f5:21:c9:4f:f7:94:bb:d2:1c:d2:19:40:52: + 5d:2f:9f:44:d3:64:8c:88:d3:08:93:ff:5e:d1:99:63:60:40: + 73:08:bb:20:3d:d1:26:a8:30:48:44:2d:d3:65:e6:af:eb:22: + ec:7c:6f:97:16:69:58:3b:e2:ef:e9:de:de:90:10:07:f4:bd: + 6a:a7:e5:82:e9:22:d5:0e:c9:32:ea:ac:30:69:c6:96:9b:51: + 6b:93:65:67:e5:84:2f:36:1c:19:d8:be:26:fa:79:05:e0:ed: + 34:fd:2c:a4:c0:44:7f:cd:c7:51:e5:a9:81:a7:90:97:46:1a: + 78:00:16:64:2c:d9:d4:85:b6:61:1a:87:de:96:f5:0c:f3:cc: + 73:d4:0d:5e:8f:64:b0:a0:97:c9:12:0c:2e:fa:3a:a1:07:1c: + bc:29:0c:e0:82:b7:3b:0d:6b:14:80:3a:11:a6:d4:f4:36:a4: + 96:d9:89:f8:81:61:77:79:02:6f:5e:64:2a:d7:f2:fa:26:d6: + 0b:bf:cc:63:5e:ff:af:7b:c4:ef:48:5d:ef:c7:44:bb:46:be: + cb:3f:c4:3e:9c:f2:98:9e:ec:7b:20:4a:54:a0:cd:2d:3a:cf: + a0:2d:4a:db:2b:97:50:82:92:68:4e:f0:f1:73:b0:b8:6f:62: + d6:97:95:15:75:03:41:5a:d6:f2:f8:a3:eb:f6:48:49:44:49: + 93:9e:6c:2c:e1:a1:d5:e6:fd:f2:d5:d9:ee:f0:86:ef:01:49: + 65:d6:fd:ae:9d:3a:a6:1d:1a:b3:9b:09:8a:49:cb:ff:b9:d2: + b7:16:7e:f5:36:05:c4:09:c1:b1:49:97:0d:8f:22:c9:8c:9e: + bb:ea:ce:f9:a5:57:47:de:04:7a:bd:e4:b6:a0:0b:bc:d1:da: + a1:20:e1:5c:c4:7a:13:fa:7c:c3:dd:a3:b2:48:98:29:83:75: + c1:6d:f8:1b:75:7c:f4:91:ae:66:d9:bf:49:3e:4c:85:01:df: + d7:8a:1c:44:9c:d0:d1:4f:7f:c2:0f:7d:f8:e0:11:4b:b6:b0: + 4e:6f:1a:f1:fb:53:f8:42:c8:54:15:6b:29:a9:b1:1c:f3:f4: + ed:52:2e:66:e9:49:1a:d0:52:66:6e:fa:8d:ff:2f:1e:d3:40: + c7:25:b7:69:1d:d4:a9:4d:ee:82:14:32:0e:82:ed:94:b6:02: + b0:00:d1:b3:20:f2:eb:9e:db:0f:c9:4f:3d:ec:b2:6e:bd:41: + d2:93:87:1f:fb:8c:b8:0e:e3:6a:f4:37:dd:4f:a0:24:e6:22: + 3d:c7:a2:46:06:bc:5e:25:74:aa:ae:fc:de:94:d9:5d:6f:1b: + 0f:e3:99:46:06:4c:20:ff:59:d1:ef:75:76:87:c8:9a:7d:97: + 67:6d:06:d8:20:83:84:1d:c4:72:43:8e:e2:ee:3a:d9:21:59: + 63:c9:a0:56:d1:42:f4:34:fe:ed:ac:a4:0a:28:0a:c0:a0:32: + 0f:f1:4d:36:b0:27:9c:a5:88:6f:b2:65:a9:43:d2:09:0c:ce: + 06:b7:1b:e4:44:d0:e3:cf:da:2f:11:df:cf:83:3a:8e:04:7e: + 5f:31:90:c1:1e:1c:b1:ca:4c:21:4d:6a:7a:c5:e0:17:61:ee: + c5:61:dd:0d:41:71:96:77:6d:a4:43:a1:69:60:22:56:ea:b1: + 88:b1:71:53:79:44:25:f2:42:c9:b3:48:f7:6c:9a:6a:be:f1: + ca:88:3e:14:b9:69:9e:57:0b:f6:b6:1b:c9:88:70:7c:a8:80: + d6:34:9f:63:59:48:86:4c:bc:eb:cb:49:1f:ad:f6:13:b0:de: + c1:0f:8f:a8:0c:f3:ce:f4:56:b5:3c:1d:82:df:9a:98:4b:5f: + 91:1f:56:f3:ad:b7:45:92:9f:44:d1:5b:63:da:1a:96:cc:db: + 9f:48:64:08:19:29:3f:a4:27:6c:ed:20:49:07:dd:b0:72:9e: + fd:59:37:73:69:07:1c:24:c4:46:5d:58:d1:0f:e4:05:08:09: + 60:b2:8b:df:a2:a5:07:99:c9:4f:cb:f3:d2:d8:bf:b7:0a:6e: + cd:73:43:a5:a0:46:1a:f8:c1:88:01:e2:7c:c1:a7:36:ad:f3: + d1:28:e5:4c:b7:5b:a3:08:70:0e:3a:d9:d3:ce:55:0f:2f:f8: + 08:7a:3c:78:0c:c0:ca:1d:8f:35:34:6d:8f:10:3b:3e:ad:3f: + 2d:55:9e:d0:aa:e7:43:39:c0:64:4b:55:f9:62:a1:f4:1d:90: + 4a:3e:06:1d:0b:8e:12:18:6e:28:30:92:88:80:99:6b:bb:a2: + f2:2b:79:1a:4f:53:e5:4d:10:bd:3b:81:9d:1c:9c:06:a1:a4: + df:61:ec:5a:05:82:38:91:84:65:f6:74:83:9a:28:eb:23:92: + 1f:ef:77:77:30:98:c4:90:45:d7:4e:80:fb:e7:50:52:0c:03: + 10:0d:b3:e4:0a:20:6c:85:fd:2a:b6:87:e2:7d:69:b0:76:ac: + b6:23:ff:09:6e:ab:7e:98:3e:72:76:bf:a1:e2:77:32:2e:51: + 85:db:cf:d8:50:b3:e2:c6:7c:75:bf:67:3a:76:c0:d5:78:2b: + 1e:c8:ee:63:31:20:7a:33:c9:90:df:8e:95:d7:be:04:32:93: + bd:60:46:2d:18:52:0d:e0:99:1f:da:1e:d1:ae:f1:ea:a8:7a: + 90:80:7e:10:89:51:c5:a2:55:38:b8:59:12:92:9f:93:87:e3: + 0f:bb:02:29:ed:75:8f:8a:17:8d:81:91:65:78:a8:1d:9d:2d: + 1e:0f:9b:53:d4:13:8d:55:92:eb:8a:45:19:f6:6b:44:03:47: + 9c:3b:18:1b:d3:f1:a1:3d:c4:66:b0:16:d6:60:26:b3:8d:89: + 52:27:29:4e:3e:b8:50:fd:64:20:fc:02:58:e2:83:6f:15:35: + e4:a6:c8:d6:2c:e3:ce:e2:9d:d1:53:a6:d9:57:90:63:24:ab: + 18:d8:6e:63:90:9a:eb:9b:80:c2:98:8a:9a:bf:20:92:b3:36: + a0:04:fa:88:2d:d6:0f:3f:9c:4f:4d:21:96:c7:4d:2e:c0:34: + f0:40:d0:f7:f3:ea:c5:57:cd:3f:ec:74:73:5e:f9:b0:7e:71: + f3:7c:6e:6a:3c:a1:22:b0:f4:40:d8:62:08:a3:97:8c:14:66: + ff:bb:83:ab:26:24:01:9f:b5:03:0e:80:5e:e9:e9:f1:14:84: + 97:4d:f8:06:db:98:2d:8c:93:e2:af:45:44:7a:d5:61:bb:d6: + f1:c4:5e:38:62:3e:1b:1d:d6:69:42:49:66:a0:83:da:23:5d: + 42:b9:c7:a0:07:5a:ef:e7:b2:9c:4d:83:63:6c:89:61:c7:d6: + 29:4d:76:6d:eb:26:6d:25:c9:fc:5d:2d:58:88:17:5e:a5:4b: + 7f:0b:6e:c7:7d:f8:6a:50:53:c7:80:35:98:76:31:cd:f0:2f: + 6c:f9:79:93:c4:bb:9b:01:89:00:df:0f:55:c5:67:19:50:b2: + 31:ca:68:f8:30:f6:0a:88:2d:e8:55:0d:af:cd:5b:cd:f9:3a: + bc:3c:87:f1:32:b5:f3:01:a9:09:44:ea:54:2b:18:33:05:d3: + c6:b8:56:e3:5a:70:38:4c:98:5f:ee:17:6b:12:2d:00:fa:c1: + 33:48:73:7c:29:51:9a:44:c7:74:b6:63:2f:b4:f8:87:3c:e4: + 44:4b:5d:0f:ec:b1:ec:56:b2:23:da:d4:1f:b7:a9:13:d9:1d: + b3:d6:19:d6:23:fc:72:9a:15:d6:6c:df:66:71:55:a6:89:9b: + ed:ef:25:ee:fb:2b:b3:58:59:d0:42:ab:da:97:88:de:cc:06: + aa:b2:85:d5:f0:a2:87:0e:cb:58:7c:14:9d:d1:8e:d0:21:9b: + 80:67:ae:73:4c:34:fd:42:36:71:dc:a5:55:4d:79:19:dc:4c: + f2:bd:76:25:e3:f0:88:62:4f:79:4b:e0:2f:30:cf:40:42:4b: + 54:1c:85:23:11:66:3f:23:6a:dc:54:f3:5b:cd:9c:b6:88:e4: + 71:87:5c:2f:7e:85:55:5b:9c:23:3a:00:1f:57:da:b6:33:06: + 8d:ce:07:89:b9:2d:7d:0b:35:8d:8a:8b:66:cd:59:16:55:db: + b0:b4:2d:3d:53:32:03:90:98:55:a4:f9:8d:f3:84:b4:16:06: + 42:3e:ca:71:ef:db:c7:59:32:fa:e3:ec:3b:fb:c9:83:83:90: + 52:99:06:c1:b4:3d:ea:f9:83:fa:a8:d9:c3:09:8b:15:d3:85: + 06:a1:e5:26:93:4d:23:aa:cd:4b:3e:5f:64:8f:2f:71:7e:c8: + d3:8c:78:ef:79:3e:ab:4c:da:77:23:2e:ff:56:35:8d:27:7d: + 7e:7e:df:03:1a:c9:c2:af:f4:62:49:f7:35:1c:6a:9b:19:f9: + 0a:e2:17:36:b6:6f:d6:ee:b6:e7:12:e3:c1:54:17:22:6a:28: + 6d:cd:9c:e0:ef:b7:1c:99:e1:94:53:8f:c5:55:65:b2:f0:4d: + 0f:c7:ef:d0:0a:b4:9f:c2:c9:9d:af:26:2e:98:5e:cd:59:79: + 80:1a:28:27:68:fb:22:f3:14:71:60:79:a0:5f:92:75:59:36: + 58:fd:80:20:07:e9:8f:34:5c:38:53:7b:4a:d1:58:77:af:1b: + 0a:0f:70:3f:db:b8:58:37:01:e6:ef:8d:3c:e5:c7:71:c6:bd: + 1a:0b:12:33:5f:9d:07:36:4d:7d:02:07:85:60:83:6f:fc:e0: + af:9f:c5:22:4b:cd:89:dc:2f:b3:53:e1:7f:b9:65:af:59:57: + 54:87:32:f2:d6:15:88:e2:2b:a7:20:85:42:26:d9:09:ee:87: + 60:0c:bf:a3:6a:e5:e5:db:6f:2c:05:7e:88:ee:aa:98:d7:6d: + 0e:3c:9f:6c:28:70:02:1a:78:b6:2e:2c:29:9e:d9:fa:1e:80: + 0a:a3:e6:dc:46:00:15:e7:c0:13:36:42:9c:f0:1a:fa:9c:7d: + d0:cd:2f:ce:dd:95:54:fb:b1:fa:bb:3f:83:26:f7:54:42:5d: + 60:7a:d1:bd:b2:17:9a:e0:02:a7:9a:d8:40:f4:2c:79:c0:4e: + 4e:a4:68:aa:33:c9:1f:2a:f3:fd:9b:50:39:37:b9:1e:59:2c: + 7b:cf:97:57:23:81:b7:07:76:8e:b1:f5:15:dc:54:c5:f9:f9: + c6:13:b7:37:2d:12:44:c6:78:1e:92:1f:ed:85:8f:14:7a:9f: + d0:1f:02:8a:f1:5e:8d:05:28:13:2c:cf:1f:41:9d:74:ec:98: + 96:51:57:a7:c0:10:9a:be:31:7d:71:a7:c2:38:cd:ce:74:60: + e4:45:ef:b0:60:87:7a:da:e9:05:38:06:19:fe:60:db:c6:2d: + a4:25:f7:5d:d1:b1:3d:12:0b:a0:fb:3c:80:b0:f5:00:48:34: + 8b:e4:a4:f1:cf:fe:be:a2:38:43:44:20:23:5e:89:c8:91:18: + fb:5e:aa:90:11:07:7a:e8:ad:61:03:17:6a:a5:a6:a9:e2:c4: + 8c:f0:5e:d7:25:fc:43:93:db:47:44:c1:25:26:38:7a:17:08: + 24:36:d3:25:95:eb:c3:17:ca:b5:d7:79:73:62:48:d6:d0:af: + e7:a0:61:83:5d:7a:27:e9:b9:7e:d2:25:17:85:c2:28:5b:9f: + e7:01:67:f7:69:83:eb:ec:cd:8e:2b:ee:f1:4c:17:a5:3e:05: + 2c:c1:eb:b7:64:d8:fa:3b:3b:c4:e4:53:18:fd:d8:da:1a:f4: + c7:c2:47:90:91:ab:3d:2b:12:1d:9e:7e:58:7e:cb:63:9c:ff: + 28:bf:a0:c3:a6:07:52:58:9a:de:2c:4c:63:5e:79:8b:21:cb: + cf:5b:08:7d:6e:44:55:32:5c:37:71:46:02:c1:28:e8:5f:c1: + 34:ca:b9:25:0a:c8:88:a8:bc:13:1f:1d:c3:6f:cd:3e:f9:95: + ad:45:7b:f9:03:05:b8:f8:c8:89:fa:a0:7a:2b:b7:15:ba:d2: + 0a:39:39:c9:0e:0d:5b:f9:11:b2:9e:11:98:90:bd:25:9d:a2: + f2:c8:c1:3b:70:a3:71:b9:9c:46:24:b1:00:1b:54:3c:ba:11: + a2:73:d4:bf:85:08:57:8f:05:6f:9f:23:12:ff:06:73:d5:6d: + 13:7c:1b:50:c4:df:8e:8a:8a:f8:f4:5c:61:c1:51:e8:d3:82: + 7b:ef:60:89:56:4c:fa:e1:b5:50:47:23:66:7e:af:af:a7:9f: + 0a:1f:55:2d:d9:ad:8f:92:01:d4:10:c8:00:63:0e:6e:95:1b: + ea:e9:d3:38:ac:7c:34:d1:8d:61:e6:be:c5:98:3d:9e:cf:70: + 28:5c:4f:80:44:4d:06:9d:1e:e0:4b:4c:91:76:7e:d8:ff:5f: + 5a:ae:b6:88:f6:25:7b:96:80:4c:59:3f:91:29:4f:44:c1:01: + 23:9c:8c:51:f1:fa:69:e0:b1:2a:20:c8:93:14:f4:99:61:a7: + 4e:9b:ee:8d:02:5a:e2:29:d7:f5:9f:ef:94:59:4c:55:c6:0f: + 1c:b8:9c:a9:b6:bf:cd:c4:30:e5:e5:84:4e:d3:13:af:6e:8f: + 8d:ac:d4:64:c0:21:5d:57:e7:9d:73:c6:90:63:b7:22:3e:a6: + a6:47:d3:be:b4:a3:ff:c6:c3:0e:2b:f0:45:ee:50:50:98:b2: + 8e:f2:bc:05:d0:24:b5:40:b2:52:b4:bf:d7:62:8a:a2:a8:d3: + 6c:3e:ad:12:46:ab:5b:c7:e1:32:99:21:7c:cb:09:37:2e:8f: + 0b:85:41:5f:45:8f:17:ca:66:6a:73:97:73:3c:3d:8d:dc:9f: + 51:dd:59:15:0f:68:4b:a2:42:4e:98:6d:1c:74:9b:5d:b4:65: + ed:22:17:a4:73:b2:11:93:f4:d2:b5:aa:93:00:c5:88:42:86: + b5:1c:3f:fc:9f:f7:f9:2f:a9:29:a5:66:e2:e5:8e:29:ef:d5: + d8:dd:93:62:26:08:7a:f6:62:6c:17:1c:b0:d6:19:b1:39:8c: + c4:54:a5:ef:34:b6:15:53:fd:88:80:eb:48:50:0d:74:8e:34: + 04:64:f1:da:13:4f:df:63:7b:c3:19:be:c4:1f:f2:13:25:cb: + 73:37:98:93:4f:8d:ed:97:88:ee:be:39:9f:03:bd:2a:4f:08: + 1d:63:19:dd:20:06:6c:4c:96:a7:66:82:7f:75:62:19:5b:87: + cd:76:e3:b9:10:76:ab:b4:bd:54:ca:3e:10:15:a4:36:42:93: + e9:56:fa:19:59:e3:90:55:ad:f7:b2:07:cd:99:9b:7c:05:01: + a9:d1:fc:eb:e6:d5:de:01:39:ac:0d:be:c7:db:fb:b0:54:08: + 48:26:f9:54:dc:15:85:a2:6f:33:10:60:ec:0d:38:ad:15:e4: + 14:83:3d:65:df:0b:ae:01:f0:15:9a:ca:bc:4f:c9:c0:57:9f: + 9a:b9:22:53:56:b3:4c:83:50:f6:5b:13:68:94:6e:12:7c:bf: + 9e:22:6d:c3:17:f4:f0:a5:73:b5:03:ef:b8:af:0e:20:c9:df: + 2d:39:e6:43:38:84:30:6b:a1:36:0a:bf:09:41:67:18:85:8e: + 77:04:a3:be:d4:9f:36:75:42:e5:84:ea:75:fa:0b:01:4a:30: + 48:9c:b3:47:9d:3c:48:41:74:76:14:30:dc:66:1e:fd:7c:58: + 2f:63:e5:74:2a:c5:a2:26:65:fe:c2:13:7b:0d:83:f7:94:3d: + 2d:f8:83:07:aa:dd:77:72:26:fe:70:29:d5:1e:83:21:ba:0e: + de:10:ba:4c:cd:19:88:b2:9a:44:f8:86:d8:fa:4a:12:3b:7f: + 02:ae:af:68:7a:87:8b:8f:63:e5:9a:da:e4:77:9d:40:50:27: + 7f:b0:7a:ac:5c:aa:b4:33:8a:dc:fe:17:74:3e:1d:5d:5c:0a: + 57:06:72:ac:ac:ed:2d:81:09:b3:6e:71:25:3b:03:29:67:b5: + 81:bd:b3:3f:36:42:f3:af:ac:db:58:fe:00:42:b4:28:89:1a: + 76:fb:11:8a:32:c9:65:03:f7:ef:6a:e6:57:48:e9:b9:d2:90: + 42:9a:cc:ff:f1:fb:06:ad:be:ff:4e:c2:64:93:39:48:4a:57: + e6:06:98:14:9f:0c:61:19:c1:f0:d4:c8:3d:1f:6c:a5:c2:28: + 66:25:aa:7a:9f:fd:08:f6:ec:c1:e5:f8:e2:37:17:f5:6b:ae: + aa:f7:a4:da:27:59:25:0e:43:4c:53:62:3b:62:6a:5e:6d:9d: + c9:01:02:f3:79:47:0e:2d:ea:62:89:a5:57:6d:de:18:b2:a2: + 13:d2:34:27:28:4f:4a:a5:d7:f3:ee:16:a0:5e:77:f9:2e:6c: + 22:81:44:ae:03:64:e1:9f:b8:d7:55:92:75:f6:66:ea:2e:45: + 31:16:aa:32:77:3f:8e:0e:b7:4a:d9:52:ad:05:28:d1:58:8a: + d4:79:b0:ba:29:15:33:5b:99:59:d2:70:95:fb:6c:0a:5d:18: + 4a:96:ab:14:96:c8:00:9c:5c:e1:f2:f6:ec:85:e4:3e:39:39: + b7:44:3d:9a:66:bd:d9:32:48:c8:5c:0c:d0:4c:b9:2d:01:49: + 1d:eb:fd:41:32:67:23:87:10:31:17:20:df:f1:3f:77:ed:b8: + d9:52:dc:3d:11:15:dd:04:93:88:f2:65:32:6d:7b:c0:d8:df: + 3a:19:61:9b:7f:e5:a2:b1:e0:6f:6a:3d:f5:82:08:a1:0e:26: + 42:e2:91:9f:c2:a2:7e:ba:66:89:a7:95:26:c5:9a:9a:7b:2e: + c7:cf:4e:70:07:2b:f6:f0:56:60:f4:56:ba:73:18:e6:b8:85: + 96:35:b2:d4:3d:3e:63:ca:be:08:54:f3:7c:03:e9:6f:98:17: + f5:03:66:da:dc:bc:4a:a8:97:d4:ff:74:89:ba:1d:22:91:58: + 50:87:43:c6:1f:ef:0f:cb:9c:da:0e:f8:6b:1e:ab:84:17:f0: + 56:17:dd:4a:19:62:4f:d6:56:ef:27:ba:81:ff:fb:5e:c6:4d: + a1:20:03:a4:4b:30:d1:09:37:8a:e3:34:cb:2e:5d:9e:6f:a4: + bb:9c:0d:7c:b0:40:66:23:7d:ac:dc:b9:7c:68:f4:db:f7:92: + c6:db:dc:dc:77:5c:d7:d3:57:a7:13:60:a3:ed:87:15:da:fe: + a5:f0:2e:46:94:ad:92:75:61:f2:a8:08:79:83:af:ea:f5:7a: + 4d:02:2a:f2:39:d6:87:ef:4f:17:49:06:86:5a:54:9d:48:0e: + ab:7b:b6:f7:eb:68:85:83:01:52:d5:a8:32:fe:31:c0:45:11: + e2:dc:d6:99:d6:27:90:b5:41:48:b0:39:da:9e:0e:d2:6d:48: + bb:c4:0a:15:53:8b:16:77:9a:b9:62:b9:18:db:ea:25:17:8f: + c4:18:cd:1c:93:33:0e:9b:e0:ef:da:22:d8:55:17:2d:90:f1: + 5e:35:a0:24:eb:3b:d4:50:45:d9:35:3b:0b:c3:d4:6e:67:b2: + 92:0e:e6:a7:14:1c:09:e4:d0:94:d8:05:b4:e4:9d:20:5f:f1: + be:ca:25:00:34:76:35:e4:3a:19:05:ec:94:8b:9f:cf:c1:1a: + 89:bd:8b:1b:8d:68:85:2c:aa:d0:95:3b:d7:b5:47:39:03:7b: + 73:38:16:8d:21:68:1a:d8:77:49:1b:02:d5:41:e9:f9:a1:da: + 40:75:f1:0a:ab:76:19:79:dd:34:28:6b:4d:d1:44:79:97:a3: + fd:15:1e:12:77:ce:e9:04:12:c3:47:75:5e:73:5d:8b:50:8e: + 7b:78:74:a2:10:44:dc:29:ec:bb:09:04:98:dd:9a:98:a1:f8: + fd:c5:5d:41:4c:9e:13:33:09:f7:59:d2:ca:7b:86:8c:0f:f0: + 8a:40:fb:6a:7d:c9:5b:18:71:28:15:e9:8a:97:b8:4e:56:a1: + 3c:82:69:f2:1e:05:b8:4e:b4:0f:c5:11:b0:d8:cd:e1:07:5e: + 39:a1:e4:a0:ad:19:c7:af:3b:a1:3c:01:69:8a:4d:8e:13:22: + 53:98:ab:9c:a5:2e:75:1c:97:d9:0c:e7:0b:d4:79:41:2a:2d: + 73:97:45:e4:b1:4b:37:54:d7:90:2f:36:f5:49:82:d6:41:e3: + 9b:1b:ee:bb:19:f3:a9:5f:74:da:90:0f:ef:c3:89:e7:21:cd: + 0a:51:71:aa:77:76:ad:e2:15:f1:ac:cf:68:34:09:d3:00:4c: + bc:c9:58:9f:b5:6c:e6:f9:4a:cc:3b:73:7a:0a:02:8d:da:98: + 77:14:34:98:5d:ef:c0:8e:71:bc:b2:dc:56:1f:ec:b0:b0:46: + 75:23:7b:00:33:44:f3:85:a7:49:81:47:28:62:76:4d:91:3e: + 57:5c:58:31:a2:b1:de:0b:49:fb:92:ad:d1:a7:1d:61:0d:03: + ef:7c:fd:9b:9a:36:ce:b1:1d:37:87:3c:ea:3e:54:37:b5:de: + ea:e6:79:27:aa:4f:2f:94:17:21:09:24:5d:33:c9:ea:2d:e8: + 87:f1:6a:d3:d6:fd:85:79:bd:66:25:2b:e6:0d:d6:23:3d:82: + d8:28:4a:31:06:7a:b6:79:3a:2a:d2:a5:00:5b:9a:f3:3f:15: + c4:cc:f5:6f:00:f3:77:b1:c6:31:9b:7d:33:eb:0e:b0:0f:f3: + 9d:4e:49:85:1d:90:01:15:fa:3d:08:7d:27:06:ea:92:3e:b0: + c7:93:da:48:70:1a:1f:7e:52:f8:4c:63:c2:d4:82:cc:40:44: + c0:84:38:fc:70:ad:c9:16:41:80:73:8c:8e:6f:dd:e9:48:27: + 8c:c1:87:c1:ca:4d:14:66:53:e1:ce:9d:1b:3a:16:14:cd:dd: + ce:12:a9:2a:ba:c9:4c:34:4b:4a:85:1f:9d:d4:6a:70:e9:df: + 18:9f:03:d2:bf:73:f3:e0:b3:8f:d2:10:09:97:fd:59:fc:50: + c8:57:a7:77:34:43:82:79:b5:56:f5:33:c2:a0:dd:2e:78:09: + 60:ee:0a:92:d3:13:5c:b3:41:79:df:fc:07:09:a5:54:aa:e5: + 59:6a:30:d0:f1:ed:bb:f1:5a:52:61:9d:06:36:dc:c8:80:70: + 77:45:05:b9:2f:4d:c4:86:fe:d7:51:51:93:88:8b:66:1c:fa: + 0d:ce:91:5e:e0:25:3b:6f:89:47:df:52:09:b7:0e:c1:82:90: + 96:17:b0:8c:af:d1:2c:00:b0:bb:18:5f:34:56:d5:f6:18:00: + 56:4c:09:ab:32:77:e0:35:56:1a:52:99:1a:d9:e1:ce:75:9f: + 24:4c:7d:e5:34:4f:52:1c:d4:6b:93:b8:a5:c5:68:97:68:a5: + 1d:1f:77:16:2d:4a:29:0d:e5:2b:9a:f9:05:2a:1d:3a:f9:7e: + 45:3e:a0:5f:88:d6:8b:bd:47:f3:a7:7b:a1:27:29:1c:3a:26: + 41:b8:fe:80:53:6d:29:64:09:1f:6f:e9:ac:ff:70:8f:06:ef: + 48:a2:07:1f:8c:d9:86:2c:84:f4:a7:01:66:d1:2f:f2:47:92: + a1:e6:de:a7:28:70:4f:bd:d6:d8:b4:ed:17:ab:4e:18:4f:e2: + 4a:62:d0:7f:30:9c:40:2e +-----BEGIN CERTIFICATE----- +MIIg7zCCAimgAwIBAgIUZUd1tFj6suEfFrVfJUm0fyoSYFYwCwYJYIZIAWUDBAMU +MIGiMQswCQYDVQQGEwJVUzEQMA4GA1UECAwHTW9udGFuYTEQMA4GA1UEBwwHQm96 +ZW1hbjEYMBYGA1UECgwPd29sZlNTTF9TTEgtRFNBMRowGAYDVQQLDBFSb290LVNM +SC1EU0Etc2hhMjEYMBYGA1UEAwwPd3d3LndvbGZzc2wuY29tMR8wHQYJKoZIhvcN +AQkBFhBpbmZvQHdvbGZzc2wuY29tMB4XDTI2MDQyODA4MTAwNVoXDTI5MDEyMjA4 +MTAwNVowgaIxCzAJBgNVBAYTAlVTMRAwDgYDVQQIDAdNb250YW5hMRAwDgYDVQQH +DAdCb3plbWFuMRgwFgYDVQQKDA93b2xmU1NMX1NMSC1EU0ExGjAYBgNVBAsMEVJv +b3QtU0xILURTQS1zaGEyMRgwFgYDVQQDDA93d3cud29sZnNzbC5jb20xHzAdBgkq +hkiG9w0BCQEWEGluZm9Ad29sZnNzbC5jb20wMDALBglghkgBZQMEAxQDIQCm4CSo +ShgQTc3G2iMkZ96WlYEApsrOQ+T9/HsajPrrfqNjMGEwHQYDVR0OBBYEFL2AIzoG +3ThX7mvClHvqv0NXOrCMMB8GA1UdIwQYMBaAFL2AIzoG3ThX7mvClHvqv0NXOrCM +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMAsGCWCGSAFlAwQDFAOC +HrEAEDxwxfWxTxx3hTS5s1eXYu/nTRdnVmN0AuFQXFvcVpRF1/lrdv374gAWC1oP +hoZ+HgxOf9CVy9SNCVhTTuKfDhEuONzAh+xvJe8bWYGrcWlRLjwv9uvyInNi4aJo +s2fbLgUW+ryutiLLwg/9iB42QycT3mEBDLpa3wppF0XCd7Xfh2KzFm6OV+A7nwKA +XfCSdlFzLnolHIh53Q1VxXOUs3ZSOftYDTT+dDhF/Jk5h8f+Syp8Ua6S7l8oFhME +tfBfk5B00OD0HQava60z/izVmuUQMn8BL36Xxv+2V5dWzFpamnneGbCcC1e7u+WL +kSzNGS18dY5xT8XFiHRcXSeC3JRYfW5xbnjF8w07hZUq2k2vNKk8AojMRR0IDJ0g +OXMGCi26il2pRDIkMrHR/dF/tBBWOhUSpfbBbxbvhF6Gq1ubp7Qh40OGGlD4lbOw +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 +-----END CERTIFICATE----- diff --git a/certs/slhdsa/client-mldsa44-shake.der b/certs/slhdsa/client-mldsa44-shake.der new file mode 100644 index 0000000000000000000000000000000000000000..42f235ca4ff04661853718a5ca12b746a0d66e1d GIT binary patch literal 9747 zcmXqLQsXyhV)tCY%*4pV#K>g8&BmF~=E0cC%)%^X(74!;+klgeIh2J>m?<>aP{4o> z#Nps!_s!2MNz6-xiLmpqJLOlU<|gJDN*IWN)Nt|em*?lC1qb`Y2m5&Fx&%8KN*hRm zWVm^Rg7WiAbfLn!#Tkj&sW5HKJpAS5<$55k#l<;#$@#g4@&>YOoLX%jZQpqrIT^(S zGV{{%9gq|l$cghBnHiWESr}Lt8W@;FiSrs+8W5#)Sp#W^FGQSkGE?(P zbaQi3iW5ytDE5b;xPd4e7w06k&dHy2QWzO|*g>8Q4)!r zHlMyPd34pIHCmPHKmL8Rqj%!1uYGM>CfbN<2_<%hZMst?{KZtN=*~isZ&S-u7f;Sq zzTNOsICO5%+xyMsZjwJk-6om|DrapGclcqnqU}2S%)jq6_FDeQWq234;n*SWgmc!} z{T%wO?L2rL=MVlAH%;f?{~y^Stuu zS)?@okcp$(5k{w!g))C7v+mcfSv=3ct;v#ok=EfWA3_DZUw*i{UP#oKar*w?tUz@s zIs04s(c!C@1ijz!sGs^;-Sv0PCVkT_TDH5-EEFsEIP9vzXskM?I`xINho8+}wKFdS z`(sz>o;jkFxbeaK9p~H9_b!~1^KT0GGm-F=2W3YiJ0dc^}%k1yG8GlXh zxHXAC-k_pvtLQ9vIF2XeY5GH!WY;abT@k791yl)DT!c5&`)nNYXobIZz(miZsetzT)LQ0!keOR7M`BsTxS=X~G)&WXX& z*W91ZcD(WCechC0J}FUBu7^^@!%xdS3Yind5#8$JsARj(R(Ms|^4}9Q*ZP($^LTe# zDV({fy!aD?*+r9_bwb*zY)`A1>d$}8#m$-mO&3U9tDtE});$+mlQ=0-?OFEE?UT7Y z5}nJJpQ~=pnq~R&IqxFhrt6K;{bmOh6yrs$_pvT6IOYTs|} z!PknL7HbIB4HrbAd)m;!c(gf3F+S%4(v;t=N9PIo%~?H15zN&$oQXy z$$$Y|`N{Hwcr46J%qt9pL9(hWJO*5B9NKJ*tgP(Js1+!4liWrIv3Ccu_A5zyeh>4x zHZzwofl=*ba{jlcDVOSY{oJ+i%7H}}rgj-$YG5&W-6PRG?Iu%H-@63UzaKufFW4&!i@)Z+!lOLHTLKd6q>}KTBlz+Md2&uVt{~Z%IUeepB`r zwMFh6hXeM%6k^ReS5{c3yH1L?JT#U&%jVs#iATR4zvX^%kH(JvYvTP+UfA4{^1tbO zXez(oExF_MspUr%U&~LLyXyC8p-oR}BGnp>e)n9l$$T=$%qjez;&*8K^G#Z^Mqx7N zr|4sR{cP!~xwq80mS_}39CSQ&d8zSMseNy5*b8W86+SOWzP*NP6_?J|&%)DIReyZm zG4WS7x2*J&@DnR1e-by|adfpoU#8NZFWZ=k*=I(?CpuXc?5$V%r?c=;PT)?Fz+H0 zU+vbu`R}_)M3U_Of6~vqq{L%4HC??l)9=)-^3+{B&0x1F znNzMU7p$E3$w!jm?lqU@DEp8flhRAR?QTo3=xmcUbgh+mbNuE)^>7Xup}&)rdu=lN z9<6wyd2ws0@aH8i&HvP2%oVrTY(3Y4{pPpcOTBYr%r0yS=gW-cSyHz0Ty9CJht;;! z$!pxWTmMymeJ+rnr;)4Abg`mkYL~)?WkQb^AHCY%rjnq&^YO~*ALbknIQ)A%$26Tx z*5w}@0w0^M^wZlavAR@pf_Y~6zZr^GjOLyCHqm+MQP$w<7^WMhXWVv8im?6UF(I<* zs#GlJKl?Q;YodI={7#tcI&FXcpXc>c)zmP5Y2*5|ci+ZcOB2^UZU=yT0W)3o}zj3(SU)pKdnjIa~|yB;M{vMxk7P;-iaMfk4p6uG#~3cPyF*g{9`SPjOHJu?K60n zya}3qL^CmFfbXF+2a-AuC!&A$T94lu% zazEK^Vcj-S^-@Ap{Gl5=J5-ilSiPn`q=UoF zK5^mSg;gaVZB}*l-_TaEjWcwwD@{5RaW%Mr=gjpp0k_|!ulaVHmFLx!WIa)q#an)F zmD&{Q{lR_a$|b_A=6X-x6uk)-*mSw#c=F8$!t*zWmaRF~RQxALcB^~%X~XG{8J0e3 ze8rkMr@#NqDreru?Mq6P7UZ4StT+8`>Fp(xu1!>V7Bus1d`fV@RlTA+t{W!E6x~=+ z#qun}S}=_9(sMo=4ZC0K3O#GZZeM6!csEX7z0xO~ol9ateu?(>An&6|^Iekn$fSLp z{qDrV-)m#lCkK^zj)s{35)~CcH|xZ=+g`k@;`ivc=_fo3YRKPVY+mxw&uYFyHOuXZ z6R)njwjlhPOH5bA&xu>AUM01=uc&K&VzlW|_4{?)$%>cn+pTA2UTmXtS90y?6I|I- z<%}LYUtFQ{*DToGJ4q{k^10Jjmfun~oH@}TsoT*mUh`9sSKb|?RpBC2f-5Qo?Po6# zIKgs9McyU-$yT8acNg#+WEAeW{moxcM`!;L-{#no)4ltdrD94<@w9><7lm6XfpJOi+_GYlo;L)gja;?fA7iy!_v_ZZmV?^8d@* zWm*>Oj@tU+ywn!9SGr31{|uCuuAdaC)^mug?VU-P8jbZe*1mWW7K=B2_$-A^P!kH@ESaEPgG5c&|vvEhiv$%9#8 z*#**f8`RD&;?`0vIezHBrs03yclP4ClQLG#I(_2nAARdRLSJ<5SvI;&v366O_c=atN-#60v6Ts-ORn>j|04Bt6Qtxtc?ufKcKxw?;$(q7F+T6^}_ zE<3Vm#^SJ9ryC9TN%;h_#aOH+?_>LTXDf?1&v zmp?eynY#$)bSHn*Z1l)n-n}zoa-hFprSXH8%G^J@x!$yRO_sf5cx#K%alegyl5NfZ zwq1HCyVq|0x%#crn}S{+`}emsL}A0xA0ZOCNv0W3cBjj4J*=yso${t_da4hH`KJTi z>)-Ne_AOZR@|{bAr=#ag_H7?mUVM@>IoslW_+IVUlD`vjTk?gsUEaM)md(CJ_DY@1 zqk|hZ&u*^Ze$e|T@-?UU)VAA8|H=4#<}+Hs`EPlsyzUt$^Q}C**Qb|uowRY=zDNB1 zd*R=!mbCn%Xp3Nw++lwBX!( zPrv#n)7%caKdNkKjf$~V(d9Of5L-}^_vw@BoFiQYMa=V!FYeosSIpLF#_(d_zQ+c} z%8|1+?w-Nb?s01MyCZvIe_wjp^gzX6%C#RerhYarsw&vKEq&pg8x10F&0i}z9$Dv; zWUC>`(OB6M?{q=5t06O2XoIQIk6Y@eg@apX* zp~zgRSnl|cXby>e_Y_2#R!!dCdg$Nz%bX{k`A%uCPrO*;dh@lnqf4Q5@&@6YC-0hn z`1~&~opn~Cm2F#xjk%T7KD#&Dgg^EqdTmy>z4M{`TXcy=@*`u1YpWOD*?gQYS?1Y= zRZ4r9-ISt=K5Yu+iesO<|KBgi)$^~skN@=lbZ(dJsxz5??icZnU%TkB;_w>?Nb$=T~{UL;??^Fqy`r1kT(%%&#_h`kQ! z7E<-Qb>$^r-JjbP^Yw4#+n*_ZW1(2{-Fmg>)bhvMEmQY;ifA0awcj?8uP~ZT&i*Us z&3xM_66^VE^j7=o8&9#QQEWYQEkAv^Z&0t0pkbPYJO8hF7I!aoT;9p>{riXPfNe{A z{NjW90t8lme`LO1>KG%}67>bAb-he%95)^ntZ6p;k;HtaI&4av$n~||Pj6{H_Ut{7 zWKwd(muunt^(-u#MB2`}ROMJ#v#2$i+!Wn)^OD2&*5_;wyzDPs;$45QAWKqIDa>(k z)I5F%!M!27VuLh~-Els_sAaFu%Klp4WP;FnojVyft#AMOt5c#bY1sEnnX7tnj*QVa zr6t|P|CyIPUbETmucS5WR9?A~h%1|Z&fd1T%l78~KIJd%Pp+Azr5!l`!$qKF-X8Zp zz4+@)iR+(p!T?f0BqC)YKyQ3v=qHudqds(S><9&b4n5LhqI{7yUa3G2;* z!@PIpqc7ciH;wz0e9{AA^ zGdtx(`Ozg=jsLoQPCaW5NeoYXY`Jgigs`BM>MEP9)S`7b_em?QN~?bTqQRv0^{1nT z&XP+S)K>=@eEu8vjj?-yf?f6d2z- zUU*6EFZ&kjmNRpDUM5|Q@U!9e4{g|>cq&G>xK46=+r~w?GnL;t8z)yfFRKv9-`|wD z+KC~%waaam!!*C z$FZG?eVMCq^m*o|m&H5zK0EDO7gb{Z?d62Ib$h2M2ApVqd~(Ldy&F|_t&3UilsM@~ zs*sV!h5Fw{^Dnx7$$V>d($37c|5u*=*~;yU%-Lh}w6*$Q-rjK0VaSQ>#e4f*)`$(^PyXykzqqZCd%LP{!rByxDc{rOj(->GnDLWUk3lo) z6TkMwg82py;`f#Rbg^7oe`E^(&SUKlIdy~TABRrSe0ai2{Mz2VTW!ufxss;7d#`-0 z;QQyh=ASHbE$&v7&`ncUJvaSv`tOYzlT(Xo%vN(82|cf6$FKM2`j^>DH7l35B&teH z-to1M!Tc$%S)Lo7pmW zEbsdBRoqW`@$Y2khiHZg^Y0hMN@Z?&IY;gP~o?=@F-B&5`!~v(7{(*qcjS&6sFu9{%}C@$0Rj6Yn32^mF)U$R_!w zX7|CcWbUJvk4teJTVQ)HC9m0bBDPic zIBRcdtGfHeKbMu-Y_`>JJG(Mry?Fzx-bHQJ^J^#QUFkab$|!VZrjO5D`QDJLUhlqM zJ2I2`w);7WRJ}fdhqLEpx8FE=Q1_*K(eHWs;?-HtwrX|S}JR59h%Tmv~`wGRendyy8ln#aavoqu6dhPm*Dd6f?7rT z)&2edIxCN-I515*`uWo3GBJ^aeG@O(MpQ29|9MEF^@noBGnXu71(x@ftXUGg3%g&` z3o8UF@vvD2e|jl%%E@S-Mor8@#iR$N{n}T~9#r-d{IM$U#TLaI0)HRy96mFD=K0nF z29{0cg*V@?>^i^t;(d>~Z|A2o@Yjf?%swu2yk>S#FGFcTmx6hJg@We>QSOke(|g?? z*8NsAwq$?EE57oK(|HL^hq!n3X}!SSLJFaI^PJ z_3ckv3biLJ_E~>u#RA^BO!^V0-tE3{W6EV6-=?q?FRsQek(b#2W<~uq(X1%*A9ah* zzGc7K;Td)4O6awFKb&-4}%so?2gt){nnW zW=JHjN>uHZ>*^2u&F^}yK)3Oy+k-Fvju*R4VF;=T;L@n52<+S=oF22v@3Mxa1@mEz zRg+{=zAfWWE_}8>W^tWB|K{8_{g*tcoF{xLuFYPz^>gPF~d#(rTyTXKky`$eCW5yG1dq(deKV^S;J6znZVExqc^*^>W~^@3pu8-DJK$cjfO* zQDr569CF2arBdSi%uN|46l^l<>p46B{%4s*)g9AHzHsF&+}hW?NULVjycxAz8dsAT zPX+};I!wm%#>9Y2lS^iix|K4d}OWmLfdP<&*LKb`+{AsUKvjkPTKasdf{&V z#n%?~Oy!*(HRa`Dtxo4+r{w}XT$Y8uLeB*IEc%obp)FgoBE`Dq8Otg&m1u9LQZ_rY z(=#$=e@t+8SitPf>#~jcYsIloI~fCKZ2uJVKPxUmcb2_Yv_w*Wys1%bpXcV+>Id>) zT7FsaF?GMgB$-8DSAAyL{zb81-+pG+Gbt|vI8p;W^|sez_qW~l zKQB;at@_7BXVcOP#oG3^rL)?uaul;1U^)DMqd<+yv-jE2_ahHP>{q;#z0mUN+v2JF z-6gC42QIAqrINH`Lt5hNyr$(#zWnL-_I|puJm`zg_uRC%|IOEPGhaI%Gi~yLt8b$7 zeoqNJ{b!2w`r%D}OG#+@Nr%hL+1KOVt4&*Zi@7Q!t!IJ2rKxx4oI5S7)m8G+ zc&k$c0Jo87HoPGJa5*nsG`~l)Ajc(E6a7;vhiD%Tc&N9`L37is~4a4 z{r>N~Mbzy-MFtNVVYDSQ09obyq2na!>ODU;ic?u&NtT(Xtu zsi@SO(;&UflY80Z z@#l4Z-Rj$KSNNtDDK+ z?_P1an!R#;^|w~OLXKnwCdF6VObsp;83q(=Shf1hmtPmVl2q0&Wt-sj_)BxntJQr| zQXaX-zsopQ9nmao$d+6iog`f&AHHHeX992S#2GRFxh@&GDyHgNR#{y3jb5L)Oz`EQ z)%jo2G$f9CH|&&p?j3y4PkzfIraMdS&dfe^%jEge15<)3^vgmyPoF3(6^LOx7~9+Y z#P!iRkEJU1^6acdX1wnrPcVNno$&vi+1knre751Njph?BGQSoUm=Ktiz$F~^-tK7b zZ1Znwzua2t1(|+_To=BazkKhq`HfjASElXLyR_w{xJbcm{_QHw-FtsI-M7|meEDdx zzhQ>k)>&(8<=KUk)wUdp4Bh!ow6OTqMDG*Z`sW1PNw7b3GM&+U;YvoU1zHLhXJ1hd z*D5&hV}_Hpn~QacW4>p3^=kh4#SdB+uP}P>dV`K|& zx^2s9-}#5V*uF-ulTWxkJ|s~3^V&~8U*!c~PTNv&>c(2db6TF|`*rsWX8VYgBVt4qZ{y3^a$W*tv|u^k$Tt>OXhR z=ezZ`{9n~1@4RnW+oTD*j$36-H@fil%5FCE3lTn3-pOpx=-nk(_htS{^{-6&PrA>U zoH(;~%Z@+a4Zr>q_!Ix`xbmUJ=T)!j?zM|}VpDlD^+@+c##wIX9wpUFu4;XDH~G&q zhd(SnYOFG!=V+{C+rY2DcRee6)w`=J%O`nu%!pKv{TLp`cu&}Rch{qTvhRb=rkXE* zEx4rV2utZ2ea`y}9Lu%W)>komKMJ-!v`(qb=})=8{ORY~O&S3*PZu9dT`0fmxw(k( zwf8TqR(R|;eZ9WVVV6~lMd$6+q5-Y-A`Uu_CX0OSdiLEc$0fF+plNe7%ODl~SdtYU z^uD{CTln$ii%l0aJ+-7&-lhIN6uM5nXD!p~U#8xY#;sNwPCq`ScGmi4OuYK`rXTY% zzI|IRdn}3BJMHJC2_Y6QRxHx-WxjQfmB&|hd+5#7kkziee%xK0$-k~D@u;2L#%$T* zVUb$%b<;hA%IESgS2ENa+>cpV`*_mhbE*&C70O@hzdA#c*@CquL!w7meac#?i?f|} zo=^xDNpt$d{kJ%7W6_g0OS^t@1#jO{#(K=}XZ2Z?E$-KH%+tgA6K3tJ*FUgk@28&p z4W)mh9=h|!-JX>>aUI{p~M zZiT&9UAsN^v1>wT)OKUjty~)o-KQiz;C^)Q>7BinubdVsF-^DmHt+P@@GtF2VyhRq z-3~R;Nm{dFiMHzHpRfA7{ndU>7IEGqTorfx;Q@}jH=gS+b4t?Bjnev1-Lh)Ie$kM% ztaD3eFRni(xjW;}BHreQi#`3S6*}C6S+p~BiiHx3?j9-co%j3U{>-Es691ClU)b=W zeD?XH4Z=%3pQbI^b>SL=+5g5kbMN=U+h0d7J+ovE_x#y&3byQ1mj9ArvR$m9`-{P{ zO?g^Z8<*{!8n^vv{ElkhU7PQ0GG8rvljC5i*_Hzj_Z4?>Z@DhrEEwf*N`95_@hkc* ze{Q#_NHLwt&+%k!&A-6y6ma3p)qJ_{}Tt#rlk$DF`L=jW&J?PmPeaQsk#&%%TR?p?v6Kdu~eI@IbDw?e~?yW{Wn zIk&g{ooA#uUxufo_qEEL#6wjqJ7y;}%PdPx&f^i)KPoo+o`>NPSx2i)v$zVkDt=6I zeB;e6ex+++PScf=2^vOwRBvor^g}HoZGZZ&;|y$BYj`*A*STq_T>WsN`_}v;^OIVi F0|3kpL&pFB literal 0 HcmV?d00001 diff --git a/certs/slhdsa/client-mldsa44-shake.pem b/certs/slhdsa/client-mldsa44-shake.pem new file mode 100644 index 0000000000..fcc1988368 --- /dev/null +++ b/certs/slhdsa/client-mldsa44-shake.pem @@ -0,0 +1,1402 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 2 (0x2) + Signature Algorithm: SLH-DSA-SHAKE-128s + Issuer: C=US, ST=Montana, L=Bozeman, O=wolfSSL_SLH-DSA, OU=Root-SLH-DSA-shake, CN=www.wolfssl.com, emailAddress=info@wolfssl.com + Validity + Not Before: Apr 28 08:10:04 2026 GMT + Not After : Jan 22 08:10:04 2029 GMT + Subject: C=US, ST=Montana, L=Bozeman, O=wolfSSL_SLH-DSA, OU=Client-mldsa44-shake, CN=www.wolfssl.com, emailAddress=info@wolfssl.com, UID=wolfSSL + Subject Public Key Info: + Public Key Algorithm: ML-DSA-44 + ML-DSA-44 Public-Key: + pub: + 9d:7b:66:85:9a:b3:cb:df:19:c5:aa:e2:ac:2a:79: + af:f1:fd:e2:b8:8d:91:da:f5:8e:86:b4:91:3c:15: + 2a:12:61:89:56:b2:dc:76:13:f4:35:1a:72:dc:a1: + 14:f6:95:76:25:a3:93:69:23:db:80:f9:13:55:9d: + 52:ed:df:83:77:46:19:f9:55:46:91:36:11:23:6a: + b4:17:40:f8:32:a8:86:d7:07:99:fd:ee:28:bd:39: + fc:6d:00:ee:59:b0:c6:c2:0b:60:ce:3b:6b:8f:08: + ff:8b:da:31:c3:b6:64:e3:7f:7d:df:51:ed:d1:c1: + b9:ec:23:ce:b9:ff:04:67:4e:93:bb:fd:6b:2b:e9: + d4:ca:22:b1:af:a4:6c:e0:cc:52:5c:0c:ef:0c:ea: + 4c:8c:a2:22:9f:c2:34:41:26:c4:01:42:64:a1:1c: + fd:19:6a:df:7d:ac:a3:9e:30:46:82:39:07:a2:2a: + c3:d4:f0:55:10:4b:e9:f0:d5:af:12:15:33:01:97: + bf:53:6a:51:27:1a:1e:3f:da:2f:5b:57:aa:02:11: + 4b:ee:0c:27:ca:f5:7b:8a:fd:ac:b2:2f:35:b4:2a: + 3d:bb:cc:a1:16:77:48:c3:45:24:01:33:25:9c:7b: + 65:e8:2b:48:4e:3c:bd:26:cc:e8:11:8f:5d:aa:2d: + cc:c4:22:61:b1:e0:9f:b8:cf:86:67:bd:a1:9c:6c: + fe:94:0b:e6:14:57:64:e0:76:c5:59:88:58:f1:a2: + 15:da:0a:7a:c8:f8:83:44:9b:f7:0d:68:fd:35:dc: + 46:82:17:e3:b0:24:23:3d:21:43:11:c3:5e:0c:54: + e5:67:e1:04:63:45:b4:bb:44:21:96:6c:24:bc:3a: + 4e:c4:0f:b4:b6:29:ef:f7:f9:0c:70:e0:a6:43:92: + 55:05:0b:24:e2:52:a8:9f:5d:90:50:38:99:33:76: + 71:39:10:2d:e9:ce:4a:99:51:21:c2:81:cd:54:6b: + f1:04:2a:04:ae:93:11:d5:d4:dc:96:c8:f5:84:3f: + c1:23:17:47:0c:7e:b5:01:a4:4d:3a:cb:c2:28:ce: + 6c:26:35:55:c0:f4:a9:7b:30:4f:20:e8:84:4b:8f: + c1:7d:51:52:34:96:11:3d:6a:34:52:03:3c:e1:27: + 3e:f0:3e:0c:b4:41:a5:06:93:51:e4:a6:e3:3d:fb: + f0:ad:f8:73:0b:3d:64:dd:00:d8:ba:09:bd:84:90: + 7e:b4:f3:84:a9:88:84:9f:f1:37:3b:ea:29:c8:21: + 8f:a6:9a:1a:70:14:34:5d:6f:e0:f3:6f:4d:ff:43: + 61:53:1b:d6:47:e5:9b:41:d8:ec:ef:7e:94:a6:4c: + 64:5a:1a:45:c2:64:17:57:cb:1e:e2:54:9c:5a:08: + 5b:85:4c:41:22:3d:be:3d:13:aa:56:a7:fb:90:29: + ad:4d:74:a6:48:ee:db:22:57:03:82:77:73:f2:00: + 36:d1:34:6c:ae:e6:a8:b5:30:b8:7a:78:a6:6b:c6: + ae:82:1c:44:f4:60:4d:dc:fd:bc:9b:a5:9e:92:55: + 55:f4:7d:7e:bf:4d:f2:cf:15:b3:4e:c8:94:3b:a4: + 54:9d:0c:b0:92:f0:77:49:af:aa:22:4d:0f:48:ac: + f9:4a:d7:b1:d2:fb:be:39:35:7b:14:43:7d:73:ad: + 8a:31:97:eb:0e:24:d2:9a:78:8d:9f:74:51:41:51: + aa:4f:c4:cd:dd:7d:c4:f7:e5:70:8c:01:18:7b:96: + dc:d7:a4:ce:dc:61:62:0c:5f:b9:5c:93:2a:4c:83: + c7:e2:2f:bf:e2:14:95:89:a8:70:21:29:8a:64:0a: + c4:eb:2f:1b:e3:34:fa:5e:95:1b:50:ed:35:1e:ba: + 11:f2:ff:98:f9:38:83:17:89:b8:d4:96:95:4e:33: + c6:90:a1:b4:e1:e3:d4:81:33:b7:2c:fc:05:52:90: + b7:4a:c1:4c:66:87:90:38:b1:0a:15:bf:d1:1c:c4: + 80:a0:68:d1:7b:69:37:16:e2:88:a8:5c:99:fc:20: + a6:a9:d4:67:2f:63:fa:67:1e:71:d9:ea:75:7c:28: + c7:53:2c:3d:54:83:f6:0b:4d:01:89:26:24:ce:73: + 1b:4d:b9:7a:a9:4a:77:f3:5a:8b:39:d6:07:49:d6: + f8:64:a0:07:b4:04:4c:cf:50:13:be:39:2b:f3:56: + 68:e4:ad:65:3b:3d:d1:57:bd:d6:bc:30:6a:e9:92: + a3:09:5e:11:bd:d4:56:91:91:da:5e:1a:e9:fd:fd: + d9:bd:60:fc:36:42:42:78:e2:8c:60:d6:be:ac:77: + 8f:6e:73:23:fe:0d:5a:1c:f2:47:47:69:92:63:64: + 35:3e:2d:af:d6:11:ce:62:83:97:d1:d3:07:da:85: + e7:3a:db:a2:ef:52:e8:ee:47:8e:01:2b:b0:93:d2: + bc:3f:b9:6a:da:15:e4:2c:46:a9:14:08:0d:a3:71: + ee:0d:ab:48:ff:e0:d3:af:2c:23:45:47:e0:3f:8e: + 05:ea:44:ed:78:9a:11:ec:5a:76:72:b9:82:3f:36: + bc:74:21:42:22:c5:2c:49:ad:1b:f4:8f:c4:26:79: + a1:e7:2f:e7:a7:d3:db:bc:70:2d:b4:b1:7e:c9:55: + 4f:de:a5:55:f8:ca:48:b8:6d:cd:59:ef:5d:89:f7: + 6b:d0:06:0c:0e:4e:7f:a9:ea:d4:82:5b:e4:35:74: + b7:84:b4:2c:20:1b:f2:46:6a:21:f5:88:d6:3e:04: + 3e:5d:54:58:4a:ac:0c:fe:ff:af:6f:aa:98:92:c9: + c7:05:9b:dc:40:38:bd:ed:cd:50:1f:51:17:39:b5: + ad:f1:5a:b3:c2:ee:e5:b3:ba:27:10:f0:03:92:72: + 5c:09:20:00:ca:f0:8e:30:c1:c7:dc:a4:14:8b:98: + 28:0d:00:d2:cb:c0:57:11:1b:25:f0:7e:54:a8:a9: + b7:b7:6b:34:0a:1f:3b:67:a1:5b:5a:74:ee:64:1e: + fe:2c:ae:a8:00:ff:1d:fb:d8:26:d9:84:90:b1:bf: + 3e:d2:19:25:a6:56:63:fd:c7:9c:b7:c8:7e:72:5c: + 67:71:48:cc:b4:c0:24:44:30:d2:64:a9:a4:ad:63: + 2a:e5:7e:e7:12:ac:61:92:59:26:e6:6b:f9:b7:93: + 0a:48:61:43:77:a7:ce:7b:83:6a:9a:39:e9:e7:0d: + a2:4d:63:65:20:ac:24:ea:54:7b:30:4b:2a:68:47: + d7:17:c6:13:84:19:d6:67:9c:05:5c:72:f9:32:63: + 35:87:aa:7b:4d:f6:47:53:d6:73:82:a3:2b:32:a3: + 8e:31:26:15:9c:13:61:8d:94:b2:da:69:fd:14:41: + a5:67:f4:66:1f:8d:14:76:d2:07:8f:4b:8a:73:c6: + 08:41:c0:ed:95:98:98:43:f3:c1:3a:20:8a:14:25: + fa:57:03:e6:cb:e8:3c:a6:d6:1a:e7:d7:06:ec:dc: + f9:a9:13:27:09:3f:85 + X509v3 extensions: + X509v3 Subject Key Identifier: + 06:BA:09:60:1C:F1:80:5D:2F:50:EF:88:EB:58:18:F9:47:2C:0D:6C + X509v3 Authority Key Identifier: + 62:90:90:E5:3A:74:18:1B:FB:68:40:07:A5:83:9D:70:2E:7E:C9:F0 + X509v3 Basic Constraints: critical + CA:FALSE + X509v3 Key Usage: critical + Digital Signature, Key Encipherment, Key Agreement + X509v3 Extended Key Usage: + TLS Web Client Authentication + Signature Algorithm: SLH-DSA-SHAKE-128s + Signature Value: + 16:ee:c0:6a:bf:22:1b:49:f7:56:4c:d6:99:6d:01:60:01:26: + c9:63:6f:f6:e5:64:d2:7e:ba:f9:ba:a1:d4:c0:a2:d0:95:8a: + 33:d2:80:04:34:eb:8c:18:8b:96:d9:02:5a:8e:ee:60:35:fd: + f0:f1:7f:f7:3a:ba:a2:57:32:6f:1b:1c:78:60:ba:24:23:7d: + ab:6d:a3:a7:cc:65:62:27:b1:e7:e8:00:23:e5:58:cf:04:a2: + 95:f3:18:68:4d:3d:cb:df:7f:2a:30:b8:fd:74:58:50:2f:82: + 6b:f4:26:a2:47:08:c3:50:bf:e9:12:05:6c:ce:76:71:7e:2d: + ae:1a:0d:77:55:5d:0b:6a:3c:ee:ba:91:c5:f5:c7:da:47:c9: + bc:28:b8:8f:d6:17:8f:e4:e8:3c:da:1a:4f:d9:4d:c2:95:0f: + 4e:da:1e:c7:7f:65:77:c5:21:eb:1f:92:9d:aa:fb:cb:12:b2: + e4:7c:59:26:80:c5:f7:49:a8:b2:37:93:08:99:94:0f:f2:5f: + b8:2b:4f:0e:92:a4:ac:20:93:09:f2:5b:c6:0e:8f:06:67:25: + 6d:da:27:0a:a4:28:72:58:c1:41:ca:d3:a5:33:b5:1a:be:ec: + d8:3f:10:29:6a:71:e7:70:63:db:ac:0a:aa:0a:2c:b5:f3:13: + 96:aa:7b:f1:e7:88:91:fa:8b:0b:1d:1b:e4:57:c8:a9:93:f2: + 17:33:b8:c5:ab:30:8e:69:22:fc:f4:b6:02:73:07:99:58:5f: + 61:42:39:70:bd:7f:24:fe:2c:a1:e2:6c:51:b9:14:a7:d0:59: + f8:15:98:d8:5c:f6:dd:27:75:39:bc:32:1d:6e:c7:48:b7:54: + fb:d8:b5:69:11:68:71:e4:2b:02:55:41:17:e7:f7:f3:73:48: + 2c:7c:72:e5:c6:17:9e:d8:ee:41:a5:f5:42:0f:ec:ff:19:6c: + 1e:87:1e:e4:46:13:0f:44:81:41:97:24:0b:a6:38:43:02:07: + d2:65:c7:0e:4c:2d:84:88:d6:f2:44:5d:b8:a2:f8:68:72:45: + 8a:62:dd:cf:39:fc:85:bc:dc:e3:ea:bb:2b:d9:fe:f7:34:58: + 62:1d:bf:fe:1b:e6:4a:1a:17:5d:b2:82:d5:d2:99:4e:da:da: + 01:0b:ee:51:c0:22:85:8d:db:18:96:22:78:d5:39:c9:ca:dd: + 3e:29:53:46:94:69:94:d6:a7:11:79:9e:f2:4c:19:00:dd:d6: + 44:83:5a:3f:54:f8:92:67:74:f6:bb:86:60:38:89:86:1d:31: + 45:7d:18:ec:c7:d9:a1:27:57:08:1c:12:fd:93:23:8d:3c:69: + 8e:e2:a8:e4:29:d1:b5:75:13:f3:a4:44:83:fe:27:e8:9d:17: + 38:b3:3b:9d:38:07:d9:f6:8d:d2:8d:9d:5c:36:d0:b2:57:0e: + 69:5d:0c:a4:76:a9:ce:6d:74:75:48:3a:b6:65:93:ac:46:0b: + 85:fe:7b:f5:e7:10:6f:6e:28:6d:2f:02:d1:78:84:95:8a:20: + f0:a6:12:e3:a3:c5:d5:87:86:24:60:2b:b9:e3:a9:97:f0:9c: + c7:50:c3:fb:b7:08:96:2c:69:05:a7:f0:40:51:e3:35:a9:4e: + 2e:b5:18:ab:75:19:90:37:69:57:fe:98:21:d4:32:9e:ca:f6: + 91:43:a5:c5:05:53:7b:5c:02:d8:35:cc:46:ba:92:58:3d:f2: + 48:90:59:7a:d5:1a:5d:09:fe:3f:ac:84:ac:5a:4d:f4:fb:60: + 93:45:96:bf:6f:fc:e7:7f:94:ac:5a:42:c3:68:fa:18:30:77: + d1:2c:8f:f9:08:49:16:8d:64:da:11:93:d8:ce:cc:33:59:97: + 59:c7:e4:34:ce:80:b6:11:b4:ab:3f:68:91:28:fd:4d:68:86: + 79:3c:45:e5:8d:be:b1:ba:a5:61:ae:e7:86:1e:e9:8d:9a:52: + c1:63:48:35:24:74:c8:4a:e9:c5:27:ed:6d:dd:f9:04:9d:06: + 12:10:89:1b:09:72:1b:dc:04:66:26:69:69:93:06:e7:d4:06: + ff:66:1e:c1:8b:98:58:31:dd:23:66:8e:f0:20:5a:67:1e:d0: + a7:ce:36:d7:5a:be:ca:03:34:7e:db:2e:4b:7f:84:df:04:3c: + 4e:e7:ac:3b:f8:11:67:9a:85:3c:02:58:c2:d1:6e:71:20:ed: + 92:62:26:58:63:23:c6:46:db:fc:88:57:0b:33:1c:9d:c0:92: + fe:63:55:81:5f:0d:a3:78:f1:cb:68:58:ca:16:e0:80:68:63: + f4:77:ef:b0:5f:eb:c4:b5:ad:66:2a:8f:0a:32:90:dc:ca:8c: + d2:b2:93:d6:0c:86:24:04:fe:96:7d:a2:b0:64:3d:79:20:c6: + ab:e3:c2:e4:99:6b:29:db:0c:14:d7:59:f6:84:d9:d8:92:fb: + 31:e5:29:83:79:c4:41:66:63:71:3f:83:3a:c4:04:ff:ad:e2: + 2b:f8:29:5b:a8:0f:02:6a:a8:67:56:9e:6e:36:b1:88:2d:2e: + 23:7e:ba:97:e5:eb:9c:e0:bc:08:09:bd:c9:63:78:21:a8:2e: + c8:b8:42:e2:75:2f:60:29:e3:2c:e7:61:fc:ff:57:f1:7d:04: + 1c:29:fc:22:b7:98:0d:a4:ec:52:97:d8:d4:1a:41:26:be:e9: + f5:93:6c:c2:e0:e0:1d:14:1f:d2:bd:57:4e:c5:58:c6:1a:6f: + c7:53:66:13:ed:2b:c4:65:01:d9:3d:21:e3:cd:e1:c4:34:2a: + b7:e4:5f:68:c5:ba:24:0b:d3:c8:17:b3:06:77:46:e6:fe:da: + 29:02:82:5e:7f:a9:be:9a:ac:f8:29:8e:bd:87:84:c0:05:79: + 88:be:0f:92:82:b9:3b:a8:7e:0d:d5:a1:8c:7a:9d:d4:ff:56: + 1f:56:6e:2a:cb:99:ec:b6:0c:a0:71:4a:ea:7c:31:f0:1f:e1: + 90:a4:7d:cd:63:35:d7:be:fe:bf:0d:60:01:d9:43:20:74:d4: + d7:02:67:b0:e5:39:f1:08:a9:9a:e2:47:c9:8b:32:43:9d:90: + 7e:d0:1c:43:95:78:94:9a:b7:c5:39:30:dc:b3:b5:f2:50:ca: + ed:cc:52:a0:0a:23:47:c2:11:48:1f:c1:c5:a2:bb:43:e4:e5: + c4:8d:1e:02:35:e3:65:57:2a:86:38:03:8a:66:fa:dc:17:16: + 77:ad:37:78:da:88:36:c7:89:06:c4:04:71:7c:84:05:b6:91: + 25:d2:60:82:5f:c2:d8:b9:88:24:a5:d0:ab:ac:7f:54:88:08: + 46:3f:61:a1:fd:a1:7a:74:f1:3c:aa:8a:8f:d8:2b:24:3d:5e: + 31:47:7e:75:62:cc:58:d5:53:70:0c:cc:d7:cc:50:db:ee:67: + ac:f6:db:05:0c:ea:d4:63:2e:15:04:a3:b4:fb:b5:1a:b2:55: + 4b:f0:47:99:a9:a4:13:05:37:2e:e5:ec:72:ec:57:10:b2:d3: + 78:c7:63:d9:e0:13:9f:b3:55:76:ac:c6:82:73:fc:6c:1d:b5: + 47:57:cb:31:97:e3:00:a5:e2:81:ea:05:69:9c:8f:8f:cc:aa: + 43:0d:e3:87:a4:75:22:a0:6e:c8:b3:2e:97:dd:75:db:a4:92: + d6:91:24:e6:52:99:ed:5f:64:53:50:d5:2e:72:dc:45:b0:90: + 1c:72:d8:a8:7a:04:e6:68:3b:11:56:01:d2:e7:0e:3c:28:3e: + fa:ae:71:49:7d:16:db:d0:85:a1:dd:5e:1f:27:79:4c:57:07: + 0a:18:a0:6f:74:2b:b7:52:4b:c5:62:9f:44:63:bc:1c:66:f5: + 9b:ee:c8:a1:fb:89:d5:dd:fe:12:08:0d:98:fb:09:19:9a:31: + 3f:26:53:51:d1:1d:9d:4c:1f:b8:2c:4f:3c:f5:57:ea:fd:69: + be:89:00:de:c3:41:13:d0:de:56:a9:b7:24:13:6a:3c:d2:ba: + ee:b7:1c:e4:c1:23:0c:c5:54:37:fa:15:15:17:ce:9a:c8:f6: + db:4a:0d:aa:5f:bc:2f:86:2f:60:e6:52:80:6f:b8:33:37:74: + f1:4e:3a:9f:40:7b:04:db:91:91:d5:ae:d6:a0:57:d6:44:5c: + 8a:78:f9:91:b4:7a:ea:62:87:47:a8:7e:83:e4:32:b2:e2:7b: + ef:ae:0b:63:21:d3:df:3e:af:03:03:a3:3c:2c:dd:19:ad:cb: + c8:0a:6b:95:1e:32:e0:e7:a3:78:2c:fd:36:53:47:4b:62:2a: + 5f:93:ce:cb:d4:a7:da:23:31:99:91:30:62:8b:41:3e:5f:29: + f2:52:4a:6e:dc:32:aa:57:14:94:53:78:79:11:3f:9b:a0:10: + c8:04:dc:24:1f:44:67:e4:b5:12:b0:dd:a0:0c:c1:01:13:88: + db:f6:4f:11:2c:2c:bf:c4:4d:83:5d:74:cb:8d:bf:03:1a:5c: + 74:34:1f:89:9d:40:7e:d8:66:34:21:cf:98:85:63:c8:52:28: + bb:a3:34:cc:5b:50:54:76:1b:e3:d7:a9:1d:e2:35:79:48:3c: + b2:2f:dd:c6:f3:5d:d0:71:8d:68:05:98:0a:2c:c5:18:cc:d9: + b0:e5:19:96:23:fa:df:55:dc:08:23:47:4b:ff:6e:7f:5c:9d: + 90:de:91:2a:07:1c:44:61:6e:71:f4:34:88:ab:de:c3:52:f8: + 06:49:d9:94:bc:4f:91:96:f7:2f:0b:2c:2d:b9:05:40:50:c9: + 7a:0f:30:a1:e1:67:83:88:44:83:50:e1:fc:d7:27:e9:86:89: + 01:7c:4a:8b:e4:7a:46:b9:69:a9:3e:81:a8:83:b6:1c:34:2e: + db:da:1c:e1:ce:4e:54:d9:d3:a1:44:09:c0:47:c2:fc:60:f1: + 99:6e:0d:72:d5:7a:4d:26:1b:d9:65:b1:2f:91:68:4a:cd:6f: + 72:3a:5b:e3:9f:2c:dc:0e:d8:9f:f9:7a:fa:1e:90:0a:d3:25: + 1c:3e:64:fa:63:62:ad:f2:6e:10:7c:64:0d:57:a7:d5:0b:95: + b9:e4:6b:e9:ea:65:a1:ca:a8:43:b9:fb:3c:88:2d:c9:fb:0c: + 7b:9b:dd:a7:2b:d6:5c:94:ee:b1:35:57:3a:ee:f7:c0:33:2c: + 89:97:7b:d7:94:17:ed:59:66:1f:67:5d:2a:02:bc:71:80:90: + 58:2c:b7:cc:be:1d:46:33:26:90:c9:88:64:3d:c9:69:04:df: + a3:a2:62:21:e7:53:81:e3:c2:ae:1a:14:68:a8:dd:1a:90:2e: + 53:db:ff:e6:bb:99:88:51:9d:15:1e:e3:c3:72:80:ff:88:ec: + fe:d5:26:98:11:f5:29:11:41:fa:fb:21:9e:4d:a6:3b:78:14: + 53:f8:80:07:27:27:81:85:32:a6:85:d6:7f:93:59:e1:aa:1a: + 5f:02:5f:59:28:15:0e:73:c3:7e:5c:02:ba:a5:a7:08:4f:05: + 5e:6f:7d:a5:66:f6:4f:98:06:a5:49:a8:19:6c:8c:50:1d:af: + cf:59:d4:c6:7e:fb:9e:36:4b:14:60:bc:ba:15:57:e7:95:b8: + 0a:ac:6f:ec:a6:1f:0a:8b:33:1e:24:37:33:98:48:21:e7:64: + 72:9e:b5:ae:88:1f:44:42:50:ec:89:62:2b:2a:b5:7e:60:8a: + d7:10:d0:5d:25:05:17:62:33:dd:df:a2:3a:1d:11:f2:08:d5: + 8c:8d:9d:c4:af:24:8c:ec:98:3d:a9:ae:5a:58:24:57:f2:6e: + 78:d5:13:2b:ac:b1:2b:41:f5:7b:57:77:fe:d6:8b:36:37:13: + 77:ff:a7:87:1c:84:a0:bb:5a:b5:f0:cf:1a:b4:06:ea:2d:22: + 6f:fe:30:23:a5:af:98:11:5e:09:42:d8:31:b6:3d:6c:4a:17: + b5:ed:11:73:98:56:78:71:c4:a8:7f:0c:ae:6d:64:eb:fb:9c: + 74:40:c8:d7:d7:8f:7f:ea:ab:6b:88:bd:be:78:2c:5e:7e:60: + b2:c8:9d:19:d0:d8:ff:82:e0:75:e8:0c:44:a2:d6:e9:67:3c: + e9:b8:5f:a4:83:b9:f5:7c:d0:e4:f5:4e:75:62:8d:32:7f:3a: + 5b:4b:a5:2b:d5:df:7c:e4:8f:35:b5:89:2c:b4:58:59:45:03: + a5:13:32:8b:e4:18:55:c7:5f:65:08:08:16:26:b0:12:f0:51: + 08:b0:c4:48:c9:c1:6a:56:6b:70:1b:dd:80:26:cd:a2:0b:2a: + 25:74:c7:c2:ff:29:31:ff:0d:ee:3f:17:2d:92:68:aa:9a:cb: + c8:f5:fc:2f:3b:bc:12:f4:2c:de:39:81:46:94:3b:46:21:91: + e7:ae:11:02:05:81:21:ec:c1:60:0d:83:06:24:53:cf:22:37: + 94:5c:e1:48:11:a3:92:ed:ec:9c:32:e2:31:ee:41:1a:af:67: + ef:0f:2f:bb:b2:ce:7e:f1:59:1b:4a:83:c4:85:8c:bf:7d:a6: + c4:b2:98:a3:56:9a:cb:81:31:be:1a:4c:51:06:5c:38:ac:77: + ce:f0:09:b6:dd:45:41:c7:d8:6b:a8:3e:31:35:d8:b4:fa:15: + 22:b3:87:31:65:a2:03:c3:11:6a:55:58:d3:f0:43:7e:37:44: + 11:6c:8b:63:f1:29:81:48:69:a7:8b:b9:58:93:51:4f:11:79: + 33:e0:e9:23:0b:f9:8b:0a:ec:84:4a:93:1d:dc:31:da:b4:32: + c7:4e:b1:8e:19:86:83:fe:b6:d2:e1:1d:bd:3e:af:ce:7f:b5: + 1b:b2:52:eb:c6:fe:fd:85:54:20:b0:c5:f8:54:18:6d:62:35: + 68:e4:bb:67:1f:b5:c3:2d:20:2b:64:ec:86:97:65:4c:08:37: + f2:c0:0b:af:ed:0e:29:8e:a0:ac:e9:ee:44:80:49:41:49:99: + 07:b6:f1:a9:d1:e4:6c:93:6b:38:ef:57:bd:2b:5d:74:fd:90: + 6d:84:6f:13:b6:d3:bb:aa:1d:06:3f:84:1d:d4:7e:1c:e2:c1: + b0:b3:9b:83:78:0b:e0:8d:fc:59:eb:09:17:95:86:db:a5:fe: + 1c:4c:f3:0e:32:a8:09:fe:a7:55:1f:2d:cc:02:37:b5:0c:0d: + d7:97:75:8a:c9:3c:46:b7:bc:17:ef:ef:13:fb:aa:a4:84:fe: + 78:9b:a4:20:26:89:b3:45:51:83:25:e2:95:9a:67:f2:70:f4: + b2:f8:52:b1:71:27:0b:ab:fa:90:e8:80:27:2f:eb:7e:24:67: + 39:c3:62:a0:ce:ef:49:4e:7f:e4:96:46:c1:47:e2:79:80:85: + 5a:5c:3d:24:2d:0b:30:18:16:a0:74:6e:f2:f2:25:9c:c4:8a: + 70:72:03:9f:33:d1:be:b8:6e:73:06:89:36:00:e8:be:be:e3: + 30:33:23:59:9a:b1:bb:98:0a:87:48:ca:ab:ee:c4:bc:5d:fb: + d2:e9:82:e0:24:30:94:d6:f8:98:95:f3:37:72:7a:70:bd:b6: + 67:a1:dc:d8:80:14:ed:37:eb:21:41:c4:ae:4c:62:3d:28:19: + 08:81:79:84:5f:42:d0:15:8a:80:69:6d:12:b0:35:32:f8:da: + 27:cb:13:53:85:9a:3e:d7:5d:9f:2d:33:16:ff:9e:61:e8:18: + 35:ee:53:96:3a:07:b8:63:df:8c:54:f7:96:3a:4e:b3:07:24: + df:eb:61:f6:e1:ad:d1:70:84:08:89:ef:c6:1d:a1:8f:fc:41: + e0:45:32:7b:d8:78:ec:5f:8f:55:e0:a4:9e:27:c4:d5:4a:98: + b2:f1:4c:10:49:3e:73:9e:bf:15:1c:69:4a:80:23:5d:ed:d7: + 67:b1:fb:48:ac:0d:80:7a:78:2a:8c:20:eb:10:9f:27:65:ee: + 3b:b1:1d:ab:18:42:0e:a8:f8:e3:ff:89:56:9b:9b:5f:bc:a6: + 52:71:c7:1b:12:a0:d0:57:76:46:36:15:6b:67:c6:56:4a:d5: + 1f:2e:f4:7f:a5:d1:8a:78:40:13:88:cc:9d:86:ef:6e:34:42: + 4e:24:45:43:54:43:8d:ff:7f:ad:f7:40:d3:8f:8b:71:14:9d: + 1a:5d:0b:5f:54:5b:08:18:be:de:20:15:02:aa:93:b7:85:c2: + fe:cf:d3:09:c8:e6:4d:94:87:7f:61:d1:7c:45:d9:eb:4b:41: + 44:71:1b:63:b0:13:6c:e4:ee:83:f8:4c:ff:77:75:9a:cd:18: + 85:06:b6:88:3c:37:3a:1a:be:3e:ec:b6:13:f1:8c:61:4a:b3: + 27:3d:dc:f0:77:f6:5b:74:28:63:e2:33:40:d6:ab:a1:dc:b3: + c7:0e:63:1c:e6:d0:aa:22:bc:03:46:22:5a:72:f2:b2:55:0a: + 5e:07:9d:bf:fe:fa:41:ab:9f:d4:ef:5f:f2:ff:cb:6d:8a:3d: + aa:cc:69:fc:df:71:fb:31:74:52:ba:ec:8a:c0:d6:80:49:60: + 80:4b:c0:46:90:b7:d1:68:4e:c3:1f:04:0d:1c:82:2b:3e:13: + e3:32:25:f4:89:06:ad:75:7c:66:ac:bc:ae:09:90:88:2a:2a: + 08:d3:f3:15:47:89:24:07:f6:5c:b5:f8:75:70:02:4b:7f:e1: + a8:cd:7b:2f:68:e5:42:14:0f:bd:a4:4f:9a:41:38:ec:91:a1: + d4:8c:27:32:cc:d7:a8:0d:53:4f:0f:c3:aa:33:7d:17:08:74: + b5:84:18:ad:5d:d9:da:b5:95:ba:35:4d:9a:24:a6:fd:3c:21: + 3d:45:9e:d4:e8:6e:c8:ab:5a:d2:16:b5:7f:1d:35:b6:e0:65: + c9:09:8d:43:37:72:1f:7f:b9:d0:7c:c2:62:af:9e:2a:36:97: + 61:10:16:eb:54:8b:12:25:4e:da:d4:e9:0e:7e:fc:db:78:9f: + 2f:da:6f:3f:cc:73:ec:38:21:7c:f7:3b:ab:49:95:77:e3:b7: + 39:65:bd:49:14:28:c7:da:bf:3d:61:0e:71:5b:06:1e:3f:f5: + 09:d9:6f:3d:94:18:af:0f:7c:2e:ab:4d:2f:33:94:38:7c:21: + 85:c2:d6:6f:67:a7:4d:52:8d:12:11:31:66:38:47:0f:fa:9e: + 38:dd:d2:88:d3:b9:00:f7:f7:f0:6b:50:b6:a5:8c:4e:5f:52: + 8e:50:10:a9:f7:e2:37:af:1a:c6:01:0a:a4:27:a0:cb:2d:4a: + 34:3c:41:b1:c5:11:7c:83:36:f8:62:03:cc:7b:56:94:7e:14: + d7:ad:8b:e5:da:29:e3:49:8d:c0:62:34:74:c4:4d:0a:a1:9f: + af:04:04:b2:14:86:cd:44:7a:6c:3b:7b:04:26:81:34:d9:15: + ba:d9:d2:40:f7:85:e7:06:e0:4a:3f:d2:d2:0d:af:de:70:6a: + 19:15:22:56:41:a3:5a:9e:0f:40:11:bd:54:ba:5d:52:29:c6: + dc:43:c8:01:2a:3f:2f:05:07:eb:2f:34:90:12:cf:2c:dc:68: + d9:3b:db:fa:fd:2c:74:27:19:31:8e:e6:23:0a:7b:a3:6c:1c: + 32:f6:22:a4:8b:73:ff:03:a6:e3:ac:b3:3e:fd:19:3b:05:95: + 0d:1e:74:58:d4:b2:f9:9b:b6:a3:8a:3d:d9:ff:8e:23:f4:87: + e4:d6:36:66:66:c0:cf:f8:44:10:84:9e:bc:47:8e:2e:5f:97: + 5b:80:f5:ac:e7:fb:47:08:e1:6a:1b:ae:87:27:ed:32:20:c8: + 49:9a:ac:21:7a:29:7b:f1:b1:0e:6b:d0:5a:62:b2:2b:8d:2c: + fa:09:81:3e:8e:51:ca:13:37:8d:c9:60:7d:b3:4e:71:c6:10: + 69:8e:32:ff:e7:44:15:4b:ad:f7:6c:6d:42:45:ac:1d:5a:c0: + 0e:08:b2:8e:0f:05:27:48:52:1d:c7:84:ca:50:51:7f:1f:03: + ee:2b:59:e4:05:d9:70:c3:0d:dd:1f:5b:d2:d8:9b:be:fb:8f: + be:25:d0:bc:ce:c9:01:53:97:a3:b3:5d:a0:be:90:ef:01:3b: + 74:8f:cb:e4:7a:9a:28:64:d2:a7:a7:2d:17:a9:33:b1:c0:f8: + 80:5c:9b:64:c8:77:c5:a4:6a:81:fe:8a:4c:ca:e6:83:54:61: + 57:61:e3:39:be:b5:90:56:52:a9:27:24:b3:3a:26:5b:2c:09: + be:1b:22:aa:66:7b:eb:e8:80:34:7d:eb:f2:c5:31:43:19:a4: + 80:27:ab:51:30:f3:fd:5e:f6:01:8b:a0:41:e2:90:4f:2d:14: + a2:e1:dc:6e:f5:68:7b:1b:40:c9:95:f9:71:e9:f8:50:58:84: + 26:5b:5c:98:78:52:70:70:33:de:c7:71:d2:26:fd:07:b4:3b: + 84:cc:9c:8c:e9:62:d5:58:4e:3c:0b:4f:55:80:b0:21:ca:5c: + 2d:73:7e:19:b7:86:b1:a2:6d:99:23:ee:43:33:63:79:43:a6: + 78:10:6f:bf:82:61:a4:da:61:e0:75:6f:03:e8:0b:15:1a:48: + eb:4a:e3:23:5f:de:b0:cb:e4:25:8f:70:33:62:a2:16:c1:93: + 43:6c:4a:69:92:56:c5:3c:07:bf:33:e1:c5:82:01:44:df:d5: + 47:2e:96:c4:8b:b0:fa:e2:7f:77:28:df:72:b2:0d:6a:02:3f: + da:e6:da:3c:da:f6:44:d2:7f:41:7b:89:a5:b5:42:2a:6a:5e: + 3e:84:07:d7:23:8f:c4:3d:ef:08:3f:bd:7b:57:96:98:47:60: + 3e:30:13:fd:16:ac:3d:40:ba:5c:61:3c:6f:fd:ea:50:a8:94: + 35:c5:30:70:9c:34:09:ca:d3:52:45:f4:26:c6:c9:a3:ed:b5: + db:b0:86:03:56:3c:fb:a4:67:1e:3b:5e:06:ca:5d:e9:6d:28: + c5:e7:69:f2:e9:73:b9:0e:f3:42:be:ae:5a:74:37:f6:e9:90: + 9d:7e:bd:94:21:50:c8:83:e3:c9:98:b1:bd:b1:24:ba:ae:5c: + a7:42:61:92:c4:65:12:32:28:d0:7f:fb:32:9f:d1:45:f4:69: + ed:3a:c9:3e:36:4d:8f:fa:6e:2f:cd:79:b7:a2:37:07:5d:6e: + 2b:2a:8f:e9:db:b0:d1:40:ac:df:1f:10:b0:97:19:8d:8c:c6: + 04:aa:5b:97:1b:a8:ef:b8:d4:a6:6c:66:ac:17:f7:20:54:70: + 41:47:21:a0:08:e8:a4:c9:c8:d3:39:3b:d3:43:ef:27:68:38: + 60:fc:37:9e:57:75:b0:a6:08:77:d2:d7:83:1a:24:0c:94:2c: + 7d:51:19:e8:66:47:d6:2e:49:70:ff:8f:4c:d7:d2:09:04:1e: + 8f:db:ff:bc:c2:99:36:57:10:8b:3b:64:ed:a7:e1:4c:34:c5: + eb:1c:3f:d5:31:d9:3d:c6:25:d5:ae:ac:d8:12:c4:a4:98:eb: + e0:7f:44:4b:b7:dd:05:58:b0:57:e4:fc:b8:67:d1:b6:71:0b: + b7:25:4d:60:ad:64:18:94:f7:67:1e:c7:f7:12:88:98:f9:05: + 2e:00:29:5a:f2:0f:2b:d1:70:9f:30:e0:5f:be:77:f9:44:39: + a5:7f:c4:94:0f:b9:c6:87:e1:09:2d:52:7f:e3:55:94:29:e1: + c8:3a:17:d6:bd:bd:b5:3c:cc:e4:d4:66:27:bb:bd:1f:7d:11: + ef:e7:ba:9f:c9:72:45:73:8b:21:18:2d:66:27:25:ce:97:e3: + 67:fb:b1:28:93:65:72:7c:36:ab:08:c4:55:cf:2a:3e:0f:2e: + fc:d7:f4:9b:a5:29:79:a7:84:61:25:1a:93:b8:f5:78:4a:72: + 53:08:02:82:84:84:30:94:3e:a3:2d:2c:9b:1a:b0:16:42:c5: + 97:21:34:ea:3e:28:60:b4:5a:83:94:58:eb:75:47:61:e9:19: + 1a:84:33:1b:95:02:52:e1:89:0a:d3:34:1d:fd:8d:b4:32:a0: + ee:dc:aa:87:b5:3c:4d:c4:95:2e:eb:5f:d6:6e:5c:de:33:0c: + 5c:db:a3:02:a9:79:c4:be:7d:bb:5a:fd:09:b9:93:71:9c:65: + 83:06:68:0c:39:dd:4f:0e:78:df:64:e8:fe:c9:89:f0:5b:00: + 90:9f:df:72:5d:1a:69:b4:e9:9c:26:ff:d3:98:b8:db:27:bb: + 6e:72:7e:0d:48:f2:65:1a:8e:4f:18:b3:5c:52:ce:28:9a:f9: + 5e:32:75:3d:a6:4a:39:f8:e3:b8:b2:e2:09:15:7c:c4:87:bf: + 9a:cc:5b:60:3f:37:18:d5:68:91:39:37:57:f3:d4:73:eb:b5: + 55:91:df:c2:59:4e:40:fe:31:06:19:ec:7c:bb:c1:56:63:0b: + c5:d3:c7:1a:08:c6:a0:3d:dc:98:3e:8f:49:72:65:b6:95:e0: + 5d:c9:e0:c6:78:f9:52:15:01:56:91:2a:4d:95:0e:17:cf:9f: + 3f:3e:b9:bb:b5:a1:98:71:65:1e:b5:d5:60:7f:e5:3e:99:fb: + 46:7c:b8:24:c6:23:d8:31:ea:b2:f0:e2:bc:63:05:c9:19:5d: + b2:b3:94:76:25:90:33:32:b1:a4:61:48:02:63:ac:b6:c8:5d: + 85:2d:c7:05:8d:75:85:27:47:d1:fc:d3:22:86:3c:b6:7f:b6: + cd:a9:60:af:37:80:05:2e:d1:2b:05:cf:ad:90:2e:d4:8a:c1: + ea:32:55:99:69:4c:4c:9d:1f:8d:54:d5:4a:ee:f5:d6:c4:99: + 03:db:47:ce:18:65:2e:8e:10:e1:9b:9e:6b:87:d8:c5:c1:2d: + e9:47:72:fb:9e:2f:17:7b:6a:57:a2:0a:14:27:e1:51:d4:61: + 2e:e6:42:f3:09:6d:42:44:d7:f9:73:4b:11:4d:37:2c:cf:87: + e4:70:60:2e:1f:3b:14:9e:9a:a5:1d:35:3b:55:60:84:72:b5: + 9a:4c:7a:6f:88:84:ae:ff:e5:ee:09:3b:3b:85:ac:ed:6a:7e: + 60:44:fe:d0:26:78:67:d5:bf:8f:fe:89:79:c7:64:40:02:92: + c5:f3:d2:d3:76:16:14:60:be:91:d0:3d:58:79:a2:8f:f9:c2: + 18:85:f8:23:78:e6:44:6a:23:20:04:ef:79:05:6a:18:0d:a1: + 8b:e8:7f:13:20:51:22:0c:06:39:53:f2:e9:1c:ca:42:32:be: + 28:7c:5c:a1:21:62:e0:75:8f:2b:d4:cd:c1:23:4e:11:f8:aa: + 6e:e8:b4:21:d8:10:fd:e0:0c:c3:cc:9f:99:cf:85:70:00:04: + b2:37:71:d9:ef:a9:8a:cf:ab:d1:df:48:9d:ed:9f:67:00:0f: + 7c:16:64:9b:c7:1c:c7:7c:9b:52:8d:00:75:70:8a:20:37:8f: + 78:20:49:b0:15:0b:54:6a:cb:bd:47:e1:7e:fb:21:33:39:07: + e1:0d:17:a9:cc:42:cf:18:29:40:5e:ee:7f:66:8d:e7:f4:13: + e4:48:75:75:78:49:f6:f5:e1:e5:06:93:6f:8d:da:1c:99:c0: + ae:13:99:11:b3:4b:99:27:b7:e5:84:71:2b:90:a3:4c:af:c2: + a8:a0:0d:9d:02:2f:58:ca:ee:bb:d0:d8:94:d3:2c:4d:82:56: + a8:e8:d5:5d:a4:1f:18:bf:ec:a8:7f:d6:15:6a:5a:37:f8:7e: + a3:cd:ed:07:d5:88:49:5a:c2:d4:55:d6:de:f8:42:2d:5a:97: + 0e:59:c8:5b:49:09:ff:dc:49:42:03:d7:05:5c:35:0d:1f:6a: + 74:8d:4d:00:91:5b:d4:cf:8c:c0:55:ee:c1:f7:0e:7f:75:b9: + e8:34:bb:79:d7:d2:da:39:21:5c:51:a9:f5:24:97:78:ca:c2: + 3a:4a:4c:f7:35:e8:79:8a:1a:d3:b0:a6:74:1b:75:ad:ef:91: + 35:2c:72:fb:64:6e:8f:d2:ac:cb:7f:82:0d:5f:db:eb:a4:1c: + cc:88:40:2b:99:c6:54:cc:63:78:7e:d1:2e:5f:14:43:11:34: + 09:a7:33:d2:c9:4f:97:b6:03:69:8c:72:58:6a:93:56:3b:be: + 47:a7:a7:83:e0:52:ca:bc:5d:e6:fc:28:fc:b4:f4:0b:ae:f0: + 68:0e:bf:1d:c3:a4:ed:a7:50:68:d2:b3:44:88:be:21:ad:a1: + 0e:13:7d:8c:df:6b:c6:a3:bf:60:b7:ce:e3:75:33:41:41:87: + 3c:51:72:36:47:74:02:93:43:10:d1:a0:9d:cb:5c:cf:0b:8e: + 85:24:07:9a:1e:86:af:6e:70:5d:20:d7:f8:5b:ac:ac:31:8e: + 5e:2d:27:b2:e4:4a:3a:bc:7d:4d:18:85:f1:fb:c9:68:18:63: + aa:61:25:8b:1e:8a:8f:51:fb:0f:45:ce:70:2d:81:f9:46:e0: + f4:fe:c7:73:46:94:00:52:7c:50:0a:28:78:78:51:89:bc:13: + 67:5c:aa:4e:d3:28:39:38:03:c3:28:aa:92:1c:64:f6:a6:08: + 23:71:e6:bf:5c:a3:7e:10:8f:b3:6d:86:2f:e9:0c:65:09:c8: + 4c:78:d6:9b:ae:b5:f3:89:e4:33:c3:6c:d2:d0:8d:5d:fc:b7: + 5f:71:8e:e4:9e:54:f1:3e:00:d1:1b:26:ca:5f:9a:b6:7f:68: + 6c:97:79:6d:b4:21:56:81:32:c1:36:03:be:81:ec:fa:83:d5: + ac:d7:dc:51:05:d3:51:fa:f7:7d:db:fe:d9:03:df:9d:a9:fb: + b2:5a:76:74:fc:40:6d:16:8d:1a:64:5f:8e:37:35:00:90:70: + b2:36:8e:8c:cd:9f:df:f3:1c:a2:7b:88:96:74:f4:0a:6e:a1: + b5:8e:83:a2:2a:7c:92:9e:98:7d:0a:28:d5:62:01:c9:52:50: + 58:f7:c8:61:20:42:bc:d3:1c:94:aa:38:c0:2f:97:03:14:33: + ed:49:e2:3b:26:e8:2b:4a:bf:4c:e3:72:1f:df:11:8a:ea:ea: + 33:92:13:62:b6:e0:3b:a1:bb:0f:a3:d6:a2:8c:95:0d:97:5a: + 94:e9:c3:2a:89:43:73:42:a7:10:0c:0a:39:71:fa:55:cc:53: + 4c:a2:f2:62:58:2b:1d:74:a8:64:3b:7c:e6:04:aa:36:24:5b: + 4b:42:75:06:3e:36:cb:98:68:9b:f1:60:43:40:a0:03:4b:0d: + 44:b6:03:f5:78:c6:f2:b9:01:51:98:b7:f2:5c:ff:6a:5e:58: + 2d:9a:3f:2a:5b:18:62:8f:5f:35:32:7d:8e:49:b3:eb:27:c0: + 6f:e9:39:f4:a8:f1:65:bf:40:92:1c:a2:f5:aa:f3:04:b7:f4: + 21:70:be:bf:03:05:cc:64:e9:50:08:65:51:49:2e:b7:7f:b7: + 42:1f:a6:a4:89:e5:03:af:a1:d8:87:bf:86:db:4f:cf:10:7a: + 3b:25:fc:44:2c:b2:a5:d0:73:2b:3f:3d:75:9a:86:d5:08:73: + 04:c0:04:c3:ff:b1:10:7c:24:e6:ef:6b:5b:df:59:c0:58:bf: + 21:dc:6b:a1:39:d5:ed:73:95:bf:47:19:7b:ff:51:a1:79:fa: + 24:62:b8:b0:66:61:eb:6e:82:a7:a4:f4:fc:8b:4b:4b:e5:a9: + 77:52:f4:2c:f7:6d:66:ed:ff:37:af:0b:03:d6:c7:5c:96:93: + c0:d5:ec:5b:6e:fb:94:51:cb:fc:94:1b:d3:a2:9d:cc:d4:f1: + 31:cd:5a:b0:61:b5:00:4c:6c:65:1d:a0:79:0a:c3:fb:c7:ad: + fe:ca:db:7b:a2:7e:ee:61:48:fe:c0:95:da:76:8c:d9:06:91: + aa:e1:4f:fd:69:80:e2:65:43:b3:25:f0:ec:6f:84:74:55:67: + c9:40:d3:83:6b:d7:5e:ef:26:96:a9:da:03:7a:54:66:8c:a0: + 10:d2:95:dd:9c:ce:cb:13:2a:8a:74:e9:33:9d:24:81:52:34: + 68:de:0e:dc:30:79:3e:8c:b7:58:a0:b2:ec:53:9e:9a:ba:5a: + 72:7d:90:97:2f:bc:a6:76:6d:46:b4:b1:f6:6a:46:69:3d:76: + 37:ba:e9:af:7b:a3:cb:4d:f7:fe:cf:38:5a:db:fc:c4:18:87: + 34:9b:a7:25:4c:5c:30:e4:f4:c2:16:9f:02:d5:f3:9e:40:f7: + 1d:c6:59:eb:0e:a0:9b:a2:4a:9f:b1:6e:03:f6:76:d6:29:0a: + e0:cb:9a:0a:82:f2:94:2a:c6:6e:ba:23:d9:d3:06:0d:4f:5f: + b3:5b:ee:45:fb:4e:fd:ce:3a:56:63:6f:1b:4d:ee:e4:91:96: + e4:7e:3b:ab:44:ba:f3:bd:ca:2e:27:b8:64:03:97:71:a5:4a: + 0e:95:88:b5:60:a2:4e:aa:02:90:26:13:30:27:a1:4c:76:ff: + 67:f2:d5:be:f9:66:23:48:f9:d3:6c:f1:25:a6:3c:ba:70:1a: + 34:db:81:47:a2:b8:0c:d2:3d:18:8c:78:79:2e:9c:80:1b:a6: + 49:0b:a6:93:63:5d:05:e1:4e:e6:51:7d:2e:46:70:f0:1c:ec: + 6e:13:a8:5d:77:bb:a7:60:30:67:fc:6a:c5:62:7f:ce:2a:b8: + e1:56:2c:57:77:e1:48:fc:eb:6f:7e:ab:db:ed:a8:4c:af:c8: + 19:eb:e9:f6:25:25:7c:ff:80:cb:21:40:ac:95:e5:e5:c3:b8: + b0:f8:ca:91:3d:c7:82:6e:78:f7:2f:63:17:02:b5:ea:d9:63: + f7:dd:d4:44:d5:6b:a9:af:7b:f6:85:0e:71:08:63:20:02:21: + ea:b6:35:30:d1:72:31:50:70:b0:aa:ab:cc:f4:fa:d1:8a:62: + 24:af:a5:06:90:4a:e3:f4:83:6c:ea:ab:8e:94:64:e2:47:5f: + ee:68:c6:7b:58:83:13:31:06:63:7d:5b:62:1b:7c:1f:57:a8: + af:09:60:0d:7d:91:98:5c:ff:0a:d2:32:45:21:65:2f:39:7a: + 38:d3:4d:5b:af:61:a6:11:e9:c2:ab:6f:f4:66:28:18:c5:4b: + 80:b9:1a:e7:4b:53:c1:4e:1f:b4:e2:02:dc:a4:dd:99:6b:c2: + da:34:e7:a5:c0:94:52:78:2f:76:55:09:cb:c8:71:75:10:5c: + 01:c1:5d:8d:83:e4:45:e2:ce:48:a5:24:3f:1f:07:05:72:36: + 0d:ee:59:c8:03:f2:35:90:ff:ee:36:ad:79:d0:0e:3d:57:05: + 81:37:90:d1:03:eb:13:10:90:51:6a:60:0a:13:56:ef:3e:c5: + 6d:9b:37:f6:26:fa:46:84:7f:11:02:fb:54:d7:13:d3:6f:a7: + bd:a6:9f:81:6a:64:d4:96:be:2e:d2:b4:e9:17:14:70:db:0f: + b7:24:83:8b:bd:fa:42:df:3b:2b:81:e9:e2:a3:4f:31:68:46: + b5:9a:ac:3d:1f:07:13:63:26:b4:c2:59:55:b9:ee:15:71:73: + ea:91:4b:c8:b6:8f:9c:50:dc:60:3f:c2:c9:67:01:37:a1:a9: + 01:3a:a0:2a:20:d1:9b:d4:27:57:2a:70:c0:f8:98:42:3b:46: + 44:3b:74:41:6f:49:77:7b:ab:0f:9f:73:e0:85:a3:a8:32:e0: + eb:b0:2c:49:50:cc:da:46:2e:52:e6:40:8c:da:92:25:a4:ca: + b6:37:8c:33:88:ae:b6:a6:7d:ee:4f:56:e8:b7:ac:2e:89:0e: + 13:87:5f:54:51:1b:f3:ad:f2:f9:ea:6e:53:d3:66:b4:70:ca: + d8:ad:21:ce:2a:49:77:bf:2d:be:82:ab:45:f8:00:58:73:11: + c3:a5:31:5a:2f:d6:8b:7f:2f:bf:59:b5:61:79:3b:d8:25:81: + 16:11:2b:39:00:91:d2:b6:d4:49:d3:5c:2d:32:19:25:f5:31: + 65:f3:ed:d5:da:61:5b:96:28:49:3b:f7:ae:3f:8b:3b:f5:3a: + ac:2d:6d:45:e1:c7:ab:85:13:c1:c3:65:a8:c6:b3:7c:25:6d: + 04:c2:d4:21:29:50:54:71:15:2b:83:88:69:8c:c9:8a:c3:43: + 76:08:35:d9:5a:1e:25:fe:47:09:e7:bb:2e:b4:ff:aa:82:1f: + 43:be:a6:86:92:90:ba:c7:3a:6a:97:32:d0:ed:d4:bb:06:37: + d0:58:4c:94:ee:1c:b0:28:8d:ba:1e:7e:f4:9f:a9:27:f5:02: + 2f:e4:8b:ce:34:c8:cc:ad:b4:b8:fc:f7:31:f5:fe:10:fc:5f: + ee:c7:23:c2:a3:cf:25:d5:2d:bd:3e:58:e4:3c:79:d9:65:c4: + 8b:d1:01:9a:46:ce:e2:62:7f:19:aa:85:e6:dd:63:fc:e6:40: + fc:04:4c:26:05:1c:f3:9c:28:a9:06:b0:0f:20:0e:d7:6a:6b: + aa:ee:d5:a9:77:92:49:88:98:59:27:5d:f1:57:56:01:de:13: + 3b:bb:8a:e2:fe:1d:ef:52:cd:65:37:a7:eb:11:a4:82:c4:04: + 75:ac:2f:09:df:a0:41:77:2b:ad:7f:7a:03:4b:e2:53:3b:c2: + ae:22:86:42:fc:77:4f:1f:cb:e7:2b:82:28:50:1c:e5:a3:c1: + 65:a1:1f:aa:e7:37:14:33:d6:ef:e8:3a:a8:48:bf:35:eb:af: + 8e:40:ba:3a:84:38:89:db:ab:15:50:85:7f:14:40:2c:e2:93: + 14:f5:8a:e6:f7:36:6c:44:5d:78:70:82:b3:5b:04:b2:26:af: + e5:87:ee:96:ca:b3:71:1c:e9:92:cb:e9:2f:9f:9c:f9:c7:a1: + 02:42:24:0e:b0:85:b7:ea:20:40:36:2b:1a:c1:5a:04:54:74: + ea:d9:b0:f2:ab:35:be:3a:73:6a:4b:5b:f2:04:63:20:e0:8d: + ee:d3:6d:71:f1:e9:e8:b2:d0:29:49:2a:1b:24:ee:65:fb:c2: + 55:ae:1f:8c:ad:02:eb:fa:35:4b:19:33:85:3a:28:42:f8:f2: + 65:89:7d:4d:68:91:d5:ed:d9:4e:03:a6:0e:be:b4:d3:48:a4: + 5c:bd:96:f9:d2:90:54:38:e8:a8:a2:2c:4d:03:da:de:05:0c: + 4d:1d:b7:55:d9:65:54:ab:45:8d:4e:0b:8a:09:63:fa:d5:22: + 0c:26:c9:b6:03:39:84:48:38:65:7c:f5:b2:de:30:79:e7:1f: + e9:a9:00:7f:30:df:5c:a9:7d:e3:92:e3:ce:25:e0:ee:71:1f: + d6:8f:d5:98:29:03:38:05:7c:68:18:8c:13:27:94:ad:1a:d1: + 9b:42:b9:c8:20:53:14:66:42:f2:0b:fd:73:5e:b1:72:e4:ec: + a5:8a:f9:0a:53:b7:b4:76:05:c6:4e:f9:7b:cd:24:b4:47:d6: + 6c:37:67:56:8f:60:9a:be:7f:2f:c0:ac:bd:f2:8c:6f:b0:75: + fd:5a:e1:47:0d:5e:db:9a:69:91:ae:0e:ad:e5:5a:2f:8a:39: + 1c:e6:1c:41:03:34:41:54:22:b1:0e:65:f0:75:1d:f1:a7:93: + 90:23:c8:67:df:81:00:af:f3:b7:2f:99:2f:57:ce:b2:bd:7c: + 98:85:32:cc:d5:0b:38:be:4e:9f:b4:50:2a:78:76:15:b6:59: + 48:b6:3b:52:1e:e5:39:b2:9d:43:e2:65:04:6c:b2:70:7f:0a: + 3c:85:dc:fd:b5:d5:86:da:56:ef:25:ad:b7:6d:e3:45:60:55: + 5a:b7:33:35:b5:0a:b1:31:47:94:61:e0:0b:e2:c1:e5:dc:bd: + 39:ea:42:a2:22:02:97:3c:f6:9e:cb:9d:57:f4:87:62:16:ab: + a2:46:db:55:34:2c:62:ac:a8:a4:2b:25:d3:f9:ea:8e:4b:4f: + 26:f9:93:14:43:bc:13:7a:5e:c7:e1:c0:08:dd:d8:e7:2f:a6: + 42:62:2f:6d:5a:2a:f0:7b:84:aa:a0:bf:15:54:ad:05:9d:75: + 9b:a3:7f:c6:19:bb:68:fc:a2:0d:83:e1:a3:49:4e:7b:20:88: + 46:13:04:2b:68:2c:73:12:61:72:dd:c4:77:8d:9e:fb:e1:bf: + 69:62:d8:18:fe:63:ef:d0:b0:f0:77:9b:cf:c5:80:13:a5:49: + e5:66:a2:ba:d0:d6:00:36:ff:81:5e:37:4b:ef:13:b7:eb:5b: + a5:cc:a4:9c:0b:9f:9b:9c:70:b4:be:23:1f:f4:68:34:b7:16: + 80:8b:f4:30:a6:b2:6e:2a:d5:81:a6:bd:95:5e:b7:e5:5f:b8: + 7b:4d:ba:b3:dc:b2:37:ab:15:d9:08:c1:75:36:b4:c0:e1:be: + 73:8a:0b:b4:d7:1b:83:11:5a:40:ca:1f:aa:13:c7:d4:2f:84: + fc:db:86:24:1a:02:ca:6f:6c:49:05:85:6f:d0:0b:42:50:d0: + d1:ee:47:85:13:4f:6d:98:15:b7:ec:a3:9e:9b:cf:da:8b:d4: + b9:bc:96:f6:38:02:69:7a:cc:af:8b:ff:0f:22:b9:ee:24:4e: + 29:76:79:56:1f:cb:3d:ca:b8:57:24:fe:8b:e4:9e:5a:c4:25: + 99:3a:1e:0c:7c:59:c1:c4:1a:6a:de:c1:21:7f:00:3c:12:e2: + 80:56:89:3a:47:cf:df:9c:0b:73:34:b0:06:cd:50:cc:7b:47: + b2:9c:0b:10:a2:73:62:40:cf:c2:cf:ca:6f:f2:2d:d6:04:00: + 0f:1e:d2:56:b8:1f:6d:44:96:f3:bd:cf:55:d4:45:b1:87:36: + 9c:dc:12:54:0c:21:f4:a6:f3:12:a6:fb:22:d4:31:f8:9c:51: + a2:cf:9f:64:0e:bb:01:f6:80:c7:c2:70:4c:a1:60:60:0b:ba: + 53:15:f8:d4:c6:42:c2:85:4c:5e:a8:28:3e:0b:88:fd:b7:9c: + db:b6:fd:9e:32:29:9f:1c:0c:74:8d:eb:24:9c:61:c2:7a:04: + b8:9b:62:83:1c:a6:65:63:6e:0c:15:2f:c5:16:9b:de:48:31: + c4:1d:41:3a:b2:9a:0a:71:b5:21:f1:62:41:ec:4b:0b:17:d4: + 8a:a1:6c:82:d4:74:90:28:32:bc:25:d8:b2:a2:f8:26:58:66: + bf:67:fa:c7:00:06:6a:ac:0d:b1:bf:2c:d9:39:23:7b:e1:a1: + 47:b5:6f:c4:9f:62:85:e7 +-----BEGIN CERTIFICATE----- +MIImDzCCB0mgAwIBAgIBAjALBglghkgBZQMEAxowgaMxCzAJBgNVBAYTAlVTMRAw +DgYDVQQIDAdNb250YW5hMRAwDgYDVQQHDAdCb3plbWFuMRgwFgYDVQQKDA93b2xm +U1NMX1NMSC1EU0ExGzAZBgNVBAsMElJvb3QtU0xILURTQS1zaGFrZTEYMBYGA1UE +AwwPd3d3LndvbGZzc2wuY29tMR8wHQYJKoZIhvcNAQkBFhBpbmZvQHdvbGZzc2wu +Y29tMB4XDTI2MDQyODA4MTAwNFoXDTI5MDEyMjA4MTAwNFowgb4xCzAJBgNVBAYT +AlVTMRAwDgYDVQQIDAdNb250YW5hMRAwDgYDVQQHDAdCb3plbWFuMRgwFgYDVQQK +DA93b2xmU1NMX1NMSC1EU0ExHTAbBgNVBAsMFENsaWVudC1tbGRzYTQ0LXNoYWtl +MRgwFgYDVQQDDA93d3cud29sZnNzbC5jb20xHzAdBgkqhkiG9w0BCQEWEGluZm9A +d29sZnNzbC5jb20xFzAVBgoJkiaJk/IsZAEBDAd3b2xmU1NMMIIFMjALBglghkgB +ZQMEAxEDggUhAJ17ZoWas8vfGcWq4qwqea/x/eK4jZHa9Y6GtJE8FSoSYYlWstx2 +E/Q1GnLcoRT2lXYlo5NpI9uA+RNVnVLt34N3Rhn5VUaRNhEjarQXQPgyqIbXB5n9 +7ii9OfxtAO5ZsMbCC2DOO2uPCP+L2jHDtmTjf33fUe3RwbnsI865/wRnTpO7/Wsr +6dTKIrGvpGzgzFJcDO8M6kyMoiKfwjRBJsQBQmShHP0Zat99rKOeMEaCOQeiKsPU +8FUQS+nw1a8SFTMBl79TalEnGh4/2i9bV6oCEUvuDCfK9XuK/ayyLzW0Kj27zKEW +d0jDRSQBMyWce2XoK0hOPL0mzOgRj12qLczEImGx4J+4z4ZnvaGcbP6UC+YUV2Tg +dsVZiFjxohXaCnrI+INEm/cNaP013EaCF+OwJCM9IUMRw14MVOVn4QRjRbS7RCGW +bCS8Ok7ED7S2Ke/3+Qxw4KZDklUFCyTiUqifXZBQOJkzdnE5EC3pzkqZUSHCgc1U +a/EEKgSukxHV1NyWyPWEP8EjF0cMfrUBpE06y8IozmwmNVXA9Kl7ME8g6IRLj8F9 +UVI0lhE9ajRSAzzhJz7wPgy0QaUGk1HkpuM9+/Ct+HMLPWTdANi6Cb2EkH6084Sp +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 +YoXn +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 1a:b9:a5:11:e8:b5:2e:6d:06:db:c8:39:df:1a:50:04:21:1e:f9:44 + Signature Algorithm: SLH-DSA-SHAKE-128s + Issuer: C=US, ST=Montana, L=Bozeman, O=wolfSSL_SLH-DSA, OU=Root-SLH-DSA-shake, CN=www.wolfssl.com, emailAddress=info@wolfssl.com + Validity + Not Before: Apr 28 08:10:04 2026 GMT + Not After : Jan 22 08:10:04 2029 GMT + Subject: C=US, ST=Montana, L=Bozeman, O=wolfSSL_SLH-DSA, OU=Root-SLH-DSA-shake, CN=www.wolfssl.com, emailAddress=info@wolfssl.com + Subject Public Key Info: + Public Key Algorithm: SLH-DSA-SHAKE-128s + SLH-DSA-SHAKE-128s Public-Key: + pub: + 2a:8c:8c:5d:98:10:81:4c:01:47:9a:ab:e4:71:4f: + 27:45:e2:ac:10:8e:95:80:94:94:30:a1:a2:2d:b9: + 2a:b3 + X509v3 extensions: + X509v3 Subject Key Identifier: + 62:90:90:E5:3A:74:18:1B:FB:68:40:07:A5:83:9D:70:2E:7E:C9:F0 + X509v3 Authority Key Identifier: + 62:90:90:E5:3A:74:18:1B:FB:68:40:07:A5:83:9D:70:2E:7E:C9:F0 + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + Signature Algorithm: SLH-DSA-SHAKE-128s + Signature Value: + f3:00:21:12:66:43:0d:fb:2c:be:12:be:ed:07:4f:ae:78:1b: + 4c:cf:e2:e8:85:cb:e4:68:f0:6e:6e:63:78:e1:10:0c:3c:7d: + 0f:57:03:dc:ac:73:81:7c:c9:5e:77:e2:d0:77:0a:b1:7e:03: + cc:3b:f6:a4:19:e4:e1:dd:89:d5:dd:cf:0b:c2:17:a0:fd:fd: + 08:d8:d3:c8:12:1c:a8:de:bb:a0:a7:ba:81:bb:c9:b0:bd:09: + fd:05:cf:f8:89:5c:38:d7:0f:a6:8f:85:98:cd:3e:a3:c1:9a: + e9:4c:6b:bb:0e:25:fc:3d:83:19:53:8a:38:ff:e8:1b:da:cb: + 35:24:3e:1c:de:8c:9d:83:f7:2a:9e:52:4b:1b:0a:14:e6:b4: + 1f:5b:de:0d:3f:68:8c:ab:e9:da:d8:61:37:c2:c0:e3:28:b2: + df:41:0e:d2:90:30:e2:f6:a4:18:a1:1f:43:c4:30:a3:68:9d: + c1:d6:81:d1:2a:2e:a6:6a:7d:c7:a3:6b:4f:f1:6e:67:5d:b0: + 08:4b:9f:0f:c1:98:4f:5e:13:80:44:d7:c0:d7:32:d6:af:42: + a1:cb:c0:86:f3:d3:db:17:89:ed:f1:bd:af:f3:eb:76:f1:2a: + 9c:0c:d9:c9:86:8b:46:f8:0a:cf:5f:e7:fb:50:a1:69:e5:5e: + a5:78:81:63:5a:9c:2d:a4:b2:2b:d6:fa:c1:f9:7e:7a:01:39: + b1:0f:17:b2:e6:74:b0:01:59:59:14:f6:49:6b:f9:63:4a:84: + 32:83:80:2c:cf:8e:4e:0b:f6:ff:41:47:6b:c2:f7:54:cf:44: + 09:0e:12:cd:8e:8f:f0:58:04:80:20:a8:70:db:a6:a8:8c:ba: + 3d:97:06:d2:0f:3d:cf:c5:39:80:5b:8a:f7:22:67:df:92:62: + 86:3f:e5:8f:fe:0f:f2:e9:8f:6c:ea:7b:ef:2d:c1:db:9c:6b: + c5:93:e6:33:70:59:9b:57:3e:3e:b4:0f:1d:97:b2:25:07:5b: + 10:05:60:d4:02:4f:cb:5d:ce:69:51:69:86:2e:74:82:c3:02: + 9d:1c:77:28:1d:b5:d4:a3:18:c6:9c:59:d4:a8:1d:0e:38:9f: + aa:13:10:c3:c2:39:d1:e2:c6:b7:f8:e3:c3:68:9e:3b:8a:91: + 41:d0:93:4f:63:06:cf:d7:e2:58:15:19:a3:ca:14:0b:d5:9f: + 81:2e:d8:35:29:ca:5e:73:75:e1:bb:30:d5:89:5f:fc:b3:b5: + de:5a:86:3e:1f:c0:65:f9:ae:73:ce:ef:7a:c0:68:65:91:5f: + 20:22:d8:91:cf:b8:ae:ad:73:bf:df:71:da:9a:fe:28:94:26: + 3e:8e:e8:50:4a:86:9a:0c:07:fb:f7:9f:29:c5:06:4b:3e:d1: + 0b:0e:8f:a4:f2:c0:db:dc:d5:b7:9e:9f:0f:53:0e:fe:74:13: + e3:91:a5:a4:40:eb:4c:43:73:eb:b7:99:4f:de:a1:f2:29:bc: + 9f:1e:d9:f3:dd:a7:60:65:7e:c6:74:27:6e:fb:a9:62:fc:c9: + 87:aa:b3:97:b6:ad:22:4d:d3:58:13:a4:b7:2c:60:fa:f1:d0: + d9:4b:43:d0:53:34:61:5c:1d:48:5a:e4:11:2a:1c:43:4e:45: + 3a:7e:6e:c7:05:0f:7d:d8:f3:1f:e2:99:f9:45:df:e9:59:b6: + 65:aa:41:78:3a:1f:68:bc:de:3c:2d:c3:1a:1a:72:7d:3f:b4: + 24:94:8e:90:f9:a7:2f:e2:86:87:77:88:8f:7b:98:82:1c:03: + 99:9d:c7:e8:ad:62:49:e0:e5:51:50:95:67:d7:aa:3b:67:c4: + 54:7c:6c:f1:fe:d5:4d:17:7d:8c:99:b4:49:4a:57:dd:9b:fd: + 46:1c:33:a1:8f:3f:42:be:56:a7:06:00:be:88:1d:01:38:c5: + 28:a8:b4:83:4a:b9:84:7d:cd:3a:7b:6d:78:2e:7f:9c:e4:46: + ca:18:9f:aa:d2:fe:24:76:e5:b3:a6:3c:de:af:b8:a2:ae:70: + b7:2e:76:13:29:1e:6b:7c:eb:54:d8:2c:45:77:e5:c6:a2:29: + a6:b2:8d:54:e2:60:f8:34:21:5b:ec:b1:98:49:fb:1a:0e:cd: + 54:63:cb:e3:0c:fc:38:11:6a:e5:4a:57:6a:95:de:3b:70:c2: + a5:05:d0:10:1c:eb:c5:39:4a:b0:e2:81:82:41:9f:0b:be:8d: + 83:fa:1c:9c:81:e6:bc:86:d1:28:69:5d:cc:67:5a:43:84:2e: + 9d:6f:cd:af:f0:79:25:63:73:0a:8f:1d:14:9d:cc:e5:65:e9: + bf:09:d9:fe:d3:dc:5a:ab:db:0e:02:1d:f8:cf:51:be:70:32: + f1:1e:c9:19:cb:52:cd:cb:60:cb:e1:3d:81:8d:b0:f5:f2:bc: + 21:c3:b2:71:7b:4c:41:37:be:43:a8:e3:da:87:5f:8f:b9:23: + a3:8c:68:d7:90:8e:ba:cd:05:72:1c:36:82:7b:c5:54:29:b0: + 41:d1:a4:e0:f8:c8:3c:c5:f7:26:51:27:c2:87:71:1a:0e:86: + 54:2f:48:cf:e1:f8:ab:f1:9f:74:36:be:d1:45:21:13:13:4e: + d5:c8:98:f7:51:0c:b0:41:25:e4:cc:04:12:7d:03:11:45:37: + f9:12:51:a3:a6:f8:25:d8:e7:19:b2:e5:20:37:71:e3:95:7d: + 1e:b5:6e:b8:e8:8b:05:42:f7:d4:97:57:e2:3d:c6:8e:8c:a9: + 86:8f:57:c0:da:41:89:8d:07:8c:b3:ce:d7:39:93:b5:6e:e0: + fb:59:af:76:88:6f:84:5f:4e:54:6b:42:de:95:4f:17:26:5c: + 48:bf:ec:65:dd:73:8c:96:c5:5d:1a:5a:79:fa:67:08:05:c9: + 72:2f:1b:1c:37:de:1a:a2:17:eb:d1:61:67:29:56:00:b0:3f: + 9c:d7:bc:ea:de:31:ed:2c:09:4b:4a:a6:c5:52:43:d5:38:6f: + 82:b4:b9:c9:9d:3b:1a:60:91:8c:b0:93:c2:91:a8:f1:9c:10: + f3:a3:9e:53:6b:e7:fd:84:83:ec:23:f9:5d:05:5d:bb:c2:16: + 51:ae:aa:f4:2a:53:3c:8c:5d:5e:f7:cd:d7:64:c3:a9:ce:f9: + 7b:31:f5:c4:fb:68:e3:97:4c:08:bf:64:7c:58:6d:4b:11:75: + 6f:a8:13:4e:24:76:63:47:ef:e9:ff:bd:0c:7c:cc:f8:5e:91: + e9:25:b6:9e:b7:42:97:a2:4d:c9:4b:f8:82:10:ea:45:a1:81: + 5d:b7:0f:ed:e0:e0:27:d4:88:c9:6e:3f:47:b8:1d:d7:66:51: + dc:0f:4b:cc:cb:fb:a8:f3:85:43:60:71:aa:66:cb:66:54:3a: + 63:bf:ac:e1:aa:c9:06:e1:4b:26:f7:df:75:a8:bf:45:70:bd: + 18:d8:91:58:bb:8a:51:0e:79:58:01:3d:45:05:5e:9d:02:b4: + 7d:06:48:0d:59:4c:fa:4a:ee:fe:72:5a:03:ad:5c:eb:e5:44: + 04:b4:20:90:5a:79:1c:2f:62:d5:49:89:59:16:c2:75:07:35: + 2c:da:f0:99:3d:5b:49:b3:be:ab:1f:2a:00:cd:18:47:3a:20: + 8f:e5:ee:d4:b9:e5:9b:af:ef:36:bb:42:f7:80:02:97:e1:e3: + 4a:52:e9:95:e4:15:eb:40:cb:c1:a0:11:17:a7:88:98:eb:34: + b3:be:56:d0:ae:2d:9c:fe:38:eb:51:8c:fb:17:74:66:b7:f5: + 57:b7:ef:c8:e5:a8:9f:4a:87:df:30:8c:f3:f1:f4:33:bb:fb: + 62:76:36:68:f8:50:ba:8c:b2:eb:cd:5c:8e:0a:03:d5:4f:fa: + 81:6b:64:e5:5b:a1:f1:27:98:26:08:69:dd:21:70:9d:fa:24: + 1f:51:a5:b5:a2:48:1f:fe:fb:ce:82:93:c9:73:cc:c3:5b:30: + 62:b7:e8:8c:82:26:57:e0:29:a7:97:c1:98:c5:99:84:f5:4a: + 99:d3:23:1d:a7:91:1a:ce:71:e1:fd:be:59:0e:da:a9:82:23: + 1d:4b:49:5f:05:7c:20:bc:ff:31:f2:c6:3b:7e:c7:39:74:37: + 33:db:f0:7a:bd:06:c5:6b:71:01:57:36:14:dd:8a:57:a8:6e: + f5:42:5f:1d:87:88:bd:70:6e:6f:94:bb:82:44:a8:b7:a4:f8: + c3:59:25:76:b6:8a:e3:2a:15:a2:22:33:90:ba:b8:9b:78:5d: + f3:bf:26:b7:a0:47:13:31:b6:00:e1:19:b0:53:25:f8:28:c7: + 60:62:b9:2d:b1:97:ae:1a:9d:41:b7:66:e2:d0:09:11:63:ea: + 03:27:1b:dd:c7:d6:20:8a:c3:a8:27:dd:b3:59:d0:0e:9e:f7: + af:be:7e:30:53:51:a9:79:53:40:31:ac:5d:20:45:0b:62:96: + 98:1a:ed:57:2b:3b:65:7a:49:85:6f:15:6c:a5:4b:53:f5:45: + 8f:a6:46:d3:8d:93:af:d3:20:be:c9:b9:fa:db:47:48:07:14: + cc:a7:1d:7e:65:66:44:f7:42:ce:40:ef:03:1a:96:bd:be:e1: + c5:33:8e:ec:72:1a:ca:b5:64:e5:98:29:68:29:27:a9:b7:75: + 84:a1:d0:c6:3b:63:18:fa:77:c0:31:00:9c:8f:64:6a:34:54: + d3:5a:43:53:d0:35:f5:e2:11:cf:9d:4e:b2:33:01:1c:49:73: + 56:af:ae:ab:04:72:e7:d9:cc:8c:7f:1d:23:0e:7d:1d:46:2f: + a7:a5:59:d5:a0:8c:31:5b:08:cd:3a:8c:b4:8d:68:db:a6:94: + 08:49:02:16:55:e3:3d:49:c9:35:f6:eb:e0:5f:e7:bf:b6:67: + 7d:f5:30:57:60:d6:f0:1e:eb:0d:03:44:9c:cb:3d:da:a1:ff: + c4:ee:0b:f2:7f:8f:4d:8a:f2:47:13:55:2c:c5:aa:cd:d9:0f: + c7:ba:61:f3:6c:e3:f8:35:1a:1f:69:c6:21:94:fa:5b:92:2d: + 76:f1:78:16:e9:31:fd:fc:77:b3:57:f5:a6:8c:8d:1c:55:9e: + c6:4e:88:d8:57:4b:e8:37:da:a8:72:95:25:63:46:4f:73:be: + 60:ff:58:10:36:ed:98:fb:63:07:e1:19:88:f4:73:a3:b3:48: + bd:78:22:85:f7:96:b0:63:9f:63:89:46:35:5a:b6:18:61:d8: + 67:8d:ba:b3:7e:83:7b:b8:7f:94:fb:93:c5:34:b7:33:d8:5d: + d7:fa:d6:8e:4a:6c:54:3c:29:e5:88:36:8c:96:1d:3b:ac:08: + 6c:b2:05:d7:71:12:39:eb:90:46:18:fe:a0:46:97:a3:00:fb: + 43:8e:b4:50:1a:b5:f3:e2:72:24:fe:45:3a:ba:71:23:c6:8b: + 5b:9b:7e:17:fc:52:3c:34:e7:16:f7:07:6c:98:1b:11:c5:8b: + 39:2b:97:59:89:4b:2d:7b:27:54:41:eb:bc:20:02:50:70:bb: + 6c:c9:34:68:d6:67:07:39:5e:4e:50:df:8b:f5:b0:ca:be:42: + da:34:64:48:f2:cc:98:92:f0:66:3f:d0:6e:87:4f:5c:ef:fd: + f5:91:b3:52:39:48:70:d0:99:a3:0f:67:d9:fd:9a:6a:f3:5c: + dc:44:e0:a4:f8:5c:c3:cc:85:64:7c:ac:6c:17:7f:23:3c:7e: + b2:10:86:c5:57:94:26:0b:6a:aa:f9:34:d7:5a:41:80:85:eb: + fc:a9:fd:14:94:ed:c9:48:e4:dd:38:a0:21:27:12:c8:44:fb: + 43:fe:1a:4a:ab:13:22:b6:9c:17:c9:7f:99:9c:22:fa:59:57: + 35:a5:6a:f7:90:67:58:65:b2:7c:6a:5e:43:2f:4f:1a:f6:b1: + 6c:33:4f:84:83:ef:f9:cc:5c:0a:9a:2e:11:25:e0:77:8c:d3: + 0b:90:15:d1:ff:7d:4b:d2:a6:a9:ba:a4:bf:08:a3:65:ff:b2: + 15:d3:b4:e9:86:74:ce:5e:86:c0:f2:0c:d0:09:27:47:48:aa: + 89:88:e7:ca:47:13:4f:f3:b8:d7:e4:aa:af:27:73:93:90:6e: + 46:fb:9b:b4:3f:2a:d7:bc:fe:1b:9e:32:09:b5:d4:ac:39:20: + ab:52:ab:42:d2:7a:89:83:d9:f0:4f:8b:8b:ad:e7:7d:51:82: + c3:9a:98:56:7e:0e:51:a9:13:35:a5:7c:36:86:36:e4:8e:e9: + d7:84:d1:82:9c:cd:ad:99:8b:11:f7:a7:66:fe:36:47:56:46: + 67:af:59:76:f7:9d:f9:3a:f9:3f:10:22:27:4a:6c:cb:32:2b: + 59:13:f4:a0:fd:d6:3b:6c:60:91:bd:aa:f3:a5:31:8d:ee:1a: + 38:90:19:3e:a3:8d:e2:10:0e:b3:a3:da:7f:75:e2:79:bf:36: + 86:16:7c:bc:94:b2:78:57:c5:45:02:6e:99:ad:cf:2d:21:c4: + 6c:59:b2:b2:94:7a:e8:46:2c:12:61:99:74:2e:87:3e:fd:25: + 62:58:89:20:35:a5:83:3d:d1:d5:5c:e2:17:58:73:9c:f0:a9: + 90:13:ef:a0:b0:38:08:a8:46:f9:07:f1:be:31:9c:ec:ac:65: + 82:a1:ee:fd:39:5d:7b:6d:53:2c:a6:23:48:59:2b:13:63:16: + 93:69:46:42:4f:98:c8:70:dc:10:a7:fe:8a:28:91:6f:26:cb: + a8:e5:26:37:75:cc:a4:cd:88:49:4f:10:0d:c2:46:44:68:7a: + 58:82:b4:15:78:47:f3:1a:76:af:cd:84:fe:e0:d6:93:1e:f9: + 21:1b:d4:a2:13:29:3c:1a:bd:2a:fe:d4:cd:65:e6:14:e1:31: + 82:14:bd:9e:09:e2:be:b9:80:8f:11:11:95:72:d9:a4:0d:c4: + 6e:24:31:9e:e9:cf:9e:a0:e2:fa:7d:4b:b0:03:25:b2:90:e6: + 7e:08:39:37:17:38:a0:93:f2:8c:ff:8c:ee:68:0e:11:74:ef: + b5:b7:47:21:32:82:9b:24:47:e0:88:bf:15:61:e2:3e:55:a6: + 87:d6:f0:ba:f7:99:75:4d:7e:2e:76:06:8c:fc:9e:f8:bb:3b: + e5:74:70:e1:30:0e:06:ad:01:a4:6d:45:c6:f4:55:47:28:45: + cd:7a:8f:29:77:28:9a:a3:bd:ca:2d:b4:ff:53:10:a1:c6:b7: + 51:59:0b:04:ff:ba:72:6d:5f:43:4e:df:36:ed:ab:d9:d6:49: + bc:8c:8e:be:53:84:2e:e3:00:a3:eb:33:49:23:ad:ae:98:7d: + a5:b0:49:29:d4:d1:5e:5a:11:5e:01:f4:f4:13:31:5c:d3:d6: + b7:08:da:25:87:7d:b5:73:12:74:06:0d:97:52:7f:60:08:42: + 2a:af:14:f5:30:89:ac:f3:32:21:2c:e8:16:fc:45:13:89:28: + 6e:4a:95:87:fc:30:36:55:7e:65:01:4f:55:52:39:39:25:40: + 21:4c:30:dc:d9:6c:5f:58:fe:57:2b:83:d9:a0:db:4f:b3:4e: + 02:48:8e:b7:70:9f:eb:0a:98:61:92:72:84:3e:53:7c:c6:f3: + 3e:3f:70:3c:c2:ff:98:4c:1b:a6:71:c1:15:f8:e5:03:4f:53: + 62:fe:ec:d9:2d:8c:83:e0:a3:42:7d:d9:16:51:04:2d:42:48: + 11:4a:62:31:06:d4:02:5d:93:31:21:aa:47:da:c9:c6:49:be: + e4:71:4e:57:36:46:94:bf:fb:e3:88:3b:59:77:6d:13:cf:34: + 62:34:ba:46:83:64:1e:22:10:74:18:a5:b2:d2:83:11:3a:ad: + b8:72:93:48:c4:6a:1d:b5:c2:d9:dd:2d:4f:bf:eb:e6:3f:9f: + e1:85:9b:f1:2e:03:5e:b0:f5:dd:8b:33:d6:7c:5e:e4:34:eb: + bd:62:dc:80:03:cf:cd:ed:ef:29:4e:ed:e6:e0:ef:d4:1e:6b: + d4:a1:bd:b1:23:73:71:f7:ac:7d:c3:eb:e6:37:ab:8d:46:e1: + 24:93:92:b0:8d:f0:84:bb:f7:f6:51:19:52:76:94:ce:b5:f4: + 3e:5e:0a:8e:e3:9d:14:43:31:4f:14:91:12:9b:81:7d:51:fe: + 22:93:28:e8:e1:d7:8b:72:90:1e:44:61:d2:07:17:f5:ef:81: + 69:27:ba:a5:a4:ea:2e:cf:9c:04:cf:fd:0f:c2:2d:4d:57:80: + 49:bb:a6:92:be:7a:8e:4a:99:b7:d4:d7:08:63:b4:2c:1b:bf: + b6:bb:31:6c:13:7f:84:19:7a:e3:c0:57:5e:c5:5f:9a:27:ed: + b2:8b:23:65:96:d5:e0:59:ec:50:0e:63:a8:df:7f:4d:dc:6e: + 35:d8:32:86:94:88:7a:20:3d:67:67:08:e5:ed:08:fa:37:7e: + 84:6f:a3:e1:d3:62:f2:f7:19:f1:ef:73:b5:6a:a8:16:42:2f: + 41:7a:e3:66:be:14:9e:5c:22:95:f4:31:17:44:a8:6c:ea:ac: + 6c:d6:c6:a9:76:eb:c9:24:1e:93:76:48:f4:14:3a:18:f2:32: + 68:f8:9e:cb:53:e1:a0:04:0b:a8:a6:4b:c2:3f:d7:4d:72:3a: + 77:34:e9:7c:b6:18:26:bb:e5:e8:d7:1b:24:86:ea:c0:c8:0a: + 81:ea:50:5a:b7:3c:ca:7a:bb:7a:85:4f:03:d2:7d:97:44:80: + 0c:ac:58:48:a0:33:74:62:69:db:99:75:b8:a7:7d:c4:64:2f: + 00:b5:a7:c1:ec:3d:69:e3:c5:b0:e6:47:ac:1b:c0:b2:15:75: + 76:84:a4:f7:05:ed:fe:6d:ea:c0:2f:d3:37:72:dc:b2:8b:23: + 45:1c:21:f1:6b:5c:af:59:12:b8:92:9f:be:59:b7:70:68:08: + d6:e5:30:b2:cc:16:37:35:22:b7:7d:7d:61:2e:f1:81:a3:08: + 99:cd:1f:b6:52:f7:f9:53:c2:dc:e4:4e:40:54:59:9a:0a:4b: + fd:92:64:59:71:64:dd:d4:94:74:ac:e4:5b:c8:a9:ad:a2:0b: + bc:66:45:ad:30:76:bb:32:81:0a:ef:92:00:50:77:0e:b2:61: + 0e:63:8a:a8:a8:d1:84:88:ae:52:53:d3:9b:5f:ae:f8:a5:35: + b7:40:51:95:ab:6e:ef:84:c4:84:0f:3b:8f:75:33:05:6d:42: + 2c:aa:20:da:17:5c:b8:cb:cd:08:54:6a:18:d1:c0:0d:7d:14: + e5:fd:64:1d:8f:e7:b6:ab:e3:4b:95:bc:b3:97:f6:e7:c6:23: + 86:9f:98:dd:0a:4a:cb:df:02:5d:1b:66:a9:58:f7:3d:b2:ec: + 1e:59:53:38:64:ad:0f:57:1b:5a:10:81:3d:f8:22:6d:af:b7: + ea:08:ca:b1:98:d6:66:89:a6:db:3a:c4:80:35:18:a3:7e:8f: + cc:32:16:d2:6b:15:83:68:15:15:ed:23:7d:f3:c3:df:a8:5e: + bb:0c:61:0e:3f:85:be:df:47:9a:58:c1:84:15:a9:14:14:e5: + f0:ae:2d:c8:dd:64:0d:db:e1:78:62:7a:2d:4e:31:bb:e4:3d: + fa:92:d9:ca:cf:b3:e2:25:79:33:b2:d3:9b:f4:c1:db:fe:24: + de:f5:47:cc:9b:d9:47:b6:b2:3c:e9:25:3d:15:5f:e1:e7:86: + 66:f1:4b:8c:56:bf:bc:13:db:cd:40:ab:45:8e:ba:f3:f0:67: + 9f:46:c6:72:c6:d6:33:7a:26:39:98:6c:13:cc:2a:cf:99:44: + ea:68:97:05:8c:dc:b9:45:a4:10:3b:43:66:af:15:44:0f:53: + c7:76:6c:b0:59:db:c5:85:c2:54:c9:5b:d0:ae:2b:c4:54:cf: + 38:60:2a:ac:a5:8f:65:15:d4:02:b1:a0:17:4b:c1:b5:5f:bf: + 6c:34:23:ee:33:f8:82:27:5d:8f:1b:58:b6:f0:b8:0f:dc:cb: + 76:19:e9:2d:b8:85:6f:55:1c:64:36:c8:8c:d3:84:c4:cd:f7: + a5:86:93:46:0a:73:45:e1:e5:cc:39:c5:f7:60:cc:ca:02:90: + 66:e0:ec:23:e9:23:c0:98:fb:75:e9:74:0b:89:9f:32:1a:68: + 89:96:db:d8:70:56:8f:85:e2:a8:39:08:fb:c0:53:8c:f2:af: + f2:79:0d:a8:d7:f1:e3:1f:fb:77:b6:70:f9:40:cf:f2:4f:5a: + eb:bc:6d:e9:f6:f1:f6:01:fe:83:1f:6f:29:d1:19:10:b5:1e: + 37:81:c9:0f:ab:5d:d6:34:80:cc:ba:bc:22:76:6c:f0:a3:1e: + cd:6d:fc:1b:8d:58:dd:a6:09:ea:3b:2a:ec:47:7b:b9:ae:e1: + b0:52:5d:86:92:5c:d1:26:66:79:5b:3b:e7:8e:61:4e:15:0a: + 55:23:cf:01:ac:12:e7:6b:13:52:3a:26:8f:a9:34:79:cc:d7: + 63:15:f8:9a:c3:5c:62:0e:fe:5a:c2:84:7b:69:fe:98:9a:c2: + ca:ef:63:93:86:4c:df:ac:95:31:b4:ed:c3:3d:87:87:03:da: + 35:5f:3c:38:27:c5:5e:05:4a:5e:4b:eb:44:ec:9b:be:b9:71: + 6d:63:de:14:de:73:0e:11:90:85:b7:8e:41:92:2a:da:7b:65: + 06:fc:86:01:3d:f0:bf:0d:45:44:51:36:c5:1b:9d:66:2f:61: + 1c:70:b1:81:63:4c:de:13:38:6a:91:ed:32:51:91:ae:92:bc: + 6d:4d:76:e1:14:39:88:3c:c5:2d:ee:95:16:b5:ec:54:40:cc: + e1:b0:ab:69:6e:3d:82:de:37:d2:b7:3a:be:89:6c:67:c5:c7: + 2b:2a:04:d8:08:4e:f2:a0:84:c2:6e:36:20:1a:e6:58:a5:5b: + 31:c9:74:ce:78:5f:4f:ef:d2:0d:95:75:f4:16:a7:61:87:17: + a7:b6:98:88:2e:8b:0e:fb:8d:f9:4e:6c:56:dc:38:5e:c7:db: + 15:86:d0:8f:e2:19:9a:e2:25:76:ac:46:05:22:77:a7:ca:f1: + 81:3b:f6:d5:1d:7c:e9:ea:89:fe:15:ea:6b:3c:28:77:d6:79: + dd:96:15:89:9b:97:1f:47:e6:95:c0:97:e4:18:3b:02:dd:4e: + 62:e1:1e:6b:78:43:e5:49:20:89:33:5b:1a:84:1e:f8:2e:12: + 73:61:85:09:b9:54:24:6e:c8:ee:b9:fa:52:78:4e:27:fb:39: + 02:59:09:46:f9:d0:be:03:78:b0:f2:17:80:72:25:ae:a3:2e: + 43:21:a3:70:6c:ec:70:2b:aa:9a:14:78:8a:b9:66:58:33:c8: + ec:6c:1f:52:f0:c9:20:55:d4:4d:88:fe:95:fd:6f:ee:ec:26: + a1:98:0e:3b:93:21:85:f5:5c:24:02:2c:ee:9e:e5:ae:c9:f6: + 5d:3f:a0:5e:75:66:19:38:ad:0d:42:c8:49:df:20:df:b6:a3: + 50:eb:de:ee:36:31:17:cc:c0:2e:cf:54:d1:5a:8c:54:3d:95: + a1:6e:75:c2:e0:e1:fc:ba:83:b0:04:1d:be:46:3c:ee:cf:e5: + a1:41:37:6f:41:72:7a:44:d2:3b:e6:42:d0:01:27:14:73:84: + 25:e1:f5:19:8f:b2:b3:53:2b:c8:f8:9c:7a:c2:87:21:e4:e4: + 69:76:1c:f2:b0:fb:b1:d2:fc:50:df:61:14:45:21:a0:5c:4d: + 30:89:52:8c:51:1e:6a:cf:02:b1:16:b8:3b:11:24:f0:e7:46: + 3b:45:d6:d7:ff:ac:f8:6f:dc:8f:96:ff:a8:56:cb:e6:05:cc: + 2f:cc:89:7d:52:9d:00:3e:56:8d:fd:ad:77:ff:06:c0:4d:e5: + 0a:22:b2:51:2a:f5:e8:e1:52:d4:ac:99:f2:96:bd:88:22:85: + c1:ce:45:3c:c6:66:b6:18:83:72:ff:03:35:04:f4:58:9d:64: + 31:5e:36:b9:8f:73:e7:4d:80:d8:85:5d:34:3b:69:be:f6:89: + f1:e2:69:8a:4f:67:45:72:f9:66:be:1c:8f:88:98:a8:f6:8a: + e2:ed:50:cb:b3:64:d7:50:a4:ee:97:d7:ae:a5:88:73:bb:10: + 28:18:47:c2:e0:00:8e:5b:e1:14:c5:9f:8a:6e:9b:5f:29:36: + 36:62:35:0f:89:6d:d6:5b:19:57:8c:bf:d1:31:be:e6:a4:f3: + 92:86:bc:be:75:f8:8a:a3:97:27:62:ae:b6:6f:54:31:64:85: + 67:0b:35:7b:d3:e6:fd:2d:6b:32:7b:2d:c0:c4:25:2a:9c:26: + c8:31:74:8f:a0:c4:4b:4c:89:ac:72:72:8b:f3:cc:74:16:a1: + 93:9c:3c:47:37:7f:3a:d0:63:b0:00:b6:64:63:5c:fc:8b:52: + 0d:ea:2a:52:bf:b7:b1:87:f1:dd:31:e4:97:74:52:0c:0f:2e: + c4:87:52:db:ff:3f:45:ad:2b:65:2f:3b:cc:05:55:c2:43:c8: + 20:34:9d:9a:92:3f:0f:a9:05:cd:b3:cf:96:9e:51:6e:d6:06: + e8:4b:a8:2a:e5:44:02:60:5d:04:94:91:bf:ee:e2:62:ac:6b: + 75:28:13:cb:b8:f5:5e:fe:24:e3:6e:96:50:f8:0b:b8:28:a4: + 8c:1c:94:24:a2:4f:57:d4:93:00:f9:f5:75:a6:80:79:a3:11: + 00:3d:83:3e:78:72:b3:b8:eb:9a:ba:a9:0e:ae:e3:00:85:de: + 29:91:03:ce:33:d3:3a:a6:74:06:7d:df:4b:6f:b2:cb:b0:ff: + 6f:99:91:bb:82:55:3a:d3:8f:f1:e9:d5:ec:d3:15:c7:2a:8f: + 3d:ad:69:6a:d3:72:f8:d2:5c:dd:e6:60:c4:36:90:2b:dc:5b: + 40:75:f1:b6:51:14:ae:2f:f8:39:1c:e4:98:cf:86:68:a5:5f: + 7e:9d:12:14:56:35:29:cb:a0:59:61:d1:28:33:d3:e6:6a:58: + 2f:3b:5e:f7:ac:69:99:98:1a:9d:15:a5:79:aa:2d:af:75:04: + 0b:42:d5:2e:87:a6:6a:6a:73:a3:74:da:11:cb:28:09:5c:83: + 86:c7:61:be:12:4e:37:d5:80:38:9a:7c:8d:84:7c:91:8e:2c: + 32:89:86:ba:94:bb:64:2e:48:ec:f1:4e:c2:c3:c1:9e:13:57: + 72:dd:b9:a0:f5:9a:5a:b1:65:00:5e:01:25:f4:ff:30:b2:df: + ae:91:84:fd:53:bb:87:6c:c8:fe:3e:5d:dd:e6:ae:57:ad:5c: + a9:66:0b:0c:f9:c7:d4:49:fa:06:19:d3:8e:88:f6:36:43:c3: + 72:f2:ad:03:4c:33:17:ee:69:a5:ae:4c:1a:21:40:28:54:8a: + 66:ef:74:c8:43:91:e2:9c:6e:a7:b2:f2:13:fd:e0:9a:d8:9f: + 36:de:e6:57:06:15:60:c4:3a:d7:f3:15:d0:40:b8:2e:97:65: + 30:c4:f6:88:39:c4:70:d8:83:a8:6f:bd:79:a2:1d:a0:3c:11: + 36:54:0e:67:f8:27:42:66:9a:96:78:f2:19:8d:7d:63:05:36: + 4b:6b:3a:1e:31:9a:e6:ed:cb:d4:b2:76:0f:5b:da:78:8d:4a: + b2:90:3b:0f:85:36:c7:5b:16:00:4c:38:d8:70:89:5f:94:48: + 34:fb:a6:7f:3e:91:36:2b:50:9c:a8:96:9f:b0:a7:40:43:b6: + e1:f2:c0:6c:e8:f2:d6:8a:ad:fe:10:ad:9f:da:38:89:c8:be: + 2c:b5:c7:bd:77:f7:79:0f:a0:52:73:5a:ea:b8:72:98:fe:70: + 78:77:bf:f3:a7:5a:d9:44:85:2e:d4:7a:21:ec:07:e8:61:c1: + 64:9f:3d:56:5c:cb:2e:c2:f7:7d:03:70:af:3e:f2:d5:8b:b7: + f6:53:88:eb:8e:70:a3:b0:eb:a6:9e:00:b7:ad:70:98:e2:6e: + 43:2d:c2:d2:09:94:64:c3:70:9a:92:d9:7f:cc:3e:bc:c0:58: + af:b5:23:c1:ca:a5:55:6a:49:ff:0e:e1:69:2c:cd:6a:8d:e4: + fc:00:41:80:c8:ee:89:ea:07:c5:31:c2:58:31:84:f9:9f:1e: + ce:11:ac:a7:4e:3d:d1:ea:4a:cd:9d:e9:22:80:1d:08:74:d8: + 37:be:ca:15:b4:7a:bf:f0:82:8f:60:ea:e2:e9:ba:71:0e:20: + 94:8a:b4:15:a1:3e:85:77:b1:d1:f0:90:5b:51:ad:9f:0b:f8: + 8f:40:f1:e2:7a:f3:b5:d6:9b:99:ce:a9:13:6b:7b:0a:46:7d: + a2:27:a1:5a:a3:5f:77:2f:9a:6b:63:ef:a4:a1:70:4c:a6:2b: + 01:24:06:3d:0f:1b:a4:50:0c:28:0c:8f:58:90:91:96:24:2d: + 7f:e2:aa:73:06:94:08:e1:19:9f:9c:64:b5:82:65:22:88:07: + d7:bf:b6:56:3e:77:e5:c8:bd:6e:8f:72:43:06:d4:1c:81:b5: + f1:ec:bf:7b:f4:a8:a9:03:f7:41:56:39:82:4d:5b:2e:96:32: + 47:c3:be:b0:00:da:c8:86:46:05:8b:d6:20:5e:c5:39:a9:61: + 8a:09:40:90:3b:76:65:8a:98:8f:d4:c4:a5:cb:40:a1:e3:cc: + 3b:25:06:1e:be:4c:5d:ca:69:e6:b2:aa:31:9c:08:2a:b3:60: + db:65:90:ea:16:95:1d:14:d2:63:37:97:8c:f1:c5:1a:c4:86: + 1f:be:60:7c:15:17:a7:26:d9:f0:ec:dc:f8:7b:6d:c3:32:d4: + de:7e:08:25:2d:26:aa:30:1a:bc:b0:5d:ff:46:0c:18:fb:bf: + db:96:f5:ca:59:a2:76:01:4e:82:3b:63:2f:89:53:10:9d:a3: + b6:57:fa:39:03:63:d2:5d:ce:a1:79:80:25:b7:1a:74:9f:1d: + d3:95:48:a5:3c:39:d9:a7:25:ef:63:29:0e:fc:fb:a5:6a:a4: + 7e:61:c9:c3:90:bc:f9:23:8a:b4:68:3f:5f:cb:de:4c:34:10: + 81:97:cd:a7:54:67:ed:b5:47:a3:75:06:89:fc:1f:70:65:86: + 2d:96:98:b9:16:92:f0:c2:bd:01:a2:8e:ac:2f:d2:03:68:6b: + 00:d4:81:7f:dc:a1:96:7d:b5:0f:76:16:b0:1a:2f:7a:bf:7c: + 4e:b8:a9:35:ba:40:5e:b3:ae:6e:8a:78:85:f8:cc:64:7d:88: + c9:2f:5c:1f:5f:19:eb:ce:2e:60:e9:e8:77:97:5b:63:11:e9: + e2:fb:81:e4:01:af:54:12:8d:be:aa:29:71:2d:54:74:c0:5f: + 07:88:8e:3a:05:86:05:56:3f:88:3a:77:54:c8:e4:94:67:29: + c4:b0:47:63:0b:d7:29:97:1f:d6:5e:22:76:a1:4d:2f:76:43: + 20:48:7a:44:ab:d7:52:25:7f:a9:14:e6:ac:98:34:22:5c:89: + 6f:c8:8d:20:2a:cf:bd:c6:19:7a:3f:1c:f6:6f:08:bc:22:6e: + 0b:78:8f:82:1c:26:b8:82:b8:ff:ec:23:7b:13:5c:95:7d:a5: + 04:3f:c7:87:ed:f2:d6:fb:a2:bc:a0:ac:f2:17:c4:e4:11:56: + c2:2f:5c:64:66:fd:0e:c0:10:38:6c:f7:6b:ff:62:15:27:55: + 45:5d:fc:f0:8e:36:68:66:72:96:40:13:7f:b2:b4:4a:ca:97: + f2:3f:a7:ec:38:95:7a:e4:cf:da:87:b7:aa:82:57:ff:7c:d5: + dc:fb:e2:a8:13:9b:2a:a6:6a:7c:82:0b:be:ef:71:67:92:9e: + 01:83:40:1a:71:64:b3:63:57:9c:55:a6:ee:de:68:85:78:70: + 97:82:f5:67:74:d4:94:b1:fe:fd:f4:4f:26:ed:49:55:78:5c: + b2:be:da:5d:f5:18:56:8a:58:4e:82:bf:88:34:8b:9c:d4:32: + 49:cf:56:ae:6d:d0:45:76:9d:c7:17:7c:90:34:b9:f5:ba:a4: + 32:92:7c:2f:77:bc:83:df:06:22:b4:f3:eb:d2:d3:36:22:32: + b8:c1:4a:44:96:b2:15:13:be:44:c3:fa:55:34:fc:32:37:10: + f2:28:39:c9:cd:d5:e0:b2:ac:d1:38:d7:71:06:50:08:68:c3: + 6a:ae:86:7e:b9:a8:3e:2a:5c:b2:6f:79:64:e2:00:b5:cd:d6: + 18:61:da:0b:93:4c:21:f7:9d:ca:e6:e8:5c:d3:75:53:38:c3: + 82:e5:35:e7:62:95:4e:73:67:11:27:22:6c:0a:ac:70:89:d5: + c8:aa:94:b1:52:5b:b9:51:35:d8:29:33:16:9a:83:95:e2:6c: + 0c:ba:e6:bc:b6:bb:26:5a:e4:92:1b:21:93:0c:03:73:ae:92: + 0b:2b:3c:f0:6e:5e:20:88:09:f1:07:f0:8d:02:15:d5:78:4f: + e1:d5:8a:42:ca:e1:09:fd:34:b5:3e:a4:0d:57:54:86:40:bb: + 5a:0e:8c:2b:86:58:f2:e5:9f:f3:b4:0b:41:1e:ad:41:d1:8c: + eb:60:e2:04:1d:97:d4:4f:53:69:34:72:c7:bd:df:cb:ae:29: + 37:31:69:1a:d4:ba:c1:56:33:ea:e3:d5:f2:9d:45:66:5b:ad: + e7:59:a3:34:fb:85:de:31:41:9f:d3:ca:71:30:5b:d5:f3:46: + ac:d2:60:ca:a8:c7:06:35:02:fa:0c:49:91:fd:a5:7c:22:81: + 2e:f6:74:ad:d0:da:5f:82:3a:3d:e5:aa:05:a1:fc:aa:c6:bb: + 48:22:da:0b:a8:7d:96:0f:54:76:c1:7b:6c:df:2f:2a:76:29: + 21:f7:8a:12:08:4d:d1:f5:80:13:d2:b8:f3:7a:62:fe:f0:d8: + 81:df:d8:32:ea:45:31:ac:6b:b7:58:f7:29:aa:1f:43:73:23: + ea:be:e2:cb:56:32:17:23:fa:25:8b:98:51:b4:b1:43:0d:0b: + 9c:5e:e7:d2:7c:1b:e0:4c:c5:df:88:fd:b7:2c:4a:19:3f:38: + 4d:6c:f0:ab:97:42:65:df:47:31:8e:76:4b:7a:9a:0f:65:67: + 07:c7:fe:84:af:de:e9:33:d3:97:4a:9f:78:74:aa:1f:99:8e: + 5e:15:59:f4:60:e5:3a:56:25:7b:52:b5:3e:ec:f2:1f:6b:3c: + 89:dc:58:01:9a:ec:dd:f3:21:c6:4e:57:e0:b6:80:1a:03:2a: + 9f:13:a9:92:d3:3b:b1:6b:db:1c:9e:7b:79:74:59:64:eb:8a: + 99:16:2f:bf:78:c1:de:a8:61:46:3d:93:0f:12:dc:0f:a6:d9: + ff:ae:b1:c2:2a:b3:aa:a3:6c:c1:fa:b0:a8:79:73:07:a4:2e: + 6f:ac:34:f4:99:c3:03:86:21:2c:17:e0:a3:b2:76:bd:32:31: + 9b:9a:98:35:d5:63:08:06:f1:3b:4e:d0:db:25:87:5f:75:14: + 33:ba:70:a3:a8:64:30:8b:3e:d0:cc:56:61:c6:ab:cc:8e:db: + ff:a9:38:bf:92:8c:30:08:bf:84:71:61:18:df:15:7a:01:cf: + d5:53:6d:f4:6c:64:5f:82:7e:14:b6:77:17:fc:d5:6c:44:02: + bf:41:db:ae:e6:d8:3e:29:50:c1:d7:be:63:cc:9c:27:26:49: + 8f:90:9b:cc:f4:c1:c4:82:8f:54:18:6e:f4:9f:d9:8f:03:5f: + 15:77:d7:fe:d0:a7:f7:21:ce:31:1a:05:9f:95:53:2e:cf:bf: + ec:f2:bc:81:8d:01:a9:47:74:71:0d:23:dc:28:45:93:b7:5d: + b7:98:7c:ef:25:e1:2b:25:9e:fe:47:34:29:e7:48:db:94:22: + bb:c0:d5:2a:03:74:4d:12:95:41:d4:dc:c1:97:af:f5:8c:e4: + e1:ff:39:a1:5b:3f:33:df:22:dd:ff:67:17:92:a3:f4:c1:af: + 6a:d9:27:17:ff:88:d0:3a:ee:d8:e9:32:b6:83:8c:46:6f:13: + 52:98:f3:66:90:be:e8:f3:0d:24:9c:7d:cf:e4:60:3c:eb:b3: + 78:70:a8:57:c5:22:fe:6b:1e:d2:31:ba:46:60:d2:ae:29:9c: + 47:fd:1b:28:89:aa:f9:af:f8:ca:c5:2e:e2:66:67:fc:75:2d: + 9f:6c:a2:48:d4:ea:93:2b:2a:7e:a5:11:31:64:d9:57:0c:75: + 79:cb:0d:2e:bf:0e:69:36:51:8e:46:7e:56:df:ad:56:73:09: + f8:78:29:f0:63:b2:a6:c3:b6:f2:83:54:c6:fa:75:f5:24:ef: + 5a:ba:bd:03:b2:ea:3c:d0:d8:cc:d2:45:00:be:75:38:ba:46: + af:09:a3:67:52:ea:46:d7:c7:01:74:cd:2f:48:df:f1:1f:64: + 2e:af:e5:99:76:b3:c3:3e:47:c8:be:2c:8a:1f:ec:4c:ea:16: + f8:09:b1:78:32:90:dd:75:bf:db:ce:ce:d9:96:7e:85:ac:c6: + a5:b9:c9:48:df:11:d3:eb:05:59:07:2c:a4:ac:06:d8:6f:b3: + b0:09:9b:0b:c4:ca:65:88:89:1e:76:fa:12:bb:66:cc:f8:7f: + d1:90:42:6c:f9:b9:5f:2d:9a:62:00:96:2e:ef:b2:5c:16:52: + d7:2e:b0:e6:52:f0:b6:d5:c2:d5:e9:73:c4:a1:42:c5:55:34: + 55:3a:75:c5:61:09:ac:a9:2d:70:d3:c7:c7:48:c8:8b:0c:2e: + 76:fb:7c:1b:e2:2a:1e:0e:d8:6a:95:b0:2c:2c:8f:43:13:56: + 68:d6:a0:85:66:9d:48:75:e0:46:89:3b:b0:b1:5d:3f:8e:a8: + d2:db:ae:35:2b:8d:b3:11:77:aa:c6:a5:11:e8:3a:d4:6b:ba: + 45:bf:44:e7:9e:63:6d:6c:11:58:c1:7a:74:d2:7d:85:78:ed: + ee:9e:dd:c5:07:b1:f5:c9:9e:d0:d6:d6:9e:2f:89:7f:67:47: + e1:51:79:72:f1:2a:5a:9f:7d:c6:8a:a3:9a:87:26:00:0a:06: + 2a:0a:95:f0:5f:6e:81:e1:71:cf:af:b3:3f:93:1b:23:47:d3: + 28:8d:8c:f6:c1:cc:12:03:c3:4f:dd:d5:e5:a9:87:2a:1f:c0: + ff:0a:69:7e:73:55:d7:87:79:9f:7d:fd:f4:f1:4b:79:49:d9: + 53:8c:58:22:e0:4f:21:bf:d6:56:cb:bd:b3:aa:a8:b4:d2:93: + 60:ac:f3:cd:57:80:27:11:ee:98:e8:c2:93:12:b6:a7:0d:a1: + 5c:e0:64:2d:8d:d7:09:70:ac:b3:c4:21:44:76:04:5d:f5:cb: + ec:15:ba:b6:1c:66:c5:72:3d:07:2e:b7:26:ae:26:8c:c0:01: + 46:7c:c7:85:63:35:6c:8d:47:bf:22:60:b3:40:e9:fa:05:06: + 7d:61:26:ed:ed:f2:b0:a2:fd:d0:e5:1b:ab:0a:8e:01:df:93: + 50:89:76:b6:ee:49:41:24:e6:41:cd:10:b1:48:73:f3:63:7c: + 72:41:83:23:89:cb:dc:af:f7:9c:7f:9d:55:68:f7:d8:c7:a6: + 57:75:38:0b:21:b6:37:b0:ec:ec:05:e6:f9:03:b7:b2:c4:fe: + d3:d2:29:29:a9:5d:54:ce:d4:72:4f:51:b7:a0:f4:45:95:f3: + 7a:2f:33:a4:3e:b0:34:f5:ff:68:1c:4a:6a:da:62:cd:1d:fe: + a7:ce:5a:b5:eb:79:08:cd:c2:78:d3:78:bf:04:af:7f:12:a2: + 5b:af:c0:b2:67:be:44:64:b6:d7:13:86:e2:bf:19:c6:e4:f6: + e0:4f:21:1f:68:1d:77:3f:6f:08:fa:54:cc:a7:b5:6a:6f:fd: + a7:9d:61:37:5a:94:46:af:71:2a:bc:8a:5e:44:d7:71:cb:49: + c2:fd:51:ff:d8:ab:35:23:1a:84:47:4e:a0:af:e5:55:ce:bd: + 49:76:57:35:4f:8b:90:23:a4:d0:11:a8:c9:bd:7e:7f:e5:d2: + c9:c0:4f:b0:95:13:25:ae:af:54:77:b1:e0:12:34:59:25:d1: + 8d:8f:36:2f:2a:ac:30:38:3e:4e:00:36:43:76:12:88:f3:d4: + c1:fa:73:e5:84:27:c0:57:94:4c:34:03:55:cc:ff:6e:a3:c2: + c5:d3:2f:2d:ac:7c:2b:74:3a:1f:40:74:df:92:60:d4:64:b4: + bb:6c:26:3e:88:6d:1d:96:e3:c6:44:01:5a:61:1f:9f:81:99: + 32:77:2e:ee:a6:85:9c:99:a5:b9:0d:e3:31:98:a9:38:bc:ee: + cf:65:07:85:5e:77:de:b7:b4:f8:91:1d:ca:45:47:00:b8:80: + ef:66:20:cb:f1:10:0f:d8:95:22:c1:fd:c1:98:29:1e:a6:44: + d6:2b:73:d9:73:31:fd:9d:fa:f2:b1:1b:eb:7e:3a:a3:fa:c4: + 8b:d6:49:54:c9:2b:1c:e7:14:00:ec:30:34:4f:c0:cf:10:5a: + 18:27:fa:c6:ff:21:11:6b:55:ff:d6:84:0b:e4:c7:0f:60:5b: + 59:d8:84:72:59:9f:e7:8b:70:8f:3f:5c:88:19:3e:b5:27:b7: + 45:ea:65:6d:7d:7c:86:55:7e:e1:a9:f3:5a:f4:3f:11:cd:ce: + 90:c8:f2:d9:a6:2d:04:ed:f1:89:40:1f:7f:4e:a4:e6:d6:b9: + af:e5:40:e9:b6:88:38:17:e3:49:98:b6:9e:ae:84:7e:5a:fa: + 03:85:7f:a1:9f:b3:1a:39:ee:7c:7f:e1:22:e3:9f:ec:f7:94: + 15:78:a1:a8:a1:10:8f:29:73:28:a9:c0:df:21:2f:a0:56:5e: + ea:fc:9f:7b:c2:96:4c:78:56:79:b3:be:de:54:80:04:a0:af: + 7f:f4:63:52:eb:30:ba:db:79:a3:9d:36:12:3a:79:03:76:6d: + ea:65:d2:b8:b3:ab:75:b6:0a:ee:09:be:fd:23:e9:32:76:4d: + 00:78:35:a1:b4:e5:4b:d6:a3:34:17:16:fd:9e:9d:d5:75:8e: + 3b:b1:84:8b:4b:8a:fc:e6:9a:4a:79:64:b0:0c:4d:5c:f0:b2: + 8c:b0:2c:d3:74:db:18:2d:18:7b:83:57:7c:fc:1d:09:9e:bb: + 0e:df:42:d0:8b:4e:5e:7f:ee:9f:bf:2c:d9:39:23:7b:e1:a1: + 47:b5:6f:c4:9f:62:85:e7 +-----BEGIN CERTIFICATE----- +MIIg8TCCAiugAwIBAgIUGrmlEei1Lm0G28g53xpQBCEe+UQwCwYJYIZIAWUDBAMa +MIGjMQswCQYDVQQGEwJVUzEQMA4GA1UECAwHTW9udGFuYTEQMA4GA1UEBwwHQm96 +ZW1hbjEYMBYGA1UECgwPd29sZlNTTF9TTEgtRFNBMRswGQYDVQQLDBJSb290LVNM +SC1EU0Etc2hha2UxGDAWBgNVBAMMD3d3dy53b2xmc3NsLmNvbTEfMB0GCSqGSIb3 +DQEJARYQaW5mb0B3b2xmc3NsLmNvbTAeFw0yNjA0MjgwODEwMDRaFw0yOTAxMjIw +ODEwMDRaMIGjMQswCQYDVQQGEwJVUzEQMA4GA1UECAwHTW9udGFuYTEQMA4GA1UE +BwwHQm96ZW1hbjEYMBYGA1UECgwPd29sZlNTTF9TTEgtRFNBMRswGQYDVQQLDBJS +b290LVNMSC1EU0Etc2hha2UxGDAWBgNVBAMMD3d3dy53b2xmc3NsLmNvbTEfMB0G +CSqGSIb3DQEJARYQaW5mb0B3b2xmc3NsLmNvbTAwMAsGCWCGSAFlAwQDGgMhACqM +jF2YEIFMAUeaq+RxTydF4qwQjpWAlJQwoaItuSqzo2MwYTAdBgNVHQ4EFgQUYpCQ +5Tp0GBv7aEAHpYOdcC5+yfAwHwYDVR0jBBgwFoAUYpCQ5Tp0GBv7aEAHpYOdcC5+ +yfAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwCwYJYIZIAWUDBAMa +A4IesQDzACESZkMN+yy+Er7tB0+ueBtMz+LohcvkaPBubmN44RAMPH0PVwPcrHOB +fMled+LQdwqxfgPMO/akGeTh3YnV3c8Lwheg/f0I2NPIEhyo3rugp7qBu8mwvQn9 +Bc/4iVw41w+mj4WYzT6jwZrpTGu7DiX8PYMZU4o4/+gb2ss1JD4c3oydg/cqnlJL +GwoU5rQfW94NP2iMq+na2GE3wsDjKLLfQQ7SkDDi9qQYoR9DxDCjaJ3B1oHRKi6m +an3Ho2tP8W5nXbAIS58PwZhPXhOARNfA1zLWr0Khy8CG89PbF4nt8b2v8+t28Sqc +DNnJhotG+ArPX+f7UKFp5V6leIFjWpwtpLIr1vrB+X56ATmxDxey5nSwAVlZFPZJ +a/ljSoQyg4Asz45OC/b/QUdrwvdUz0QJDhLNjo/wWASAIKhw26aojLo9lwbSDz3P +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 +-----END CERTIFICATE----- diff --git a/certs/slhdsa/gen-slhdsa-mldsa-certs.sh b/certs/slhdsa/gen-slhdsa-mldsa-certs.sh new file mode 100755 index 0000000000..163abde9e7 --- /dev/null +++ b/certs/slhdsa/gen-slhdsa-mldsa-certs.sh @@ -0,0 +1,168 @@ +#!/usr/bin/env bash +# +# Regenerate SLH-DSA root certificates and ML-DSA-44 entity certificates +# used by tests/test-tls13-slhdsa-{shake,sha2}.conf. +# +# Requires: OpenSSL >= 3.5 (native SLH-DSA + ML-DSA support). +# +# The ML-DSA-44 entity keys are reused from ../mldsa/ (mldsa44_bare-priv.der +# for the server, mldsa44_seed-priv.der for the client) so this script does +# not generate or write new entity private keys. + +check_result(){ + if [ "$1" -ne 0 ]; then + echo "Failed at \"$2\", Abort" + exit 1 + else + echo "Step Succeeded!" + fi +} + +# Always operate inside the script's own directory so relative paths +# (../mldsa/, ../renewcerts/) resolve regardless of where the script +# was invoked from. +cd "$(dirname "$0")" + +# Capability probe: bail out cleanly if the local OpenSSL doesn't speak +# SLH-DSA (e.g. < 3.5). The committed PEM/DER under this directory are the +# authoritative test fixtures; this script is for renewal only. `-help` +# prints regardless of algorithm support, so we actually try a generation +# (output discarded) and check the exit code. +if ! openssl genpkey -algorithm SLH-DSA-SHAKE-128s -out /dev/null \ + >/dev/null 2>&1; then + echo "OpenSSL does not support SLH-DSA" + echo "Skipping SLH-DSA certificate renewal" + exit 0 +fi + +if ! openssl genpkey -algorithm ML-DSA-44 -out /dev/null \ + >/dev/null 2>&1; then + echo "OpenSSL does not support ML-DSA" + echo "Skipping SLH-DSA certificate renewal" + exit 0 +fi + +CNF=../renewcerts/wolfssl.cnf +SERVER_KEY_DER=../mldsa/mldsa44_bare-priv.der +CLIENT_KEY_DER=../mldsa/mldsa44_seed-priv.der + +if [ ! -f "$SERVER_KEY_DER" ] || [ ! -f "$CLIENT_KEY_DER" ]; then + echo "Missing reused ML-DSA-44 entity keys under ../mldsa/" + exit 1 +fi + +# wolfSSL example server only loads PEM keys from CLI, so emit a PEM +# transcoding of each reused DER key under this directory. These are +# byte-for-byte the same key material as the source .der files; we just +# wrap them in PEM headers so the .conf-driven test harness can use them. +SERVER_KEY=server-mldsa44-priv.pem +CLIENT_KEY=client-mldsa44-priv.pem + +openssl pkey -in "$SERVER_KEY_DER" -inform DER -out "$SERVER_KEY" +check_result $? "Convert server ML-DSA-44 key to PEM" +openssl pkey -in "$CLIENT_KEY_DER" -inform DER -out "$CLIENT_KEY" +check_result $? "Convert client ML-DSA-44 key to PEM" + +# $1 = tag (shake|sha2), $2 = OpenSSL algorithm name +gen_variant() { + local tag=$1 + local alg=$2 + local root_base="root-slhdsa-${tag}-128s" + + echo "=====================================================================" + echo " Generating ${alg} root + ML-DSA-44 entity certs (tag=${tag})" + echo "=====================================================================" + + ############################################################ + # Self-signed SLH-DSA root + ############################################################ + echo "Generating ${root_base} key + self-signed cert" + openssl genpkey -algorithm "$alg" -out "${root_base}-priv.pem" + check_result $? "Generate SLH-DSA root key (${tag})" + + echo -e "US\\nMontana\\nBozeman\\nwolfSSL_SLH-DSA\\nRoot-SLH-DSA-${tag}\\nwww.wolfssl.com\\ninfo@wolfssl.com\\n.\\n.\\n" | \ + openssl req -new -key "${root_base}-priv.pem" -config "$CNF" -nodes \ + -out "${root_base}.csr" + check_result $? "Generate root CSR (${tag})" + + openssl x509 -req -in "${root_base}.csr" -days 1000 \ + -extfile "$CNF" -extensions ca_ecc_cert \ + -signkey "${root_base}-priv.pem" \ + -out "${root_base}.pem" + check_result $? "Generate root cert (${tag})" + rm -f "${root_base}.csr" + + openssl x509 -in "${root_base}.pem" -outform DER > "${root_base}.der" + check_result $? "Convert root cert to DER (${tag})" + openssl pkey -in "${root_base}-priv.pem" -outform DER \ + -out "${root_base}-priv.der" + check_result $? "Convert root key to DER (${tag})" + + openssl x509 -in "${root_base}.pem" -text > tmp.pem + mv tmp.pem "${root_base}.pem" + + ############################################################ + # ML-DSA-44 server cert signed by the SLH-DSA root + ############################################################ + local server_cert="server-mldsa44-${tag}.pem" + echo "Generating ${server_cert}" + echo -e "US\\nMontana\\nBozeman\\nwolfSSL_SLH-DSA\\nServer-mldsa44-${tag}\\nwww.wolfssl.com\\ninfo@wolfssl.com\\n\\n\\n\\n" | \ + openssl req -new -key "$SERVER_KEY" -config "$CNF" -nodes \ + -out "server-mldsa44-${tag}.csr" + check_result $? "Generate server CSR (${tag})" + + openssl x509 -req -in "server-mldsa44-${tag}.csr" -days 1000 \ + -extfile "$CNF" -extensions server_ecc \ + -CA "${root_base}.pem" -CAkey "${root_base}-priv.pem" \ + -set_serial 01 \ + -out "server-mldsa44-${tag}-cert.pem" + check_result $? "Sign server cert (${tag})" + rm -f "server-mldsa44-${tag}.csr" + + openssl x509 -in "server-mldsa44-${tag}-cert.pem" -outform DER \ + > "server-mldsa44-${tag}.der" + check_result $? "Server cert to DER (${tag})" + + openssl x509 -in "server-mldsa44-${tag}-cert.pem" -text > tmp.pem + mv tmp.pem "server-mldsa44-${tag}-cert.pem" + + # Server-served chain: leaf || root (ed25519 convention) + cat "server-mldsa44-${tag}-cert.pem" "${root_base}.pem" > "$server_cert" + rm -f "server-mldsa44-${tag}-cert.pem" + + ############################################################ + # ML-DSA-44 client cert signed by the SLH-DSA root + ############################################################ + local client_cert="client-mldsa44-${tag}.pem" + echo "Generating ${client_cert}" + echo -e "US\\nMontana\\nBozeman\\nwolfSSL_SLH-DSA\\nClient-mldsa44-${tag}\\nwww.wolfssl.com\\ninfo@wolfssl.com\\n\\n\\n\\n" | \ + openssl req -new -key "$CLIENT_KEY" -config "$CNF" -nodes \ + -out "client-mldsa44-${tag}.csr" + check_result $? "Generate client CSR (${tag})" + + openssl x509 -req -in "client-mldsa44-${tag}.csr" -days 1000 \ + -extfile "$CNF" -extensions client_ecc \ + -CA "${root_base}.pem" -CAkey "${root_base}-priv.pem" \ + -set_serial 02 \ + -out "client-mldsa44-${tag}-cert.pem" + check_result $? "Sign client cert (${tag})" + rm -f "client-mldsa44-${tag}.csr" + + openssl x509 -in "client-mldsa44-${tag}-cert.pem" -outform DER \ + > "client-mldsa44-${tag}.der" + check_result $? "Client cert to DER (${tag})" + + openssl x509 -in "client-mldsa44-${tag}-cert.pem" -text > tmp.pem + mv tmp.pem "client-mldsa44-${tag}-cert.pem" + + cat "client-mldsa44-${tag}-cert.pem" "${root_base}.pem" > "$client_cert" + rm -f "client-mldsa44-${tag}-cert.pem" + + echo "Variant ${tag} complete." +} + +gen_variant shake SLH-DSA-SHAKE-128s +gen_variant sha2 SLH-DSA-SHA2-128s + +echo +echo "All SLH-DSA / ML-DSA-44 test certificates regenerated." diff --git a/certs/slhdsa/include.am b/certs/slhdsa/include.am new file mode 100644 index 0000000000..2d9a1bdd37 --- /dev/null +++ b/certs/slhdsa/include.am @@ -0,0 +1,36 @@ +# vim:ft=automake +# All paths should be given relative to the root +# + +EXTRA_DIST += \ + certs/slhdsa/bench_slhdsa_shake128s_key.der \ + certs/slhdsa/bench_slhdsa_shake128f_key.der \ + certs/slhdsa/bench_slhdsa_shake192s_key.der \ + certs/slhdsa/bench_slhdsa_shake192f_key.der \ + certs/slhdsa/bench_slhdsa_shake256s_key.der \ + certs/slhdsa/bench_slhdsa_shake256f_key.der \ + certs/slhdsa/bench_slhdsa_sha2_128s_key.der \ + certs/slhdsa/bench_slhdsa_sha2_128f_key.der \ + certs/slhdsa/bench_slhdsa_sha2_192s_key.der \ + certs/slhdsa/bench_slhdsa_sha2_192f_key.der \ + certs/slhdsa/bench_slhdsa_sha2_256s_key.der \ + certs/slhdsa/bench_slhdsa_sha2_256f_key.der \ + certs/slhdsa/gen-slhdsa-mldsa-certs.sh \ + certs/slhdsa/server-mldsa44-priv.pem \ + certs/slhdsa/client-mldsa44-priv.pem \ + certs/slhdsa/root-slhdsa-shake-128s-priv.pem \ + certs/slhdsa/root-slhdsa-shake-128s-priv.der \ + certs/slhdsa/root-slhdsa-shake-128s.pem \ + certs/slhdsa/root-slhdsa-shake-128s.der \ + certs/slhdsa/server-mldsa44-shake.pem \ + certs/slhdsa/server-mldsa44-shake.der \ + certs/slhdsa/client-mldsa44-shake.pem \ + certs/slhdsa/client-mldsa44-shake.der \ + certs/slhdsa/root-slhdsa-sha2-128s-priv.pem \ + certs/slhdsa/root-slhdsa-sha2-128s-priv.der \ + certs/slhdsa/root-slhdsa-sha2-128s.pem \ + certs/slhdsa/root-slhdsa-sha2-128s.der \ + certs/slhdsa/server-mldsa44-sha2.pem \ + certs/slhdsa/server-mldsa44-sha2.der \ + certs/slhdsa/client-mldsa44-sha2.pem \ + certs/slhdsa/client-mldsa44-sha2.der diff --git a/certs/slhdsa/root-slhdsa-sha2-128s-priv.der b/certs/slhdsa/root-slhdsa-sha2-128s-priv.der new file mode 100644 index 0000000000000000000000000000000000000000..ba68f102d6ddab28e09405b7cafc2bbfc1e6a0c1 GIT binary patch literal 84 zcmXpAVq#=4;AZ1YX!Br9WoBU(VR7)_*?G))|LvQ%W<@GTzDN$?`En(!a#!2G)2~+= riZiS@zU+a@3NHx(-?PVVDXXO4n>MwPVcDs3&QJdSsg~;b^|}rKBhe+s literal 0 HcmV?d00001 diff --git a/certs/slhdsa/root-slhdsa-sha2-128s-priv.pem b/certs/slhdsa/root-slhdsa-sha2-128s-priv.pem new file mode 100644 index 0000000000..4607e1650f --- /dev/null +++ b/certs/slhdsa/root-slhdsa-sha2-128s-priv.pem @@ -0,0 +1,4 @@ +-----BEGIN PRIVATE KEY----- +MFICAQAwCwYJYIZIAWUDBAMUBEBIDLnGQ7/b2dqaWSNZ6GNUDPTUVnm6hv7L66kx +FwCox6bgJKhKGBBNzcbaIyRn3paVgQCmys5D5P38exqM+ut+ +-----END PRIVATE KEY----- diff --git a/certs/slhdsa/root-slhdsa-sha2-128s.der b/certs/slhdsa/root-slhdsa-sha2-128s.der new file mode 100644 index 0000000000000000000000000000000000000000..3b8bce092d40c2b6bd000ebd6e7d9d222831eb6d GIT binary patch literal 8435 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 literal 0 HcmV?d00001 diff --git a/certs/slhdsa/root-slhdsa-sha2-128s.pem b/certs/slhdsa/root-slhdsa-sha2-128s.pem new file mode 100644 index 0000000000..0c646aa929 --- /dev/null +++ b/certs/slhdsa/root-slhdsa-sha2-128s.pem @@ -0,0 +1,644 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 65:47:75:b4:58:fa:b2:e1:1f:16:b5:5f:25:49:b4:7f:2a:12:60:56 + Signature Algorithm: SLH-DSA-SHA2-128s + Issuer: C=US, ST=Montana, L=Bozeman, O=wolfSSL_SLH-DSA, OU=Root-SLH-DSA-sha2, CN=www.wolfssl.com, emailAddress=info@wolfssl.com + Validity + Not Before: Apr 28 08:10:05 2026 GMT + Not After : Jan 22 08:10:05 2029 GMT + Subject: C=US, ST=Montana, L=Bozeman, O=wolfSSL_SLH-DSA, OU=Root-SLH-DSA-sha2, CN=www.wolfssl.com, emailAddress=info@wolfssl.com + Subject Public Key Info: + Public Key Algorithm: SLH-DSA-SHA2-128s + SLH-DSA-SHA2-128s Public-Key: + pub: + a6:e0:24:a8:4a:18:10:4d:cd:c6:da:23:24:67:de: + 96:95:81:00:a6:ca:ce:43:e4:fd:fc:7b:1a:8c:fa: + eb:7e + X509v3 extensions: + X509v3 Subject Key Identifier: + BD:80:23:3A:06:DD:38:57:EE:6B:C2:94:7B:EA:BF:43:57:3A:B0:8C + X509v3 Authority Key Identifier: + BD:80:23:3A:06:DD:38:57:EE:6B:C2:94:7B:EA:BF:43:57:3A:B0:8C + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + Signature Algorithm: SLH-DSA-SHA2-128s + Signature Value: + 10:3c:70:c5:f5:b1:4f:1c:77:85:34:b9:b3:57:97:62:ef:e7: + 4d:17:67:56:63:74:02:e1:50:5c:5b:dc:56:94:45:d7:f9:6b: + 76:fd:fb:e2:00:16:0b:5a:0f:86:86:7e:1e:0c:4e:7f:d0:95: + cb:d4:8d:09:58:53:4e:e2:9f:0e:11:2e:38:dc:c0:87:ec:6f: + 25:ef:1b:59:81:ab:71:69:51:2e:3c:2f:f6:eb:f2:22:73:62: + e1:a2:68:b3:67:db:2e:05:16:fa:bc:ae:b6:22:cb:c2:0f:fd: + 88:1e:36:43:27:13:de:61:01:0c:ba:5a:df:0a:69:17:45:c2: + 77:b5:df:87:62:b3:16:6e:8e:57:e0:3b:9f:02:80:5d:f0:92: + 76:51:73:2e:7a:25:1c:88:79:dd:0d:55:c5:73:94:b3:76:52: + 39:fb:58:0d:34:fe:74:38:45:fc:99:39:87:c7:fe:4b:2a:7c: + 51:ae:92:ee:5f:28:16:13:04:b5:f0:5f:93:90:74:d0:e0:f4: + 1d:06:af:6b:ad:33:fe:2c:d5:9a:e5:10:32:7f:01:2f:7e:97: + c6:ff:b6:57:97:56:cc:5a:5a:9a:79:de:19:b0:9c:0b:57:bb: + bb:e5:8b:91:2c:cd:19:2d:7c:75:8e:71:4f:c5:c5:88:74:5c: + 5d:27:82:dc:94:58:7d:6e:71:6e:78:c5:f3:0d:3b:85:95:2a: + da:4d:af:34:a9:3c:02:88:cc:45:1d:08:0c:9d:20:39:73:06: + 0a:2d:ba:8a:5d:a9:44:32:24:32:b1:d1:fd:d1:7f:b4:10:56: + 3a:15:12:a5:f6:c1:6f:16:ef:84:5e:86:ab:5b:9b:a7:b4:21: + e3:43:86:1a:50:f8:95:b3:b0:10:56:0e:26:b6:5a:46:75:51: + e2:7a:5a:76:2b:14:4e:57:5d:88:61:27:16:8c:e0:6a:ad:87: + b1:19:89:80:87:aa:6a:59:69:18:fc:e3:5a:78:83:d8:58:3a: + ec:8e:b9:28:2a:22:e6:13:8f:ad:df:4e:4d:9e:99:6b:34:9a: + c5:c1:81:0e:28:1a:16:e5:60:d1:7d:1c:d7:5f:f8:3e:7d:1c: + 7c:2d:18:5f:3a:5c:d2:d2:0b:db:c4:4f:69:57:a7:6d:60:95: + 5e:04:fb:71:31:71:d1:e4:ee:dd:10:34:a5:9b:0c:7b:29:e9: + 4b:85:3a:2f:64:87:93:9a:8f:06:9f:75:8a:c2:b3:a6:0c:ff: + 94:7a:c8:f4:e6:14:31:b1:6f:20:ad:34:5c:3f:1a:67:c7:0e: + 0e:89:00:c5:9f:d6:56:4b:8d:86:dc:64:94:e0:7e:4d:8b:cd: + 43:5f:3b:46:c9:92:f0:a4:0d:df:b9:ab:38:aa:5b:3b:9c:af: + fa:fb:d5:f6:0b:25:96:30:33:28:3d:3f:1e:a6:10:43:58:53: + ae:88:a7:5b:8e:55:66:57:2e:0d:88:a9:5b:d3:71:0a:23:05: + 47:82:ca:e6:0c:c8:d1:f2:99:9f:c9:37:2a:59:99:d4:f0:a5: + 82:18:0b:98:f0:ee:be:0f:11:6f:2a:6a:14:dd:c4:c9:bc:ed: + 80:ac:7c:ca:65:eb:fa:af:b3:29:a7:b2:c3:1c:42:1e:7d:3f: + d3:1a:f0:1b:30:f5:a3:53:8c:13:d3:96:82:01:a8:2e:d2:ae: + ea:f1:50:17:ae:cb:a4:7b:55:72:55:8b:90:28:f0:d9:5b:81: + f4:78:9b:b0:fe:a0:c4:6e:dc:25:fc:94:64:71:12:bf:fc:cd: + 31:50:26:2d:e2:ef:38:05:14:82:b6:62:83:a9:86:cb:df:05: + ef:27:6a:cc:2c:8f:1c:5d:40:13:c1:e3:24:a6:7d:3c:83:1a: + 78:79:7d:63:75:4f:68:b9:9c:75:b9:07:ed:62:16:29:22:c1: + cd:f2:52:02:e9:17:b0:d0:44:13:9c:25:c7:fd:39:df:eb:d5: + 32:5e:bf:c5:47:81:18:83:63:96:89:4c:31:02:8f:c4:e9:7f: + 27:8e:01:3f:44:4e:96:b0:73:ad:56:a7:95:4d:ab:a3:03:e2: + dc:33:65:d2:17:87:e8:07:be:95:17:64:3e:6c:87:cd:3a:e6: + 0a:b8:e6:8b:e2:e9:d9:60:2a:ef:d5:c8:2f:7a:8d:ec:70:16: + 10:a2:1d:12:16:41:a3:c1:07:2f:95:b1:d4:7f:9f:ca:16:ca: + 72:1d:2d:df:3a:6f:93:eb:9e:76:34:3f:dd:a7:47:12:18:5b: + f4:34:2b:73:42:33:15:c8:19:0c:a8:10:d5:d3:04:81:e2:d1: + b4:3f:7e:53:34:d8:db:02:d6:60:b4:24:8c:28:4d:31:51:0b: + 4e:c8:f1:4c:99:98:a7:36:ab:bc:ce:a2:d6:67:f5:b2:64:ec: + 0e:e3:f3:82:46:d3:87:ce:1b:a9:46:d3:dc:1a:27:e2:5f:bf: + 55:33:ca:e0:de:02:84:26:ed:57:58:27:f4:d6:3c:0d:a7:db: + 40:2d:d8:c8:0c:84:47:97:fb:bf:49:8c:d2:1c:80:ff:da:d6: + 3f:93:00:77:f3:31:f0:c8:57:46:5a:9a:15:25:0b:2d:d1:1b: + 5a:eb:ae:09:0e:3e:24:e6:a9:eb:72:be:e4:45:d2:41:db:21: + dd:a7:1b:6e:62:3e:43:d9:62:34:31:62:76:d4:2e:39:48:fd: + 54:9c:51:6a:f7:71:44:88:c0:c3:98:3b:66:e1:8e:0a:9d:e3: + 68:a9:6a:d2:52:80:97:3d:9e:14:c9:bc:36:33:6f:24:9c:7b: + e1:8a:a5:a1:12:44:bf:61:a2:3b:da:18:b9:7f:9f:89:bb:10: + 33:8f:46:18:92:49:5e:10:81:a6:0b:06:19:19:a3:e8:06:c8: + fe:4e:94:20:de:70:36:7b:40:ee:04:ca:fc:fa:81:aa:87:9d: + ad:f3:57:78:0c:34:51:f4:fa:ef:78:58:1e:e9:0f:b9:75:f6: + a5:09:a0:91:7f:80:19:80:17:4b:5c:a9:b9:6d:b6:00:f8:17: + 90:e1:b7:4f:21:33:64:1d:d1:d5:a8:78:a0:98:46:0a:0a:0e: + 72:dc:2a:67:8e:57:44:00:76:2e:79:b9:4e:c7:78:b2:a7:12: + 17:75:44:6c:ce:a6:d7:ae:25:54:6c:5d:eb:3d:92:74:65:26: + f7:6d:23:1a:43:91:ad:2e:20:c8:f4:fa:13:a9:97:ea:7e:a9: + 61:94:81:a7:cd:b3:60:a9:62:4c:ec:8b:91:21:a9:d3:7c:39: + 9f:3f:4c:f8:8f:16:81:3f:23:3a:20:64:7a:10:ce:82:d7:24: + 28:ea:e0:74:6a:ea:62:bd:e3:06:90:1e:92:ca:fa:2d:25:a5: + 70:52:8f:a1:3f:9f:7a:7a:f3:55:4d:4b:8b:1d:1e:ce:d0:61: + 44:68:e5:c2:69:e8:14:2f:5c:90:96:72:8f:7e:39:61:c1:d4: + 3d:36:bf:12:b4:de:31:3e:7e:f4:45:d9:6b:d8:9c:61:06:fe: + 7d:43:ae:e3:c8:f4:3b:0d:7a:5d:b6:35:46:5d:5b:30:e9:9f: + de:49:53:d8:a7:97:61:33:ec:fe:dd:4a:89:c3:db:aa:39:4b: + 01:f8:20:27:a3:0b:12:2f:03:fd:8d:69:5f:90:2a:62:97:93: + a6:d4:12:80:ee:98:47:93:d9:89:7d:46:f3:2d:61:8e:e6:9d: + 7e:7e:42:07:0f:3e:15:08:9b:49:36:98:1c:1e:dc:57:5d:eb: + ab:35:4b:33:eb:2f:fd:a5:6e:92:45:5d:21:df:d4:74:83:02: + a9:3c:bd:88:ed:d7:05:da:b5:2a:56:e1:ae:7c:53:a8:9d:f3: + 24:bf:82:1d:09:20:66:b9:b8:4b:ee:b7:e0:9a:15:e3:99:bc: + e3:93:a4:2e:93:4a:c2:0c:8b:42:ee:29:42:f5:93:e9:b6:73: + 8d:8d:24:4c:78:26:b7:dc:64:c7:94:8e:f3:2f:81:68:91:a5: + 57:ec:c7:b3:7d:73:02:d0:20:18:16:7a:3b:dd:e9:65:08:84: + 6b:40:19:f6:79:71:13:ca:8f:be:8a:ae:c2:a4:67:ae:0e:5b: + a8:55:01:38:5a:0e:0a:51:04:57:12:76:e6:cf:d8:57:25:a7: + 8c:03:da:22:13:dd:90:e1:27:26:e0:d8:dc:9b:5a:6b:3a:0f: + e2:e3:8d:54:73:6e:12:02:72:f4:2b:c3:9b:80:3f:6f:fb:8a: + 9e:fd:bb:e4:d7:c6:14:8a:19:d6:9f:30:bc:00:98:41:92:2b: + bd:a5:8e:ab:93:89:9d:6e:d4:8e:82:17:88:a6:19:2b:8b:a4: + 67:e9:5b:ee:7f:bb:e6:a4:d7:cd:85:7a:c1:2d:15:8b:3d:4e: + 25:71:63:5c:7e:72:b7:bc:e7:8e:a8:ad:d5:a4:2f:d2:56:cf: + b1:29:49:03:9e:d3:b9:ce:35:60:8d:d3:50:97:5f:4e:ac:72: + f4:b0:20:e4:91:75:cc:27:5e:ce:ae:04:77:1b:84:02:fe:0c: + bc:a7:dd:62:3e:55:e9:e7:5b:a3:c8:1d:08:34:18:53:bd:fa: + 05:0c:e9:fc:84:73:0d:4b:9f:56:52:e5:09:e8:46:43:3b:4e: + 59:fa:84:67:d5:c2:94:3d:ea:cb:9d:29:31:4d:91:61:90:f2: + 1f:29:68:dc:34:5f:13:fd:b1:f2:38:72:85:f1:16:1c:7f:05: + e5:b8:32:57:3f:6a:68:ce:e5:58:1a:14:e5:1f:e7:b7:1c:04: + a6:e1:c5:86:c8:78:e3:62:92:fd:ff:9b:f1:e8:60:9c:40:b9: + 1c:1d:7b:52:ad:ee:de:fa:04:bf:0b:bd:d9:34:bf:ef:4a:1b: + f2:0c:72:43:1e:55:24:b1:56:ae:0c:44:99:ef:b5:fb:e5:ee: + c6:20:7c:15:5f:66:c8:32:c3:e0:33:76:00:d3:b0:7e:be:0a: + 28:79:3f:98:51:78:12:73:ae:b3:24:a5:a1:d3:1c:f8:6c:5a: + e7:c0:47:5f:86:a5:67:d5:3b:20:19:49:91:fd:c6:32:0c:96: + e9:df:ea:e1:8e:cf:4a:bd:9f:95:eb:88:2c:3c:f6:34:da:89: + f7:3a:d1:bb:0f:97:f0:38:99:ec:89:b4:b3:92:bf:ed:13:7d: + bc:14:54:16:63:01:f3:60:f0:f6:c4:e0:db:00:dc:c8:5f:13: + 11:82:1d:04:73:a4:f1:8d:d0:8e:7a:4d:1f:9c:0e:8d:dc:fe: + 7d:8f:97:5e:a1:97:c2:73:e7:45:94:19:19:93:f5:4f:fc:25: + 8b:c3:1a:19:a7:1d:91:0a:bf:28:78:41:06:7d:09:d4:95:c5: + d2:8f:47:04:cf:3f:9a:be:72:b0:8a:d0:29:0d:87:b8:22:11: + 2a:c6:c7:27:81:12:6f:9e:18:88:9c:8a:25:04:05:66:b1:ef: + b1:4c:48:f7:f7:53:ec:c8:72:bc:70:25:5e:19:be:3c:d7:f6: + 1a:52:77:05:15:db:ba:99:2a:d6:bd:ce:a1:70:fc:30:40:cc: + bd:4d:e4:36:f0:fc:b9:54:31:48:d3:9c:bb:3b:51:08:a5:e8: + b0:3b:5b:0a:69:91:2c:f7:d4:50:07:4c:a8:2f:7b:43:82:64: + fb:c3:ca:48:5c:b9:f7:f3:bc:d6:21:43:c3:b5:26:61:06:86: + 23:c6:7f:05:d7:0b:c1:e5:7d:5f:5a:c3:09:1a:7c:06:cb:35: + f8:a3:70:13:14:37:b6:98:00:88:24:b0:90:4f:f4:99:99:75: + d5:15:23:7b:5a:09:db:33:30:8b:b9:da:b2:08:7c:ea:39:3c: + 88:96:a8:39:da:1e:22:5a:b3:be:f7:40:58:7a:6d:7b:88:de: + 4c:57:30:f1:38:a5:cc:6a:e7:b3:c4:ef:8a:f1:4d:ca:2c:bf: + 5b:05:02:30:97:10:12:dd:3f:8a:bf:0a:86:4f:57:63:79:bc: + 2c:21:a2:c2:07:26:a4:96:d2:1a:d2:73:86:a9:af:2d:ca:ae: + 6f:07:e7:26:f4:47:65:8e:0e:29:8f:ca:ce:16:cd:90:00:f0: + a6:19:a4:30:b8:d7:8a:da:de:5a:5b:54:91:9a:e1:75:6b:49: + f6:b8:67:0d:02:d2:c4:ec:67:f5:0f:c2:dc:11:c5:65:69:f5: + 1f:44:44:af:1f:91:9c:29:1f:8b:e1:8e:9d:5c:9e:ac:72:fa: + 4b:c9:29:9a:f1:1e:d1:64:6b:8e:22:5a:34:0f:53:47:ce:0b: + e3:07:49:cb:86:de:35:ec:17:e4:d5:df:cb:f4:de:0c:e1:b8: + 93:97:88:9e:f6:0d:b3:fa:f7:4b:a6:52:ef:48:61:c1:43:f2: + 32:f7:af:77:ab:75:c0:6c:08:b6:cd:63:cb:b6:64:e8:01:ed: + e4:62:39:36:38:ab:70:4d:c3:a4:b4:92:be:79:e0:f2:7d:7f: + 06:52:48:bd:ba:c2:56:6d:af:1f:86:b6:7a:eb:e9:b4:fc:8c: + 13:83:fc:25:f8:93:5f:52:c4:bb:4a:08:5a:a0:bf:bd:24:37: + 4b:44:e4:a7:ea:fa:36:49:dd:86:1a:f9:f0:24:1b:ab:c1:1e: + 8c:03:f8:8a:86:99:fd:3d:9d:9f:68:1a:96:47:73:18:22:3b: + 7b:c0:76:02:1d:61:79:73:ac:f9:2c:45:ce:87:53:b5:f5:44: + 8d:73:9b:38:d9:bb:a4:11:fd:f8:0c:16:c6:74:49:f0:e0:18: + 10:c6:d1:2c:2b:5d:c4:17:72:60:e0:7c:d9:48:b3:eb:38:ba: + 4f:e9:82:c2:10:9a:cd:bd:8e:e8:ff:be:f0:57:d8:e5:94:50: + 15:6d:87:42:32:8b:d7:8a:07:22:8e:e2:31:e7:95:9b:22:4f: + 5d:0d:51:02:49:1e:fc:66:51:bb:81:01:96:64:63:d8:57:43: + 66:0d:1f:6c:b4:9a:16:b6:dd:09:c8:6d:0e:c0:79:1f:a6:49: + c8:11:79:d1:18:34:9a:4e:4f:1d:80:1e:47:5b:75:07:a1:74: + fa:52:d2:69:d1:24:d7:2a:cd:72:c6:c8:ec:7d:6b:6b:b6:f9: + e5:5e:9e:d4:24:a0:00:df:ab:b9:6d:57:58:90:18:ac:1c:bd: + af:c1:88:d8:90:5c:82:de:fa:4b:40:51:01:6d:45:c2:83:18: + a3:38:ca:e6:5d:c0:5a:dd:b9:68:0e:0d:c3:c2:f8:6a:8c:ee: + a8:6f:19:c2:d6:78:d6:57:33:7a:fb:c6:0a:db:47:aa:55:89: + 47:a6:20:6f:0b:78:84:69:20:da:b5:6c:1b:d3:2c:d7:db:94: + 38:e0:75:e7:6c:8f:4d:f5:e5:42:16:c6:91:93:6a:41:39:a5: + 77:92:02:49:63:0f:74:c3:b2:55:3f:b1:33:e5:7b:d9:ff:59: + ae:a1:6e:1c:06:bf:76:98:dc:ae:94:39:49:3f:5d:d6:b0:fa: + 06:3e:29:8e:40:62:b8:b7:dc:22:11:50:48:19:41:37:c5:e4: + 34:b8:25:60:98:ed:b9:4a:68:47:a9:e6:2d:d7:e5:ef:35:e7: + 6f:a8:9f:a5:b2:0f:0d:98:fa:9e:ff:fb:c5:57:83:69:98:b0: + 37:06:fb:4c:0d:17:ad:e9:68:2b:c3:42:1c:f6:0c:ac:7f:ca: + 1b:ba:a9:90:b8:f6:e1:a2:2a:45:8d:f5:aa:e5:8b:4a:16:f6: + 0e:3a:38:ee:25:d9:5f:b6:f8:fc:7b:a8:c6:88:e3:ea:f0:1f: + a1:b0:e7:46:e4:b0:59:08:95:02:25:0c:6a:8a:3d:56:3d:c9: + a8:12:dd:47:b4:2d:5a:f6:ae:43:cc:3e:4c:7f:4e:ab:b1:78: + 2a:59:6d:6f:ca:93:21:e4:f6:ad:91:a6:1d:da:a9:16:8f:e6: + 1a:d2:c9:22:13:62:8f:be:28:96:bd:23:59:38:91:75:b5:84: + bc:ae:b9:5f:07:4a:dd:fd:a8:fc:e6:6d:0d:04:e2:76:fe:30: + 0b:e9:9b:60:1c:98:bf:92:80:57:45:ba:53:d2:61:f7:50:51: + d2:ad:9c:03:39:96:39:ee:45:64:04:b3:ca:02:bf:ec:3b:d1: + ab:ec:8d:97:9a:ec:1a:ac:62:99:85:f6:15:c7:d9:b0:2b:f4: + dc:55:f4:19:ac:7e:36:59:70:ee:8c:79:98:89:61:86:25:bd: + b3:38:9e:49:ed:8a:ce:61:1d:d1:13:99:96:74:9e:4f:43:78: + c0:c9:a2:f3:62:92:f8:aa:6b:ca:91:7e:29:d1:80:27:64:68: + e1:0f:9b:fc:fe:64:99:0f:d6:8e:d3:78:d8:ea:fd:e5:0a:55: + 34:8b:f1:b4:d9:1b:a5:bb:30:f9:1a:f4:19:3c:3d:af:ac:5f: + ce:9b:27:08:18:52:6f:b0:aa:02:0d:46:84:73:92:f1:0b:16: + 12:9b:cf:bc:f3:97:bc:c2:9c:18:57:cc:55:63:21:de:f7:32: + c1:3e:fb:88:de:f7:ae:f0:11:10:5b:5f:04:df:9d:3d:19:2f: + 89:cb:72:b4:5b:f2:49:81:76:c2:57:ec:d9:44:ff:b8:8d:19: + 6a:2d:bf:31:47:34:e0:b1:03:32:26:15:e4:d7:44:41:d1:5e: + f9:ba:e2:5f:50:45:44:08:44:7f:9b:09:f4:37:ff:8b:d9:d6: + 55:66:d0:60:b2:8b:94:34:8d:97:dd:73:2f:02:22:be:9a:bd: + d3:57:8c:c3:c6:e1:e1:19:64:f1:6d:3e:41:20:6f:4e:47:bb: + 29:41:bd:a9:8c:ab:01:41:ea:2a:51:c7:f2:9f:ec:ca:9b:1e: + be:e7:f9:3a:5e:66:f8:dd:30:3c:dd:3d:53:61:1e:ad:93:31: + 01:c4:c4:b3:2c:b1:14:a3:68:a2:a2:6a:f9:60:e7:63:19:e4: + 89:19:89:1d:ad:de:85:5d:43:4c:57:61:17:b4:7d:f9:18:93: + 93:c6:88:40:0a:3d:7e:a4:e9:ab:fd:56:c0:2b:5f:35:68:26: + d4:e2:c8:f7:75:08:1c:11:4f:a0:64:a8:15:2d:f2:e9:58:0a: + 31:ec:cb:f8:ba:3b:85:aa:95:93:5e:47:05:27:c4:32:6d:56: + 71:6f:38:8d:db:93:99:57:35:cf:25:83:99:77:d3:7e:93:cd: + a0:04:ae:e5:e9:20:e7:63:b1:ed:69:8c:46:3d:1c:f6:84:bf: + 67:a5:71:60:d5:ec:9f:5b:d9:12:12:9e:0a:b2:85:40:94:34: + 9a:74:6b:25:1e:3b:03:2b:2c:55:7f:51:4a:6a:93:07:dd:e6: + d4:89:fb:1a:95:1d:cd:bb:d1:61:47:6d:8c:09:56:44:b3:52: + c9:ca:df:a1:27:45:77:a1:e3:31:ec:da:b4:ad:15:20:ac:f7: + cc:88:1a:b6:84:f5:21:c9:4f:f7:94:bb:d2:1c:d2:19:40:52: + 5d:2f:9f:44:d3:64:8c:88:d3:08:93:ff:5e:d1:99:63:60:40: + 73:08:bb:20:3d:d1:26:a8:30:48:44:2d:d3:65:e6:af:eb:22: + ec:7c:6f:97:16:69:58:3b:e2:ef:e9:de:de:90:10:07:f4:bd: + 6a:a7:e5:82:e9:22:d5:0e:c9:32:ea:ac:30:69:c6:96:9b:51: + 6b:93:65:67:e5:84:2f:36:1c:19:d8:be:26:fa:79:05:e0:ed: + 34:fd:2c:a4:c0:44:7f:cd:c7:51:e5:a9:81:a7:90:97:46:1a: + 78:00:16:64:2c:d9:d4:85:b6:61:1a:87:de:96:f5:0c:f3:cc: + 73:d4:0d:5e:8f:64:b0:a0:97:c9:12:0c:2e:fa:3a:a1:07:1c: + bc:29:0c:e0:82:b7:3b:0d:6b:14:80:3a:11:a6:d4:f4:36:a4: + 96:d9:89:f8:81:61:77:79:02:6f:5e:64:2a:d7:f2:fa:26:d6: + 0b:bf:cc:63:5e:ff:af:7b:c4:ef:48:5d:ef:c7:44:bb:46:be: + cb:3f:c4:3e:9c:f2:98:9e:ec:7b:20:4a:54:a0:cd:2d:3a:cf: + a0:2d:4a:db:2b:97:50:82:92:68:4e:f0:f1:73:b0:b8:6f:62: + d6:97:95:15:75:03:41:5a:d6:f2:f8:a3:eb:f6:48:49:44:49: + 93:9e:6c:2c:e1:a1:d5:e6:fd:f2:d5:d9:ee:f0:86:ef:01:49: + 65:d6:fd:ae:9d:3a:a6:1d:1a:b3:9b:09:8a:49:cb:ff:b9:d2: + b7:16:7e:f5:36:05:c4:09:c1:b1:49:97:0d:8f:22:c9:8c:9e: + bb:ea:ce:f9:a5:57:47:de:04:7a:bd:e4:b6:a0:0b:bc:d1:da: + a1:20:e1:5c:c4:7a:13:fa:7c:c3:dd:a3:b2:48:98:29:83:75: + c1:6d:f8:1b:75:7c:f4:91:ae:66:d9:bf:49:3e:4c:85:01:df: + d7:8a:1c:44:9c:d0:d1:4f:7f:c2:0f:7d:f8:e0:11:4b:b6:b0: + 4e:6f:1a:f1:fb:53:f8:42:c8:54:15:6b:29:a9:b1:1c:f3:f4: + ed:52:2e:66:e9:49:1a:d0:52:66:6e:fa:8d:ff:2f:1e:d3:40: + c7:25:b7:69:1d:d4:a9:4d:ee:82:14:32:0e:82:ed:94:b6:02: + b0:00:d1:b3:20:f2:eb:9e:db:0f:c9:4f:3d:ec:b2:6e:bd:41: + d2:93:87:1f:fb:8c:b8:0e:e3:6a:f4:37:dd:4f:a0:24:e6:22: + 3d:c7:a2:46:06:bc:5e:25:74:aa:ae:fc:de:94:d9:5d:6f:1b: + 0f:e3:99:46:06:4c:20:ff:59:d1:ef:75:76:87:c8:9a:7d:97: + 67:6d:06:d8:20:83:84:1d:c4:72:43:8e:e2:ee:3a:d9:21:59: + 63:c9:a0:56:d1:42:f4:34:fe:ed:ac:a4:0a:28:0a:c0:a0:32: + 0f:f1:4d:36:b0:27:9c:a5:88:6f:b2:65:a9:43:d2:09:0c:ce: + 06:b7:1b:e4:44:d0:e3:cf:da:2f:11:df:cf:83:3a:8e:04:7e: + 5f:31:90:c1:1e:1c:b1:ca:4c:21:4d:6a:7a:c5:e0:17:61:ee: + c5:61:dd:0d:41:71:96:77:6d:a4:43:a1:69:60:22:56:ea:b1: + 88:b1:71:53:79:44:25:f2:42:c9:b3:48:f7:6c:9a:6a:be:f1: + ca:88:3e:14:b9:69:9e:57:0b:f6:b6:1b:c9:88:70:7c:a8:80: + d6:34:9f:63:59:48:86:4c:bc:eb:cb:49:1f:ad:f6:13:b0:de: + c1:0f:8f:a8:0c:f3:ce:f4:56:b5:3c:1d:82:df:9a:98:4b:5f: + 91:1f:56:f3:ad:b7:45:92:9f:44:d1:5b:63:da:1a:96:cc:db: + 9f:48:64:08:19:29:3f:a4:27:6c:ed:20:49:07:dd:b0:72:9e: + fd:59:37:73:69:07:1c:24:c4:46:5d:58:d1:0f:e4:05:08:09: + 60:b2:8b:df:a2:a5:07:99:c9:4f:cb:f3:d2:d8:bf:b7:0a:6e: + cd:73:43:a5:a0:46:1a:f8:c1:88:01:e2:7c:c1:a7:36:ad:f3: + d1:28:e5:4c:b7:5b:a3:08:70:0e:3a:d9:d3:ce:55:0f:2f:f8: + 08:7a:3c:78:0c:c0:ca:1d:8f:35:34:6d:8f:10:3b:3e:ad:3f: + 2d:55:9e:d0:aa:e7:43:39:c0:64:4b:55:f9:62:a1:f4:1d:90: + 4a:3e:06:1d:0b:8e:12:18:6e:28:30:92:88:80:99:6b:bb:a2: + f2:2b:79:1a:4f:53:e5:4d:10:bd:3b:81:9d:1c:9c:06:a1:a4: + df:61:ec:5a:05:82:38:91:84:65:f6:74:83:9a:28:eb:23:92: + 1f:ef:77:77:30:98:c4:90:45:d7:4e:80:fb:e7:50:52:0c:03: + 10:0d:b3:e4:0a:20:6c:85:fd:2a:b6:87:e2:7d:69:b0:76:ac: + b6:23:ff:09:6e:ab:7e:98:3e:72:76:bf:a1:e2:77:32:2e:51: + 85:db:cf:d8:50:b3:e2:c6:7c:75:bf:67:3a:76:c0:d5:78:2b: + 1e:c8:ee:63:31:20:7a:33:c9:90:df:8e:95:d7:be:04:32:93: + bd:60:46:2d:18:52:0d:e0:99:1f:da:1e:d1:ae:f1:ea:a8:7a: + 90:80:7e:10:89:51:c5:a2:55:38:b8:59:12:92:9f:93:87:e3: + 0f:bb:02:29:ed:75:8f:8a:17:8d:81:91:65:78:a8:1d:9d:2d: + 1e:0f:9b:53:d4:13:8d:55:92:eb:8a:45:19:f6:6b:44:03:47: + 9c:3b:18:1b:d3:f1:a1:3d:c4:66:b0:16:d6:60:26:b3:8d:89: + 52:27:29:4e:3e:b8:50:fd:64:20:fc:02:58:e2:83:6f:15:35: + e4:a6:c8:d6:2c:e3:ce:e2:9d:d1:53:a6:d9:57:90:63:24:ab: + 18:d8:6e:63:90:9a:eb:9b:80:c2:98:8a:9a:bf:20:92:b3:36: + a0:04:fa:88:2d:d6:0f:3f:9c:4f:4d:21:96:c7:4d:2e:c0:34: + f0:40:d0:f7:f3:ea:c5:57:cd:3f:ec:74:73:5e:f9:b0:7e:71: + f3:7c:6e:6a:3c:a1:22:b0:f4:40:d8:62:08:a3:97:8c:14:66: + ff:bb:83:ab:26:24:01:9f:b5:03:0e:80:5e:e9:e9:f1:14:84: + 97:4d:f8:06:db:98:2d:8c:93:e2:af:45:44:7a:d5:61:bb:d6: + f1:c4:5e:38:62:3e:1b:1d:d6:69:42:49:66:a0:83:da:23:5d: + 42:b9:c7:a0:07:5a:ef:e7:b2:9c:4d:83:63:6c:89:61:c7:d6: + 29:4d:76:6d:eb:26:6d:25:c9:fc:5d:2d:58:88:17:5e:a5:4b: + 7f:0b:6e:c7:7d:f8:6a:50:53:c7:80:35:98:76:31:cd:f0:2f: + 6c:f9:79:93:c4:bb:9b:01:89:00:df:0f:55:c5:67:19:50:b2: + 31:ca:68:f8:30:f6:0a:88:2d:e8:55:0d:af:cd:5b:cd:f9:3a: + bc:3c:87:f1:32:b5:f3:01:a9:09:44:ea:54:2b:18:33:05:d3: + c6:b8:56:e3:5a:70:38:4c:98:5f:ee:17:6b:12:2d:00:fa:c1: + 33:48:73:7c:29:51:9a:44:c7:74:b6:63:2f:b4:f8:87:3c:e4: + 44:4b:5d:0f:ec:b1:ec:56:b2:23:da:d4:1f:b7:a9:13:d9:1d: + b3:d6:19:d6:23:fc:72:9a:15:d6:6c:df:66:71:55:a6:89:9b: + ed:ef:25:ee:fb:2b:b3:58:59:d0:42:ab:da:97:88:de:cc:06: + aa:b2:85:d5:f0:a2:87:0e:cb:58:7c:14:9d:d1:8e:d0:21:9b: + 80:67:ae:73:4c:34:fd:42:36:71:dc:a5:55:4d:79:19:dc:4c: + f2:bd:76:25:e3:f0:88:62:4f:79:4b:e0:2f:30:cf:40:42:4b: + 54:1c:85:23:11:66:3f:23:6a:dc:54:f3:5b:cd:9c:b6:88:e4: + 71:87:5c:2f:7e:85:55:5b:9c:23:3a:00:1f:57:da:b6:33:06: + 8d:ce:07:89:b9:2d:7d:0b:35:8d:8a:8b:66:cd:59:16:55:db: + b0:b4:2d:3d:53:32:03:90:98:55:a4:f9:8d:f3:84:b4:16:06: + 42:3e:ca:71:ef:db:c7:59:32:fa:e3:ec:3b:fb:c9:83:83:90: + 52:99:06:c1:b4:3d:ea:f9:83:fa:a8:d9:c3:09:8b:15:d3:85: + 06:a1:e5:26:93:4d:23:aa:cd:4b:3e:5f:64:8f:2f:71:7e:c8: + d3:8c:78:ef:79:3e:ab:4c:da:77:23:2e:ff:56:35:8d:27:7d: + 7e:7e:df:03:1a:c9:c2:af:f4:62:49:f7:35:1c:6a:9b:19:f9: + 0a:e2:17:36:b6:6f:d6:ee:b6:e7:12:e3:c1:54:17:22:6a:28: + 6d:cd:9c:e0:ef:b7:1c:99:e1:94:53:8f:c5:55:65:b2:f0:4d: + 0f:c7:ef:d0:0a:b4:9f:c2:c9:9d:af:26:2e:98:5e:cd:59:79: + 80:1a:28:27:68:fb:22:f3:14:71:60:79:a0:5f:92:75:59:36: + 58:fd:80:20:07:e9:8f:34:5c:38:53:7b:4a:d1:58:77:af:1b: + 0a:0f:70:3f:db:b8:58:37:01:e6:ef:8d:3c:e5:c7:71:c6:bd: + 1a:0b:12:33:5f:9d:07:36:4d:7d:02:07:85:60:83:6f:fc:e0: + af:9f:c5:22:4b:cd:89:dc:2f:b3:53:e1:7f:b9:65:af:59:57: + 54:87:32:f2:d6:15:88:e2:2b:a7:20:85:42:26:d9:09:ee:87: + 60:0c:bf:a3:6a:e5:e5:db:6f:2c:05:7e:88:ee:aa:98:d7:6d: + 0e:3c:9f:6c:28:70:02:1a:78:b6:2e:2c:29:9e:d9:fa:1e:80: + 0a:a3:e6:dc:46:00:15:e7:c0:13:36:42:9c:f0:1a:fa:9c:7d: + d0:cd:2f:ce:dd:95:54:fb:b1:fa:bb:3f:83:26:f7:54:42:5d: + 60:7a:d1:bd:b2:17:9a:e0:02:a7:9a:d8:40:f4:2c:79:c0:4e: + 4e:a4:68:aa:33:c9:1f:2a:f3:fd:9b:50:39:37:b9:1e:59:2c: + 7b:cf:97:57:23:81:b7:07:76:8e:b1:f5:15:dc:54:c5:f9:f9: + c6:13:b7:37:2d:12:44:c6:78:1e:92:1f:ed:85:8f:14:7a:9f: + d0:1f:02:8a:f1:5e:8d:05:28:13:2c:cf:1f:41:9d:74:ec:98: + 96:51:57:a7:c0:10:9a:be:31:7d:71:a7:c2:38:cd:ce:74:60: + e4:45:ef:b0:60:87:7a:da:e9:05:38:06:19:fe:60:db:c6:2d: + a4:25:f7:5d:d1:b1:3d:12:0b:a0:fb:3c:80:b0:f5:00:48:34: + 8b:e4:a4:f1:cf:fe:be:a2:38:43:44:20:23:5e:89:c8:91:18: + fb:5e:aa:90:11:07:7a:e8:ad:61:03:17:6a:a5:a6:a9:e2:c4: + 8c:f0:5e:d7:25:fc:43:93:db:47:44:c1:25:26:38:7a:17:08: + 24:36:d3:25:95:eb:c3:17:ca:b5:d7:79:73:62:48:d6:d0:af: + e7:a0:61:83:5d:7a:27:e9:b9:7e:d2:25:17:85:c2:28:5b:9f: + e7:01:67:f7:69:83:eb:ec:cd:8e:2b:ee:f1:4c:17:a5:3e:05: + 2c:c1:eb:b7:64:d8:fa:3b:3b:c4:e4:53:18:fd:d8:da:1a:f4: + c7:c2:47:90:91:ab:3d:2b:12:1d:9e:7e:58:7e:cb:63:9c:ff: + 28:bf:a0:c3:a6:07:52:58:9a:de:2c:4c:63:5e:79:8b:21:cb: + cf:5b:08:7d:6e:44:55:32:5c:37:71:46:02:c1:28:e8:5f:c1: + 34:ca:b9:25:0a:c8:88:a8:bc:13:1f:1d:c3:6f:cd:3e:f9:95: + ad:45:7b:f9:03:05:b8:f8:c8:89:fa:a0:7a:2b:b7:15:ba:d2: + 0a:39:39:c9:0e:0d:5b:f9:11:b2:9e:11:98:90:bd:25:9d:a2: + f2:c8:c1:3b:70:a3:71:b9:9c:46:24:b1:00:1b:54:3c:ba:11: + a2:73:d4:bf:85:08:57:8f:05:6f:9f:23:12:ff:06:73:d5:6d: + 13:7c:1b:50:c4:df:8e:8a:8a:f8:f4:5c:61:c1:51:e8:d3:82: + 7b:ef:60:89:56:4c:fa:e1:b5:50:47:23:66:7e:af:af:a7:9f: + 0a:1f:55:2d:d9:ad:8f:92:01:d4:10:c8:00:63:0e:6e:95:1b: + ea:e9:d3:38:ac:7c:34:d1:8d:61:e6:be:c5:98:3d:9e:cf:70: + 28:5c:4f:80:44:4d:06:9d:1e:e0:4b:4c:91:76:7e:d8:ff:5f: + 5a:ae:b6:88:f6:25:7b:96:80:4c:59:3f:91:29:4f:44:c1:01: + 23:9c:8c:51:f1:fa:69:e0:b1:2a:20:c8:93:14:f4:99:61:a7: + 4e:9b:ee:8d:02:5a:e2:29:d7:f5:9f:ef:94:59:4c:55:c6:0f: + 1c:b8:9c:a9:b6:bf:cd:c4:30:e5:e5:84:4e:d3:13:af:6e:8f: + 8d:ac:d4:64:c0:21:5d:57:e7:9d:73:c6:90:63:b7:22:3e:a6: + a6:47:d3:be:b4:a3:ff:c6:c3:0e:2b:f0:45:ee:50:50:98:b2: + 8e:f2:bc:05:d0:24:b5:40:b2:52:b4:bf:d7:62:8a:a2:a8:d3: + 6c:3e:ad:12:46:ab:5b:c7:e1:32:99:21:7c:cb:09:37:2e:8f: + 0b:85:41:5f:45:8f:17:ca:66:6a:73:97:73:3c:3d:8d:dc:9f: + 51:dd:59:15:0f:68:4b:a2:42:4e:98:6d:1c:74:9b:5d:b4:65: + ed:22:17:a4:73:b2:11:93:f4:d2:b5:aa:93:00:c5:88:42:86: + b5:1c:3f:fc:9f:f7:f9:2f:a9:29:a5:66:e2:e5:8e:29:ef:d5: + d8:dd:93:62:26:08:7a:f6:62:6c:17:1c:b0:d6:19:b1:39:8c: + c4:54:a5:ef:34:b6:15:53:fd:88:80:eb:48:50:0d:74:8e:34: + 04:64:f1:da:13:4f:df:63:7b:c3:19:be:c4:1f:f2:13:25:cb: + 73:37:98:93:4f:8d:ed:97:88:ee:be:39:9f:03:bd:2a:4f:08: + 1d:63:19:dd:20:06:6c:4c:96:a7:66:82:7f:75:62:19:5b:87: + cd:76:e3:b9:10:76:ab:b4:bd:54:ca:3e:10:15:a4:36:42:93: + e9:56:fa:19:59:e3:90:55:ad:f7:b2:07:cd:99:9b:7c:05:01: + a9:d1:fc:eb:e6:d5:de:01:39:ac:0d:be:c7:db:fb:b0:54:08: + 48:26:f9:54:dc:15:85:a2:6f:33:10:60:ec:0d:38:ad:15:e4: + 14:83:3d:65:df:0b:ae:01:f0:15:9a:ca:bc:4f:c9:c0:57:9f: + 9a:b9:22:53:56:b3:4c:83:50:f6:5b:13:68:94:6e:12:7c:bf: + 9e:22:6d:c3:17:f4:f0:a5:73:b5:03:ef:b8:af:0e:20:c9:df: + 2d:39:e6:43:38:84:30:6b:a1:36:0a:bf:09:41:67:18:85:8e: + 77:04:a3:be:d4:9f:36:75:42:e5:84:ea:75:fa:0b:01:4a:30: + 48:9c:b3:47:9d:3c:48:41:74:76:14:30:dc:66:1e:fd:7c:58: + 2f:63:e5:74:2a:c5:a2:26:65:fe:c2:13:7b:0d:83:f7:94:3d: + 2d:f8:83:07:aa:dd:77:72:26:fe:70:29:d5:1e:83:21:ba:0e: + de:10:ba:4c:cd:19:88:b2:9a:44:f8:86:d8:fa:4a:12:3b:7f: + 02:ae:af:68:7a:87:8b:8f:63:e5:9a:da:e4:77:9d:40:50:27: + 7f:b0:7a:ac:5c:aa:b4:33:8a:dc:fe:17:74:3e:1d:5d:5c:0a: + 57:06:72:ac:ac:ed:2d:81:09:b3:6e:71:25:3b:03:29:67:b5: + 81:bd:b3:3f:36:42:f3:af:ac:db:58:fe:00:42:b4:28:89:1a: + 76:fb:11:8a:32:c9:65:03:f7:ef:6a:e6:57:48:e9:b9:d2:90: + 42:9a:cc:ff:f1:fb:06:ad:be:ff:4e:c2:64:93:39:48:4a:57: + e6:06:98:14:9f:0c:61:19:c1:f0:d4:c8:3d:1f:6c:a5:c2:28: + 66:25:aa:7a:9f:fd:08:f6:ec:c1:e5:f8:e2:37:17:f5:6b:ae: + aa:f7:a4:da:27:59:25:0e:43:4c:53:62:3b:62:6a:5e:6d:9d: + c9:01:02:f3:79:47:0e:2d:ea:62:89:a5:57:6d:de:18:b2:a2: + 13:d2:34:27:28:4f:4a:a5:d7:f3:ee:16:a0:5e:77:f9:2e:6c: + 22:81:44:ae:03:64:e1:9f:b8:d7:55:92:75:f6:66:ea:2e:45: + 31:16:aa:32:77:3f:8e:0e:b7:4a:d9:52:ad:05:28:d1:58:8a: + d4:79:b0:ba:29:15:33:5b:99:59:d2:70:95:fb:6c:0a:5d:18: + 4a:96:ab:14:96:c8:00:9c:5c:e1:f2:f6:ec:85:e4:3e:39:39: + b7:44:3d:9a:66:bd:d9:32:48:c8:5c:0c:d0:4c:b9:2d:01:49: + 1d:eb:fd:41:32:67:23:87:10:31:17:20:df:f1:3f:77:ed:b8: + d9:52:dc:3d:11:15:dd:04:93:88:f2:65:32:6d:7b:c0:d8:df: + 3a:19:61:9b:7f:e5:a2:b1:e0:6f:6a:3d:f5:82:08:a1:0e:26: + 42:e2:91:9f:c2:a2:7e:ba:66:89:a7:95:26:c5:9a:9a:7b:2e: + c7:cf:4e:70:07:2b:f6:f0:56:60:f4:56:ba:73:18:e6:b8:85: + 96:35:b2:d4:3d:3e:63:ca:be:08:54:f3:7c:03:e9:6f:98:17: + f5:03:66:da:dc:bc:4a:a8:97:d4:ff:74:89:ba:1d:22:91:58: + 50:87:43:c6:1f:ef:0f:cb:9c:da:0e:f8:6b:1e:ab:84:17:f0: + 56:17:dd:4a:19:62:4f:d6:56:ef:27:ba:81:ff:fb:5e:c6:4d: + a1:20:03:a4:4b:30:d1:09:37:8a:e3:34:cb:2e:5d:9e:6f:a4: + bb:9c:0d:7c:b0:40:66:23:7d:ac:dc:b9:7c:68:f4:db:f7:92: + c6:db:dc:dc:77:5c:d7:d3:57:a7:13:60:a3:ed:87:15:da:fe: + a5:f0:2e:46:94:ad:92:75:61:f2:a8:08:79:83:af:ea:f5:7a: + 4d:02:2a:f2:39:d6:87:ef:4f:17:49:06:86:5a:54:9d:48:0e: + ab:7b:b6:f7:eb:68:85:83:01:52:d5:a8:32:fe:31:c0:45:11: + e2:dc:d6:99:d6:27:90:b5:41:48:b0:39:da:9e:0e:d2:6d:48: + bb:c4:0a:15:53:8b:16:77:9a:b9:62:b9:18:db:ea:25:17:8f: + c4:18:cd:1c:93:33:0e:9b:e0:ef:da:22:d8:55:17:2d:90:f1: + 5e:35:a0:24:eb:3b:d4:50:45:d9:35:3b:0b:c3:d4:6e:67:b2: + 92:0e:e6:a7:14:1c:09:e4:d0:94:d8:05:b4:e4:9d:20:5f:f1: + be:ca:25:00:34:76:35:e4:3a:19:05:ec:94:8b:9f:cf:c1:1a: + 89:bd:8b:1b:8d:68:85:2c:aa:d0:95:3b:d7:b5:47:39:03:7b: + 73:38:16:8d:21:68:1a:d8:77:49:1b:02:d5:41:e9:f9:a1:da: + 40:75:f1:0a:ab:76:19:79:dd:34:28:6b:4d:d1:44:79:97:a3: + fd:15:1e:12:77:ce:e9:04:12:c3:47:75:5e:73:5d:8b:50:8e: + 7b:78:74:a2:10:44:dc:29:ec:bb:09:04:98:dd:9a:98:a1:f8: + fd:c5:5d:41:4c:9e:13:33:09:f7:59:d2:ca:7b:86:8c:0f:f0: + 8a:40:fb:6a:7d:c9:5b:18:71:28:15:e9:8a:97:b8:4e:56:a1: + 3c:82:69:f2:1e:05:b8:4e:b4:0f:c5:11:b0:d8:cd:e1:07:5e: + 39:a1:e4:a0:ad:19:c7:af:3b:a1:3c:01:69:8a:4d:8e:13:22: + 53:98:ab:9c:a5:2e:75:1c:97:d9:0c:e7:0b:d4:79:41:2a:2d: + 73:97:45:e4:b1:4b:37:54:d7:90:2f:36:f5:49:82:d6:41:e3: + 9b:1b:ee:bb:19:f3:a9:5f:74:da:90:0f:ef:c3:89:e7:21:cd: + 0a:51:71:aa:77:76:ad:e2:15:f1:ac:cf:68:34:09:d3:00:4c: + bc:c9:58:9f:b5:6c:e6:f9:4a:cc:3b:73:7a:0a:02:8d:da:98: + 77:14:34:98:5d:ef:c0:8e:71:bc:b2:dc:56:1f:ec:b0:b0:46: + 75:23:7b:00:33:44:f3:85:a7:49:81:47:28:62:76:4d:91:3e: + 57:5c:58:31:a2:b1:de:0b:49:fb:92:ad:d1:a7:1d:61:0d:03: + ef:7c:fd:9b:9a:36:ce:b1:1d:37:87:3c:ea:3e:54:37:b5:de: + ea:e6:79:27:aa:4f:2f:94:17:21:09:24:5d:33:c9:ea:2d:e8: + 87:f1:6a:d3:d6:fd:85:79:bd:66:25:2b:e6:0d:d6:23:3d:82: + d8:28:4a:31:06:7a:b6:79:3a:2a:d2:a5:00:5b:9a:f3:3f:15: + c4:cc:f5:6f:00:f3:77:b1:c6:31:9b:7d:33:eb:0e:b0:0f:f3: + 9d:4e:49:85:1d:90:01:15:fa:3d:08:7d:27:06:ea:92:3e:b0: + c7:93:da:48:70:1a:1f:7e:52:f8:4c:63:c2:d4:82:cc:40:44: + c0:84:38:fc:70:ad:c9:16:41:80:73:8c:8e:6f:dd:e9:48:27: + 8c:c1:87:c1:ca:4d:14:66:53:e1:ce:9d:1b:3a:16:14:cd:dd: + ce:12:a9:2a:ba:c9:4c:34:4b:4a:85:1f:9d:d4:6a:70:e9:df: + 18:9f:03:d2:bf:73:f3:e0:b3:8f:d2:10:09:97:fd:59:fc:50: + c8:57:a7:77:34:43:82:79:b5:56:f5:33:c2:a0:dd:2e:78:09: + 60:ee:0a:92:d3:13:5c:b3:41:79:df:fc:07:09:a5:54:aa:e5: + 59:6a:30:d0:f1:ed:bb:f1:5a:52:61:9d:06:36:dc:c8:80:70: + 77:45:05:b9:2f:4d:c4:86:fe:d7:51:51:93:88:8b:66:1c:fa: + 0d:ce:91:5e:e0:25:3b:6f:89:47:df:52:09:b7:0e:c1:82:90: + 96:17:b0:8c:af:d1:2c:00:b0:bb:18:5f:34:56:d5:f6:18:00: + 56:4c:09:ab:32:77:e0:35:56:1a:52:99:1a:d9:e1:ce:75:9f: + 24:4c:7d:e5:34:4f:52:1c:d4:6b:93:b8:a5:c5:68:97:68:a5: + 1d:1f:77:16:2d:4a:29:0d:e5:2b:9a:f9:05:2a:1d:3a:f9:7e: + 45:3e:a0:5f:88:d6:8b:bd:47:f3:a7:7b:a1:27:29:1c:3a:26: + 41:b8:fe:80:53:6d:29:64:09:1f:6f:e9:ac:ff:70:8f:06:ef: + 48:a2:07:1f:8c:d9:86:2c:84:f4:a7:01:66:d1:2f:f2:47:92: + a1:e6:de:a7:28:70:4f:bd:d6:d8:b4:ed:17:ab:4e:18:4f:e2: + 4a:62:d0:7f:30:9c:40:2e +-----BEGIN CERTIFICATE----- +MIIg7zCCAimgAwIBAgIUZUd1tFj6suEfFrVfJUm0fyoSYFYwCwYJYIZIAWUDBAMU +MIGiMQswCQYDVQQGEwJVUzEQMA4GA1UECAwHTW9udGFuYTEQMA4GA1UEBwwHQm96 +ZW1hbjEYMBYGA1UECgwPd29sZlNTTF9TTEgtRFNBMRowGAYDVQQLDBFSb290LVNM +SC1EU0Etc2hhMjEYMBYGA1UEAwwPd3d3LndvbGZzc2wuY29tMR8wHQYJKoZIhvcN +AQkBFhBpbmZvQHdvbGZzc2wuY29tMB4XDTI2MDQyODA4MTAwNVoXDTI5MDEyMjA4 +MTAwNVowgaIxCzAJBgNVBAYTAlVTMRAwDgYDVQQIDAdNb250YW5hMRAwDgYDVQQH +DAdCb3plbWFuMRgwFgYDVQQKDA93b2xmU1NMX1NMSC1EU0ExGjAYBgNVBAsMEVJv +b3QtU0xILURTQS1zaGEyMRgwFgYDVQQDDA93d3cud29sZnNzbC5jb20xHzAdBgkq +hkiG9w0BCQEWEGluZm9Ad29sZnNzbC5jb20wMDALBglghkgBZQMEAxQDIQCm4CSo +ShgQTc3G2iMkZ96WlYEApsrOQ+T9/HsajPrrfqNjMGEwHQYDVR0OBBYEFL2AIzoG +3ThX7mvClHvqv0NXOrCMMB8GA1UdIwQYMBaAFL2AIzoG3ThX7mvClHvqv0NXOrCM +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMAsGCWCGSAFlAwQDFAOC +HrEAEDxwxfWxTxx3hTS5s1eXYu/nTRdnVmN0AuFQXFvcVpRF1/lrdv374gAWC1oP +hoZ+HgxOf9CVy9SNCVhTTuKfDhEuONzAh+xvJe8bWYGrcWlRLjwv9uvyInNi4aJo +s2fbLgUW+ryutiLLwg/9iB42QycT3mEBDLpa3wppF0XCd7Xfh2KzFm6OV+A7nwKA +XfCSdlFzLnolHIh53Q1VxXOUs3ZSOftYDTT+dDhF/Jk5h8f+Syp8Ua6S7l8oFhME +tfBfk5B00OD0HQava60z/izVmuUQMn8BL36Xxv+2V5dWzFpamnneGbCcC1e7u+WL +kSzNGS18dY5xT8XFiHRcXSeC3JRYfW5xbnjF8w07hZUq2k2vNKk8AojMRR0IDJ0g +OXMGCi26il2pRDIkMrHR/dF/tBBWOhUSpfbBbxbvhF6Gq1ubp7Qh40OGGlD4lbOw +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 +-----END CERTIFICATE----- diff --git a/certs/slhdsa/root-slhdsa-shake-128s-priv.der b/certs/slhdsa/root-slhdsa-shake-128s-priv.der new file mode 100644 index 0000000000000000000000000000000000000000..632893c0ad223758c5ce52aac68c23ba82b716f1 GIT binary patch literal 84 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 literal 0 HcmV?d00001 diff --git a/certs/slhdsa/server-mldsa44-sha2.pem b/certs/slhdsa/server-mldsa44-sha2.pem new file mode 100644 index 0000000000..ce7383cd12 --- /dev/null +++ b/certs/slhdsa/server-mldsa44-sha2.pem @@ -0,0 +1,1404 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: SLH-DSA-SHA2-128s + Issuer: C=US, ST=Montana, L=Bozeman, O=wolfSSL_SLH-DSA, OU=Root-SLH-DSA-sha2, CN=www.wolfssl.com, emailAddress=info@wolfssl.com + Validity + Not Before: Apr 28 08:10:05 2026 GMT + Not After : Jan 22 08:10:05 2029 GMT + Subject: C=US, ST=Montana, L=Bozeman, O=wolfSSL_SLH-DSA, OU=Server-mldsa44-sha2, CN=www.wolfssl.com, emailAddress=info@wolfssl.com, UID=wolfSSL + Subject Public Key Info: + Public Key Algorithm: ML-DSA-44 + ML-DSA-44 Public-Key: + pub: + 18:52:01:a7:a0:6b:91:d4:b2:86:a2:e8:6f:de:5c: + 07:c2:d7:35:88:2b:3f:61:e2:7c:99:74:4b:e5:c7: + 88:3e:d8:bd:dc:12:08:35:fa:93:cb:92:81:c8:fa: + 7b:88:0b:2d:88:6e:da:61:03:fc:6f:f3:91:69:1e: + ab:93:47:27:a4:d8:40:fd:a2:6f:af:8d:a6:2f:df: + 3d:a8:bd:3f:75:b1:40:ff:83:c3:40:07:75:13:92: + ee:4b:53:75:45:02:7c:d0:81:21:aa:51:94:a8:a2: + fe:02:28:e5:2d:f3:4c:23:e7:f8:1a:60:ed:38:13: + a4:66:ac:d8:9c:21:72:29:1d:7b:69:52:0a:50:8c: + cd:89:ff:7c:ad:6c:c8:10:8d:e3:ed:07:2e:92:9a: + 93:f8:05:fd:6b:a5:de:54:fa:7a:61:4c:45:c6:cd: + d7:4f:20:26:4c:cf:c3:12:67:e9:33:aa:45:e1:5a: + 34:1b:be:50:0a:ed:62:f7:a4:ea:b0:16:f3:76:8b: + ac:ce:59:fb:e6:c0:31:a3:fe:07:35:e0:37:95:ee: + a7:5b:37:2c:7a:3e:df:c7:7e:e1:a9:23:a4:61:27: + ea:25:5e:17:04:ca:37:90:44:9b:68:4b:a3:06:b2: + d3:1c:ce:cd:60:a3:b1:39:f4:8b:40:6a:71:4a:f2: + 5a:36:67:09:b7:2a:61:81:2f:3a:f7:b2:d8:25:fe: + 98:1e:8a:5c:1e:f9:42:3a:ed:13:b8:4e:b8:59:5a: + 77:d4:57:1c:69:68:3d:f5:7b:69:2d:23:85:13:cd: + e4:bd:d6:47:15:c1:c3:81:92:cc:e2:73:df:8a:ee: + 1f:8f:d5:d0:96:1b:4e:cc:6c:ae:77:aa:94:2a:85: + 05:94:f9:76:f6:5c:7d:e4:21:38:2e:36:3f:eb:82: + f8:54:1f:13:8c:ea:ab:36:fe:f5:f1:b9:46:81:dd: + e5:5c:47:ab:c5:4f:72:b3:c4:83:2a:ee:66:50:ec: + 9e:83:35:f9:92:23:b3:a6:50:65:7b:4f:60:fc:e8: + fe:4c:f6:a7:1b:16:41:8e:55:3a:3f:01:82:d2:84: + bd:c5:72:18:47:a4:ff:c5:43:a7:e1:11:3a:1e:d8: + 98:ad:81:c7:4c:f5:40:fa:e1:37:51:d4:63:46:cb: + 33:f2:01:94:3b:4f:dc:4f:a1:13:67:d5:80:c9:1b: + 88:2a:db:ca:d5:f6:5a:73:27:d1:89:bd:ba:b8:3c: + b6:87:a6:85:e2:b2:ad:27:a1:33:6c:d0:20:1b:bc: + d6:7a:34:2c:da:bf:ac:ce:69:47:51:f0:7a:21:f5: + 83:91:06:ab:3e:87:0e:c1:f5:1c:6e:8b:94:25:e3: + ab:5f:ce:57:b4:70:c6:11:92:a0:a3:5e:4b:91:b9: + df:fd:ce:48:2e:12:4f:12:fb:4b:c3:ca:f7:1b:24: + 70:3a:8a:2e:91:aa:f7:60:8a:c5:d1:3b:8b:eb:c0: + 46:39:09:a9:9e:70:c9:15:51:ab:9e:e8:b6:36:51: + 14:65:a7:3f:0b:d0:f6:49:a6:f2:82:ab:d5:57:95: + cf:54:5b:ac:8f:c6:5f:4d:0d:c0:d3:2c:84:f4:e3: + 9f:a5:92:41:f8:6d:2b:53:ad:a2:f1:b2:c9:b4:21: + f6:67:d4:fe:35:32:58:1b:c8:8b:5a:f5:0e:53:0e: + 79:e9:a9:12:9a:b4:9a:83:f5:f0:8c:d6:80:c1:20: + fe:42:3f:b6:00:10:2a:9f:82:2c:3d:c2:e5:3b:c7: + 94:e1:95:ca:65:bd:85:a2:c3:4a:68:ea:f9:d5:ea: + c6:cc:e8:62:a1:1b:5c:eb:03:ff:3a:26:52:c8:de: + b1:98:c5:9e:e7:49:bb:2e:3c:90:f8:51:15:f2:e4: + 71:82:0e:fb:0e:6b:52:33:bb:42:ef:14:e0:17:42: + 38:f8:4d:1e:8a:ff:13:c0:d6:a3:13:eb:35:f1:38: + 4e:08:fb:c8:cd:e0:be:b3:2b:2e:0e:05:ba:a2:c3: + c5:f9:46:e8:49:08:0c:b4:9b:c7:6a:c5:83:18:45: + cd:b5:68:b4:c1:d3:99:42:eb:cb:9d:cf:00:6f:bc: + 69:41:0c:fb:76:1f:f8:cc:f3:7c:04:cf:48:4a:1b: + f9:33:47:25:3f:bd:c5:d7:e9:3b:58:10:e5:08:7b: + a3:8e:fe:75:d6:9a:16:15:89:2d:c6:ce:dc:85:e2: + d1:f6:2d:de:fc:aa:86:7d:e3:e0:86:a0:8a:c1:27: + d6:9c:d5:ff:78:40:9c:aa:69:d2:e4:6c:3a:aa:6c: + 34:57:69:28:7c:5f:b5:dd:77:61:4f:ce:df:db:56: + 57:47:2a:03:67:42:ce:68:c4:59:79:2a:b6:15:f2: + a3:5d:2c:f2:a5:80:ea:fa:5e:e3:27:0b:42:52:01: + fb:b6:da:41:58:e1:f9:20:b2:4d:90:08:80:d8:e1: + ae:07:94:60:b5:ef:e0:0f:7f:8d:a8:d1:70:2c:2d: + 33:72:28:c6:04:c3:5f:a4:10:a9:8e:61:8a:59:f3: + 64:15:ce:0f:cb:30:35:af:31:b5:63:42:b2:37:f6: + 20:0d:f0:97:0f:fb:c9:30:9a:c1:62:1f:d3:0e:30: + 6f:77:23:37:2e:77:2c:bc:aa:44:fa:4d:2e:6c:fa: + 62:1d:2e:dd:ac:14:7a:70:f0:0f:23:42:50:27:8c: + 6d:b0:ae:54:6c:8d:bf:5d:f7:df:81:30:1a:e1:5f: + 01:dd:b3:22:08:67:43:3b:39:89:9f:88:ab:15:a6: + 4b:26:4a:b0:57:07:94:3b:e6:e5:82:00:f7:63:89: + 98:78:d8:3c:fd:0c:f2:d6:f4:ae:a4:7b:43:35:1c: + 09:44:96:41:07:1b:32:d7:a1:b0:55:04:8e:f1:70: + d0:9c:ca:f7:cc:87:41:6c:bf:3f:56:fa:e6:8e:f6: + 85:d6:f8:af:8f:2f:ff:a7:06:05:a5:75:91:62:d0: + 8a:90:6e:50:5d:bb:41:7a:9e:eb:a5:5e:3f:37:d2: + f6:ce:0e:c4:aa:a2:8c:c6:29:c5:b7:37:bc:ca:08: + 6e:ba:7f:aa:6a:d8:47:e9:95:de:4a:c9:5d:28:40: + 31:c1:17:75:6e:5d:bf:97:d0:d2:e6:47:d7:9c:be: + 4a:f9:af:64:b7:d0:2f:7f:0d:81:4b:ad:82:98:5d: + 71:5b:d1:d1:77:d2:61:c1:17:ce:d6:fb:75:4c:e2: + be:94:52:04:f4:92:6b:38:e9:76:1e:ee:64:ec:9c: + b5:e7:8c:3e:c6:dd:9e:8e:8e:19:2f:aa:5e:0d:85: + fd:de:af:d3:ab:b0:29:62:c4:f5:0a:ad:85:ea:78: + 19:be:b9:bd:fc:0d:cf:06:0a:7f:e3:3d:fd:10:f7: + 1e:37:0e:05:54:35:b0:5a:15:28:6e:d6:4c:d1:60: + 68:70:ff:1d:c8:65:a9:e6:8f:cf:52:19:15:e3:4e: + 94:9a:b0:b8:c5:f8:56:9e:99:b2:2b:a4:ea:e8:de: + 48:15:e5:9e:8c:5c:31 + X509v3 extensions: + X509v3 Subject Key Identifier: + 5D:1C:9D:E4:A8:EC:8A:2D:DF:C6:2A:BE:4B:DD:4F:9B:09:CB:B5:82 + X509v3 Authority Key Identifier: + BD:80:23:3A:06:DD:38:57:EE:6B:C2:94:7B:EA:BF:43:57:3A:B0:8C + X509v3 Basic Constraints: critical + CA:FALSE + X509v3 Key Usage: critical + Digital Signature, Key Encipherment, Key Agreement + X509v3 Extended Key Usage: + TLS Web Server Authentication + Netscape Cert Type: + SSL Server + Signature Algorithm: SLH-DSA-SHA2-128s + Signature Value: + d2:e5:f4:8a:cc:a2:1e:10:a9:d5:cd:94:02:ff:ab:63:f5:8e: + c4:3a:89:e0:26:fc:2a:ed:d4:b8:70:5e:b6:bd:a1:a6:5b:ca: + 48:06:e2:96:3a:61:9f:46:f8:df:21:fb:2b:e0:c2:f9:6d:94: + 6c:c7:f0:76:9d:cc:bd:fe:de:86:4c:18:3a:ee:b3:42:56:ca: + e4:7b:04:7c:7c:d3:5c:30:67:9d:c0:f9:3f:3a:6d:f1:6b:80: + 4e:98:2c:0e:33:f4:1b:87:ee:de:5e:f3:70:80:0d:d6:c5:be: + 75:f5:e5:0c:1e:ab:b9:a3:0b:08:46:be:77:fe:06:3c:fe:92: + a3:b6:17:65:1f:59:84:4b:32:7b:fa:7a:59:77:85:24:1a:fc: + b0:25:cc:3c:a0:4b:5a:2a:84:5b:67:ca:96:03:24:b6:36:df: + 41:88:c8:46:16:20:4e:e6:8d:d8:db:cf:2c:a6:f2:c6:c7:25: + 5f:7d:95:3e:42:40:19:29:f8:d8:da:55:c3:1c:92:db:da:5a: + 20:96:f1:1a:be:6c:fb:e5:2e:84:5b:b4:02:45:6b:74:f7:ab: + 94:80:98:ba:16:cb:c8:d8:7a:4d:c6:f7:de:8f:22:9b:d1:cc: + b3:f0:d1:af:53:a0:a3:e1:69:2d:93:cc:a9:0d:48:41:a8:80: + 17:17:d4:e2:d3:78:a1:19:18:13:7f:76:20:70:4c:f2:e3:c6: + cd:c2:11:a7:a9:88:6e:48:eb:10:9b:55:90:bb:17:39:0d:8f: + c8:21:aa:26:98:58:b9:2a:a6:dc:4d:79:94:85:5d:8d:d2:3a: + e9:cd:92:37:70:6d:83:b7:d2:53:92:0f:21:b8:60:0a:5d:c6: + f8:d2:20:86:ed:d7:34:d4:4e:2b:f4:3a:d1:d0:75:45:c2:4e: + 6d:a7:c3:f6:9e:ab:5d:4b:e8:5b:8b:e0:ce:b9:68:5f:4e:8d: + 9a:18:f5:d2:54:06:f1:3a:de:30:05:5c:f8:fb:09:74:14:3f: + 48:14:e9:c7:32:1b:27:5a:39:b1:74:b1:e1:39:29:e9:2b:4b: + e4:92:38:8e:bf:39:55:a2:ab:70:62:1c:cb:eb:12:22:f1:06: + 08:a3:86:5c:c6:1e:84:9a:03:c5:a7:14:36:59:07:ed:d0:ef: + e3:40:06:af:a6:76:a9:97:51:e2:99:36:f4:11:f9:36:18:50: + e5:7e:7f:23:de:fb:29:96:e6:51:8d:02:57:a3:61:8b:5d:1c: + f9:5c:60:e7:03:3d:93:5d:09:2f:39:e6:b8:20:f4:1e:17:4f: + e8:ef:75:de:5c:14:a9:45:5a:53:ff:72:a1:4d:4e:76:af:2f: + eb:e0:c7:9c:69:cf:3c:44:41:86:6c:c0:d9:02:e5:67:a9:44: + 13:97:19:09:01:3e:03:05:3c:61:10:a3:b1:f8:72:48:35:c0: + 7c:42:fe:a5:f4:c0:30:c4:ce:9a:11:6e:56:b8:75:8b:74:de: + ef:f0:e4:84:7b:fa:7d:00:8b:83:43:47:85:2d:5d:ce:8a:bd: + 9b:59:75:4e:91:af:c6:40:7f:2e:65:e3:7d:ca:af:f0:7d:4e: + 9a:4c:83:bc:26:68:1f:3b:5a:4b:94:76:ae:2e:e5:ed:1c:95: + f0:10:2b:73:99:9c:6d:e8:30:55:ac:3e:80:28:a0:c5:a4:ed: + ea:77:30:c1:fb:c7:11:b8:a7:41:55:d3:9c:e8:29:7e:83:e1: + d9:e0:7c:45:c9:92:db:f7:c2:22:ca:f6:a8:c2:1b:a2:65:c0: + 55:ed:c3:2a:20:fa:54:99:52:dd:a6:ba:f1:19:a2:ed:55:ee: + cc:84:71:1e:2b:7a:28:43:d6:f3:47:e8:f6:ed:f8:48:3e:81: + 77:b4:e4:07:d3:63:85:61:75:22:d9:f8:ed:21:b5:c9:ad:58: + 65:6d:10:43:01:e0:b7:20:5c:73:78:d3:65:78:93:04:19:c8: + b5:d1:cd:3b:a9:71:70:49:72:28:99:df:e6:ad:85:6f:40:42: + 85:84:f1:40:bf:57:b6:52:40:7b:5c:72:62:71:eb:26:53:44: + 09:5b:88:bf:f9:fb:52:5f:d1:36:72:bf:0c:23:fe:06:54:2a: + 1d:78:0c:54:6b:e3:64:ec:ca:9b:09:65:ac:a7:4d:b9:2e:59: + 50:53:fb:76:ea:1d:60:31:f0:31:b3:60:03:0c:e8:10:27:94: + 0f:c1:08:c7:4a:e1:0c:f2:ab:8b:0d:22:36:f3:18:70:7d:be: + b7:50:74:13:a7:5a:3e:b6:a7:87:3e:d2:47:6a:34:56:fc:cd: + e9:63:de:e8:51:76:45:98:81:13:ea:01:84:93:3f:23:b1:fd: + de:11:69:c3:2d:fa:c2:6f:22:67:dd:84:d8:bd:84:77:f4:44: + 59:60:c7:fd:da:7a:08:8e:a0:1f:38:38:fa:2f:5d:ea:0a:47: + c5:e7:4d:9c:78:2f:b5:4a:af:e7:37:fa:34:fd:47:09:d3:c1: + 43:0f:13:28:7f:8b:49:99:7d:11:00:5a:e7:eb:20:e0:0c:1e: + e2:33:d9:33:7a:42:80:ed:17:91:e7:ed:ab:ee:d7:4b:43:e6: + 31:1a:cd:6e:13:a0:3f:65:1c:6b:1c:8c:4c:e1:0d:1b:f7:fb: + a8:73:87:d8:81:d0:03:3e:2a:19:b2:7e:61:16:b4:3a:74:4a: + 7f:d6:f1:40:70:82:f0:6e:f2:e8:60:bf:e0:76:ed:f1:2a:5a: + 71:64:85:3f:23:97:36:04:5a:ef:7f:aa:24:06:2c:2b:b0:5c: + 45:92:1f:4c:2f:d0:eb:c8:d1:e3:d0:c0:65:77:d4:b9:5e:df: + 56:0a:ce:96:12:4c:b9:2e:cd:b1:42:49:d7:76:79:dd:f1:62: + 53:0d:7c:c2:ea:79:e8:bb:9e:b7:45:ff:e1:12:fd:d3:d9:09: + 41:74:63:ad:fb:e8:da:d9:ea:82:7b:0f:ae:46:51:d1:43:60: + d2:ba:88:da:47:47:a6:0b:c5:85:c2:78:3b:3c:5e:9a:a5:02: + 69:e1:a2:d8:26:e3:64:26:69:10:8f:99:a3:55:7e:98:e7:ac: + f2:82:df:b1:62:56:a1:19:ad:0d:8d:8c:f9:15:fc:23:42:be: + 4f:ba:67:21:5b:d2:a7:b7:92:a4:77:23:5d:d8:52:04:bd:d4: + e9:84:09:0a:a2:4d:0a:64:5f:ac:a2:16:ce:aa:85:c0:e3:41: + d7:12:08:0d:93:52:17:5a:c0:88:b8:07:db:90:3f:63:3a:5d: + 69:71:0e:c1:c7:d3:bd:9d:a1:37:1c:e2:b7:71:77:ff:58:36: + a0:90:0f:4a:f7:67:d1:02:fc:87:e5:c6:d1:fe:6c:6e:dd:cb: + 26:51:cd:e3:aa:78:6c:c2:78:b2:f4:dd:7a:94:b8:72:2f:f0: + 44:59:29:06:df:25:d2:85:03:07:9e:c6:12:8f:8a:a7:ef:84: + b0:5b:87:20:1e:d1:10:b3:61:8f:d0:40:6d:57:4e:e1:fb:3a: + 97:96:fe:55:55:f8:49:74:fb:96:f8:c2:a0:ad:6f:d4:24:cc: + 78:da:87:0a:cd:23:c4:a3:ff:ca:fe:98:d1:4d:48:d7:c5:d0: + 47:c0:01:81:28:b0:87:8e:f2:18:43:b1:bd:ee:d1:2e:35:0f: + bd:9d:6f:9f:93:86:dd:87:4b:bd:f3:55:75:37:ec:ac:7d:d2: + 09:2a:da:90:82:33:18:66:89:b3:37:b6:c9:b2:d6:ae:d3:13: + 37:43:74:a0:ff:e2:81:9d:79:5f:7a:97:7f:c4:bf:63:0a:58: + e2:05:b4:09:85:3b:4e:c5:8c:6d:99:ab:33:9b:f6:00:0b:4d: + ed:2d:5b:ae:77:0b:97:a2:71:04:68:18:8c:c1:d6:94:89:08: + de:e2:2d:81:0b:c9:17:20:2d:13:9d:06:76:44:54:7b:1a:63: + fc:c9:3b:92:9d:11:b1:ff:17:c4:3a:2e:09:73:12:c0:03:b0: + fd:a2:dd:c0:19:88:ab:03:b5:1c:a0:27:12:00:d7:ba:54:df: + 0c:a8:88:ec:34:0e:c4:af:b5:bf:04:fd:ef:3a:fd:21:14:87: + 29:9c:aa:43:95:bf:34:27:27:60:c6:69:48:a3:68:63:ff:9c: + 03:d5:80:9b:aa:68:ba:f0:71:28:4d:82:24:ca:7f:4e:27:04: + 30:bd:81:b7:50:af:86:1c:58:d3:14:0d:be:2e:ab:a0:47:e9: + 57:52:7d:c6:87:27:f6:c6:ba:71:d5:82:e7:10:de:76:dd:c0: + 6e:00:74:f7:87:36:08:2a:4f:dd:31:98:cc:fe:62:52:ee:d7: + 31:c3:52:9b:87:36:9d:6a:de:40:eb:82:fb:11:67:40:a2:8c: + d3:5e:89:11:70:12:8a:1c:46:2f:e0:ee:26:bf:39:dd:18:f9: + 13:94:c9:53:2c:36:b9:b0:50:e7:21:ca:ed:a2:d5:3f:21:de: + 8f:65:81:cd:7d:2e:fb:8a:55:25:c7:56:38:4c:9a:64:52:81: + ee:92:d6:1b:3a:dd:d1:ac:a5:48:a4:a3:42:1b:85:ed:d6:be: + 08:c4:8f:79:5d:81:af:36:30:45:c6:71:d6:99:5a:60:3a:79: + 91:b7:1a:1f:1f:ae:17:68:92:10:20:ed:6f:dd:38:df:01:54: + e9:49:d9:b0:da:1a:a1:fa:85:a9:5c:4a:81:49:3a:04:7d:4a: + eb:7d:aa:b0:7b:58:81:32:70:dd:05:b5:d5:07:b2:b8:cc:a0: + 47:25:f7:ad:e1:d2:da:dc:0d:32:bf:76:e1:8a:85:e3:15:65: + 94:79:aa:0c:7d:62:40:cf:2b:f2:54:81:5b:df:bb:0d:ef:dc: + 63:57:b3:fe:df:f5:cf:28:4f:9f:30:da:45:0a:67:07:30:9c: + 22:2f:51:94:fe:d9:7a:37:17:63:61:30:98:3f:0a:43:32:60: + 16:18:6e:e2:e2:2f:3d:b1:a1:50:0f:58:7a:a6:62:78:a6:43: + 47:3e:85:d0:0e:7e:ef:ca:de:03:f8:fe:a2:ee:70:31:a9:d3: + 31:bc:2d:fb:16:d4:8b:a8:0d:55:cd:a4:78:fb:f0:f0:74:cb: + b4:32:3a:43:e2:90:c8:e6:ec:f7:8f:f3:bf:a1:7a:e1:ba:ed: + 09:81:35:bd:7a:2e:a0:1f:07:d5:e3:5a:f5:d4:54:17:a8:74: + 9b:1d:c6:50:40:56:d8:63:9e:01:50:39:8b:65:39:77:9a:f1: + 78:a4:e4:57:33:70:9e:23:84:ad:5e:c8:78:1d:2a:9a:c8:6d: + b0:9a:4e:46:bd:60:a7:f4:67:fd:fc:e4:99:6d:22:22:0e:10: + b0:13:bc:11:a7:65:3f:5e:20:c9:65:59:4f:d2:6b:23:a4:cb: + de:a7:46:9d:d7:e5:3b:d0:6a:29:2c:77:45:d9:8d:3a:e6:b2: + f8:d6:2c:45:c2:5f:7f:64:d6:5d:f3:8f:1e:a6:f3:93:20:e1: + 74:2e:38:75:75:2c:5b:96:52:93:e0:a7:53:5d:a3:8f:c2:2b: + 72:6e:00:f0:06:71:0f:0f:7f:92:93:5b:16:32:c8:9a:30:52: + 42:6e:6a:90:3d:2e:b4:87:ee:68:97:e6:24:30:d2:9d:c6:30: + ed:bd:ba:c0:99:4d:4d:e9:71:98:7d:ac:6f:8e:e6:32:29:45: + e8:46:e1:77:2a:15:6c:cd:01:93:b4:e4:2d:ad:ae:df:49:a2: + 40:dc:97:62:52:ef:80:26:91:f1:c5:3b:76:b6:ae:fd:f7:2b: + 13:d6:67:f5:98:18:76:b1:70:f9:fd:1b:ad:22:fb:12:6c:c2: + 23:00:89:85:c6:af:e6:6d:95:dc:06:3d:fd:6b:6e:cc:0f:3a: + 66:b8:50:4a:e3:eb:e4:34:f8:7d:57:1b:6b:87:ce:06:78:e1: + 66:30:8a:cc:b9:af:76:b1:9b:bf:ce:76:2b:86:a3:95:b4:ff: + 5e:50:0b:1f:3c:5b:13:e3:7c:c8:cc:77:4e:1b:6f:ab:e6:00: + 49:a3:1f:2a:36:b1:dd:0d:70:10:13:13:b9:ab:5f:2b:2b:bf: + 32:2a:65:b9:87:55:2d:59:96:ec:fb:36:c1:33:f9:e8:6d:a1: + ad:0b:f4:a2:8f:ec:fb:c8:1d:43:36:2d:a8:43:9f:52:53:27: + 16:3b:ef:b7:01:e7:35:e9:96:15:6a:f4:af:fe:6a:93:42:65: + 0c:6a:d1:a5:8c:21:4e:db:0e:30:52:00:73:df:75:bb:a4:4b: + 36:b3:c5:f0:92:30:d9:4c:ce:a6:1f:9b:46:b5:17:60:d1:56: + ec:29:e2:eb:94:e5:ef:6f:ea:01:af:10:26:e6:b5:7d:81:db: + ad:f6:63:87:ae:0e:13:98:29:3d:d8:1f:ea:10:92:5f:70:7b: + d6:d6:1f:aa:ad:4e:ee:db:3f:5e:36:a6:95:92:46:9b:9e:c0: + 24:55:16:5e:e5:75:80:eb:3c:f3:e9:10:1c:96:47:06:9a:59: + 4e:d7:a8:31:b6:26:bb:f1:9c:d5:d0:49:64:dd:03:28:1f:64: + 18:6c:d1:27:a7:ca:88:f3:24:bc:7e:96:72:2d:09:f9:98:42: + f3:16:6e:df:72:e1:27:8b:8b:fc:e4:e1:3b:cc:79:73:17:14: + 29:54:8b:30:73:63:cb:6a:02:4e:53:91:44:4d:29:d1:66:d8: + 07:ca:9b:c8:fc:b2:d2:d5:cd:a8:04:a5:ff:67:49:04:8c:bd: + a2:2c:ee:f1:53:68:71:f9:85:08:8b:e7:79:26:05:4f:c1:d3: + 36:57:8b:f6:04:28:22:65:85:4c:f4:d1:dd:ae:57:e4:8b:73: + aa:32:88:6d:e5:ca:88:b8:7b:aa:b9:f3:5f:0f:3c:08:fc:d4: + 40:e9:c6:3d:97:cb:10:85:02:81:c0:ad:02:94:20:7a:56:29: + b9:b9:31:d8:ae:bd:b2:e2:13:4e:ac:98:6e:7b:46:3d:3d:99: + 41:fd:5a:e1:31:fb:ab:f9:1e:bc:99:6d:0b:14:8f:29:10:9d: + 7b:4c:60:f8:0a:ca:99:67:db:8a:3a:ff:24:ac:4e:5c:d6:4f: + 9a:bb:51:7e:e8:c2:a3:46:17:86:4e:3d:9f:8d:14:3c:aa:3d: + 99:e4:b2:70:a8:97:4f:ab:28:d1:ef:34:22:02:81:dc:bc:b5: + d3:98:68:c5:9c:e7:bf:24:61:77:b7:fe:ad:7f:ea:49:64:42: + 4c:f2:22:1a:2e:3c:23:7a:12:91:45:a4:6c:e7:60:26:ae:41: + 9d:39:95:bb:18:0c:5d:3e:77:6e:e7:aa:42:be:64:9d:a4:f0: + 17:1e:fb:ae:8f:49:5a:bf:8a:d3:4d:f3:72:25:a0:13:48:9c: + 7e:cb:19:60:49:5b:92:9c:94:77:34:8e:bd:d4:a2:e3:92:ff: + cc:d2:86:4d:61:f9:ae:86:f1:76:f6:c7:5a:6d:bc:17:e7:9c: + 53:e1:b0:f0:66:13:ad:4e:de:98:92:8b:1a:e4:b9:da:00:a3: + 75:ce:27:3c:85:3f:56:31:4e:7d:10:1b:7f:32:00:7b:0d:33: + 11:4f:bb:2d:e0:c2:bb:ec:0e:69:ec:65:fa:5e:0a:06:6b:74: + 6a:bb:58:2e:41:c7:17:9d:10:09:e6:fa:4f:34:7c:07:c3:00: + 01:a5:0c:30:0f:12:38:ef:ea:e9:c9:9b:62:2f:07:9b:e6:78: + 7a:14:f7:22:ed:ea:24:91:00:fc:14:36:af:20:a3:e0:ee:0f: + aa:4f:8f:ab:2e:79:dc:6c:b0:f6:46:0b:c3:04:43:c2:e3:76: + a5:2d:f5:23:e6:0e:59:1c:13:2f:4f:0c:de:7e:2e:a2:8b:19: + a8:08:91:e1:e6:87:11:05:2d:6d:f6:23:dd:5d:08:1a:e1:e5: + 3f:45:46:30:bf:1a:05:af:8c:0b:f2:b3:d5:99:14:a3:e5:c4: + 58:8b:90:06:33:34:b4:65:b8:bc:10:bb:6f:44:be:61:b1:de: + b8:b0:66:f3:45:f2:6a:4f:4d:66:8a:00:c4:d5:34:da:4a:e9: + 73:d5:20:a4:bd:ec:0e:b2:44:2b:d6:7f:a5:86:05:3f:fb:6f: + 8e:75:cf:df:4b:8b:d6:00:ca:1a:63:58:f3:90:6d:f1:a5:a3: + 43:3c:50:8d:0d:bb:ea:8e:2b:4c:55:f1:89:ac:18:3b:3c:85: + e2:fc:0a:0a:71:ad:a1:45:e4:6e:c9:73:46:ee:31:39:89:b0: + e8:7a:44:f6:fc:7a:b5:d3:bc:1d:fd:8f:65:33:b9:79:1f:be: + e5:9a:d2:5c:00:57:0c:8b:b9:f6:85:b2:07:c1:4a:3e:c3:27: + dc:c5:c0:d7:16:fd:ae:69:16:30:bd:2a:f3:de:99:92:8b:41: + b5:21:9a:a2:bf:c4:08:f0:d6:6e:18:37:f6:c4:ee:27:a7:3c: + 05:0e:b7:32:02:5e:aa:5e:5d:ff:5b:d2:2b:1b:bd:56:cc:2d: + ce:99:d3:e4:b7:73:db:a2:e7:f1:16:59:21:c2:bf:be:fa:c3: + 80:73:77:73:c1:b0:4c:32:2a:9e:80:5a:30:4a:6c:d4:f9:f3: + df:41:66:67:2c:de:2a:74:35:7c:21:31:6d:c1:54:6e:e2:17: + 4a:f8:fb:96:69:78:4c:4f:c8:1f:d0:b3:6f:05:d3:12:f6:e1: + 88:b6:a3:a1:e7:57:9b:3f:c4:d4:f6:b8:f2:89:81:af:8e:e1: + be:16:37:69:3b:05:99:af:35:49:8a:9f:43:6a:b2:da:8a:8c: + 69:9a:3c:81:24:4a:54:58:d7:9d:76:69:5a:b8:db:af:e3:64: + 95:d0:bc:40:50:3f:b1:3b:b1:f3:99:f3:40:74:b6:cc:e7:39: + 93:e4:94:96:9e:34:44:15:12:ec:87:d2:45:40:f7:c7:24:53: + 7e:91:0c:6c:d9:ca:e7:b1:92:9e:7f:79:22:fd:69:16:fb:ea: + a5:e7:67:17:71:bd:aa:9f:c5:93:78:91:64:28:af:56:a2:3d: + 47:76:84:2e:44:73:85:24:fb:ea:b4:bb:b4:c4:92:08:4a:ba: + b0:f4:78:4b:87:42:30:04:0e:b2:bb:3f:d3:9c:ef:35:bd:0b: + f8:09:a8:88:a5:f9:5b:3a:93:d2:8f:07:05:6d:7b:82:82:60: + 3e:70:24:cd:a5:e5:38:3a:5a:1f:1d:01:d2:75:2d:be:b2:89: + bd:7b:bc:eb:18:10:70:07:89:e2:a9:10:92:f6:f7:55:84:9e: + 59:88:5e:97:38:05:7c:df:a7:ca:94:dd:8d:c1:c0:ae:1d:2a: + a1:54:85:e0:3e:80:7f:ed:e4:90:eb:bf:39:72:67:c9:81:dd: + ea:d4:51:e3:5f:19:39:54:cb:46:5f:d0:d2:c8:67:c1:85:2f: + 22:c6:a7:97:eb:25:06:05:a5:1f:80:45:ff:62:52:f6:a5:78: + da:91:aa:29:26:2f:43:c8:23:86:04:9a:04:ea:b4:5d:c4:62: + 76:97:d1:9b:11:80:aa:70:88:db:32:67:9b:ad:0c:26:8b:7c: + 09:ee:0b:73:d7:60:22:d9:48:c4:20:b6:02:9e:4b:f4:c0:9a: + 43:b2:0b:6a:e9:c7:27:0f:14:9c:5a:7c:20:08:12:a4:c9:57: + d6:a1:35:5f:a8:6e:71:29:fd:87:e5:53:f0:56:eb:15:c4:0a: + c9:e6:49:1d:c8:22:b7:a2:0e:42:7c:90:46:bf:0e:cb:a9:16: + 65:2f:65:24:f0:d2:a9:81:cf:8c:2c:5b:30:5b:4c:4a:22:ed: + 74:c9:c8:e6:b8:ea:4b:24:9d:95:ca:2d:3d:00:08:79:ec:73: + 97:29:64:1f:c6:a1:21:60:7a:bd:e7:15:cb:7f:0d:84:15:84: + 8b:4f:37:3d:e4:79:5f:52:65:a3:bd:b0:8c:af:db:6a:d6:de: + a4:f6:80:bd:f8:cb:7c:cc:6f:1e:f1:db:5f:ee:0d:f2:81:95: + 00:05:56:36:f8:38:c7:46:b5:53:03:ae:dc:77:b8:d9:c6:99: + 60:c4:ee:f2:fc:30:55:cf:53:51:9f:fc:64:62:bd:93:d7:eb: + fd:2d:4b:b7:be:06:23:14:8f:34:34:75:d6:47:f1:82:35:74: + a1:ee:91:e0:62:55:6b:b3:33:19:da:d0:aa:88:c7:cc:e8:ee: + 1e:6a:b5:90:60:db:ff:ab:6d:26:ee:64:69:33:a4:6f:2d:15: + c7:d0:26:bd:2d:b4:0a:93:de:b8:51:3f:9d:20:df:41:dc:04: + f0:89:bc:75:85:04:11:0c:e3:81:2d:ec:8d:56:43:d9:6d:af: + 5a:b5:7f:9c:79:cf:50:e1:21:d6:86:8d:ca:94:4b:35:a5:e7: + a6:a3:bb:0f:6e:45:1f:5a:f2:d3:cc:ad:1c:94:a6:43:c8:89: + 4a:8f:35:96:a6:29:d7:12:97:af:2a:13:11:86:b8:5f:c6:5a: + c6:b3:c0:99:c1:56:5f:c2:ce:fb:d1:f9:1c:71:c2:c8:ba:08: + d1:2d:ce:9e:da:fd:9d:99:0e:6a:2e:46:10:84:07:02:1f:9a: + 03:69:6f:92:46:65:ff:06:34:77:74:29:c5:6f:9d:91:c2:36: + 78:2f:cd:4d:23:af:6d:9d:18:e4:5f:8f:54:a5:b2:8b:db:a3: + 5d:c2:df:8c:2a:de:86:23:10:f0:63:85:e4:83:5e:46:68:dc: + 29:26:34:a6:eb:a9:67:bb:3d:33:c0:17:1c:f2:0a:e5:0c:9d: + 7a:95:e1:22:07:54:e5:a0:a9:1e:51:fd:59:86:cb:cc:9a:3d: + 5b:06:bd:4c:2e:cd:93:c1:04:9c:a7:04:1c:f5:b6:15:fb:c0: + 95:e6:cf:43:a8:2b:b6:1f:02:74:44:c9:b8:3c:22:15:f6:90: + b1:30:bf:5f:bd:ee:82:9c:9b:88:1a:7e:7c:b9:38:7c:d7:55: + a7:3b:6a:23:ac:83:f1:da:d9:49:76:27:b3:9f:8a:00:58:c8: + 84:37:de:d2:47:9b:22:88:2b:ed:f0:c9:d2:cb:01:8c:bc:07: + 7f:7c:93:7f:5f:7e:95:9b:d1:0f:c8:46:2c:68:fa:f0:b2:1d: + 46:8d:b3:bc:0c:3e:d3:ce:d6:5b:5b:74:83:9c:5e:61:26:1f: + ed:39:e0:5d:78:03:db:e6:6c:6f:bb:bb:b8:f1:21:a7:85:ed: + 9f:01:1a:24:a6:19:5c:67:88:13:60:aa:a3:82:21:12:a4:a2: + 75:f3:8d:77:72:b3:46:da:5c:5c:2c:08:de:43:d2:a5:84:a8: + 39:bd:21:69:4b:98:d6:42:63:6b:91:27:10:4f:6d:50:2d:72: + 23:fd:16:c8:57:f5:1d:b3:6c:21:68:27:ab:30:42:2c:4f:36: + 0c:39:e4:d4:87:62:0a:3a:e1:de:81:10:10:85:65:04:49:34: + c0:77:1d:80:06:73:4d:b8:13:a4:6d:d7:eb:cc:88:5c:52:84: + 4b:db:13:9a:d3:f1:bb:40:3e:3a:64:f9:f3:3b:ae:e3:d3:b1: + 8b:b1:ff:90:96:48:15:10:a4:b9:90:16:2f:af:62:ba:80:05: + 83:0c:b5:61:45:38:7b:61:78:b2:35:52:fb:71:ba:31:c4:0c: + db:2a:68:86:03:b7:d8:12:30:52:71:1c:c6:13:e6:09:75:c5: + 0b:5f:42:a2:d1:0a:af:52:42:f2:0d:9a:a6:9d:20:35:73:e0: + 6d:fb:ca:ae:5d:ca:16:4f:3d:e5:d6:4f:ab:57:8b:19:ea:6c: + 2d:13:0f:65:a4:d3:c1:aa:71:12:a3:a8:e2:07:5d:ef:e6:33: + c0:b5:95:96:1b:a2:a1:8c:9d:34:b1:3f:21:5c:ba:75:42:16: + 8f:90:6e:a8:57:3a:d6:e2:28:e3:07:c2:db:f7:c9:fc:d1:5e: + 5a:45:20:03:51:2f:f4:bb:96:a5:7d:84:ed:e2:6f:a2:7d:ed: + a9:26:2c:b3:13:f1:7f:24:06:90:a8:ea:eb:3a:d6:5c:f6:43: + cd:5e:a5:8b:7c:aa:4d:92:a3:f9:47:16:80:6b:47:f3:c4:f6: + 4f:27:de:6b:0a:b2:ca:b9:73:38:fa:2c:f9:0a:41:74:b7:c4: + e1:8b:ed:70:4a:79:09:e1:32:c3:d2:02:38:29:16:e8:e4:18: + 4d:5a:ca:fc:cb:0c:af:52:bb:0a:48:62:19:c8:85:f9:85:f4: + b9:fc:11:8f:37:ec:2c:df:41:90:2d:f2:f3:27:e5:a2:ca:ca: + 33:a9:db:f9:2e:93:00:bd:1b:a9:fd:5e:ff:38:5f:68:fa:7c: + 81:23:82:40:04:a2:1f:b4:66:8b:b1:90:c6:0c:f7:b8:04:6f: + 38:d0:25:1b:3c:d5:dd:78:fa:fd:f2:c0:2d:a3:db:6a:5c:7c: + c1:e1:5c:f4:48:eb:38:fe:c0:5e:0f:ce:da:06:34:8e:b9:56: + 88:2a:12:51:16:b7:9e:e8:00:d4:b3:75:9f:eb:b4:87:5e:5b: + 55:2e:cb:92:93:56:bc:02:21:a0:b4:c8:d7:4e:3d:ea:10:19: + 38:90:3a:31:2c:84:2d:d4:a0:35:b6:25:06:e4:bf:1b:e3:20: + 58:73:37:49:f0:55:de:d6:34:c2:3c:db:8e:34:b6:a8:b1:27: + 3e:a1:01:b1:f4:9d:c3:87:98:42:97:af:2f:fa:c3:a5:2c:b4: + b4:4f:d7:d0:90:5a:25:18:48:16:12:23:b8:6c:62:0b:c3:69: + 79:ff:bc:3f:03:5e:43:4e:ec:f1:e9:33:d4:13:01:29:70:94: + 96:5f:82:96:84:65:3b:61:76:60:12:83:eb:5a:d5:b8:56:42: + 3d:e9:79:82:94:d1:0b:7c:13:6a:67:f2:ce:ff:58:da:58:5c: + 76:51:09:42:1c:d0:5a:79:29:8f:d6:50:a7:4f:b9:6f:e4:d4: + 4e:68:ba:22:3d:dc:a4:6f:76:ff:28:d3:64:77:54:ec:2c:49: + 9b:0f:cc:62:86:ba:8e:88:21:cc:bd:7d:bd:fa:0c:7b:22:09: + 30:dd:30:7f:e3:1d:13:21:a3:a6:8d:89:78:20:ad:ff:d8:17: + 85:1f:30:fe:dc:a9:3c:ec:bc:ba:1e:3e:e9:05:44:6f:c9:9f: + 7a:46:e5:68:27:65:e7:c1:bb:4e:89:0a:e7:f1:56:44:47:b1: + 0b:c1:eb:57:eb:33:58:14:1d:dd:f4:e4:de:e9:4c:a7:da:d1: + 6d:4c:ba:c9:33:7e:a4:01:91:e6:da:3d:0b:af:26:ae:5b:9c: + ea:92:8b:82:45:7c:1a:1c:d7:ba:fc:83:c7:a0:53:72:2a:57: + f9:1f:aa:a7:b8:5d:a1:7a:21:c0:f6:b1:72:2a:8b:3c:d1:fb: + 6f:2c:c4:d8:3d:da:c0:52:67:df:c0:74:98:46:4c:3e:69:b1: + 0e:58:9b:a0:8e:a5:52:75:5b:9c:46:94:c4:19:b5:e8:e0:35: + b9:ef:44:db:2f:9c:17:a2:c6:e8:9b:a6:73:df:a5:c2:e2:cc: + 9b:0c:4b:f5:8d:9b:06:3d:26:bf:f3:3d:35:9f:1e:63:c8:53: + 6c:63:13:87:9d:ad:31:61:3d:5a:6c:4d:76:41:de:59:fc:77: + e6:4c:1b:0b:db:2c:40:e5:d1:fc:30:47:fe:e3:c4:67:82:32: + 9c:9f:6b:53:a3:c3:bd:78:a7:e8:0f:aa:0d:d5:c4:46:d6:68: + a5:6c:14:3a:62:c7:ec:42:81:f7:d5:da:90:e0:3e:e1:bb:88: + fc:fd:85:96:b2:dd:46:b0:cf:fc:46:53:3b:7d:ae:cb:91:74: + df:d2:15:f6:ea:ef:6e:10:89:85:0f:2d:ea:ad:d1:77:ab:62: + f1:56:6f:60:c0:bf:6a:eb:83:77:e4:e7:71:e5:ec:63:6c:af: + bb:d5:60:f8:bc:10:68:ef:84:aa:45:3d:f9:46:46:4b:3e:47: + 1d:6c:3b:c6:2c:1c:54:e8:97:cb:87:39:87:99:4d:5a:2f:81: + a3:8c:d1:9c:2e:92:43:6e:e6:76:51:48:94:09:1d:07:64:00: + 5d:c0:8c:ee:43:b7:ea:08:15:bb:a1:aa:44:63:d6:5e:e8:53: + 17:12:e7:69:41:43:fd:bd:8e:ae:de:0a:33:13:38:df:45:f9: + 4f:94:db:83:14:60:30:d7:d0:3a:9f:c5:cc:d5:07:95:90:2a: + 5b:fb:82:05:20:03:4f:23:24:09:0c:92:93:a5:88:df:2e:dc: + a3:83:39:b2:a5:90:35:c7:9d:30:c7:68:e5:1c:da:a6:dc:cc: + e8:00:77:bc:15:4c:f6:3c:c2:7e:c3:7e:c8:b9:0f:2f:7d:55: + 34:32:8e:87:e2:db:de:46:f3:d8:75:84:9c:67:a0:76:61:5a: + af:2f:4b:1e:95:73:3c:13:ca:bb:83:3c:6d:2a:66:4c:d1:58: + a0:a3:ef:1a:71:ac:e9:ab:7c:6c:81:51:e9:35:c8:85:65:a8: + da:1b:16:6e:f6:6f:53:34:da:62:4b:d3:c1:73:88:c0:38:1a: + 79:0b:b2:ca:cd:4f:9f:7e:69:3f:c7:62:6d:c6:fb:cd:50:fa: + 48:04:c2:e0:3f:e2:55:ae:57:07:25:b0:bf:bf:c2:92:c1:83: + a5:2a:15:61:ce:bb:72:79:24:9f:7a:03:a3:c9:30:8c:c7:02: + 37:72:6f:b0:bc:75:9f:14:88:9d:5a:b6:8c:ad:8b:bd:6b:f2: + 53:67:e1:23:17:e5:68:a2:47:7c:40:83:01:c3:dc:eb:c0:0c: + c2:a6:b2:60:32:2e:99:e1:82:20:ac:ad:5e:df:d4:14:81:f2: + 7c:f1:1d:94:82:c0:ec:44:83:e0:e0:ca:23:cd:d9:81:f4:34: + 34:29:52:01:74:fb:38:0e:b9:60:54:a5:ab:1b:36:6d:0b:f9: + c6:cc:66:bb:e5:c0:7b:33:d8:72:63:2b:d7:9f:06:96:b2:3f: + 2e:b9:55:78:3e:cd:f6:85:1c:1b:23:98:f8:7b:e1:2c:53:a5: + e0:ae:de:0f:d9:bd:a5:5e:45:7c:d0:cc:33:f7:30:ed:b7:9b: + 12:1b:5b:55:3c:7a:d8:40:b4:74:43:cd:79:dd:fa:1e:3b:d1: + 56:59:48:4d:2e:81:a9:1b:c7:a3:97:fe:b4:7b:5c:01:7d:7c: + 39:ce:31:44:67:fe:e4:43:3d:94:46:d6:21:42:e5:3b:16:e3: + 90:d5:64:a4:53:21:b0:76:1a:92:9c:fc:68:8c:c0:f4:71:e2: + c1:ba:3f:fe:ee:a1:db:a5:80:44:1b:7d:d4:e6:47:8d:70:3f: + ea:5e:1e:4c:7a:9e:43:a4:a6:5f:b2:cf:a3:9e:e0:bb:04:7f: + 74:05:04:a4:a9:77:1c:01:49:c2:67:bd:c6:af:7a:e0:5d:aa: + 55:e3:da:46:3e:90:c0:82:c9:4e:46:e5:f6:97:69:72:6b:ba: + ea:cd:5b:43:ed:69:64:fa:14:eb:ea:de:34:c0:02:8c:bf:37: + 0d:33:fb:a9:0f:db:3f:47:f2:11:e1:f9:cb:e0:87:83:d3:5c: + ab:9e:c3:5a:2f:7c:fc:67:95:87:b4:7a:fa:ae:14:c1:bb:ee: + 5b:23:be:af:ac:2e:58:d8:97:1a:48:62:3e:2a:43:be:7e:7d: + 76:ea:b8:9b:96:78:84:7f:ee:75:8d:71:41:d6:af:29:c5:78: + 24:9d:9f:60:d8:a1:9d:3a:5c:f5:ae:11:c9:d6:69:30:71:44: + 64:8c:7a:8c:18:a3:9e:04:cc:d3:02:c8:58:6b:18:12:64:b5: + ec:c0:ea:12:ad:52:a3:86:53:44:9e:b2:b4:18:18:ae:3c:3c: + 96:a2:79:4a:c4:84:c7:7c:c1:5c:25:3c:d8:e7:9e:27:4c:c1: + 44:ec:54:e4:19:8a:84:23:f2:c3:21:d3:4d:e4:71:0a:ba:9e: + 7f:fa:5f:e0:d4:db:26:41:57:04:86:de:87:aa:a6:91:c4:5c: + 53:92:fa:6d:b4:fd:a8:74:7d:97:fb:54:30:80:f7:99:c0:f8: + f3:19:62:61:d1:bc:70:aa:98:1f:67:31:cf:83:7e:67:47:f4: + dd:68:94:4e:ee:51:dd:06:77:c3:9c:d2:62:40:4c:46:8a:eb: + 68:69:f5:35:25:cb:6e:d2:18:ad:e8:80:f5:02:20:2c:a1:6b: + 03:30:5a:1f:09:7d:a7:8c:64:46:8d:e2:8b:2e:48:3d:59:f1: + f7:ae:48:bc:54:30:08:82:ba:15:a5:8f:21:f8:53:14:d6:1b: + c8:5f:49:4e:6b:59:6d:60:0c:aa:50:95:10:55:6d:cc:fd:03: + f6:a3:e5:6a:83:a2:cb:be:8a:f1:fc:74:40:93:69:f8:ce:32: + d0:8b:3f:ae:ab:76:b8:bb:fe:75:05:9e:de:b2:63:a5:ca:40: + 8e:e2:38:fd:7a:32:61:e5:41:93:9a:e7:3d:46:8d:14:c1:b6: + 8b:1e:85:95:b0:44:2f:f9:e4:81:55:22:b5:bf:6f:22:1f:9a: + 5f:e9:60:03:c8:a4:89:e3:cb:c4:b3:1d:85:05:28:7a:2f:06: + ba:4a:e7:31:46:33:b3:8b:68:70:49:39:c8:63:d1:f6:d3:2a: + ee:9b:24:7f:c0:f2:b9:8e:76:c4:84:9b:55:1c:fa:07:02:ae: + 86:59:b9:45:be:8d:4b:7a:ed:aa:02:86:33:ae:4e:d3:27:f0: + 1a:98:43:78:87:65:2c:8d:b1:85:af:a4:99:45:a9:78:c1:9a: + e6:4c:97:b8:ca:28:5a:eb:23:33:b8:3c:0c:73:67:28:0e:cb: + 82:4a:e7:33:94:ad:56:99:cb:7c:4e:3b:f6:85:7a:62:9d:66: + a3:71:43:91:f2:fa:d2:e0:46:a0:3a:d5:d7:49:64:0b:32:0b: + 50:6e:81:76:07:a1:d2:18:25:83:24:8a:65:a2:e4:6e:e5:46: + 70:ee:87:8a:9d:25:ef:3c:92:54:a5:fd:06:00:af:ac:85:8e: + cc:4b:8e:03:53:18:14:e0:10:fa:cc:40:33:50:e8:f8:94:f3: + ac:fe:60:a6:1c:05:23:94:56:ab:d3:bf:6b:13:3e:53:ff:45: + b5:c2:0d:12:4f:0d:c6:8d:97:7d:ad:04:53:c1:aa:3b:7b:b8: + 46:a7:0e:88:e7:fa:df:a4:e4:81:d4:d3:9e:14:0c:d6:28:48: + 67:73:5c:41:80:3a:a9:d3:19:00:88:f3:65:72:74:84:2c:d3: + 09:6c:98:7f:67:b0:ae:ae:71:d2:db:c1:ae:f6:dc:ff:c7:d2: + 0a:e9:5e:a1:fd:86:a2:aa:9b:76:82:dd:d6:9d:19:0c:5c:80: + e2:91:90:99:95:4b:3d:47:2b:e2:0e:f7:ed:a3:b8:77:d5:5f: + ae:28:a2:e0:ad:68:46:bc:39:7a:a2:89:2e:eb:b0:85:c7:32: + c6:e2:65:c5:e3:f4:21:85:48:0c:f1:eb:21:69:49:eb:5d:a7: + ca:73:11:05:e3:50:7c:ad:82:5a:4a:90:34:05:05:19:73:3c: + 71:28:8f:f3:93:c9:09:2c:1c:73:aa:db:0e:0d:63:e4:06:d3: + 67:fd:94:c9:5a:12:ae:84:8f:79:26:fc:47:a9:0c:74:63:2a: + 99:61:e6:18:c2:c1:02:30:ec:c8:18:1f:b5:46:20:ee:6e:42: + 7d:82:6e:03:41:7a:44:c9:f9:a7:56:34:73:00:bf:78:a1:c1: + 8d:d4:05:04:e9:8f:da:e4:87:4a:b4:61:99:7b:b2:11:53:26: + 56:b8:06:c3:c3:d0:5d:84:6b:87:7d:fb:7f:88:af:31:4d:45: + a2:58:77:2c:21:23:3f:39:23:17:79:aa:2e:18:2f:31:60:6b: + cd:94:00:31:54:56:ca:b7:a6:bd:b1:1a:72:68:40:9b:ba:c6: + 2f:6e:2f:00:55:b1:e0:06:94:77:e8:c2:40:6a:7e:73:04:9a: + eb:95:81:bd:1f:57:f4:2f:84:c2:f1:50:49:86:11:0b:9f:dc: + 95:d1:5a:28:99:5e:56:ee:d2:b7:9b:45:d8:54:81:81:b9:35: + 0e:91:a8:25:a6:72:14:bf:19:cb:50:d6:e4:9b:b2:5a:69:ac: + 34:dc:70:89:ad:74:00:dc:47:64:b9:ad:fc:24:a4:0e:e6:95: + 41:9d:80:2f:05:2c:89:30:c6:b2:20:0f:36:c2:56:01:ff:65: + 9f:b4:bb:af:23:69:2f:f4:1a:7a:44:e9:cc:c2:89:93:80:e5: + 2c:b3:62:f2:20:69:47:39:90:3d:28:df:1d:11:12:f1:94:0f: + 77:ad:65:71:77:3e:03:c4:44:6a:d1:8e:fe:9b:e1:74:d9:32: + 5c:e2:27:4b:36:aa:d8:cc:58:66:a8:c5:35:cf:27:3e:07:8f: + 13:56:98:da:96:66:63:84:4a:0e:07:b0:0a:48:7c:49:63:af: + a5:2a:07:d6:f9:1c:fb:b5:5d:dd:43:1b:51:cc:f0:55:d7:9f: + 08:a9:87:2e:fa:4d:65:8d:8c:f9:42:af:e2:ed:4b:8b:9e:e7: + 8d:da:35:63:9a:22:7b:bf:f2:06:3c:10:ed:72:87:15:4b:80: + 33:3a:aa:16:34:22:ae:c4:e6:e8:8c:8b:8d:4c:59:ba:a9:d0: + 48:56:56:1d:06:00:b8:cc:57:ea:b9:b7:5c:9f:55:f1:f5:d2: + 59:ba:3d:2f:44:38:3b:20:f4:48:e1:3e:34:45:de:02:d7:64: + 9e:fb:c7:00:62:79:16:8d:20:69:45:c2:69:cc:a0:cf:9e:7a: + b1:9d:d0:33:7f:c7:4b:22:ce:25:34:bb:b3:c4:c0:21:62:d6: + a6:03:63:12:fb:d5:c8:ee:fd:30:ba:11:26:0f:21:9f:d0:e3: + fc:84:41:0b:8b:2e:c0:9f:ce:76:0a:8d:48:86:ad:f7:2c:6a: + 5f:82:2a:ac:a3:d4:55:f0:37:6a:5a:fb:6d:b0:59:da:26:ba: + f6:b1:b9:62:42:82:83:6a:3b:a6:7f:84:92:1a:2d:b7:08:1f: + 86:9b:81:02:96:ce:d5:12:52:45:16:c1:9d:a4:88:e9:a9:b5: + d5:0e:b0:cf:98:53:69:9c:8a:5d:89:fe:05:85:96:83:16:68: + ac:18:89:f1:7e:21:25:9d:cf:29:b4:cf:2e:99:22:e8:03:20: + 26:52:1c:f9:0d:47:f7:58:9d:fd:59:52:e7:5a:5f:08:14:31: + d2:e6:06:f8:0f:a0:e8:38:80:9c:c9:5f:f6:f3:cb:ee:66:27: + 36:7c:2d:2b:0c:77:1b:66:cf:cb:a3:10:7f:a7:ce:75:ba:46: + 71:5c:5d:87:2f:3a:52:ba:d3:c1:56:a9:93:ce:ed:3f:64:84: + 21:37:69:5a:0b:0c:cf:31:99:62:89:31:fc:67:31:af:9d:d0: + 5c:e9:38:0d:f8:cb:c5:47:41:24:d1:b9:98:50:f2:ae:49:65: + 21:10:1c:18:3a:84:64:ce:5f:39:0a:c8:f5:5a:ea:ae:33:23: + c4:c2:24:06:4e:af:1a:fe:53:8e:b2:84:3d:12:a5:cf:4b:d4: + 18:15:a7:88:4c:26:95:19:c4:7b:57:b6:a8:c1:44:d5:2e:65: + e5:d3:f2:95:58:25:f6:2e:71:63:d0:1c:93:39:a0:4a:15:ac: + ae:4c:6b:5b:5c:5b:93:d8:5a:5f:f5:12:dc:55:27:89:10:7c: + 29:f6:5c:c7:3f:23:5f:fc:a0:a4:53:d9:50:fb:c2:58:6d:b4: + f1:d0:1b:69:33:1b:a9:20:bd:4d:ca:c8:f0:bf:a5:a9:af:5b: + 9f:f9:61:09:c6:81:58:cf:67:e7:21:24:93:89:93:b2:08:92: + 32:2c:ab:ca:e4:df:ef:16:d5:f8:e4:df:61:63:bb:94:28:7e: + 1a:18:2f:7b:63:25:fd:5a:18:ad:8e:49:5f:21:38:52:80:36: + 1c:74:e6:03:75:6e:f9:0e:7e:d3:e3:a3:d0:01:9e:9e:97:af: + b5:bd:bd:7b:f7:05:c4:38:53:ee:6f:f2:5b:11:36:73:f8:59: + 5e:54:c1:28:73:12:d3:0c:d7:5f:75:56:e8:39:f3:02:59:8e: + 96:8d:71:4b:9c:e6:ee:46:1e:87:72:86:7c:3d:eb:f1:f2:05: + b8:a3:8c:e9:e9:2e:43:95:3f:18:e2:86:b2:94:bf:6e:1e:0a: + fb:3b:10:78:da:94:e3:e1:7b:3c:28:0a:b0:63:d1:2b:57:9e: + 5a:b6:b3:94:9e:a9:44:72:1d:c5:c5:c8:ea:42:0c:a0:31:8c: + e8:8a:30:b0:13:33:a9:a8:ab:41:4f:f9:f2:9b:cf:53:fc:bb: + da:b1:86:eb:dc:13:7d:61:db:eb:e1:cf:84:ab:a5:2a:45:a7: + ab:e2:97:15:0c:79:24:c1:09:f5:f8:f8:02:13:b9:be:37:78: + 04:22:eb:a7:d5:fc:03:24:fc:ee:76:df:53:11:35:45:63:c1: + a8:5f:ad:88:80:2a:c7:9b:ea:8e:0f:05:0c:09:31:18:f0:31: + b2:e1:15:d2:47:f4:3b:1b:a1:06:47:e1:0c:ee:66:f2:2a:ae: + 12:91:72:93:b0:92:2b:e0:28:dc:62:4b:62:ed:fb:6c:9f:81: + 8b:fe:ae:79:60:e5:23:9d:20:f1:96:5e:08:d8:bf:85:16:9e: + 0e:4d:a3:41:7d:43:91:a2:fa:90:4b:bf:6c:2b:c2:15:fa:19: + 71:10:2d:88:89:48:70:3b:16:32:6b:ab:c8:74:5f:1c:96:2c: + dd:c3:59:72:e3:ab:78:25:b8:86:c3:84:4f:2b:f7:23:5d:fc: + a9:d0:30:51:ff:fa:71:d4:c6:b3:6c:2c:94:c6:6f:3d:1c:2b: + 71:80:72:c0:27:64:cb:79:65:3b:7a:01:f8:a4:b6:66:ea:0d: + 90:45:97:f4:7c:bf:0f:9f:83:a9:06:ae:84:87:41:97:3d:46: + 5b:4f:09:22:ee:23:a0:35:79:c7:92:b5:56:24:88:2c:eb:75: + d4:74:e3:02:92:08:e0:7f:b9:3f:94:ec:21:95:ef:38:f3:dc: + f4:32:75:f7:e6:21:3c:8a +-----BEGIN CERTIFICATE----- +MIImIjCCB1ygAwIBAgIBATALBglghkgBZQMEAxQwgaIxCzAJBgNVBAYTAlVTMRAw +DgYDVQQIDAdNb250YW5hMRAwDgYDVQQHDAdCb3plbWFuMRgwFgYDVQQKDA93b2xm +U1NMX1NMSC1EU0ExGjAYBgNVBAsMEVJvb3QtU0xILURTQS1zaGEyMRgwFgYDVQQD +DA93d3cud29sZnNzbC5jb20xHzAdBgkqhkiG9w0BCQEWEGluZm9Ad29sZnNzbC5j +b20wHhcNMjYwNDI4MDgxMDA1WhcNMjkwMTIyMDgxMDA1WjCBvTELMAkGA1UEBhMC +VVMxEDAOBgNVBAgMB01vbnRhbmExEDAOBgNVBAcMB0JvemVtYW4xGDAWBgNVBAoM +D3dvbGZTU0xfU0xILURTQTEcMBoGA1UECwwTU2VydmVyLW1sZHNhNDQtc2hhMjEY +MBYGA1UEAwwPd3d3LndvbGZzc2wuY29tMR8wHQYJKoZIhvcNAQkBFhBpbmZvQHdv +bGZzc2wuY29tMRcwFQYKCZImiZPyLGQBAQwHd29sZlNTTDCCBTIwCwYJYIZIAWUD +BAMRA4IFIQAYUgGnoGuR1LKGouhv3lwHwtc1iCs/YeJ8mXRL5ceIPti93BIINfqT +y5KByPp7iAstiG7aYQP8b/ORaR6rk0cnpNhA/aJvr42mL989qL0/dbFA/4PDQAd1 +E5LuS1N1RQJ80IEhqlGUqKL+AijlLfNMI+f4GmDtOBOkZqzYnCFyKR17aVIKUIzN +if98rWzIEI3j7QcukpqT+AX9a6XeVPp6YUxFxs3XTyAmTM/DEmfpM6pF4Vo0G75Q +Cu1i96TqsBbzdouszln75sAxo/4HNeA3le6nWzcsej7fx37hqSOkYSfqJV4XBMo3 +kESbaEujBrLTHM7NYKOxOfSLQGpxSvJaNmcJtyphgS8697LYJf6YHopcHvlCOu0T +uE64WVp31FccaWg99XtpLSOFE83kvdZHFcHDgZLM4nPfiu4fj9XQlhtOzGyud6qU +KoUFlPl29lx95CE4LjY/64L4VB8TjOqrNv718blGgd3lXEerxU9ys8SDKu5mUOye +gzX5kiOzplBle09g/Oj+TPanGxZBjlU6PwGC0oS9xXIYR6T/xUOn4RE6HtiYrYHH +TPVA+uE3UdRjRssz8gGUO0/cT6ETZ9WAyRuIKtvK1fZacyfRib26uDy2h6aF4rKt +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 +kgjgf7k/lOwhle8489z0MnX35iE8ig== +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 65:47:75:b4:58:fa:b2:e1:1f:16:b5:5f:25:49:b4:7f:2a:12:60:56 + Signature Algorithm: SLH-DSA-SHA2-128s + Issuer: C=US, ST=Montana, L=Bozeman, O=wolfSSL_SLH-DSA, OU=Root-SLH-DSA-sha2, CN=www.wolfssl.com, emailAddress=info@wolfssl.com + Validity + Not Before: Apr 28 08:10:05 2026 GMT + Not After : Jan 22 08:10:05 2029 GMT + Subject: C=US, ST=Montana, L=Bozeman, O=wolfSSL_SLH-DSA, OU=Root-SLH-DSA-sha2, CN=www.wolfssl.com, emailAddress=info@wolfssl.com + Subject Public Key Info: + Public Key Algorithm: SLH-DSA-SHA2-128s + SLH-DSA-SHA2-128s Public-Key: + pub: + a6:e0:24:a8:4a:18:10:4d:cd:c6:da:23:24:67:de: + 96:95:81:00:a6:ca:ce:43:e4:fd:fc:7b:1a:8c:fa: + eb:7e + X509v3 extensions: + X509v3 Subject Key Identifier: + BD:80:23:3A:06:DD:38:57:EE:6B:C2:94:7B:EA:BF:43:57:3A:B0:8C + X509v3 Authority Key Identifier: + BD:80:23:3A:06:DD:38:57:EE:6B:C2:94:7B:EA:BF:43:57:3A:B0:8C + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + Signature Algorithm: SLH-DSA-SHA2-128s + Signature Value: + 10:3c:70:c5:f5:b1:4f:1c:77:85:34:b9:b3:57:97:62:ef:e7: + 4d:17:67:56:63:74:02:e1:50:5c:5b:dc:56:94:45:d7:f9:6b: + 76:fd:fb:e2:00:16:0b:5a:0f:86:86:7e:1e:0c:4e:7f:d0:95: + cb:d4:8d:09:58:53:4e:e2:9f:0e:11:2e:38:dc:c0:87:ec:6f: + 25:ef:1b:59:81:ab:71:69:51:2e:3c:2f:f6:eb:f2:22:73:62: + e1:a2:68:b3:67:db:2e:05:16:fa:bc:ae:b6:22:cb:c2:0f:fd: + 88:1e:36:43:27:13:de:61:01:0c:ba:5a:df:0a:69:17:45:c2: + 77:b5:df:87:62:b3:16:6e:8e:57:e0:3b:9f:02:80:5d:f0:92: + 76:51:73:2e:7a:25:1c:88:79:dd:0d:55:c5:73:94:b3:76:52: + 39:fb:58:0d:34:fe:74:38:45:fc:99:39:87:c7:fe:4b:2a:7c: + 51:ae:92:ee:5f:28:16:13:04:b5:f0:5f:93:90:74:d0:e0:f4: + 1d:06:af:6b:ad:33:fe:2c:d5:9a:e5:10:32:7f:01:2f:7e:97: + c6:ff:b6:57:97:56:cc:5a:5a:9a:79:de:19:b0:9c:0b:57:bb: + bb:e5:8b:91:2c:cd:19:2d:7c:75:8e:71:4f:c5:c5:88:74:5c: + 5d:27:82:dc:94:58:7d:6e:71:6e:78:c5:f3:0d:3b:85:95:2a: + da:4d:af:34:a9:3c:02:88:cc:45:1d:08:0c:9d:20:39:73:06: + 0a:2d:ba:8a:5d:a9:44:32:24:32:b1:d1:fd:d1:7f:b4:10:56: + 3a:15:12:a5:f6:c1:6f:16:ef:84:5e:86:ab:5b:9b:a7:b4:21: + e3:43:86:1a:50:f8:95:b3:b0:10:56:0e:26:b6:5a:46:75:51: + e2:7a:5a:76:2b:14:4e:57:5d:88:61:27:16:8c:e0:6a:ad:87: + b1:19:89:80:87:aa:6a:59:69:18:fc:e3:5a:78:83:d8:58:3a: + ec:8e:b9:28:2a:22:e6:13:8f:ad:df:4e:4d:9e:99:6b:34:9a: + c5:c1:81:0e:28:1a:16:e5:60:d1:7d:1c:d7:5f:f8:3e:7d:1c: + 7c:2d:18:5f:3a:5c:d2:d2:0b:db:c4:4f:69:57:a7:6d:60:95: + 5e:04:fb:71:31:71:d1:e4:ee:dd:10:34:a5:9b:0c:7b:29:e9: + 4b:85:3a:2f:64:87:93:9a:8f:06:9f:75:8a:c2:b3:a6:0c:ff: + 94:7a:c8:f4:e6:14:31:b1:6f:20:ad:34:5c:3f:1a:67:c7:0e: + 0e:89:00:c5:9f:d6:56:4b:8d:86:dc:64:94:e0:7e:4d:8b:cd: + 43:5f:3b:46:c9:92:f0:a4:0d:df:b9:ab:38:aa:5b:3b:9c:af: + fa:fb:d5:f6:0b:25:96:30:33:28:3d:3f:1e:a6:10:43:58:53: + ae:88:a7:5b:8e:55:66:57:2e:0d:88:a9:5b:d3:71:0a:23:05: + 47:82:ca:e6:0c:c8:d1:f2:99:9f:c9:37:2a:59:99:d4:f0:a5: + 82:18:0b:98:f0:ee:be:0f:11:6f:2a:6a:14:dd:c4:c9:bc:ed: + 80:ac:7c:ca:65:eb:fa:af:b3:29:a7:b2:c3:1c:42:1e:7d:3f: + d3:1a:f0:1b:30:f5:a3:53:8c:13:d3:96:82:01:a8:2e:d2:ae: + ea:f1:50:17:ae:cb:a4:7b:55:72:55:8b:90:28:f0:d9:5b:81: + f4:78:9b:b0:fe:a0:c4:6e:dc:25:fc:94:64:71:12:bf:fc:cd: + 31:50:26:2d:e2:ef:38:05:14:82:b6:62:83:a9:86:cb:df:05: + ef:27:6a:cc:2c:8f:1c:5d:40:13:c1:e3:24:a6:7d:3c:83:1a: + 78:79:7d:63:75:4f:68:b9:9c:75:b9:07:ed:62:16:29:22:c1: + cd:f2:52:02:e9:17:b0:d0:44:13:9c:25:c7:fd:39:df:eb:d5: + 32:5e:bf:c5:47:81:18:83:63:96:89:4c:31:02:8f:c4:e9:7f: + 27:8e:01:3f:44:4e:96:b0:73:ad:56:a7:95:4d:ab:a3:03:e2: + dc:33:65:d2:17:87:e8:07:be:95:17:64:3e:6c:87:cd:3a:e6: + 0a:b8:e6:8b:e2:e9:d9:60:2a:ef:d5:c8:2f:7a:8d:ec:70:16: + 10:a2:1d:12:16:41:a3:c1:07:2f:95:b1:d4:7f:9f:ca:16:ca: + 72:1d:2d:df:3a:6f:93:eb:9e:76:34:3f:dd:a7:47:12:18:5b: + f4:34:2b:73:42:33:15:c8:19:0c:a8:10:d5:d3:04:81:e2:d1: + b4:3f:7e:53:34:d8:db:02:d6:60:b4:24:8c:28:4d:31:51:0b: + 4e:c8:f1:4c:99:98:a7:36:ab:bc:ce:a2:d6:67:f5:b2:64:ec: + 0e:e3:f3:82:46:d3:87:ce:1b:a9:46:d3:dc:1a:27:e2:5f:bf: + 55:33:ca:e0:de:02:84:26:ed:57:58:27:f4:d6:3c:0d:a7:db: + 40:2d:d8:c8:0c:84:47:97:fb:bf:49:8c:d2:1c:80:ff:da:d6: + 3f:93:00:77:f3:31:f0:c8:57:46:5a:9a:15:25:0b:2d:d1:1b: + 5a:eb:ae:09:0e:3e:24:e6:a9:eb:72:be:e4:45:d2:41:db:21: + dd:a7:1b:6e:62:3e:43:d9:62:34:31:62:76:d4:2e:39:48:fd: + 54:9c:51:6a:f7:71:44:88:c0:c3:98:3b:66:e1:8e:0a:9d:e3: + 68:a9:6a:d2:52:80:97:3d:9e:14:c9:bc:36:33:6f:24:9c:7b: + e1:8a:a5:a1:12:44:bf:61:a2:3b:da:18:b9:7f:9f:89:bb:10: + 33:8f:46:18:92:49:5e:10:81:a6:0b:06:19:19:a3:e8:06:c8: + fe:4e:94:20:de:70:36:7b:40:ee:04:ca:fc:fa:81:aa:87:9d: + ad:f3:57:78:0c:34:51:f4:fa:ef:78:58:1e:e9:0f:b9:75:f6: + a5:09:a0:91:7f:80:19:80:17:4b:5c:a9:b9:6d:b6:00:f8:17: + 90:e1:b7:4f:21:33:64:1d:d1:d5:a8:78:a0:98:46:0a:0a:0e: + 72:dc:2a:67:8e:57:44:00:76:2e:79:b9:4e:c7:78:b2:a7:12: + 17:75:44:6c:ce:a6:d7:ae:25:54:6c:5d:eb:3d:92:74:65:26: + f7:6d:23:1a:43:91:ad:2e:20:c8:f4:fa:13:a9:97:ea:7e:a9: + 61:94:81:a7:cd:b3:60:a9:62:4c:ec:8b:91:21:a9:d3:7c:39: + 9f:3f:4c:f8:8f:16:81:3f:23:3a:20:64:7a:10:ce:82:d7:24: + 28:ea:e0:74:6a:ea:62:bd:e3:06:90:1e:92:ca:fa:2d:25:a5: + 70:52:8f:a1:3f:9f:7a:7a:f3:55:4d:4b:8b:1d:1e:ce:d0:61: + 44:68:e5:c2:69:e8:14:2f:5c:90:96:72:8f:7e:39:61:c1:d4: + 3d:36:bf:12:b4:de:31:3e:7e:f4:45:d9:6b:d8:9c:61:06:fe: + 7d:43:ae:e3:c8:f4:3b:0d:7a:5d:b6:35:46:5d:5b:30:e9:9f: + de:49:53:d8:a7:97:61:33:ec:fe:dd:4a:89:c3:db:aa:39:4b: + 01:f8:20:27:a3:0b:12:2f:03:fd:8d:69:5f:90:2a:62:97:93: + a6:d4:12:80:ee:98:47:93:d9:89:7d:46:f3:2d:61:8e:e6:9d: + 7e:7e:42:07:0f:3e:15:08:9b:49:36:98:1c:1e:dc:57:5d:eb: + ab:35:4b:33:eb:2f:fd:a5:6e:92:45:5d:21:df:d4:74:83:02: + a9:3c:bd:88:ed:d7:05:da:b5:2a:56:e1:ae:7c:53:a8:9d:f3: + 24:bf:82:1d:09:20:66:b9:b8:4b:ee:b7:e0:9a:15:e3:99:bc: + e3:93:a4:2e:93:4a:c2:0c:8b:42:ee:29:42:f5:93:e9:b6:73: + 8d:8d:24:4c:78:26:b7:dc:64:c7:94:8e:f3:2f:81:68:91:a5: + 57:ec:c7:b3:7d:73:02:d0:20:18:16:7a:3b:dd:e9:65:08:84: + 6b:40:19:f6:79:71:13:ca:8f:be:8a:ae:c2:a4:67:ae:0e:5b: + a8:55:01:38:5a:0e:0a:51:04:57:12:76:e6:cf:d8:57:25:a7: + 8c:03:da:22:13:dd:90:e1:27:26:e0:d8:dc:9b:5a:6b:3a:0f: + e2:e3:8d:54:73:6e:12:02:72:f4:2b:c3:9b:80:3f:6f:fb:8a: + 9e:fd:bb:e4:d7:c6:14:8a:19:d6:9f:30:bc:00:98:41:92:2b: + bd:a5:8e:ab:93:89:9d:6e:d4:8e:82:17:88:a6:19:2b:8b:a4: + 67:e9:5b:ee:7f:bb:e6:a4:d7:cd:85:7a:c1:2d:15:8b:3d:4e: + 25:71:63:5c:7e:72:b7:bc:e7:8e:a8:ad:d5:a4:2f:d2:56:cf: + b1:29:49:03:9e:d3:b9:ce:35:60:8d:d3:50:97:5f:4e:ac:72: + f4:b0:20:e4:91:75:cc:27:5e:ce:ae:04:77:1b:84:02:fe:0c: + bc:a7:dd:62:3e:55:e9:e7:5b:a3:c8:1d:08:34:18:53:bd:fa: + 05:0c:e9:fc:84:73:0d:4b:9f:56:52:e5:09:e8:46:43:3b:4e: + 59:fa:84:67:d5:c2:94:3d:ea:cb:9d:29:31:4d:91:61:90:f2: + 1f:29:68:dc:34:5f:13:fd:b1:f2:38:72:85:f1:16:1c:7f:05: + e5:b8:32:57:3f:6a:68:ce:e5:58:1a:14:e5:1f:e7:b7:1c:04: + a6:e1:c5:86:c8:78:e3:62:92:fd:ff:9b:f1:e8:60:9c:40:b9: + 1c:1d:7b:52:ad:ee:de:fa:04:bf:0b:bd:d9:34:bf:ef:4a:1b: + f2:0c:72:43:1e:55:24:b1:56:ae:0c:44:99:ef:b5:fb:e5:ee: + c6:20:7c:15:5f:66:c8:32:c3:e0:33:76:00:d3:b0:7e:be:0a: + 28:79:3f:98:51:78:12:73:ae:b3:24:a5:a1:d3:1c:f8:6c:5a: + e7:c0:47:5f:86:a5:67:d5:3b:20:19:49:91:fd:c6:32:0c:96: + e9:df:ea:e1:8e:cf:4a:bd:9f:95:eb:88:2c:3c:f6:34:da:89: + f7:3a:d1:bb:0f:97:f0:38:99:ec:89:b4:b3:92:bf:ed:13:7d: + bc:14:54:16:63:01:f3:60:f0:f6:c4:e0:db:00:dc:c8:5f:13: + 11:82:1d:04:73:a4:f1:8d:d0:8e:7a:4d:1f:9c:0e:8d:dc:fe: + 7d:8f:97:5e:a1:97:c2:73:e7:45:94:19:19:93:f5:4f:fc:25: + 8b:c3:1a:19:a7:1d:91:0a:bf:28:78:41:06:7d:09:d4:95:c5: + d2:8f:47:04:cf:3f:9a:be:72:b0:8a:d0:29:0d:87:b8:22:11: + 2a:c6:c7:27:81:12:6f:9e:18:88:9c:8a:25:04:05:66:b1:ef: + b1:4c:48:f7:f7:53:ec:c8:72:bc:70:25:5e:19:be:3c:d7:f6: + 1a:52:77:05:15:db:ba:99:2a:d6:bd:ce:a1:70:fc:30:40:cc: + bd:4d:e4:36:f0:fc:b9:54:31:48:d3:9c:bb:3b:51:08:a5:e8: + b0:3b:5b:0a:69:91:2c:f7:d4:50:07:4c:a8:2f:7b:43:82:64: + fb:c3:ca:48:5c:b9:f7:f3:bc:d6:21:43:c3:b5:26:61:06:86: + 23:c6:7f:05:d7:0b:c1:e5:7d:5f:5a:c3:09:1a:7c:06:cb:35: + f8:a3:70:13:14:37:b6:98:00:88:24:b0:90:4f:f4:99:99:75: + d5:15:23:7b:5a:09:db:33:30:8b:b9:da:b2:08:7c:ea:39:3c: + 88:96:a8:39:da:1e:22:5a:b3:be:f7:40:58:7a:6d:7b:88:de: + 4c:57:30:f1:38:a5:cc:6a:e7:b3:c4:ef:8a:f1:4d:ca:2c:bf: + 5b:05:02:30:97:10:12:dd:3f:8a:bf:0a:86:4f:57:63:79:bc: + 2c:21:a2:c2:07:26:a4:96:d2:1a:d2:73:86:a9:af:2d:ca:ae: + 6f:07:e7:26:f4:47:65:8e:0e:29:8f:ca:ce:16:cd:90:00:f0: + a6:19:a4:30:b8:d7:8a:da:de:5a:5b:54:91:9a:e1:75:6b:49: + f6:b8:67:0d:02:d2:c4:ec:67:f5:0f:c2:dc:11:c5:65:69:f5: + 1f:44:44:af:1f:91:9c:29:1f:8b:e1:8e:9d:5c:9e:ac:72:fa: + 4b:c9:29:9a:f1:1e:d1:64:6b:8e:22:5a:34:0f:53:47:ce:0b: + e3:07:49:cb:86:de:35:ec:17:e4:d5:df:cb:f4:de:0c:e1:b8: + 93:97:88:9e:f6:0d:b3:fa:f7:4b:a6:52:ef:48:61:c1:43:f2: + 32:f7:af:77:ab:75:c0:6c:08:b6:cd:63:cb:b6:64:e8:01:ed: + e4:62:39:36:38:ab:70:4d:c3:a4:b4:92:be:79:e0:f2:7d:7f: + 06:52:48:bd:ba:c2:56:6d:af:1f:86:b6:7a:eb:e9:b4:fc:8c: + 13:83:fc:25:f8:93:5f:52:c4:bb:4a:08:5a:a0:bf:bd:24:37: + 4b:44:e4:a7:ea:fa:36:49:dd:86:1a:f9:f0:24:1b:ab:c1:1e: + 8c:03:f8:8a:86:99:fd:3d:9d:9f:68:1a:96:47:73:18:22:3b: + 7b:c0:76:02:1d:61:79:73:ac:f9:2c:45:ce:87:53:b5:f5:44: + 8d:73:9b:38:d9:bb:a4:11:fd:f8:0c:16:c6:74:49:f0:e0:18: + 10:c6:d1:2c:2b:5d:c4:17:72:60:e0:7c:d9:48:b3:eb:38:ba: + 4f:e9:82:c2:10:9a:cd:bd:8e:e8:ff:be:f0:57:d8:e5:94:50: + 15:6d:87:42:32:8b:d7:8a:07:22:8e:e2:31:e7:95:9b:22:4f: + 5d:0d:51:02:49:1e:fc:66:51:bb:81:01:96:64:63:d8:57:43: + 66:0d:1f:6c:b4:9a:16:b6:dd:09:c8:6d:0e:c0:79:1f:a6:49: + c8:11:79:d1:18:34:9a:4e:4f:1d:80:1e:47:5b:75:07:a1:74: + fa:52:d2:69:d1:24:d7:2a:cd:72:c6:c8:ec:7d:6b:6b:b6:f9: + e5:5e:9e:d4:24:a0:00:df:ab:b9:6d:57:58:90:18:ac:1c:bd: + af:c1:88:d8:90:5c:82:de:fa:4b:40:51:01:6d:45:c2:83:18: + a3:38:ca:e6:5d:c0:5a:dd:b9:68:0e:0d:c3:c2:f8:6a:8c:ee: + a8:6f:19:c2:d6:78:d6:57:33:7a:fb:c6:0a:db:47:aa:55:89: + 47:a6:20:6f:0b:78:84:69:20:da:b5:6c:1b:d3:2c:d7:db:94: + 38:e0:75:e7:6c:8f:4d:f5:e5:42:16:c6:91:93:6a:41:39:a5: + 77:92:02:49:63:0f:74:c3:b2:55:3f:b1:33:e5:7b:d9:ff:59: + ae:a1:6e:1c:06:bf:76:98:dc:ae:94:39:49:3f:5d:d6:b0:fa: + 06:3e:29:8e:40:62:b8:b7:dc:22:11:50:48:19:41:37:c5:e4: + 34:b8:25:60:98:ed:b9:4a:68:47:a9:e6:2d:d7:e5:ef:35:e7: + 6f:a8:9f:a5:b2:0f:0d:98:fa:9e:ff:fb:c5:57:83:69:98:b0: + 37:06:fb:4c:0d:17:ad:e9:68:2b:c3:42:1c:f6:0c:ac:7f:ca: + 1b:ba:a9:90:b8:f6:e1:a2:2a:45:8d:f5:aa:e5:8b:4a:16:f6: + 0e:3a:38:ee:25:d9:5f:b6:f8:fc:7b:a8:c6:88:e3:ea:f0:1f: + a1:b0:e7:46:e4:b0:59:08:95:02:25:0c:6a:8a:3d:56:3d:c9: + a8:12:dd:47:b4:2d:5a:f6:ae:43:cc:3e:4c:7f:4e:ab:b1:78: + 2a:59:6d:6f:ca:93:21:e4:f6:ad:91:a6:1d:da:a9:16:8f:e6: + 1a:d2:c9:22:13:62:8f:be:28:96:bd:23:59:38:91:75:b5:84: + bc:ae:b9:5f:07:4a:dd:fd:a8:fc:e6:6d:0d:04:e2:76:fe:30: + 0b:e9:9b:60:1c:98:bf:92:80:57:45:ba:53:d2:61:f7:50:51: + d2:ad:9c:03:39:96:39:ee:45:64:04:b3:ca:02:bf:ec:3b:d1: + ab:ec:8d:97:9a:ec:1a:ac:62:99:85:f6:15:c7:d9:b0:2b:f4: + dc:55:f4:19:ac:7e:36:59:70:ee:8c:79:98:89:61:86:25:bd: + b3:38:9e:49:ed:8a:ce:61:1d:d1:13:99:96:74:9e:4f:43:78: + c0:c9:a2:f3:62:92:f8:aa:6b:ca:91:7e:29:d1:80:27:64:68: + e1:0f:9b:fc:fe:64:99:0f:d6:8e:d3:78:d8:ea:fd:e5:0a:55: + 34:8b:f1:b4:d9:1b:a5:bb:30:f9:1a:f4:19:3c:3d:af:ac:5f: + ce:9b:27:08:18:52:6f:b0:aa:02:0d:46:84:73:92:f1:0b:16: + 12:9b:cf:bc:f3:97:bc:c2:9c:18:57:cc:55:63:21:de:f7:32: + c1:3e:fb:88:de:f7:ae:f0:11:10:5b:5f:04:df:9d:3d:19:2f: + 89:cb:72:b4:5b:f2:49:81:76:c2:57:ec:d9:44:ff:b8:8d:19: + 6a:2d:bf:31:47:34:e0:b1:03:32:26:15:e4:d7:44:41:d1:5e: + f9:ba:e2:5f:50:45:44:08:44:7f:9b:09:f4:37:ff:8b:d9:d6: + 55:66:d0:60:b2:8b:94:34:8d:97:dd:73:2f:02:22:be:9a:bd: + d3:57:8c:c3:c6:e1:e1:19:64:f1:6d:3e:41:20:6f:4e:47:bb: + 29:41:bd:a9:8c:ab:01:41:ea:2a:51:c7:f2:9f:ec:ca:9b:1e: + be:e7:f9:3a:5e:66:f8:dd:30:3c:dd:3d:53:61:1e:ad:93:31: + 01:c4:c4:b3:2c:b1:14:a3:68:a2:a2:6a:f9:60:e7:63:19:e4: + 89:19:89:1d:ad:de:85:5d:43:4c:57:61:17:b4:7d:f9:18:93: + 93:c6:88:40:0a:3d:7e:a4:e9:ab:fd:56:c0:2b:5f:35:68:26: + d4:e2:c8:f7:75:08:1c:11:4f:a0:64:a8:15:2d:f2:e9:58:0a: + 31:ec:cb:f8:ba:3b:85:aa:95:93:5e:47:05:27:c4:32:6d:56: + 71:6f:38:8d:db:93:99:57:35:cf:25:83:99:77:d3:7e:93:cd: + a0:04:ae:e5:e9:20:e7:63:b1:ed:69:8c:46:3d:1c:f6:84:bf: + 67:a5:71:60:d5:ec:9f:5b:d9:12:12:9e:0a:b2:85:40:94:34: + 9a:74:6b:25:1e:3b:03:2b:2c:55:7f:51:4a:6a:93:07:dd:e6: + d4:89:fb:1a:95:1d:cd:bb:d1:61:47:6d:8c:09:56:44:b3:52: + c9:ca:df:a1:27:45:77:a1:e3:31:ec:da:b4:ad:15:20:ac:f7: + cc:88:1a:b6:84:f5:21:c9:4f:f7:94:bb:d2:1c:d2:19:40:52: + 5d:2f:9f:44:d3:64:8c:88:d3:08:93:ff:5e:d1:99:63:60:40: + 73:08:bb:20:3d:d1:26:a8:30:48:44:2d:d3:65:e6:af:eb:22: + ec:7c:6f:97:16:69:58:3b:e2:ef:e9:de:de:90:10:07:f4:bd: + 6a:a7:e5:82:e9:22:d5:0e:c9:32:ea:ac:30:69:c6:96:9b:51: + 6b:93:65:67:e5:84:2f:36:1c:19:d8:be:26:fa:79:05:e0:ed: + 34:fd:2c:a4:c0:44:7f:cd:c7:51:e5:a9:81:a7:90:97:46:1a: + 78:00:16:64:2c:d9:d4:85:b6:61:1a:87:de:96:f5:0c:f3:cc: + 73:d4:0d:5e:8f:64:b0:a0:97:c9:12:0c:2e:fa:3a:a1:07:1c: + bc:29:0c:e0:82:b7:3b:0d:6b:14:80:3a:11:a6:d4:f4:36:a4: + 96:d9:89:f8:81:61:77:79:02:6f:5e:64:2a:d7:f2:fa:26:d6: + 0b:bf:cc:63:5e:ff:af:7b:c4:ef:48:5d:ef:c7:44:bb:46:be: + cb:3f:c4:3e:9c:f2:98:9e:ec:7b:20:4a:54:a0:cd:2d:3a:cf: + a0:2d:4a:db:2b:97:50:82:92:68:4e:f0:f1:73:b0:b8:6f:62: + d6:97:95:15:75:03:41:5a:d6:f2:f8:a3:eb:f6:48:49:44:49: + 93:9e:6c:2c:e1:a1:d5:e6:fd:f2:d5:d9:ee:f0:86:ef:01:49: + 65:d6:fd:ae:9d:3a:a6:1d:1a:b3:9b:09:8a:49:cb:ff:b9:d2: + b7:16:7e:f5:36:05:c4:09:c1:b1:49:97:0d:8f:22:c9:8c:9e: + bb:ea:ce:f9:a5:57:47:de:04:7a:bd:e4:b6:a0:0b:bc:d1:da: + a1:20:e1:5c:c4:7a:13:fa:7c:c3:dd:a3:b2:48:98:29:83:75: + c1:6d:f8:1b:75:7c:f4:91:ae:66:d9:bf:49:3e:4c:85:01:df: + d7:8a:1c:44:9c:d0:d1:4f:7f:c2:0f:7d:f8:e0:11:4b:b6:b0: + 4e:6f:1a:f1:fb:53:f8:42:c8:54:15:6b:29:a9:b1:1c:f3:f4: + ed:52:2e:66:e9:49:1a:d0:52:66:6e:fa:8d:ff:2f:1e:d3:40: + c7:25:b7:69:1d:d4:a9:4d:ee:82:14:32:0e:82:ed:94:b6:02: + b0:00:d1:b3:20:f2:eb:9e:db:0f:c9:4f:3d:ec:b2:6e:bd:41: + d2:93:87:1f:fb:8c:b8:0e:e3:6a:f4:37:dd:4f:a0:24:e6:22: + 3d:c7:a2:46:06:bc:5e:25:74:aa:ae:fc:de:94:d9:5d:6f:1b: + 0f:e3:99:46:06:4c:20:ff:59:d1:ef:75:76:87:c8:9a:7d:97: + 67:6d:06:d8:20:83:84:1d:c4:72:43:8e:e2:ee:3a:d9:21:59: + 63:c9:a0:56:d1:42:f4:34:fe:ed:ac:a4:0a:28:0a:c0:a0:32: + 0f:f1:4d:36:b0:27:9c:a5:88:6f:b2:65:a9:43:d2:09:0c:ce: + 06:b7:1b:e4:44:d0:e3:cf:da:2f:11:df:cf:83:3a:8e:04:7e: + 5f:31:90:c1:1e:1c:b1:ca:4c:21:4d:6a:7a:c5:e0:17:61:ee: + c5:61:dd:0d:41:71:96:77:6d:a4:43:a1:69:60:22:56:ea:b1: + 88:b1:71:53:79:44:25:f2:42:c9:b3:48:f7:6c:9a:6a:be:f1: + ca:88:3e:14:b9:69:9e:57:0b:f6:b6:1b:c9:88:70:7c:a8:80: + d6:34:9f:63:59:48:86:4c:bc:eb:cb:49:1f:ad:f6:13:b0:de: + c1:0f:8f:a8:0c:f3:ce:f4:56:b5:3c:1d:82:df:9a:98:4b:5f: + 91:1f:56:f3:ad:b7:45:92:9f:44:d1:5b:63:da:1a:96:cc:db: + 9f:48:64:08:19:29:3f:a4:27:6c:ed:20:49:07:dd:b0:72:9e: + fd:59:37:73:69:07:1c:24:c4:46:5d:58:d1:0f:e4:05:08:09: + 60:b2:8b:df:a2:a5:07:99:c9:4f:cb:f3:d2:d8:bf:b7:0a:6e: + cd:73:43:a5:a0:46:1a:f8:c1:88:01:e2:7c:c1:a7:36:ad:f3: + d1:28:e5:4c:b7:5b:a3:08:70:0e:3a:d9:d3:ce:55:0f:2f:f8: + 08:7a:3c:78:0c:c0:ca:1d:8f:35:34:6d:8f:10:3b:3e:ad:3f: + 2d:55:9e:d0:aa:e7:43:39:c0:64:4b:55:f9:62:a1:f4:1d:90: + 4a:3e:06:1d:0b:8e:12:18:6e:28:30:92:88:80:99:6b:bb:a2: + f2:2b:79:1a:4f:53:e5:4d:10:bd:3b:81:9d:1c:9c:06:a1:a4: + df:61:ec:5a:05:82:38:91:84:65:f6:74:83:9a:28:eb:23:92: + 1f:ef:77:77:30:98:c4:90:45:d7:4e:80:fb:e7:50:52:0c:03: + 10:0d:b3:e4:0a:20:6c:85:fd:2a:b6:87:e2:7d:69:b0:76:ac: + b6:23:ff:09:6e:ab:7e:98:3e:72:76:bf:a1:e2:77:32:2e:51: + 85:db:cf:d8:50:b3:e2:c6:7c:75:bf:67:3a:76:c0:d5:78:2b: + 1e:c8:ee:63:31:20:7a:33:c9:90:df:8e:95:d7:be:04:32:93: + bd:60:46:2d:18:52:0d:e0:99:1f:da:1e:d1:ae:f1:ea:a8:7a: + 90:80:7e:10:89:51:c5:a2:55:38:b8:59:12:92:9f:93:87:e3: + 0f:bb:02:29:ed:75:8f:8a:17:8d:81:91:65:78:a8:1d:9d:2d: + 1e:0f:9b:53:d4:13:8d:55:92:eb:8a:45:19:f6:6b:44:03:47: + 9c:3b:18:1b:d3:f1:a1:3d:c4:66:b0:16:d6:60:26:b3:8d:89: + 52:27:29:4e:3e:b8:50:fd:64:20:fc:02:58:e2:83:6f:15:35: + e4:a6:c8:d6:2c:e3:ce:e2:9d:d1:53:a6:d9:57:90:63:24:ab: + 18:d8:6e:63:90:9a:eb:9b:80:c2:98:8a:9a:bf:20:92:b3:36: + a0:04:fa:88:2d:d6:0f:3f:9c:4f:4d:21:96:c7:4d:2e:c0:34: + f0:40:d0:f7:f3:ea:c5:57:cd:3f:ec:74:73:5e:f9:b0:7e:71: + f3:7c:6e:6a:3c:a1:22:b0:f4:40:d8:62:08:a3:97:8c:14:66: + ff:bb:83:ab:26:24:01:9f:b5:03:0e:80:5e:e9:e9:f1:14:84: + 97:4d:f8:06:db:98:2d:8c:93:e2:af:45:44:7a:d5:61:bb:d6: + f1:c4:5e:38:62:3e:1b:1d:d6:69:42:49:66:a0:83:da:23:5d: + 42:b9:c7:a0:07:5a:ef:e7:b2:9c:4d:83:63:6c:89:61:c7:d6: + 29:4d:76:6d:eb:26:6d:25:c9:fc:5d:2d:58:88:17:5e:a5:4b: + 7f:0b:6e:c7:7d:f8:6a:50:53:c7:80:35:98:76:31:cd:f0:2f: + 6c:f9:79:93:c4:bb:9b:01:89:00:df:0f:55:c5:67:19:50:b2: + 31:ca:68:f8:30:f6:0a:88:2d:e8:55:0d:af:cd:5b:cd:f9:3a: + bc:3c:87:f1:32:b5:f3:01:a9:09:44:ea:54:2b:18:33:05:d3: + c6:b8:56:e3:5a:70:38:4c:98:5f:ee:17:6b:12:2d:00:fa:c1: + 33:48:73:7c:29:51:9a:44:c7:74:b6:63:2f:b4:f8:87:3c:e4: + 44:4b:5d:0f:ec:b1:ec:56:b2:23:da:d4:1f:b7:a9:13:d9:1d: + b3:d6:19:d6:23:fc:72:9a:15:d6:6c:df:66:71:55:a6:89:9b: + ed:ef:25:ee:fb:2b:b3:58:59:d0:42:ab:da:97:88:de:cc:06: + aa:b2:85:d5:f0:a2:87:0e:cb:58:7c:14:9d:d1:8e:d0:21:9b: + 80:67:ae:73:4c:34:fd:42:36:71:dc:a5:55:4d:79:19:dc:4c: + f2:bd:76:25:e3:f0:88:62:4f:79:4b:e0:2f:30:cf:40:42:4b: + 54:1c:85:23:11:66:3f:23:6a:dc:54:f3:5b:cd:9c:b6:88:e4: + 71:87:5c:2f:7e:85:55:5b:9c:23:3a:00:1f:57:da:b6:33:06: + 8d:ce:07:89:b9:2d:7d:0b:35:8d:8a:8b:66:cd:59:16:55:db: + b0:b4:2d:3d:53:32:03:90:98:55:a4:f9:8d:f3:84:b4:16:06: + 42:3e:ca:71:ef:db:c7:59:32:fa:e3:ec:3b:fb:c9:83:83:90: + 52:99:06:c1:b4:3d:ea:f9:83:fa:a8:d9:c3:09:8b:15:d3:85: + 06:a1:e5:26:93:4d:23:aa:cd:4b:3e:5f:64:8f:2f:71:7e:c8: + d3:8c:78:ef:79:3e:ab:4c:da:77:23:2e:ff:56:35:8d:27:7d: + 7e:7e:df:03:1a:c9:c2:af:f4:62:49:f7:35:1c:6a:9b:19:f9: + 0a:e2:17:36:b6:6f:d6:ee:b6:e7:12:e3:c1:54:17:22:6a:28: + 6d:cd:9c:e0:ef:b7:1c:99:e1:94:53:8f:c5:55:65:b2:f0:4d: + 0f:c7:ef:d0:0a:b4:9f:c2:c9:9d:af:26:2e:98:5e:cd:59:79: + 80:1a:28:27:68:fb:22:f3:14:71:60:79:a0:5f:92:75:59:36: + 58:fd:80:20:07:e9:8f:34:5c:38:53:7b:4a:d1:58:77:af:1b: + 0a:0f:70:3f:db:b8:58:37:01:e6:ef:8d:3c:e5:c7:71:c6:bd: + 1a:0b:12:33:5f:9d:07:36:4d:7d:02:07:85:60:83:6f:fc:e0: + af:9f:c5:22:4b:cd:89:dc:2f:b3:53:e1:7f:b9:65:af:59:57: + 54:87:32:f2:d6:15:88:e2:2b:a7:20:85:42:26:d9:09:ee:87: + 60:0c:bf:a3:6a:e5:e5:db:6f:2c:05:7e:88:ee:aa:98:d7:6d: + 0e:3c:9f:6c:28:70:02:1a:78:b6:2e:2c:29:9e:d9:fa:1e:80: + 0a:a3:e6:dc:46:00:15:e7:c0:13:36:42:9c:f0:1a:fa:9c:7d: + d0:cd:2f:ce:dd:95:54:fb:b1:fa:bb:3f:83:26:f7:54:42:5d: + 60:7a:d1:bd:b2:17:9a:e0:02:a7:9a:d8:40:f4:2c:79:c0:4e: + 4e:a4:68:aa:33:c9:1f:2a:f3:fd:9b:50:39:37:b9:1e:59:2c: + 7b:cf:97:57:23:81:b7:07:76:8e:b1:f5:15:dc:54:c5:f9:f9: + c6:13:b7:37:2d:12:44:c6:78:1e:92:1f:ed:85:8f:14:7a:9f: + d0:1f:02:8a:f1:5e:8d:05:28:13:2c:cf:1f:41:9d:74:ec:98: + 96:51:57:a7:c0:10:9a:be:31:7d:71:a7:c2:38:cd:ce:74:60: + e4:45:ef:b0:60:87:7a:da:e9:05:38:06:19:fe:60:db:c6:2d: + a4:25:f7:5d:d1:b1:3d:12:0b:a0:fb:3c:80:b0:f5:00:48:34: + 8b:e4:a4:f1:cf:fe:be:a2:38:43:44:20:23:5e:89:c8:91:18: + fb:5e:aa:90:11:07:7a:e8:ad:61:03:17:6a:a5:a6:a9:e2:c4: + 8c:f0:5e:d7:25:fc:43:93:db:47:44:c1:25:26:38:7a:17:08: + 24:36:d3:25:95:eb:c3:17:ca:b5:d7:79:73:62:48:d6:d0:af: + e7:a0:61:83:5d:7a:27:e9:b9:7e:d2:25:17:85:c2:28:5b:9f: + e7:01:67:f7:69:83:eb:ec:cd:8e:2b:ee:f1:4c:17:a5:3e:05: + 2c:c1:eb:b7:64:d8:fa:3b:3b:c4:e4:53:18:fd:d8:da:1a:f4: + c7:c2:47:90:91:ab:3d:2b:12:1d:9e:7e:58:7e:cb:63:9c:ff: + 28:bf:a0:c3:a6:07:52:58:9a:de:2c:4c:63:5e:79:8b:21:cb: + cf:5b:08:7d:6e:44:55:32:5c:37:71:46:02:c1:28:e8:5f:c1: + 34:ca:b9:25:0a:c8:88:a8:bc:13:1f:1d:c3:6f:cd:3e:f9:95: + ad:45:7b:f9:03:05:b8:f8:c8:89:fa:a0:7a:2b:b7:15:ba:d2: + 0a:39:39:c9:0e:0d:5b:f9:11:b2:9e:11:98:90:bd:25:9d:a2: + f2:c8:c1:3b:70:a3:71:b9:9c:46:24:b1:00:1b:54:3c:ba:11: + a2:73:d4:bf:85:08:57:8f:05:6f:9f:23:12:ff:06:73:d5:6d: + 13:7c:1b:50:c4:df:8e:8a:8a:f8:f4:5c:61:c1:51:e8:d3:82: + 7b:ef:60:89:56:4c:fa:e1:b5:50:47:23:66:7e:af:af:a7:9f: + 0a:1f:55:2d:d9:ad:8f:92:01:d4:10:c8:00:63:0e:6e:95:1b: + ea:e9:d3:38:ac:7c:34:d1:8d:61:e6:be:c5:98:3d:9e:cf:70: + 28:5c:4f:80:44:4d:06:9d:1e:e0:4b:4c:91:76:7e:d8:ff:5f: + 5a:ae:b6:88:f6:25:7b:96:80:4c:59:3f:91:29:4f:44:c1:01: + 23:9c:8c:51:f1:fa:69:e0:b1:2a:20:c8:93:14:f4:99:61:a7: + 4e:9b:ee:8d:02:5a:e2:29:d7:f5:9f:ef:94:59:4c:55:c6:0f: + 1c:b8:9c:a9:b6:bf:cd:c4:30:e5:e5:84:4e:d3:13:af:6e:8f: + 8d:ac:d4:64:c0:21:5d:57:e7:9d:73:c6:90:63:b7:22:3e:a6: + a6:47:d3:be:b4:a3:ff:c6:c3:0e:2b:f0:45:ee:50:50:98:b2: + 8e:f2:bc:05:d0:24:b5:40:b2:52:b4:bf:d7:62:8a:a2:a8:d3: + 6c:3e:ad:12:46:ab:5b:c7:e1:32:99:21:7c:cb:09:37:2e:8f: + 0b:85:41:5f:45:8f:17:ca:66:6a:73:97:73:3c:3d:8d:dc:9f: + 51:dd:59:15:0f:68:4b:a2:42:4e:98:6d:1c:74:9b:5d:b4:65: + ed:22:17:a4:73:b2:11:93:f4:d2:b5:aa:93:00:c5:88:42:86: + b5:1c:3f:fc:9f:f7:f9:2f:a9:29:a5:66:e2:e5:8e:29:ef:d5: + d8:dd:93:62:26:08:7a:f6:62:6c:17:1c:b0:d6:19:b1:39:8c: + c4:54:a5:ef:34:b6:15:53:fd:88:80:eb:48:50:0d:74:8e:34: + 04:64:f1:da:13:4f:df:63:7b:c3:19:be:c4:1f:f2:13:25:cb: + 73:37:98:93:4f:8d:ed:97:88:ee:be:39:9f:03:bd:2a:4f:08: + 1d:63:19:dd:20:06:6c:4c:96:a7:66:82:7f:75:62:19:5b:87: + cd:76:e3:b9:10:76:ab:b4:bd:54:ca:3e:10:15:a4:36:42:93: + e9:56:fa:19:59:e3:90:55:ad:f7:b2:07:cd:99:9b:7c:05:01: + a9:d1:fc:eb:e6:d5:de:01:39:ac:0d:be:c7:db:fb:b0:54:08: + 48:26:f9:54:dc:15:85:a2:6f:33:10:60:ec:0d:38:ad:15:e4: + 14:83:3d:65:df:0b:ae:01:f0:15:9a:ca:bc:4f:c9:c0:57:9f: + 9a:b9:22:53:56:b3:4c:83:50:f6:5b:13:68:94:6e:12:7c:bf: + 9e:22:6d:c3:17:f4:f0:a5:73:b5:03:ef:b8:af:0e:20:c9:df: + 2d:39:e6:43:38:84:30:6b:a1:36:0a:bf:09:41:67:18:85:8e: + 77:04:a3:be:d4:9f:36:75:42:e5:84:ea:75:fa:0b:01:4a:30: + 48:9c:b3:47:9d:3c:48:41:74:76:14:30:dc:66:1e:fd:7c:58: + 2f:63:e5:74:2a:c5:a2:26:65:fe:c2:13:7b:0d:83:f7:94:3d: + 2d:f8:83:07:aa:dd:77:72:26:fe:70:29:d5:1e:83:21:ba:0e: + de:10:ba:4c:cd:19:88:b2:9a:44:f8:86:d8:fa:4a:12:3b:7f: + 02:ae:af:68:7a:87:8b:8f:63:e5:9a:da:e4:77:9d:40:50:27: + 7f:b0:7a:ac:5c:aa:b4:33:8a:dc:fe:17:74:3e:1d:5d:5c:0a: + 57:06:72:ac:ac:ed:2d:81:09:b3:6e:71:25:3b:03:29:67:b5: + 81:bd:b3:3f:36:42:f3:af:ac:db:58:fe:00:42:b4:28:89:1a: + 76:fb:11:8a:32:c9:65:03:f7:ef:6a:e6:57:48:e9:b9:d2:90: + 42:9a:cc:ff:f1:fb:06:ad:be:ff:4e:c2:64:93:39:48:4a:57: + e6:06:98:14:9f:0c:61:19:c1:f0:d4:c8:3d:1f:6c:a5:c2:28: + 66:25:aa:7a:9f:fd:08:f6:ec:c1:e5:f8:e2:37:17:f5:6b:ae: + aa:f7:a4:da:27:59:25:0e:43:4c:53:62:3b:62:6a:5e:6d:9d: + c9:01:02:f3:79:47:0e:2d:ea:62:89:a5:57:6d:de:18:b2:a2: + 13:d2:34:27:28:4f:4a:a5:d7:f3:ee:16:a0:5e:77:f9:2e:6c: + 22:81:44:ae:03:64:e1:9f:b8:d7:55:92:75:f6:66:ea:2e:45: + 31:16:aa:32:77:3f:8e:0e:b7:4a:d9:52:ad:05:28:d1:58:8a: + d4:79:b0:ba:29:15:33:5b:99:59:d2:70:95:fb:6c:0a:5d:18: + 4a:96:ab:14:96:c8:00:9c:5c:e1:f2:f6:ec:85:e4:3e:39:39: + b7:44:3d:9a:66:bd:d9:32:48:c8:5c:0c:d0:4c:b9:2d:01:49: + 1d:eb:fd:41:32:67:23:87:10:31:17:20:df:f1:3f:77:ed:b8: + d9:52:dc:3d:11:15:dd:04:93:88:f2:65:32:6d:7b:c0:d8:df: + 3a:19:61:9b:7f:e5:a2:b1:e0:6f:6a:3d:f5:82:08:a1:0e:26: + 42:e2:91:9f:c2:a2:7e:ba:66:89:a7:95:26:c5:9a:9a:7b:2e: + c7:cf:4e:70:07:2b:f6:f0:56:60:f4:56:ba:73:18:e6:b8:85: + 96:35:b2:d4:3d:3e:63:ca:be:08:54:f3:7c:03:e9:6f:98:17: + f5:03:66:da:dc:bc:4a:a8:97:d4:ff:74:89:ba:1d:22:91:58: + 50:87:43:c6:1f:ef:0f:cb:9c:da:0e:f8:6b:1e:ab:84:17:f0: + 56:17:dd:4a:19:62:4f:d6:56:ef:27:ba:81:ff:fb:5e:c6:4d: + a1:20:03:a4:4b:30:d1:09:37:8a:e3:34:cb:2e:5d:9e:6f:a4: + bb:9c:0d:7c:b0:40:66:23:7d:ac:dc:b9:7c:68:f4:db:f7:92: + c6:db:dc:dc:77:5c:d7:d3:57:a7:13:60:a3:ed:87:15:da:fe: + a5:f0:2e:46:94:ad:92:75:61:f2:a8:08:79:83:af:ea:f5:7a: + 4d:02:2a:f2:39:d6:87:ef:4f:17:49:06:86:5a:54:9d:48:0e: + ab:7b:b6:f7:eb:68:85:83:01:52:d5:a8:32:fe:31:c0:45:11: + e2:dc:d6:99:d6:27:90:b5:41:48:b0:39:da:9e:0e:d2:6d:48: + bb:c4:0a:15:53:8b:16:77:9a:b9:62:b9:18:db:ea:25:17:8f: + c4:18:cd:1c:93:33:0e:9b:e0:ef:da:22:d8:55:17:2d:90:f1: + 5e:35:a0:24:eb:3b:d4:50:45:d9:35:3b:0b:c3:d4:6e:67:b2: + 92:0e:e6:a7:14:1c:09:e4:d0:94:d8:05:b4:e4:9d:20:5f:f1: + be:ca:25:00:34:76:35:e4:3a:19:05:ec:94:8b:9f:cf:c1:1a: + 89:bd:8b:1b:8d:68:85:2c:aa:d0:95:3b:d7:b5:47:39:03:7b: + 73:38:16:8d:21:68:1a:d8:77:49:1b:02:d5:41:e9:f9:a1:da: + 40:75:f1:0a:ab:76:19:79:dd:34:28:6b:4d:d1:44:79:97:a3: + fd:15:1e:12:77:ce:e9:04:12:c3:47:75:5e:73:5d:8b:50:8e: + 7b:78:74:a2:10:44:dc:29:ec:bb:09:04:98:dd:9a:98:a1:f8: + fd:c5:5d:41:4c:9e:13:33:09:f7:59:d2:ca:7b:86:8c:0f:f0: + 8a:40:fb:6a:7d:c9:5b:18:71:28:15:e9:8a:97:b8:4e:56:a1: + 3c:82:69:f2:1e:05:b8:4e:b4:0f:c5:11:b0:d8:cd:e1:07:5e: + 39:a1:e4:a0:ad:19:c7:af:3b:a1:3c:01:69:8a:4d:8e:13:22: + 53:98:ab:9c:a5:2e:75:1c:97:d9:0c:e7:0b:d4:79:41:2a:2d: + 73:97:45:e4:b1:4b:37:54:d7:90:2f:36:f5:49:82:d6:41:e3: + 9b:1b:ee:bb:19:f3:a9:5f:74:da:90:0f:ef:c3:89:e7:21:cd: + 0a:51:71:aa:77:76:ad:e2:15:f1:ac:cf:68:34:09:d3:00:4c: + bc:c9:58:9f:b5:6c:e6:f9:4a:cc:3b:73:7a:0a:02:8d:da:98: + 77:14:34:98:5d:ef:c0:8e:71:bc:b2:dc:56:1f:ec:b0:b0:46: + 75:23:7b:00:33:44:f3:85:a7:49:81:47:28:62:76:4d:91:3e: + 57:5c:58:31:a2:b1:de:0b:49:fb:92:ad:d1:a7:1d:61:0d:03: + ef:7c:fd:9b:9a:36:ce:b1:1d:37:87:3c:ea:3e:54:37:b5:de: + ea:e6:79:27:aa:4f:2f:94:17:21:09:24:5d:33:c9:ea:2d:e8: + 87:f1:6a:d3:d6:fd:85:79:bd:66:25:2b:e6:0d:d6:23:3d:82: + d8:28:4a:31:06:7a:b6:79:3a:2a:d2:a5:00:5b:9a:f3:3f:15: + c4:cc:f5:6f:00:f3:77:b1:c6:31:9b:7d:33:eb:0e:b0:0f:f3: + 9d:4e:49:85:1d:90:01:15:fa:3d:08:7d:27:06:ea:92:3e:b0: + c7:93:da:48:70:1a:1f:7e:52:f8:4c:63:c2:d4:82:cc:40:44: + c0:84:38:fc:70:ad:c9:16:41:80:73:8c:8e:6f:dd:e9:48:27: + 8c:c1:87:c1:ca:4d:14:66:53:e1:ce:9d:1b:3a:16:14:cd:dd: + ce:12:a9:2a:ba:c9:4c:34:4b:4a:85:1f:9d:d4:6a:70:e9:df: + 18:9f:03:d2:bf:73:f3:e0:b3:8f:d2:10:09:97:fd:59:fc:50: + c8:57:a7:77:34:43:82:79:b5:56:f5:33:c2:a0:dd:2e:78:09: + 60:ee:0a:92:d3:13:5c:b3:41:79:df:fc:07:09:a5:54:aa:e5: + 59:6a:30:d0:f1:ed:bb:f1:5a:52:61:9d:06:36:dc:c8:80:70: + 77:45:05:b9:2f:4d:c4:86:fe:d7:51:51:93:88:8b:66:1c:fa: + 0d:ce:91:5e:e0:25:3b:6f:89:47:df:52:09:b7:0e:c1:82:90: + 96:17:b0:8c:af:d1:2c:00:b0:bb:18:5f:34:56:d5:f6:18:00: + 56:4c:09:ab:32:77:e0:35:56:1a:52:99:1a:d9:e1:ce:75:9f: + 24:4c:7d:e5:34:4f:52:1c:d4:6b:93:b8:a5:c5:68:97:68:a5: + 1d:1f:77:16:2d:4a:29:0d:e5:2b:9a:f9:05:2a:1d:3a:f9:7e: + 45:3e:a0:5f:88:d6:8b:bd:47:f3:a7:7b:a1:27:29:1c:3a:26: + 41:b8:fe:80:53:6d:29:64:09:1f:6f:e9:ac:ff:70:8f:06:ef: + 48:a2:07:1f:8c:d9:86:2c:84:f4:a7:01:66:d1:2f:f2:47:92: + a1:e6:de:a7:28:70:4f:bd:d6:d8:b4:ed:17:ab:4e:18:4f:e2: + 4a:62:d0:7f:30:9c:40:2e +-----BEGIN CERTIFICATE----- +MIIg7zCCAimgAwIBAgIUZUd1tFj6suEfFrVfJUm0fyoSYFYwCwYJYIZIAWUDBAMU +MIGiMQswCQYDVQQGEwJVUzEQMA4GA1UECAwHTW9udGFuYTEQMA4GA1UEBwwHQm96 +ZW1hbjEYMBYGA1UECgwPd29sZlNTTF9TTEgtRFNBMRowGAYDVQQLDBFSb290LVNM +SC1EU0Etc2hhMjEYMBYGA1UEAwwPd3d3LndvbGZzc2wuY29tMR8wHQYJKoZIhvcN +AQkBFhBpbmZvQHdvbGZzc2wuY29tMB4XDTI2MDQyODA4MTAwNVoXDTI5MDEyMjA4 +MTAwNVowgaIxCzAJBgNVBAYTAlVTMRAwDgYDVQQIDAdNb250YW5hMRAwDgYDVQQH +DAdCb3plbWFuMRgwFgYDVQQKDA93b2xmU1NMX1NMSC1EU0ExGjAYBgNVBAsMEVJv +b3QtU0xILURTQS1zaGEyMRgwFgYDVQQDDA93d3cud29sZnNzbC5jb20xHzAdBgkq +hkiG9w0BCQEWEGluZm9Ad29sZnNzbC5jb20wMDALBglghkgBZQMEAxQDIQCm4CSo +ShgQTc3G2iMkZ96WlYEApsrOQ+T9/HsajPrrfqNjMGEwHQYDVR0OBBYEFL2AIzoG +3ThX7mvClHvqv0NXOrCMMB8GA1UdIwQYMBaAFL2AIzoG3ThX7mvClHvqv0NXOrCM +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMAsGCWCGSAFlAwQDFAOC +HrEAEDxwxfWxTxx3hTS5s1eXYu/nTRdnVmN0AuFQXFvcVpRF1/lrdv374gAWC1oP +hoZ+HgxOf9CVy9SNCVhTTuKfDhEuONzAh+xvJe8bWYGrcWlRLjwv9uvyInNi4aJo +s2fbLgUW+ryutiLLwg/9iB42QycT3mEBDLpa3wppF0XCd7Xfh2KzFm6OV+A7nwKA +XfCSdlFzLnolHIh53Q1VxXOUs3ZSOftYDTT+dDhF/Jk5h8f+Syp8Ua6S7l8oFhME +tfBfk5B00OD0HQava60z/izVmuUQMn8BL36Xxv+2V5dWzFpamnneGbCcC1e7u+WL +kSzNGS18dY5xT8XFiHRcXSeC3JRYfW5xbnjF8w07hZUq2k2vNKk8AojMRR0IDJ0g +OXMGCi26il2pRDIkMrHR/dF/tBBWOhUSpfbBbxbvhF6Gq1ubp7Qh40OGGlD4lbOw +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 +-----END CERTIFICATE----- diff --git a/certs/slhdsa/server-mldsa44-shake.der b/certs/slhdsa/server-mldsa44-shake.der new file mode 100644 index 0000000000000000000000000000000000000000..2a5d3ea75b590a48c970bafd47c7bf26e76fda8e GIT binary patch literal 9768 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 diff --git a/certs/sphincs/bench_sphincs_fast_level3_key.der b/certs/sphincs/bench_sphincs_fast_level3_key.der deleted file mode 100644 index cd691372bad05482b36b3118742745f2b06acaec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 166 zcmXqLT+GDCV8Fq~rhSf|jf0D&aWYHegiTiI%e?z`zF#}@iEZkOcjwof*T1(%Fuk|G z*KVd^`dh;+R`-Lqj*5scoZRdZ!P#Ktp6->%3WeD8 c)=SMgS{Cx*on<|_9p@zcmv?y7@RF(?04Xp@M*si- diff --git a/certs/sphincs/bench_sphincs_fast_level5_key.der b/certs/sphincs/bench_sphincs_fast_level5_key.der deleted file mode 100644 index 19f4f4da07ff0310e660127c04c176699b8b54b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 214 zcmXqLyv)SNV8Fq~rhSf|jgyO|@i0r{fz_A)T8lHBy}Ie$C9|jBW$&DDx*eR=#hZJ{ zMy6(lZ}ExMdaJ4qs2$<0+j4og@Rz)Qd`p)^gfF@~Gim3pL(yt)^Je}Md#-1-me{=T8?@6RQe>yBkJzfL Lv+(6qO7#N(w5nnf diff --git a/certs/sphincs/bench_sphincs_small_level1_key.der b/certs/sphincs/bench_sphincs_small_level1_key.der deleted file mode 100644 index 5133d7bca7ec30a1f028fc03a76b92339fc2203d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 115 zcmXpgWMX76;9z6ZKF80-F2It+lJH+GEOku|cad)I4oxr7y7!@f_kB6=EML27dP1Pg r=_Y5Fdm^^}&uwHj@1Fl+e*coSJA)1yem~e&SNwZkQFzyN7eev?Z%Q?` diff --git a/certs/sphincs/bench_sphincs_small_level3_key.der b/certs/sphincs/bench_sphincs_small_level3_key.der deleted file mode 100644 index 691d52e5e393fa25ba918fd105b3a45a57fb6239..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 166 zcmXqLT+GDCV8Fq~rhSf|jf01!aWYHegvf&~UGbkkZr<^KMtz%?kK~`g9YXDMg09tH z+pzNcTNkzUht9d*d^}a^nczY5^rfA5&9hz}?wM`3Yh#&L)Vs6O(mn;>>gmkfzyIgb eJ+%!hrYBDbjmY5&O62~$=b`+TW%2V#RSy6mTUBrX diff --git a/certs/sphincs/bench_sphincs_small_level5_key.der b/certs/sphincs/bench_sphincs_small_level5_key.der deleted file mode 100644 index c90cdf68b387edb485cbcf13ac4d48a8fedde4be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 214 zcmXqLyv)SNV8Fq~rhSf|jgyC^@i0r{f#9dAjxwkF*EjD=aW3$aZTs=-RqAZlJs&H> z+XMA;19tGvn&0zc_KRO~9~RCy)opU6F!;lA*=xM_lM|N$stkXg5 ziH8?m7D_j@zMgJ)_0D}CpH;3aV%Gl}(XF5e&2bvwN(XbF?%Ym-@iZK`Si7gW0M Kn{p_VQvCpl!ejUV diff --git a/certs/sphincs/include.am b/certs/sphincs/include.am deleted file mode 100644 index 2d44e66b7c..0000000000 --- a/certs/sphincs/include.am +++ /dev/null @@ -1,11 +0,0 @@ -# vim:ft=automake -# All paths should be given relative to the root -# - -EXTRA_DIST += \ - certs/sphincs/bench_sphincs_fast_level1_key.der \ - certs/sphincs/bench_sphincs_fast_level3_key.der \ - certs/sphincs/bench_sphincs_fast_level5_key.der \ - certs/sphincs/bench_sphincs_small_level1_key.der \ - certs/sphincs/bench_sphincs_small_level3_key.der \ - certs/sphincs/bench_sphincs_small_level5_key.der diff --git a/cmake/functions.cmake b/cmake/functions.cmake index 6bd57e4ec3..a485ebc5e9 100644 --- a/cmake/functions.cmake +++ b/cmake/functions.cmake @@ -217,10 +217,6 @@ function(generate_build_flags) set(BUILD_FALCON "yes" PARENT_SCOPE) set(BUILD_OQS_HELPER "yes" PARENT_SCOPE) endif() - if(WOLFSSL_OQS OR WOLFSSL_USER_SETTINGS) - set(BUILD_SPHINCS "yes" PARENT_SCOPE) - set(BUILD_OQS_HELPER "yes" PARENT_SCOPE) - endif() if(WOLFSSL_LMS OR WOLFSSL_USER_SETTINGS) set(BUILD_WC_LMS "yes" PARENT_SCOPE) endif() @@ -1033,10 +1029,6 @@ function(generate_lib_src_list LIB_SOURCES) list(APPEND LIB_SOURCES wolfcrypt/src/falcon.c) endif() - if(BUILD_SPHINCS) - list(APPEND LIB_SOURCES wolfcrypt/src/sphincs.c) - endif() - if(BUILD_DILITHIUM) list(APPEND LIB_SOURCES wolfcrypt/src/dilithium.c) diff --git a/doc/dox_comments/header_files/asn.h b/doc/dox_comments/header_files/asn.h index b4995dd83a..03bbe38c03 100644 --- a/doc/dox_comments/header_files/asn.h +++ b/doc/dox_comments/header_files/asn.h @@ -254,7 +254,7 @@ int wc_DhPublicKeyDecode(const byte* input, word32* inOutIdx, DhKey* key, 4. Encodes the signature into the certificate/CSR DER structure NOTE: Only RSA and ECC key types are supported. Ed25519, Ed448, and - post-quantum algorithms (Falcon, Dilithium, SPHINCS+) sign messages + post-quantum algorithms (Falcon, Dilithium, SLH-DSA) sign messages directly rather than hashes, so they cannot use this callback-based API. Use wc_SignCert_ex for those algorithms. diff --git a/gencertbuf.pl b/gencertbuf.pl index 110465666d..9b0f746784 100755 --- a/gencertbuf.pl +++ b/gencertbuf.pl @@ -153,17 +153,6 @@ my @fileList_falcon = ( ["certs/falcon/bench_falcon_level5_key.der", "bench_falcon_level5_key" ], ); -#Sphincs+ Post-Quantum Keys -#Used with HAVE_SPHINCS -my @fileList_sphincs = ( - ["certs/sphincs/bench_sphincs_fast_level1_key.der", "bench_sphincs_fast_level1_key" ], - ["certs/sphincs/bench_sphincs_fast_level3_key.der", "bench_sphincs_fast_level3_key" ], - ["certs/sphincs/bench_sphincs_fast_level5_key.der", "bench_sphincs_fast_level5_key" ], - ["certs/sphincs/bench_sphincs_small_level1_key.der", "bench_sphincs_small_level1_key" ], - ["certs/sphincs/bench_sphincs_small_level3_key.der", "bench_sphincs_small_level3_key" ], - ["certs/sphincs/bench_sphincs_small_level5_key.der", "bench_sphincs_small_level5_key" ], - ); - # CN-IP test certs (no SAN, CN contains IP literal or wildcard) # Used with OPENSSL_EXTRA && !NO_RSA my @fileList_cn_ip = ( @@ -184,7 +173,6 @@ my $num_4096 = @fileList_4096; my $num_sm2 = @fileList_sm2; my $num_sm2_der = @fileList_sm2_der; my $num_falcon = @fileList_falcon; -my $num_sphincs = @fileList_sphincs; my $num_cn_ip = @fileList_cn_ip; # open our output file, "+>" creates and/or truncates @@ -2106,26 +2094,6 @@ static const unsigned char bench_dilithium_level5_pubkey[] = { "; -# convert and print sphincs keys -print OUT_FILE "#if defined(HAVE_SPHINCS)\n\n"; -for (my $i = 0; $i < $num_sphincs; $i++) { - - my $fname = $fileList_sphincs[$i][0]; - my $sname = $fileList_sphincs[$i][1]; - - print OUT_FILE "/* $fname */\n"; - print OUT_FILE "static const unsigned char $sname\[] =\n"; - print OUT_FILE "{\n"; - file_to_hex($fname); - print OUT_FILE "};\n"; - # In C89/C90 (which Watcom generally defaults to), sizeof must be a - # compile-time constant expression when used in a static initializer. - # So don't use `static const int sizeof_` here: - print OUT_FILE "#define sizeof_$sname (sizeof($sname))\n\n" -} - -print OUT_FILE "#endif /* HAVE_SPHINCS */\n\n"; - # convert and print 256-bit cert/keys print OUT_FILE "#if defined(HAVE_ECC) && defined(USE_CERT_BUFFERS_256)\n\n"; for (my $i = 0; $i < $num_ecc; $i++) { diff --git a/rpm/spec.in b/rpm/spec.in index 8f2b872135..eaad7e3ac6 100644 --- a/rpm/spec.in +++ b/rpm/spec.in @@ -99,8 +99,6 @@ fi - Add include of kyber headers * Tue Aug 30 2022 Jacob Barthelmeh - Add include of QUIC documentation -* Wed Aug 17 2022 Anthony Hu -- Add a new header sphincs.h. * Wed Jul 20 2022 Anthony Hu - Add a new header dilithium.h. * Fri Jul 8 2022 Jacob Barthelmeh diff --git a/scripts/asn1_oid_sum.pl b/scripts/asn1_oid_sum.pl index fb48857a3b..b67fa26036 100755 --- a/scripts/asn1_oid_sum.pl +++ b/scripts/asn1_oid_sum.pl @@ -302,12 +302,18 @@ my @dilithium_5 = ( 1, 3, 6, 1, 4, 1, 2, 267, 12, 8, 7 ); my @mldsa_2 = ( 2, 16, 840, 1, 101, 3, 4, 3, 17 ); my @mldsa_3 = ( 2, 16, 840, 1, 101, 3, 4, 3, 18 ); my @mldsa_5 = ( 2, 16, 840, 1, 101, 3, 4, 3, 19 ); -my @sphincs_fast_1 = ( 1, 3, 9999, 6, 7, 4 ); -my @sphincs_fast_3 = ( 1, 3, 9999, 6, 8, 3 ); -my @sphincs_fast_5 = ( 1, 3, 9999, 6, 9, 3 ); -my @sphincs_small_1 = ( 1, 3, 9999, 6, 7, 10 ); -my @sphincs_small_3 = ( 1, 3, 9999, 6, 8, 7 ); -my @sphincs_small_5 = ( 1, 3, 9999, 6, 9, 7 ); +my @slhdsa_sha2_128s = (2, 16, 840, 1, 101, 3, 4, 3, 20); +my @slhdsa_sha2_128f = (2, 16, 840, 1, 101, 3, 4, 3, 21); +my @slhdsa_sha2_192s = (2, 16, 840, 1, 101, 3, 4, 3, 22); +my @slhdsa_sha2_192f = (2, 16, 840, 1, 101, 3, 4, 3, 23); +my @slhdsa_sha2_256s = (2, 16, 840, 1, 101, 3, 4, 3, 24); +my @slhdsa_sha2_256f = (2, 16, 840, 1, 101, 3, 4, 3, 25); +my @slhdsa_shake_128s = (2, 16, 840, 1, 101, 3, 4, 3, 26); +my @slhdsa_shake_128f = (2, 16, 840, 1, 101, 3, 4, 3, 27); +my @slhdsa_shake_192s = (2, 16, 840, 1, 101, 3, 4, 3, 28); +my @slhdsa_shake_192f = (2, 16, 840, 1, 101, 3, 4, 3, 29); +my @slhdsa_shake_256s = (2, 16, 840, 1, 101, 3, 4, 3, 30); +my @slhdsa_shake_256f = (2, 16, 840, 1, 101, 3, 4, 3, 31); my @keys = ( { name => "ANON", oid => \@anon }, @@ -330,13 +336,18 @@ my @keys = ( { name => "ML_DSA_LEVEL2", oid => \@mldsa_2 }, { name => "ML_DSA_LEVEL3", oid => \@mldsa_3 }, { name => "ML_DSA_LEVEL5", oid => \@mldsa_5 }, - { name => "SPHINCS_FAST_LEVEL1", oid => \@sphincs_fast_1 }, - { name => "SPHINCS_FAST_LEVEL3", oid => \@sphincs_fast_3, - oid_sum => 283 }, - { name => "SPHINCS_FAST_LEVEL5", oid => \@sphincs_fast_5 }, - { name => "SPHINCS_SMALL_LEVEL1", oid => \@sphincs_small_1 }, - { name => "SPHINCS_SMALL_LEVEL3", oid => \@sphincs_small_3 }, - { name => "SPHINCS_SMALL_LEVEL5", oid => \@sphincs_small_5 }, + { name => "SLH_DSA_SHA2_128S", oid => \@slhdsa_sha2_128s }, + { name => "SLH_DSA_SHA2_128F", oid => \@slhdsa_sha2_128f }, + { name => "SLH_DSA_SHA2_192S", oid => \@slhdsa_sha2_192s }, + { name => "SLH_DSA_SHA2_192F", oid => \@slhdsa_sha2_192f }, + { name => "SLH_DSA_SHA2_256S", oid => \@slhdsa_sha2_256s }, + { name => "SLH_DSA_SHA2_256F", oid => \@slhdsa_sha2_256f }, + { name => "SLH_DSA_SHAKE_128S", oid => \@slhdsa_shake_128s }, + { name => "SLH_DSA_SHAKE_128F", oid => \@slhdsa_shake_128f }, + { name => "SLH_DSA_SHAKE_192S", oid => \@slhdsa_shake_192s }, + { name => "SLH_DSA_SHAKE_192F", oid => \@slhdsa_shake_192f }, + { name => "SLH_DSA_SHAKE_256S", oid => \@slhdsa_shake_256s }, + { name => "SLH_DSA_SHAKE_256F", oid => \@slhdsa_shake_256f }, ); print_sum_enum("Key", "k", \@keys); @@ -1126,17 +1137,29 @@ my @sig_types = ( same => 1 }, { name => "CTC_ML_DSA_LEVEL5", oid => \@mldsa_5, same => 1 }, - { name => "CTC_SPHINCS_FAST_LEVEL1", oid => \@sphincs_fast_1, + { name => "CTC_SLH_DSA_SHA2_128S", oid => \@slhdsa_sha2_128s, same => 1 }, - { name => "CTC_SPHINCS_FAST_LEVEL3", oid => \@sphincs_fast_3, - same => 1, oid_sum => 283 }, - { name => "CTC_SPHINCS_FAST_LEVEL5", oid => \@sphincs_fast_5, + { name => "CTC_SLH_DSA_SHA2_128F", oid => \@slhdsa_sha2_128f, same => 1 }, - { name => "CTC_SPHINCS_SMALL_LEVEL1", oid => \@sphincs_small_1, + { name => "CTC_SLH_DSA_SHA2_192S", oid => \@slhdsa_sha2_192s, same => 1 }, - { name => "CTC_SPHINCS_SMALL_LEVEL3", oid => \@sphincs_small_3, + { name => "CTC_SLH_DSA_SHA2_192F", oid => \@slhdsa_sha2_192f, same => 1 }, - { name => "CTC_SPHINCS_SMALL_LEVEL5", oid => \@sphincs_small_5, + { name => "CTC_SLH_DSA_SHA2_256S", oid => \@slhdsa_sha2_256s, + same => 1 }, + { name => "CTC_SLH_DSA_SHA2_256F", oid => \@slhdsa_sha2_256f, + same => 1 }, + { name => "CTC_SLH_DSA_SHAKE_128S", oid => \@slhdsa_shake_128s, + same => 1 }, + { name => "CTC_SLH_DSA_SHAKE_128F", oid => \@slhdsa_shake_128f, + same => 1 }, + { name => "CTC_SLH_DSA_SHAKE_192S", oid => \@slhdsa_shake_192s, + same => 1 }, + { name => "CTC_SLH_DSA_SHAKE_192F", oid => \@slhdsa_shake_192f, + same => 1 }, + { name => "CTC_SLH_DSA_SHAKE_256S", oid => \@slhdsa_shake_256s, + same => 1 }, + { name => "CTC_SLH_DSA_SHAKE_256F", oid => \@slhdsa_shake_256f, same => 1 }, ); diff --git a/src/include.am b/src/include.am index ecb4760e1c..dd2527f084 100644 --- a/src/include.am +++ b/src/include.am @@ -1978,7 +1978,6 @@ endif if BUILD_LIBOQS src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/falcon.c -src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/sphincs.c src_libwolfssl@LIBSUFFIX@_la_SOURCES += wolfcrypt/src/port/liboqs/liboqs.c endif diff --git a/src/ssl.c b/src/ssl.c index 759580bd8e..44409ac317 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -118,9 +118,6 @@ #if defined(HAVE_DILITHIUM) #include #endif /* HAVE_DILITHIUM */ - #if defined(HAVE_SPHINCS) - #include - #endif /* HAVE_SPHINCS */ #if defined(OPENSSL_ALL) || defined(HAVE_STUNNEL) #ifdef HAVE_OCSP #include diff --git a/src/x509.c b/src/x509.c index b0e695d707..ae044624bc 100644 --- a/src/x509.c +++ b/src/x509.c @@ -12179,8 +12179,8 @@ static int CertFromX509(Cert* cert, WOLFSSL_X509* x509) #if defined(HAVE_DILITHIUM) dilithium_key* dilithium = NULL; #endif - #if defined(HAVE_SPHINCS) - sphincs_key* sphincs = NULL; + #if defined(WOLFSSL_HAVE_SLHDSA) + SlhDsaKey* slhdsa = NULL; #endif WC_RNG rng; word32 idx = 0; @@ -12411,63 +12411,58 @@ static int CertFromX509(Cert* cert, WOLFSSL_X509* x509) key = (void*)dilithium; } #endif - #if defined(HAVE_SPHINCS) - if ((x509->pubKeyOID == SPHINCS_FAST_LEVEL1k) || - (x509->pubKeyOID == SPHINCS_FAST_LEVEL3k) || - (x509->pubKeyOID == SPHINCS_FAST_LEVEL5k) || - (x509->pubKeyOID == SPHINCS_SMALL_LEVEL1k) || - (x509->pubKeyOID == SPHINCS_SMALL_LEVEL3k) || - (x509->pubKeyOID == SPHINCS_SMALL_LEVEL5k)) { - sphincs = (sphincs_key*)XMALLOC(sizeof(sphincs_key), NULL, - DYNAMIC_TYPE_SPHINCS); - if (sphincs == NULL) { - WOLFSSL_MSG("Failed to allocate memory for sphincs_key"); + #if defined(WOLFSSL_HAVE_SLHDSA) + if (wc_IsSlhDsaOid(x509->pubKeyOID)) { + int paramInt = wc_SlhDsaOidToParam(x509->pubKeyOID); + int certType = wc_SlhDsaOidToCertType(x509->pubKeyOID); + + /* The OID is a recognised SLH-DSA OID but the parameter set + * isn't built in; surface NOT_COMPILED_IN directly so + * callers can render an accurate diagnostic. */ + if (paramInt == WC_NO_ERR_TRACE(NOT_COMPILED_IN) || + certType == WC_NO_ERR_TRACE(NOT_COMPILED_IN)) { + WOLFSSL_MSG("SLH-DSA variant not compiled in"); + XFREE(cert, NULL, DYNAMIC_TYPE_CERT); + return NOT_COMPILED_IN; + } + /* Defensive: wc_IsSlhDsaOid already implies both lookups + * succeed, but check explicitly so any future drift between the + * three OID helpers surfaces as a clean failure rather than + * undefined behaviour from casting -1 to enum SlhDsaParam. */ + if (paramInt < 0 || certType < 0) { + WOLFSSL_MSG("SLH-DSA OID helper mismatch"); XFREE(cert, NULL, DYNAMIC_TYPE_CERT); return WOLFSSL_FAILURE; } - ret = wc_sphincs_init(sphincs); + slhdsa = (SlhDsaKey*)XMALLOC(sizeof(SlhDsaKey), NULL, + DYNAMIC_TYPE_SLHDSA); + if (slhdsa == NULL) { + WOLFSSL_MSG("Failed to allocate memory for SlhDsaKey"); + XFREE(cert, NULL, DYNAMIC_TYPE_CERT); + return WOLFSSL_FAILURE; + } + + type = certType; + + ret = wc_SlhDsaKey_Init(slhdsa, (enum SlhDsaParam)paramInt, NULL, + INVALID_DEVID); if (ret != 0) { - XFREE(sphincs, NULL, DYNAMIC_TYPE_SPHINCS); + XFREE(slhdsa, NULL, DYNAMIC_TYPE_SLHDSA); XFREE(cert, NULL, DYNAMIC_TYPE_CERT); return ret; } - if (x509->pubKeyOID == SPHINCS_FAST_LEVEL1k) { - type = SPHINCS_FAST_LEVEL1_TYPE; - wc_sphincs_set_level_and_optim(sphincs, 1, FAST_VARIANT); - } - else if (x509->pubKeyOID == SPHINCS_FAST_LEVEL3k) { - type = SPHINCS_FAST_LEVEL3_TYPE; - wc_sphincs_set_level_and_optim(sphincs, 3, FAST_VARIANT); - } - else if (x509->pubKeyOID == SPHINCS_FAST_LEVEL3k) { - type = SPHINCS_FAST_LEVEL5_TYPE; - wc_sphincs_set_level_and_optim(sphincs, 5, FAST_VARIANT); - } - else if (x509->pubKeyOID == SPHINCS_SMALL_LEVEL1k) { - type = SPHINCS_SMALL_LEVEL1_TYPE; - wc_sphincs_set_level_and_optim(sphincs, 1, SMALL_VARIANT); - } - else if (x509->pubKeyOID == SPHINCS_SMALL_LEVEL3k) { - type = SPHINCS_SMALL_LEVEL3_TYPE; - wc_sphincs_set_level_and_optim(sphincs, 3, SMALL_VARIANT); - } - else if (x509->pubKeyOID == SPHINCS_SMALL_LEVEL3k) { - type = SPHINCS_SMALL_LEVEL5_TYPE; - wc_sphincs_set_level_and_optim(sphincs, 5, SMALL_VARIANT); - } - - ret = wc_Sphincs_PublicKeyDecode(x509->pubKey.buffer, &idx, sphincs, - x509->pubKey.length); + ret = wc_SlhDsaKey_PublicKeyDecode(x509->pubKey.buffer, &idx, + slhdsa, x509->pubKey.length); if (ret != 0) { WOLFSSL_ERROR_VERBOSE(ret); - wc_sphincs_free(sphincs); - XFREE(sphincs, NULL, DYNAMIC_TYPE_SPHINCS); + wc_SlhDsaKey_Free(slhdsa); + XFREE(slhdsa, NULL, DYNAMIC_TYPE_SLHDSA); XFREE(cert, NULL, DYNAMIC_TYPE_CERT); return ret; } - key = (void*)sphincs; + key = (void*)slhdsa; } #endif if (key == NULL) { @@ -12591,15 +12586,15 @@ cleanup: XFREE(dilithium, NULL, DYNAMIC_TYPE_DILITHIUM); } #endif - #if defined(HAVE_SPHINCS) - if ((x509->pubKeyOID == SPHINCS_FAST_LEVEL1k) || - (x509->pubKeyOID == SPHINCS_FAST_LEVEL3k) || - (x509->pubKeyOID == SPHINCS_FAST_LEVEL5k) || - (x509->pubKeyOID == SPHINCS_SMALL_LEVEL1k) || - (x509->pubKeyOID == SPHINCS_SMALL_LEVEL3k) || - (x509->pubKeyOID == SPHINCS_SMALL_LEVEL5k)) { - wc_sphincs_free(sphincs); - XFREE(sphincs, NULL, DYNAMIC_TYPE_SPHINCS); + #if defined(WOLFSSL_HAVE_SLHDSA) + /* wc_IsSlhDsaOid returns 1 even for OIDs whose backend is + * NOT_COMPILED_IN; the early-return at the top of the SLH-DSA + * branch keeps slhdsa==NULL in that case. Guard the cleanup so + * future restructuring (a goto cleanup from inside the + * unbuilt-variant handler) cannot dereference a NULL key. */ + if (wc_IsSlhDsaOid(x509->pubKeyOID) && slhdsa != NULL) { + wc_SlhDsaKey_Free(slhdsa); + XFREE(slhdsa, NULL, DYNAMIC_TYPE_SLHDSA); } #endif XFREE(cert, NULL, DYNAMIC_TYPE_CERT); diff --git a/tests/api/test_slhdsa.c b/tests/api/test_slhdsa.c index 4d54bb6929..646123f472 100644 --- a/tests/api/test_slhdsa.c +++ b/tests/api/test_slhdsa.c @@ -32,59 +32,198 @@ #include #endif #include +#include +#include #include #include +#ifdef WOLFSSL_HAVE_SLHDSA +/* Pick the first available parameter set so tests that just need any one valid + * SLH-DSA configuration compile and run in SHAKE-only, SHA-2-only, or mixed + * builds. Preference order: SHAKE 128s/f, 192s/f, 256s/f, then the SHA-2 + * variants in the same order. */ +#if defined(WOLFSSL_SLHDSA_PARAM_128S) + #define TEST_SLHDSA_DEFAULT_PARAM SLHDSA_SHAKE128S + #define TEST_SLHDSA_DEFAULT_SIG_LEN WC_SLHDSA_SHAKE128S_SIG_LEN + #define TEST_SLHDSA_DEFAULT_PRIV_LEN WC_SLHDSA_SHAKE128S_PRIV_LEN + #define TEST_SLHDSA_DEFAULT_PUB_LEN WC_SLHDSA_SHAKE128S_PUB_LEN + #define TEST_SLHDSA_DEFAULT_SEED_LEN WC_SLHDSA_SHAKE128S_SEED_LEN +#elif defined(WOLFSSL_SLHDSA_PARAM_128F) + #define TEST_SLHDSA_DEFAULT_PARAM SLHDSA_SHAKE128F + #define TEST_SLHDSA_DEFAULT_SIG_LEN WC_SLHDSA_SHAKE128F_SIG_LEN + #define TEST_SLHDSA_DEFAULT_PRIV_LEN WC_SLHDSA_SHAKE128F_PRIV_LEN + #define TEST_SLHDSA_DEFAULT_PUB_LEN WC_SLHDSA_SHAKE128F_PUB_LEN + #define TEST_SLHDSA_DEFAULT_SEED_LEN WC_SLHDSA_SHAKE128F_SEED_LEN +#elif defined(WOLFSSL_SLHDSA_PARAM_192S) + #define TEST_SLHDSA_DEFAULT_PARAM SLHDSA_SHAKE192S + #define TEST_SLHDSA_DEFAULT_SIG_LEN WC_SLHDSA_SHAKE192S_SIG_LEN + #define TEST_SLHDSA_DEFAULT_PRIV_LEN WC_SLHDSA_SHAKE192S_PRIV_LEN + #define TEST_SLHDSA_DEFAULT_PUB_LEN WC_SLHDSA_SHAKE192S_PUB_LEN + #define TEST_SLHDSA_DEFAULT_SEED_LEN WC_SLHDSA_SHAKE192S_SEED_LEN +#elif defined(WOLFSSL_SLHDSA_PARAM_192F) + #define TEST_SLHDSA_DEFAULT_PARAM SLHDSA_SHAKE192F + #define TEST_SLHDSA_DEFAULT_SIG_LEN WC_SLHDSA_SHAKE192F_SIG_LEN + #define TEST_SLHDSA_DEFAULT_PRIV_LEN WC_SLHDSA_SHAKE192F_PRIV_LEN + #define TEST_SLHDSA_DEFAULT_PUB_LEN WC_SLHDSA_SHAKE192F_PUB_LEN + #define TEST_SLHDSA_DEFAULT_SEED_LEN WC_SLHDSA_SHAKE192F_SEED_LEN +#elif defined(WOLFSSL_SLHDSA_PARAM_256S) + #define TEST_SLHDSA_DEFAULT_PARAM SLHDSA_SHAKE256S + #define TEST_SLHDSA_DEFAULT_SIG_LEN WC_SLHDSA_SHAKE256S_SIG_LEN + #define TEST_SLHDSA_DEFAULT_PRIV_LEN WC_SLHDSA_SHAKE256S_PRIV_LEN + #define TEST_SLHDSA_DEFAULT_PUB_LEN WC_SLHDSA_SHAKE256S_PUB_LEN + #define TEST_SLHDSA_DEFAULT_SEED_LEN WC_SLHDSA_SHAKE256S_SEED_LEN +#elif defined(WOLFSSL_SLHDSA_PARAM_256F) + #define TEST_SLHDSA_DEFAULT_PARAM SLHDSA_SHAKE256F + #define TEST_SLHDSA_DEFAULT_SIG_LEN WC_SLHDSA_SHAKE256F_SIG_LEN + #define TEST_SLHDSA_DEFAULT_PRIV_LEN WC_SLHDSA_SHAKE256F_PRIV_LEN + #define TEST_SLHDSA_DEFAULT_PUB_LEN WC_SLHDSA_SHAKE256F_PUB_LEN + #define TEST_SLHDSA_DEFAULT_SEED_LEN WC_SLHDSA_SHAKE256F_SEED_LEN +#elif defined(WOLFSSL_SLHDSA_PARAM_SHA2_128S) + #define TEST_SLHDSA_DEFAULT_PARAM SLHDSA_SHA2_128S + #define TEST_SLHDSA_DEFAULT_SIG_LEN WC_SLHDSA_SHA2_128S_SIG_LEN + #define TEST_SLHDSA_DEFAULT_PRIV_LEN WC_SLHDSA_SHA2_128S_PRIV_LEN + #define TEST_SLHDSA_DEFAULT_PUB_LEN WC_SLHDSA_SHA2_128S_PUB_LEN + #define TEST_SLHDSA_DEFAULT_SEED_LEN WC_SLHDSA_SHA2_128S_SEED_LEN +#elif defined(WOLFSSL_SLHDSA_PARAM_SHA2_128F) + #define TEST_SLHDSA_DEFAULT_PARAM SLHDSA_SHA2_128F + #define TEST_SLHDSA_DEFAULT_SIG_LEN WC_SLHDSA_SHA2_128F_SIG_LEN + #define TEST_SLHDSA_DEFAULT_PRIV_LEN WC_SLHDSA_SHA2_128F_PRIV_LEN + #define TEST_SLHDSA_DEFAULT_PUB_LEN WC_SLHDSA_SHA2_128F_PUB_LEN + #define TEST_SLHDSA_DEFAULT_SEED_LEN WC_SLHDSA_SHA2_128F_SEED_LEN +#elif defined(WOLFSSL_SLHDSA_PARAM_SHA2_192S) + #define TEST_SLHDSA_DEFAULT_PARAM SLHDSA_SHA2_192S + #define TEST_SLHDSA_DEFAULT_SIG_LEN WC_SLHDSA_SHA2_192S_SIG_LEN + #define TEST_SLHDSA_DEFAULT_PRIV_LEN WC_SLHDSA_SHA2_192S_PRIV_LEN + #define TEST_SLHDSA_DEFAULT_PUB_LEN WC_SLHDSA_SHA2_192S_PUB_LEN + #define TEST_SLHDSA_DEFAULT_SEED_LEN WC_SLHDSA_SHA2_192S_SEED_LEN +#elif defined(WOLFSSL_SLHDSA_PARAM_SHA2_192F) + #define TEST_SLHDSA_DEFAULT_PARAM SLHDSA_SHA2_192F + #define TEST_SLHDSA_DEFAULT_SIG_LEN WC_SLHDSA_SHA2_192F_SIG_LEN + #define TEST_SLHDSA_DEFAULT_PRIV_LEN WC_SLHDSA_SHA2_192F_PRIV_LEN + #define TEST_SLHDSA_DEFAULT_PUB_LEN WC_SLHDSA_SHA2_192F_PUB_LEN + #define TEST_SLHDSA_DEFAULT_SEED_LEN WC_SLHDSA_SHA2_192F_SEED_LEN +#elif defined(WOLFSSL_SLHDSA_PARAM_SHA2_256S) + #define TEST_SLHDSA_DEFAULT_PARAM SLHDSA_SHA2_256S + #define TEST_SLHDSA_DEFAULT_SIG_LEN WC_SLHDSA_SHA2_256S_SIG_LEN + #define TEST_SLHDSA_DEFAULT_PRIV_LEN WC_SLHDSA_SHA2_256S_PRIV_LEN + #define TEST_SLHDSA_DEFAULT_PUB_LEN WC_SLHDSA_SHA2_256S_PUB_LEN + #define TEST_SLHDSA_DEFAULT_SEED_LEN WC_SLHDSA_SHA2_256S_SEED_LEN +#elif defined(WOLFSSL_SLHDSA_PARAM_SHA2_256F) + #define TEST_SLHDSA_DEFAULT_PARAM SLHDSA_SHA2_256F + #define TEST_SLHDSA_DEFAULT_SIG_LEN WC_SLHDSA_SHA2_256F_SIG_LEN + #define TEST_SLHDSA_DEFAULT_PRIV_LEN WC_SLHDSA_SHA2_256F_PRIV_LEN + #define TEST_SLHDSA_DEFAULT_PUB_LEN WC_SLHDSA_SHA2_256F_PUB_LEN + #define TEST_SLHDSA_DEFAULT_SEED_LEN WC_SLHDSA_SHA2_256F_SEED_LEN +#endif +#endif /* WOLFSSL_HAVE_SLHDSA */ + + /* * Test basic init/free and NULL parameter handling for SLH-DSA key operations. */ int test_wc_slhdsa(void) { EXPECT_DECLS; -#if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_NO_SHAKE) +#ifdef WOLFSSL_HAVE_SLHDSA + /* `key` is only used by the per-variant Init/Free blocks below, so + * gate its declaration on the same precondition (at least one + * parameter set compiled in) to avoid -Wunused-variable when SLH-DSA + * is enabled but no params are. */ +#ifdef TEST_SLHDSA_DEFAULT_PARAM SlhDsaKey key; - /* Test NULL parameter handling for init. */ - ExpectIntEQ(wc_SlhDsaKey_Init(NULL, SLHDSA_SHAKE128S, NULL, INVALID_DEVID), - WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + /* Test NULL parameter handling for init. Use whichever variant the + * build actually has so a SHA-2-only build doesn't pass a SHAKE param + * id and conflate BAD_FUNC_ARG (NULL key) with NOT_COMPILED_IN + * (variant disabled). */ + ExpectIntEQ(wc_SlhDsaKey_Init(NULL, TEST_SLHDSA_DEFAULT_PARAM, NULL, + INVALID_DEVID), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); +#endif /* Test wc_SlhDsaKey_Free with NULL - should not crash. */ wc_SlhDsaKey_Free(NULL); - /* Test valid init for each supported parameter set. */ + /* Test valid init for each supported parameter set. Each block zeros + * `key` first so a future regression where wc_SlhDsaKey_Free leaves + * a residual field set cannot be papered over by the next Init's + * partial reinitialisation. */ #ifdef WOLFSSL_SLHDSA_PARAM_128S + XMEMSET(&key, 0, sizeof(key)); ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128S, NULL, INVALID_DEVID), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_PARAM_128F + XMEMSET(&key, 0, sizeof(key)); ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_PARAM_192S + XMEMSET(&key, 0, sizeof(key)); ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE192S, NULL, INVALID_DEVID), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_PARAM_192F + XMEMSET(&key, 0, sizeof(key)); ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE192F, NULL, INVALID_DEVID), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_PARAM_256S + XMEMSET(&key, 0, sizeof(key)); ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE256S, NULL, INVALID_DEVID), 0); wc_SlhDsaKey_Free(&key); #endif #ifdef WOLFSSL_SLHDSA_PARAM_256F + XMEMSET(&key, 0, sizeof(key)); ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE256F, NULL, INVALID_DEVID), 0); wc_SlhDsaKey_Free(&key); #endif +#ifdef WOLFSSL_SLHDSA_SHA2 +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128S + XMEMSET(&key, 0, sizeof(key)); + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_128S, NULL, INVALID_DEVID), + 0); + wc_SlhDsaKey_Free(&key); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128F + XMEMSET(&key, 0, sizeof(key)); + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_128F, NULL, INVALID_DEVID), + 0); + wc_SlhDsaKey_Free(&key); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192S + XMEMSET(&key, 0, sizeof(key)); + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_192S, NULL, INVALID_DEVID), + 0); + wc_SlhDsaKey_Free(&key); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192F + XMEMSET(&key, 0, sizeof(key)); + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_192F, NULL, INVALID_DEVID), + 0); + wc_SlhDsaKey_Free(&key); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256S + XMEMSET(&key, 0, sizeof(key)); + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_256S, NULL, INVALID_DEVID), + 0); + wc_SlhDsaKey_Free(&key); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256F + XMEMSET(&key, 0, sizeof(key)); + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_256F, NULL, INVALID_DEVID), + 0); + wc_SlhDsaKey_Free(&key); +#endif +#endif /* WOLFSSL_SLHDSA_SHA2 */ -#endif /* WOLFSSL_HAVE_SLHDSA && !WOLFSSL_SLHDSA_NO_SHAKE */ +#endif /* WOLFSSL_HAVE_SLHDSA */ return EXPECT_RESULT(); } @@ -94,8 +233,11 @@ int test_wc_slhdsa(void) int test_wc_slhdsa_sizes(void) { EXPECT_DECLS; -#if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_NO_SHAKE) +#ifdef WOLFSSL_HAVE_SLHDSA + /* See test_wc_slhdsa() for the rationale on this guard. */ +#ifdef TEST_SLHDSA_DEFAULT_PARAM SlhDsaKey key; +#endif /* Test NULL parameter handling for size functions. */ #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY @@ -152,8 +294,7 @@ int test_wc_slhdsa_sizes(void) ExpectIntEQ(wc_SlhDsaKey_PrivateSize(&key), WC_SLHDSA_SHAKE192S_PRIV_LEN); #endif ExpectIntEQ(wc_SlhDsaKey_PublicSize(&key), WC_SLHDSA_SHAKE192S_PUB_LEN); - /* Verify signature size is positive. */ - ExpectIntGT(wc_SlhDsaKey_SigSize(&key), 0); + ExpectIntEQ(wc_SlhDsaKey_SigSize(&key), WC_SLHDSA_SHAKE192S_SIG_LEN); wc_SlhDsaKey_Free(&key); #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY @@ -162,8 +303,8 @@ int test_wc_slhdsa_sizes(void) #endif ExpectIntEQ(wc_SlhDsaKey_PublicSizeFromParam(SLHDSA_SHAKE192S), WC_SLHDSA_SHAKE192S_PUB_LEN); - /* Verify SigSizeFromParam returns positive value. */ - ExpectIntGT(wc_SlhDsaKey_SigSizeFromParam(SLHDSA_SHAKE192S), 0); + ExpectIntEQ(wc_SlhDsaKey_SigSizeFromParam(SLHDSA_SHAKE192S), + WC_SLHDSA_SHAKE192S_SIG_LEN); #endif #ifdef WOLFSSL_SLHDSA_PARAM_192F @@ -226,7 +367,129 @@ int test_wc_slhdsa_sizes(void) WC_SLHDSA_SHAKE256F_SIG_LEN); #endif -#endif /* WOLFSSL_HAVE_SLHDSA && !WOLFSSL_SLHDSA_NO_SHAKE */ +#ifdef WOLFSSL_SLHDSA_SHA2 +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128S + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_128S, NULL, INVALID_DEVID), + 0); +#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY + ExpectIntEQ(wc_SlhDsaKey_PrivateSize(&key), WC_SLHDSA_SHA2_128S_PRIV_LEN); +#endif + ExpectIntEQ(wc_SlhDsaKey_PublicSize(&key), WC_SLHDSA_SHA2_128S_PUB_LEN); + ExpectIntEQ(wc_SlhDsaKey_SigSize(&key), WC_SLHDSA_SHA2_128S_SIG_LEN); + wc_SlhDsaKey_Free(&key); + +#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY + ExpectIntEQ(wc_SlhDsaKey_PrivateSizeFromParam(SLHDSA_SHA2_128S), + WC_SLHDSA_SHA2_128S_PRIV_LEN); +#endif + ExpectIntEQ(wc_SlhDsaKey_PublicSizeFromParam(SLHDSA_SHA2_128S), + WC_SLHDSA_SHA2_128S_PUB_LEN); + ExpectIntEQ(wc_SlhDsaKey_SigSizeFromParam(SLHDSA_SHA2_128S), + WC_SLHDSA_SHA2_128S_SIG_LEN); +#endif + +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128F + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_128F, NULL, INVALID_DEVID), + 0); +#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY + ExpectIntEQ(wc_SlhDsaKey_PrivateSize(&key), WC_SLHDSA_SHA2_128F_PRIV_LEN); +#endif + ExpectIntEQ(wc_SlhDsaKey_PublicSize(&key), WC_SLHDSA_SHA2_128F_PUB_LEN); + ExpectIntEQ(wc_SlhDsaKey_SigSize(&key), WC_SLHDSA_SHA2_128F_SIG_LEN); + wc_SlhDsaKey_Free(&key); + +#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY + ExpectIntEQ(wc_SlhDsaKey_PrivateSizeFromParam(SLHDSA_SHA2_128F), + WC_SLHDSA_SHA2_128F_PRIV_LEN); +#endif + ExpectIntEQ(wc_SlhDsaKey_PublicSizeFromParam(SLHDSA_SHA2_128F), + WC_SLHDSA_SHA2_128F_PUB_LEN); + ExpectIntEQ(wc_SlhDsaKey_SigSizeFromParam(SLHDSA_SHA2_128F), + WC_SLHDSA_SHA2_128F_SIG_LEN); +#endif + +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192S + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_192S, NULL, INVALID_DEVID), + 0); +#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY + ExpectIntEQ(wc_SlhDsaKey_PrivateSize(&key), WC_SLHDSA_SHA2_192S_PRIV_LEN); +#endif + ExpectIntEQ(wc_SlhDsaKey_PublicSize(&key), WC_SLHDSA_SHA2_192S_PUB_LEN); + ExpectIntEQ(wc_SlhDsaKey_SigSize(&key), WC_SLHDSA_SHA2_192S_SIG_LEN); + wc_SlhDsaKey_Free(&key); + +#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY + ExpectIntEQ(wc_SlhDsaKey_PrivateSizeFromParam(SLHDSA_SHA2_192S), + WC_SLHDSA_SHA2_192S_PRIV_LEN); +#endif + ExpectIntEQ(wc_SlhDsaKey_PublicSizeFromParam(SLHDSA_SHA2_192S), + WC_SLHDSA_SHA2_192S_PUB_LEN); + ExpectIntEQ(wc_SlhDsaKey_SigSizeFromParam(SLHDSA_SHA2_192S), + WC_SLHDSA_SHA2_192S_SIG_LEN); +#endif + +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192F + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_192F, NULL, INVALID_DEVID), + 0); +#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY + ExpectIntEQ(wc_SlhDsaKey_PrivateSize(&key), WC_SLHDSA_SHA2_192F_PRIV_LEN); +#endif + ExpectIntEQ(wc_SlhDsaKey_PublicSize(&key), WC_SLHDSA_SHA2_192F_PUB_LEN); + ExpectIntEQ(wc_SlhDsaKey_SigSize(&key), WC_SLHDSA_SHA2_192F_SIG_LEN); + wc_SlhDsaKey_Free(&key); + +#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY + ExpectIntEQ(wc_SlhDsaKey_PrivateSizeFromParam(SLHDSA_SHA2_192F), + WC_SLHDSA_SHA2_192F_PRIV_LEN); +#endif + ExpectIntEQ(wc_SlhDsaKey_PublicSizeFromParam(SLHDSA_SHA2_192F), + WC_SLHDSA_SHA2_192F_PUB_LEN); + ExpectIntEQ(wc_SlhDsaKey_SigSizeFromParam(SLHDSA_SHA2_192F), + WC_SLHDSA_SHA2_192F_SIG_LEN); +#endif + +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256S + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_256S, NULL, INVALID_DEVID), + 0); +#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY + ExpectIntEQ(wc_SlhDsaKey_PrivateSize(&key), WC_SLHDSA_SHA2_256S_PRIV_LEN); +#endif + ExpectIntEQ(wc_SlhDsaKey_PublicSize(&key), WC_SLHDSA_SHA2_256S_PUB_LEN); + ExpectIntEQ(wc_SlhDsaKey_SigSize(&key), WC_SLHDSA_SHA2_256S_SIG_LEN); + wc_SlhDsaKey_Free(&key); + +#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY + ExpectIntEQ(wc_SlhDsaKey_PrivateSizeFromParam(SLHDSA_SHA2_256S), + WC_SLHDSA_SHA2_256S_PRIV_LEN); +#endif + ExpectIntEQ(wc_SlhDsaKey_PublicSizeFromParam(SLHDSA_SHA2_256S), + WC_SLHDSA_SHA2_256S_PUB_LEN); + ExpectIntEQ(wc_SlhDsaKey_SigSizeFromParam(SLHDSA_SHA2_256S), + WC_SLHDSA_SHA2_256S_SIG_LEN); +#endif + +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256F + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_256F, NULL, INVALID_DEVID), + 0); +#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY + ExpectIntEQ(wc_SlhDsaKey_PrivateSize(&key), WC_SLHDSA_SHA2_256F_PRIV_LEN); +#endif + ExpectIntEQ(wc_SlhDsaKey_PublicSize(&key), WC_SLHDSA_SHA2_256F_PUB_LEN); + ExpectIntEQ(wc_SlhDsaKey_SigSize(&key), WC_SLHDSA_SHA2_256F_SIG_LEN); + wc_SlhDsaKey_Free(&key); + +#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY + ExpectIntEQ(wc_SlhDsaKey_PrivateSizeFromParam(SLHDSA_SHA2_256F), + WC_SLHDSA_SHA2_256F_PRIV_LEN); +#endif + ExpectIntEQ(wc_SlhDsaKey_PublicSizeFromParam(SLHDSA_SHA2_256F), + WC_SLHDSA_SHA2_256F_PUB_LEN); + ExpectIntEQ(wc_SlhDsaKey_SigSizeFromParam(SLHDSA_SHA2_256F), + WC_SLHDSA_SHA2_256F_SIG_LEN); +#endif +#endif /* WOLFSSL_SLHDSA_SHA2 */ + +#endif /* WOLFSSL_HAVE_SLHDSA */ return EXPECT_RESULT(); } @@ -291,12 +554,51 @@ int test_wc_slhdsa_make_key(void) wc_SlhDsaKey_Free(&key); #endif +#ifdef WOLFSSL_SLHDSA_SHA2 +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128S + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_128S, NULL, INVALID_DEVID), + 0); + ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); + wc_SlhDsaKey_Free(&key); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128F + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_128F, NULL, INVALID_DEVID), + 0); + ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); + wc_SlhDsaKey_Free(&key); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192S + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_192S, NULL, INVALID_DEVID), + 0); + ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); + wc_SlhDsaKey_Free(&key); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192F + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_192F, NULL, INVALID_DEVID), + 0); + ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); + wc_SlhDsaKey_Free(&key); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256S + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_256S, NULL, INVALID_DEVID), + 0); + ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); + wc_SlhDsaKey_Free(&key); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256F + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_256F, NULL, INVALID_DEVID), + 0); + ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); + wc_SlhDsaKey_Free(&key); +#endif +#endif /* WOLFSSL_SLHDSA_SHA2 */ + /* Test MakeKeyWithRandom. */ -#ifdef WOLFSSL_SLHDSA_PARAM_128S +#ifdef TEST_SLHDSA_DEFAULT_PARAM { - byte sk_seed[WC_SLHDSA_SHAKE128S_SEED_LEN]; - byte sk_prf[WC_SLHDSA_SHAKE128S_SEED_LEN]; - byte pk_seed[WC_SLHDSA_SHAKE128S_SEED_LEN]; + byte sk_seed[TEST_SLHDSA_DEFAULT_SEED_LEN]; + byte sk_prf[TEST_SLHDSA_DEFAULT_SEED_LEN]; + byte pk_seed[TEST_SLHDSA_DEFAULT_SEED_LEN]; XMEMSET(sk_seed, 0x01, sizeof(sk_seed)); XMEMSET(sk_prf, 0x02, sizeof(sk_prf)); @@ -307,7 +609,7 @@ int test_wc_slhdsa_make_key(void) sizeof(sk_seed), sk_prf, sizeof(sk_prf), pk_seed, sizeof(pk_seed)), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128S, NULL, + ExpectIntEQ(wc_SlhDsaKey_Init(&key, TEST_SLHDSA_DEFAULT_PARAM, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKeyWithRandom(&key, NULL, sizeof(sk_seed), sk_prf, sizeof(sk_prf), pk_seed, sizeof(pk_seed)), @@ -364,31 +666,9 @@ int test_wc_slhdsa_sign(void) ExpectIntEQ(wc_SlhDsaKey_Sign(NULL, ctx, sizeof(ctx), msg, sizeof(msg), sig, &sigLen, &rng), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); -#ifdef WOLFSSL_SLHDSA_PARAM_128S - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128S, NULL, INVALID_DEVID), - 0); - expSigLen = WC_SLHDSA_SHAKE128S_SIG_LEN; -#elif defined(WOLFSSL_SLHDSA_PARAM_128F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID), - 0); - expSigLen = WC_SLHDSA_SHAKE128F_SIG_LEN; -#elif defined(WOLFSSL_SLHDSA_PARAM_192S) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE192S, NULL, INVALID_DEVID), - 0); - expSigLen = WC_SLHDSA_SHAKE192S_SIG_LEN; -#elif defined(WOLFSSL_SLHDSA_PARAM_192F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE192F, NULL, INVALID_DEVID), - 0); - expSigLen = WC_SLHDSA_SHAKE192F_SIG_LEN; -#elif defined(WOLFSSL_SLHDSA_PARAM_256S) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE256S, NULL, INVALID_DEVID), - 0); - expSigLen = WC_SLHDSA_SHAKE256S_SIG_LEN; -#elif defined(WOLFSSL_SLHDSA_PARAM_256F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE256F, NULL, INVALID_DEVID), - 0); - expSigLen = WC_SLHDSA_SHAKE256F_SIG_LEN; -#endif + ExpectIntEQ(wc_SlhDsaKey_Init(&key, TEST_SLHDSA_DEFAULT_PARAM, NULL, + INVALID_DEVID), 0); + expSigLen = TEST_SLHDSA_DEFAULT_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); sigLen = WC_SLHDSA_MAX_SIG_LEN; @@ -420,25 +700,8 @@ int test_wc_slhdsa_sign(void) wc_SlhDsaKey_Free(&key); /* Test SignDeterministic. */ -#ifdef WOLFSSL_SLHDSA_PARAM_128S - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128S, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_128F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_192S) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE192S, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_192F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE192F, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_256S) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE256S, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_256F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE256F, NULL, INVALID_DEVID), - 0); -#endif + ExpectIntEQ(wc_SlhDsaKey_Init(&key, TEST_SLHDSA_DEFAULT_PARAM, NULL, + INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); sigLen = WC_SLHDSA_MAX_SIG_LEN; @@ -455,25 +718,8 @@ int test_wc_slhdsa_sign(void) byte addRnd[WC_SLHDSA_MAX_SEED]; XMEMSET(addRnd, 0x55, sizeof(addRnd)); -#ifdef WOLFSSL_SLHDSA_PARAM_128S - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128S, NULL, + ExpectIntEQ(wc_SlhDsaKey_Init(&key, TEST_SLHDSA_DEFAULT_PARAM, NULL, INVALID_DEVID), 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_128F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, - INVALID_DEVID), 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_192S) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE192S, NULL, - INVALID_DEVID), 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_192F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE192F, NULL, - INVALID_DEVID), 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_256S) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE256S, NULL, - INVALID_DEVID), 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_256F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE256F, NULL, - INVALID_DEVID), 0); -#endif ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); sigLen = WC_SLHDSA_MAX_SIG_LEN; @@ -519,25 +765,8 @@ int test_wc_slhdsa_verify(void) ExpectIntEQ(wc_InitRng(&rng), 0); -#ifdef WOLFSSL_SLHDSA_PARAM_128S - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128S, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_128F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_192S) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE192S, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_192F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE192F, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_256S) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE256S, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_256F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE256F, NULL, INVALID_DEVID), - 0); -#endif + ExpectIntEQ(wc_SlhDsaKey_Init(&key, TEST_SLHDSA_DEFAULT_PARAM, NULL, + INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); /* Generate a signature. */ @@ -703,6 +932,81 @@ int test_wc_slhdsa_sign_vfy(void) wc_SlhDsaKey_Free(&key); #endif +#ifdef WOLFSSL_SLHDSA_SHA2 +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128S + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_128S, NULL, INVALID_DEVID), + 0); + ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); + sigLen = WC_SLHDSA_MAX_SIG_LEN; + ExpectIntEQ(wc_SlhDsaKey_Sign(&key, ctx, sizeof(ctx), msg, sizeof(msg), + sig, &sigLen, &rng), 0); + ExpectIntEQ(sigLen, WC_SLHDSA_SHA2_128S_SIG_LEN); + ExpectIntEQ(wc_SlhDsaKey_Verify(&key, ctx, sizeof(ctx), msg, sizeof(msg), + sig, sigLen), 0); + wc_SlhDsaKey_Free(&key); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128F + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_128F, NULL, INVALID_DEVID), + 0); + ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); + sigLen = WC_SLHDSA_MAX_SIG_LEN; + ExpectIntEQ(wc_SlhDsaKey_Sign(&key, ctx, sizeof(ctx), msg, sizeof(msg), + sig, &sigLen, &rng), 0); + ExpectIntEQ(sigLen, WC_SLHDSA_SHA2_128F_SIG_LEN); + ExpectIntEQ(wc_SlhDsaKey_Verify(&key, ctx, sizeof(ctx), msg, sizeof(msg), + sig, sigLen), 0); + wc_SlhDsaKey_Free(&key); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192S + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_192S, NULL, INVALID_DEVID), + 0); + ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); + sigLen = WC_SLHDSA_MAX_SIG_LEN; + ExpectIntEQ(wc_SlhDsaKey_Sign(&key, ctx, sizeof(ctx), msg, sizeof(msg), + sig, &sigLen, &rng), 0); + ExpectIntEQ(sigLen, WC_SLHDSA_SHA2_192S_SIG_LEN); + ExpectIntEQ(wc_SlhDsaKey_Verify(&key, ctx, sizeof(ctx), msg, sizeof(msg), + sig, sigLen), 0); + wc_SlhDsaKey_Free(&key); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192F + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_192F, NULL, INVALID_DEVID), + 0); + ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); + sigLen = WC_SLHDSA_MAX_SIG_LEN; + ExpectIntEQ(wc_SlhDsaKey_Sign(&key, ctx, sizeof(ctx), msg, sizeof(msg), + sig, &sigLen, &rng), 0); + ExpectIntEQ(sigLen, WC_SLHDSA_SHA2_192F_SIG_LEN); + ExpectIntEQ(wc_SlhDsaKey_Verify(&key, ctx, sizeof(ctx), msg, sizeof(msg), + sig, sigLen), 0); + wc_SlhDsaKey_Free(&key); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256S + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_256S, NULL, INVALID_DEVID), + 0); + ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); + sigLen = WC_SLHDSA_MAX_SIG_LEN; + ExpectIntEQ(wc_SlhDsaKey_Sign(&key, ctx, sizeof(ctx), msg, sizeof(msg), + sig, &sigLen, &rng), 0); + ExpectIntEQ(sigLen, WC_SLHDSA_SHA2_256S_SIG_LEN); + ExpectIntEQ(wc_SlhDsaKey_Verify(&key, ctx, sizeof(ctx), msg, sizeof(msg), + sig, sigLen), 0); + wc_SlhDsaKey_Free(&key); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256F + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_256F, NULL, INVALID_DEVID), + 0); + ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); + sigLen = WC_SLHDSA_MAX_SIG_LEN; + ExpectIntEQ(wc_SlhDsaKey_Sign(&key, ctx, sizeof(ctx), msg, sizeof(msg), + sig, &sigLen, &rng), 0); + ExpectIntEQ(sigLen, WC_SLHDSA_SHA2_256F_SIG_LEN); + ExpectIntEQ(wc_SlhDsaKey_Verify(&key, ctx, sizeof(ctx), msg, sizeof(msg), + sig, sigLen), 0); + wc_SlhDsaKey_Free(&key); +#endif +#endif /* WOLFSSL_SLHDSA_SHA2 */ + wc_FreeRng(&rng); XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif /* WOLFSSL_HAVE_SLHDSA */ @@ -733,31 +1037,9 @@ int test_wc_slhdsa_sign_hash(void) ExpectIntEQ(wc_InitRng(&rng), 0); -#ifdef WOLFSSL_SLHDSA_PARAM_128S - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128S, NULL, INVALID_DEVID), - 0); - expSigLen = WC_SLHDSA_SHAKE128S_SIG_LEN; -#elif defined(WOLFSSL_SLHDSA_PARAM_128F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID), - 0); - expSigLen = WC_SLHDSA_SHAKE128F_SIG_LEN; -#elif defined(WOLFSSL_SLHDSA_PARAM_192S) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE192S, NULL, INVALID_DEVID), - 0); - expSigLen = WC_SLHDSA_SHAKE192S_SIG_LEN; -#elif defined(WOLFSSL_SLHDSA_PARAM_192F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE192F, NULL, INVALID_DEVID), - 0); - expSigLen = WC_SLHDSA_SHAKE192F_SIG_LEN; -#elif defined(WOLFSSL_SLHDSA_PARAM_256S) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE256S, NULL, INVALID_DEVID), - 0); - expSigLen = WC_SLHDSA_SHAKE256S_SIG_LEN; -#elif defined(WOLFSSL_SLHDSA_PARAM_256F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE256F, NULL, INVALID_DEVID), - 0); - expSigLen = WC_SLHDSA_SHAKE256F_SIG_LEN; -#endif + ExpectIntEQ(wc_SlhDsaKey_Init(&key, TEST_SLHDSA_DEFAULT_PARAM, NULL, + INVALID_DEVID), 0); + expSigLen = TEST_SLHDSA_DEFAULT_SIG_LEN; ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); /* Test SignHash NULL parameter handling. */ @@ -886,37 +1168,10 @@ int test_wc_slhdsa_export_import(void) ExpectIntEQ(wc_SlhDsaKey_ImportPublic(NULL, pubKey, pubKeyLen), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); -#ifdef WOLFSSL_SLHDSA_PARAM_128S - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128S, NULL, INVALID_DEVID), - 0); - expPrivKeyLen = 4 * 16; - expPubKeyLen = 2 * 16; -#elif defined(WOLFSSL_SLHDSA_PARAM_128F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID), - 0); - expPrivKeyLen = 4 * 16; - expPubKeyLen = 2 * 16; -#elif defined(WOLFSSL_SLHDSA_PARAM_192S) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE192S, NULL, INVALID_DEVID), - 0); - expPrivKeyLen = 4 * 24; - expPubKeyLen = 2 * 24; -#elif defined(WOLFSSL_SLHDSA_PARAM_192F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE192F, NULL, INVALID_DEVID), - 0); - expPrivKeyLen = 4 * 24; - expPubKeyLen = 2 * 24; -#elif defined(WOLFSSL_SLHDSA_PARAM_256S) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE256S, NULL, INVALID_DEVID), - 0); - expPrivKeyLen = 4 * 32; - expPubKeyLen = 2 * 32; -#elif defined(WOLFSSL_SLHDSA_PARAM_256F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE256F, NULL, INVALID_DEVID), - 0); - expPrivKeyLen = 4 * 32; - expPubKeyLen = 2 * 32; -#endif + ExpectIntEQ(wc_SlhDsaKey_Init(&key, TEST_SLHDSA_DEFAULT_PARAM, NULL, + INVALID_DEVID), 0); + expPrivKeyLen = TEST_SLHDSA_DEFAULT_PRIV_LEN; + expPubKeyLen = TEST_SLHDSA_DEFAULT_PUB_LEN; ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); /* Test export with NULL buffer. */ @@ -952,25 +1207,8 @@ int test_wc_slhdsa_export_import(void) sig, &sigLen, &rng), 0); /* Test import into new key and verify. */ -#ifdef WOLFSSL_SLHDSA_PARAM_128S - ExpectIntEQ(wc_SlhDsaKey_Init(&key2, SLHDSA_SHAKE128S, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_128F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key2, SLHDSA_SHAKE128F, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_192S) - ExpectIntEQ(wc_SlhDsaKey_Init(&key2, SLHDSA_SHAKE192S, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_192F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key2, SLHDSA_SHAKE192F, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_256S) - ExpectIntEQ(wc_SlhDsaKey_Init(&key2, SLHDSA_SHAKE256S, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_256F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key2, SLHDSA_SHAKE256F, NULL, INVALID_DEVID), - 0); -#endif + ExpectIntEQ(wc_SlhDsaKey_Init(&key2, TEST_SLHDSA_DEFAULT_PARAM, NULL, + INVALID_DEVID), 0); /* Test import with NULL data. */ ExpectIntEQ(wc_SlhDsaKey_ImportPrivate(&key2, NULL, privKeyLen), @@ -992,25 +1230,8 @@ int test_wc_slhdsa_export_import(void) wc_SlhDsaKey_Free(&key2); /* Test import of private key. */ -#ifdef WOLFSSL_SLHDSA_PARAM_128S - ExpectIntEQ(wc_SlhDsaKey_Init(&key2, SLHDSA_SHAKE128S, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_128F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key2, SLHDSA_SHAKE128F, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_192S) - ExpectIntEQ(wc_SlhDsaKey_Init(&key2, SLHDSA_SHAKE192S, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_192F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key2, SLHDSA_SHAKE192F, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_256S) - ExpectIntEQ(wc_SlhDsaKey_Init(&key2, SLHDSA_SHAKE256S, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_256F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key2, SLHDSA_SHAKE256F, NULL, INVALID_DEVID), - 0); -#endif + ExpectIntEQ(wc_SlhDsaKey_Init(&key2, TEST_SLHDSA_DEFAULT_PARAM, NULL, + INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_ImportPrivate(&key2, privKey, privKeyLen), 0); /* Sign with imported key. */ sigLen = WC_SLHDSA_MAX_SIG_LEN; @@ -1058,25 +1279,8 @@ int test_wc_slhdsa_check_key(void) /* Test NULL parameter handling. */ ExpectIntEQ(wc_SlhDsaKey_CheckKey(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); -#ifdef WOLFSSL_SLHDSA_PARAM_128S - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128S, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_128F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_192S) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE192S, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_192F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE192F, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_256S) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE256S, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_256F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE256F, NULL, INVALID_DEVID), - 0); -#endif + ExpectIntEQ(wc_SlhDsaKey_Init(&key, TEST_SLHDSA_DEFAULT_PARAM, NULL, + INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_MakeKey(&key, &rng), 0); /* Test check of valid key. */ @@ -1091,84 +1295,1236 @@ int test_wc_slhdsa_check_key(void) wc_SlhDsaKey_Free(&key); /* Test check with only public key imported - requires private key. */ -#ifdef WOLFSSL_SLHDSA_PARAM_128S - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128S, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_128F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_192S) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE192S, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_192F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE192F, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_256S) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE256S, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_256F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE256F, NULL, INVALID_DEVID), - 0); -#endif + ExpectIntEQ(wc_SlhDsaKey_Init(&key, TEST_SLHDSA_DEFAULT_PARAM, NULL, + INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_ImportPublic(&key, pubKey, pubKeyLen), 0); /* CheckKey requires a private key to validate. */ ExpectIntEQ(wc_SlhDsaKey_CheckKey(&key), WC_NO_ERR_TRACE(MISSING_KEY)); wc_SlhDsaKey_Free(&key); /* Test check with only private key imported. */ -#ifdef WOLFSSL_SLHDSA_PARAM_128S - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128S, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_128F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_192S) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE192S, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_192F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE192F, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_256S) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE256S, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_256F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE256F, NULL, INVALID_DEVID), - 0); -#endif + ExpectIntEQ(wc_SlhDsaKey_Init(&key, TEST_SLHDSA_DEFAULT_PARAM, NULL, + INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_ImportPrivate(&key, privKey, privKeyLen), 0); ExpectIntEQ(wc_SlhDsaKey_CheckKey(&key), 0); wc_SlhDsaKey_Free(&key); - /* Test check with both keys imported. - * Note: ImportPublic overwrites flags, so import Public first then Private. - */ -#ifdef WOLFSSL_SLHDSA_PARAM_128S - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128S, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_128F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_192S) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE192S, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_192F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE192F, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_256S) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE256S, NULL, INVALID_DEVID), - 0); -#elif defined(WOLFSSL_SLHDSA_PARAM_256F) - ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE256F, NULL, INVALID_DEVID), - 0); -#endif + /* Test check with both keys imported. */ + ExpectIntEQ(wc_SlhDsaKey_Init(&key, TEST_SLHDSA_DEFAULT_PARAM, NULL, + INVALID_DEVID), 0); ExpectIntEQ(wc_SlhDsaKey_ImportPublic(&key, pubKey, pubKeyLen), 0); ExpectIntEQ(wc_SlhDsaKey_ImportPrivate(&key, privKey, privKeyLen), 0); ExpectIntEQ(wc_SlhDsaKey_CheckKey(&key), 0); wc_SlhDsaKey_Free(&key); + /* Regression: Private-then-Public order. ImportPrivate sets + * flags = WC_SLHDSA_FLAG_BOTH_KEYS; if ImportPublic clobbered flags + * with `=` instead of `|=`, the FLAG_PRIVATE bit would be dropped and + * CheckKey would return MISSING_KEY. */ + ExpectIntEQ(wc_SlhDsaKey_Init(&key, TEST_SLHDSA_DEFAULT_PARAM, NULL, + INVALID_DEVID), 0); + ExpectIntEQ(wc_SlhDsaKey_ImportPrivate(&key, privKey, privKeyLen), 0); + ExpectIntEQ(wc_SlhDsaKey_ImportPublic(&key, pubKey, pubKeyLen), 0); + ExpectIntEQ(wc_SlhDsaKey_CheckKey(&key), 0); + wc_SlhDsaKey_Free(&key); + wc_FreeRng(&rng); XFREE(pubKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(privKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif /* WOLFSSL_HAVE_SLHDSA */ return EXPECT_RESULT(); } + +#if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) && \ + defined(WC_ENABLE_ASYM_KEY_EXPORT) +/* Round-trip a single SLH-DSA parameter set through the DER codec: + * generate -> KeyToDer -> PrivateKeyDecode -> sign/verify round-trip. + * Also tests PublicKeyToDer -> PublicKeyDecode, and that the decode + * correctly auto-detects the parameter set from the OID. */ +static int slhdsa_der_roundtrip_one(enum SlhDsaParam param) +{ + EXPECT_DECLS; + SlhDsaKey keyGen; + SlhDsaKey keyPriv; + SlhDsaKey keyPub; + WC_RNG rng; + byte* derBuf = NULL; + byte* sig = NULL; + const word32 derBufSz = 16 * 1024; + word32 derLen; + word32 idx; + word32 sigLen; + enum SlhDsaParam placeholder = param; + static const byte msg[] = "SLH-DSA DER round-trip"; + static const enum SlhDsaParam candidates[] = { + SLHDSA_SHAKE256S, SLHDSA_SHAKE128F, SLHDSA_SHAKE192S, + SLHDSA_SHAKE192F, SLHDSA_SHAKE256F, SLHDSA_SHAKE128S, + #ifdef WOLFSSL_SLHDSA_SHA2 + SLHDSA_SHA2_128S, SLHDSA_SHA2_128F, SLHDSA_SHA2_192S, + SLHDSA_SHA2_192F, SLHDSA_SHA2_256S, SLHDSA_SHA2_256F, + #endif + }; + size_t cIdx; + + /* Pick a placeholder different from the encoded param so a regression + * that disables OID auto-detection would fail the post-decode equality + * check. Walk the candidate list and probe each via wc_SlhDsaKey_Init; + * the first one that initialises successfully (i.e. is compiled in) is + * used. Falls back to the encoded param if no other variant is + * available, in which case the test reduces to a smoke check. */ + for (cIdx = 0; cIdx < sizeof(candidates)/sizeof(candidates[0]); cIdx++) { + SlhDsaKey probe; + if (candidates[cIdx] == param) { + continue; + } + XMEMSET(&probe, 0, sizeof(probe)); + if (wc_SlhDsaKey_Init(&probe, candidates[cIdx], NULL, + INVALID_DEVID) == 0) { + placeholder = candidates[cIdx]; + wc_SlhDsaKey_Free(&probe); + break; + } + } + + XMEMSET(&rng, 0, sizeof(rng)); + XMEMSET(&keyGen, 0, sizeof(keyGen)); + XMEMSET(&keyPriv, 0, sizeof(keyPriv)); + XMEMSET(&keyPub, 0, sizeof(keyPub)); + + derBuf = (byte*)XMALLOC(derBufSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + ExpectNotNull(derBuf); + sig = (byte*)XMALLOC(WC_SLHDSA_MAX_SIG_LEN, NULL, DYNAMIC_TYPE_TMP_BUFFER); + ExpectNotNull(sig); + + ExpectIntEQ(wc_InitRng(&rng), 0); + ExpectIntEQ(wc_SlhDsaKey_Init(&keyGen, param, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_SlhDsaKey_MakeKey(&keyGen, &rng), 0); + + /* Size-query contract: passing output=NULL returns the encoded size + * without touching the buffer. The real encode below must produce + * exactly this many bytes -- a size-query regression (e.g. forgetting + * to add verSz) would surface here as a mismatch. */ + { + int querySize; + ExpectIntGT(querySize = wc_SlhDsaKey_KeyToDer(&keyGen, NULL, 0), 0); + ExpectIntGT(derLen = (word32)wc_SlhDsaKey_KeyToDer(&keyGen, derBuf, + derBufSz), 0); + ExpectIntEQ((int)derLen, querySize); + + /* BUFFER_E contract: too-small buffer is rejected without writing + * anything past the limit. Pass inLen = querySize - 1 so the + * length check fails for any encoding. */ + ExpectIntEQ(wc_SlhDsaKey_KeyToDer(&keyGen, derBuf, + (word32)(querySize - 1)), WC_NO_ERR_TRACE(BUFFER_E)); + + /* PrivateKeyToDer is an RFC 9909 alias of KeyToDer; sizes must + * match and BUFFER_E must propagate. */ + ExpectIntEQ(wc_SlhDsaKey_PrivateKeyToDer(&keyGen, NULL, 0), querySize); + ExpectIntEQ(wc_SlhDsaKey_PrivateKeyToDer(&keyGen, derBuf, + (word32)(querySize - 1)), WC_NO_ERR_TRACE(BUFFER_E)); + } + + /* Decode into a fresh key. The decode must auto-detect the real + * parameter set from the OID embedded in the DER encoding. */ + ExpectIntEQ(wc_SlhDsaKey_Init(&keyPriv, placeholder, NULL, INVALID_DEVID), + 0); + idx = 0; + ExpectIntEQ(wc_SlhDsaKey_PrivateKeyDecode(derBuf, &idx, &keyPriv, derLen), + 0); + /* Verify the decoded key reports the ORIGINAL parameter set. */ + if (keyPriv.params != NULL) { + ExpectIntEQ((int)keyPriv.params->param, (int)param); + } + /* Byte-level equivalence check: re-encode the decoded private key + * and compare against the original DER. This catches a regression + * even in single-variant builds where placeholder == param made the + * params equality test above tautological -- if the decoder ignored + * the OID and kept stale state, the bytes won't match. */ + { + byte* roundBuf = (byte*)XMALLOC(derBufSz, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + word32 roundLen; + ExpectNotNull(roundBuf); + ExpectIntGT(roundLen = (word32)wc_SlhDsaKey_KeyToDer(&keyPriv, + roundBuf, derBufSz), 0); + ExpectIntEQ((int)roundLen, (int)derLen); + if (roundBuf != NULL) { + ExpectIntEQ(XMEMCMP(roundBuf, derBuf, roundLen), 0); + } + XFREE(roundBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + } + + /* Sign with the decoded private key and verify with the originally + * generated key. This proves the decoded key material is correct. */ + sigLen = WC_SLHDSA_MAX_SIG_LEN; + ExpectIntEQ(wc_SlhDsaKey_Sign(&keyPriv, NULL, 0, msg, (word32)sizeof(msg), + sig, &sigLen, &rng), 0); + ExpectIntEQ(wc_SlhDsaKey_Verify(&keyGen, NULL, 0, msg, (word32)sizeof(msg), + sig, sigLen), 0); + + /* Also test PrivateKeyToDer -> PrivateKeyDecode round-trip. */ + { + SlhDsaKey keyPriv2; + word32 derLen2; + word32 idx2 = 0; + XMEMSET(&keyPriv2, 0, sizeof(keyPriv2)); + ExpectIntGT(derLen2 = (word32)wc_SlhDsaKey_PrivateKeyToDer(&keyGen, + derBuf, derBufSz), 0); + ExpectIntEQ(wc_SlhDsaKey_Init(&keyPriv2, placeholder, NULL, + INVALID_DEVID), 0); + ExpectIntEQ(wc_SlhDsaKey_PrivateKeyDecode(derBuf, &idx2, &keyPriv2, + derLen2), 0); + /* Verify the PrivateKeyToDer output matches KeyToDer. */ + sigLen = WC_SLHDSA_MAX_SIG_LEN; + ExpectIntEQ(wc_SlhDsaKey_Sign(&keyPriv2, NULL, 0, msg, + (word32)sizeof(msg), sig, &sigLen, &rng), 0); + ExpectIntEQ(wc_SlhDsaKey_Verify(&keyGen, NULL, 0, msg, + (word32)sizeof(msg), sig, sigLen), 0); + wc_SlhDsaKey_Free(&keyPriv2); + } + + /* PKCS#8 v2 (RFC 5958) acceptance: the decoder explicitly allows + * version=0 or version=1. The encoder only ever writes version=0, + * so without a targeted check the v=1 branch would never fire and a + * regression that rejected v2 wrappers (legal RFC 5958 OneAsymmetricKey + * input from external tools) would slip through. Walk past the outer + * SEQUENCE header (which uses short or long-form length depending on + * the parameter set's encoded size) to land on the INTEGER version + * field, then flip its value from 0 to 1. */ + { + SlhDsaKey keyPrivV2; + word32 idxV2 = 0; + word32 verPos; + byte saved; + + XMEMSET(&keyPrivV2, 0, sizeof(keyPrivV2)); + ExpectIntGT((int)derLen, 5); + ExpectIntEQ((int)derBuf[0], 0x30); /* outer SEQUENCE tag */ + if ((derBuf[1] & 0x80) == 0) { + verPos = 2; /* short-form length */ + } + else { + verPos = 2 + (derBuf[1] & 0x7F); /* long-form length */ + } + ExpectIntLT((int)verPos + 3, (int)derLen); + ExpectIntEQ((int)derBuf[verPos], 0x02); /* INTEGER tag */ + ExpectIntEQ((int)derBuf[verPos + 1], 0x01); /* INTEGER length */ + ExpectIntEQ((int)derBuf[verPos + 2], 0x00); /* v0 baseline */ + saved = derBuf[verPos + 2]; + derBuf[verPos + 2] = 0x01; + + ExpectIntEQ(wc_SlhDsaKey_Init(&keyPrivV2, placeholder, NULL, + INVALID_DEVID), 0); + ExpectIntEQ(wc_SlhDsaKey_PrivateKeyDecode(derBuf, &idxV2, &keyPrivV2, + derLen), 0); + if (keyPrivV2.params != NULL) { + ExpectIntEQ((int)keyPrivV2.params->param, (int)param); + } + /* Confirm the v2-decoded private material is functionally + * identical: a signature it produces verifies under keyGen. */ + sigLen = WC_SLHDSA_MAX_SIG_LEN; + ExpectIntEQ(wc_SlhDsaKey_Sign(&keyPrivV2, NULL, 0, msg, + (word32)sizeof(msg), sig, &sigLen, &rng), 0); + ExpectIntEQ(wc_SlhDsaKey_Verify(&keyGen, NULL, 0, msg, + (word32)sizeof(msg), sig, sigLen), 0); + derBuf[verPos + 2] = saved; + wc_SlhDsaKey_Free(&keyPrivV2); + } + + /* Now round-trip the public key alone, with size-query and BUFFER_E + * contract checks for both withAlg modes. */ + { + int querySpki, queryRaw; + byte rawPub[WC_SLHDSA_MAX_PUB_LEN]; + word32 rawPubLen = (word32)sizeof(rawPub); + + /* withAlg=1: full SubjectPublicKeyInfo (used by certificate code). */ + ExpectIntGT(querySpki = wc_SlhDsaKey_PublicKeyToDer(&keyGen, NULL, 0, + 1), 0); + ExpectIntGT(derLen = (word32)wc_SlhDsaKey_PublicKeyToDer(&keyGen, + derBuf, derBufSz, 1), 0); + ExpectIntEQ((int)derLen, querySpki); + ExpectIntEQ(wc_SlhDsaKey_PublicKeyToDer(&keyGen, derBuf, + (word32)(querySpki - 1), 1), WC_NO_ERR_TRACE(BUFFER_E)); + + /* withAlg=0: raw 2*n public-key bytes only -- this is the path + * SetKeyIdFromPublicKey in asn.c walks when computing SKID/AKID + * for SLH-DSA certificates. Verify the bytes match what + * ExportPublic produces so a regression in this branch (e.g. + * accidentally emitting the SPKI envelope, or returning the + * wrong length) breaks the test rather than silently corrupting + * key identifiers in issued certs. */ + ExpectIntGT(queryRaw = wc_SlhDsaKey_PublicKeyToDer(&keyGen, NULL, 0, + 0), 0); + ExpectIntEQ(queryRaw, (int)(2 * keyGen.params->n)); + ExpectIntGT(wc_SlhDsaKey_PublicKeyToDer(&keyGen, derBuf, derBufSz, 0), + 0); + ExpectIntEQ(wc_SlhDsaKey_PublicKeyToDer(&keyGen, derBuf, + (word32)(queryRaw - 1), 0), WC_NO_ERR_TRACE(BUFFER_E)); + + ExpectIntEQ(wc_SlhDsaKey_ExportPublic(&keyGen, rawPub, &rawPubLen), 0); + ExpectIntEQ((int)rawPubLen, queryRaw); + ExpectIntEQ(XMEMCMP(derBuf, rawPub, rawPubLen), 0); + + /* Re-encode the SPKI so the decode test below sees the + * withAlg=1 buffer (raw output above is not decodable as SPKI). */ + ExpectIntGT(derLen = (word32)wc_SlhDsaKey_PublicKeyToDer(&keyGen, + derBuf, derBufSz, 1), 0); + } + + ExpectIntEQ(wc_SlhDsaKey_Init(&keyPub, placeholder, NULL, INVALID_DEVID), + 0); + idx = 0; + ExpectIntEQ(wc_SlhDsaKey_PublicKeyDecode(derBuf, &idx, &keyPub, derLen), 0); + if (keyPub.params != NULL) { + ExpectIntEQ((int)keyPub.params->param, (int)param); + } + /* The decoded public key should verify the signature we just produced. */ + ExpectIntEQ(wc_SlhDsaKey_Verify(&keyPub, NULL, 0, msg, (word32)sizeof(msg), + sig, sigLen), 0); + + wc_SlhDsaKey_Free(&keyPub); + wc_SlhDsaKey_Free(&keyPriv); + wc_SlhDsaKey_Free(&keyGen); + wc_FreeRng(&rng); + XFREE(sig, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + return EXPECT_RESULT(); +} +#endif + +/* + * DER codec round-trip test: encode each compiled-in SLH-DSA parameter set + * to DER, decode it (without telling the decoder which parameter set it is), + * confirm auto-detect produces the right parameter, and verify a signature + * produced with the decoded key. This test would fail if PrivateKeyDecode + * / PublicKeyDecode did not auto-detect the parameter set from the OID. + */ +int test_wc_slhdsa_der_roundtrip(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) && \ + defined(WC_ENABLE_ASYM_KEY_EXPORT) +#ifdef WOLFSSL_SLHDSA_PARAM_128S + ExpectIntEQ(slhdsa_der_roundtrip_one(SLHDSA_SHAKE128S), TEST_SUCCESS); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_128F + ExpectIntEQ(slhdsa_der_roundtrip_one(SLHDSA_SHAKE128F), TEST_SUCCESS); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_192S + ExpectIntEQ(slhdsa_der_roundtrip_one(SLHDSA_SHAKE192S), TEST_SUCCESS); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_192F + ExpectIntEQ(slhdsa_der_roundtrip_one(SLHDSA_SHAKE192F), TEST_SUCCESS); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_256S + ExpectIntEQ(slhdsa_der_roundtrip_one(SLHDSA_SHAKE256S), TEST_SUCCESS); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_256F + ExpectIntEQ(slhdsa_der_roundtrip_one(SLHDSA_SHAKE256F), TEST_SUCCESS); +#endif +#ifdef WOLFSSL_SLHDSA_SHA2 +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128S + ExpectIntEQ(slhdsa_der_roundtrip_one(SLHDSA_SHA2_128S), TEST_SUCCESS); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128F + ExpectIntEQ(slhdsa_der_roundtrip_one(SLHDSA_SHA2_128F), TEST_SUCCESS); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192S + ExpectIntEQ(slhdsa_der_roundtrip_one(SLHDSA_SHA2_192S), TEST_SUCCESS); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192F + ExpectIntEQ(slhdsa_der_roundtrip_one(SLHDSA_SHA2_192F), TEST_SUCCESS); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256S + ExpectIntEQ(slhdsa_der_roundtrip_one(SLHDSA_SHA2_256S), TEST_SUCCESS); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256F + ExpectIntEQ(slhdsa_der_roundtrip_one(SLHDSA_SHA2_256F), TEST_SUCCESS); +#endif +#endif /* WOLFSSL_SLHDSA_SHA2 */ +#endif /* WOLFSSL_HAVE_SLHDSA && !VERIFY_ONLY && WC_ENABLE_ASYM_KEY_EXPORT */ + return EXPECT_RESULT(); +} + +/* + * Negative / error-path tests for the DER encode/decode functions. + */ +int test_wc_slhdsa_der_negative(void) +{ + EXPECT_DECLS; +#ifdef WOLFSSL_HAVE_SLHDSA + SlhDsaKey key; + word32 idx; + byte buf[16]; + + XMEMSET(&key, 0, sizeof(key)); + + /* PrivateKeyDecode: NULL parameters */ +#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY + idx = 0; + ExpectIntEQ(wc_SlhDsaKey_PrivateKeyDecode(NULL, &idx, &key, 10), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_SlhDsaKey_PrivateKeyDecode(buf, NULL, &key, 10), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_SlhDsaKey_PrivateKeyDecode(buf, &idx, NULL, 10), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_SlhDsaKey_PrivateKeyDecode(buf, &idx, &key, 0), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + /* PrivateKeyDecode: truncated data */ + idx = 0; + XMEMSET(buf, 0, sizeof(buf)); + ExpectIntNE(wc_SlhDsaKey_PrivateKeyDecode(buf, &idx, &key, sizeof(buf)), 0); +#endif + + /* PublicKeyDecode: NULL parameters */ + idx = 0; + ExpectIntEQ(wc_SlhDsaKey_PublicKeyDecode(NULL, &idx, &key, 10), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_SlhDsaKey_PublicKeyDecode(buf, NULL, &key, 10), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_SlhDsaKey_PublicKeyDecode(buf, &idx, NULL, 10), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_SlhDsaKey_PublicKeyDecode(buf, &idx, &key, 0), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + +#if defined(WC_ENABLE_ASYM_KEY_EXPORT) && !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) + /* KeyToDer / PrivateKeyToDer: NULL key */ + ExpectIntEQ(wc_SlhDsaKey_KeyToDer(NULL, buf, sizeof(buf)), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_SlhDsaKey_PrivateKeyToDer(NULL, buf, sizeof(buf)), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* KeyToDer: public-only key should return MISSING_KEY. Build the + * public-only state through the public API (generate a key, export + * the public part, import it into a fresh key) rather than poking + * key->flags directly. */ +#ifdef WOLFSSL_SLHDSA_PARAM_128S + { + SlhDsaKey srcKey; + SlhDsaKey pubOnly; + WC_RNG rng; + byte pub[WC_SLHDSA_MAX_PUB_LEN]; + word32 pubLen = (word32)sizeof(pub); + + XMEMSET(&srcKey, 0, sizeof(srcKey)); + XMEMSET(&pubOnly, 0, sizeof(pubOnly)); + XMEMSET(&rng, 0, sizeof(rng)); + + ExpectIntEQ(wc_InitRng(&rng), 0); + ExpectIntEQ(wc_SlhDsaKey_Init(&srcKey, SLHDSA_SHAKE128S, NULL, + INVALID_DEVID), 0); + ExpectIntEQ(wc_SlhDsaKey_MakeKey(&srcKey, &rng), 0); + ExpectIntEQ(wc_SlhDsaKey_ExportPublic(&srcKey, pub, &pubLen), 0); + + ExpectIntEQ(wc_SlhDsaKey_Init(&pubOnly, SLHDSA_SHAKE128S, NULL, + INVALID_DEVID), 0); + ExpectIntEQ(wc_SlhDsaKey_ImportPublic(&pubOnly, pub, pubLen), 0); + ExpectIntEQ(wc_SlhDsaKey_KeyToDer(&pubOnly, NULL, 0), + WC_NO_ERR_TRACE(MISSING_KEY)); + ExpectIntEQ(wc_SlhDsaKey_PrivateKeyToDer(&pubOnly, NULL, 0), + WC_NO_ERR_TRACE(MISSING_KEY)); + wc_SlhDsaKey_Free(&pubOnly); + wc_SlhDsaKey_Free(&srcKey); + wc_FreeRng(&rng); + } +#endif +#endif /* WC_ENABLE_ASYM_KEY_EXPORT && !VERIFY_ONLY */ + + /* PublicKeyToDer: NULL key */ +#ifdef WC_ENABLE_ASYM_KEY_EXPORT + ExpectIntEQ(wc_SlhDsaKey_PublicKeyToDer(NULL, buf, sizeof(buf), 1), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); +#endif + + /* RFC 5958 OneAsymmetricKey trailing-field validation: + * [0] IMPLICIT Attributes OPTIONAL -- at most once + * [1] IMPLICIT PublicKey OPTIONAL -- at most once, after [0] + * The decoder must reject duplicates, out-of-order tags, and + * unrecognised tags. Build a valid SHAKE128S DER then mutate it. */ +#if defined(WC_ENABLE_ASYM_KEY_EXPORT) && \ + !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) && \ + defined(WOLFSSL_SLHDSA_PARAM_128S) + { + SlhDsaKey srcKey; + WC_RNG rng; + byte goodDer[256]; + int goodLen = 0; + size_t i; + struct { + const byte* trailing; + word32 trailingLen; + int expectAccept; /* 0 = expect ASN_PARSE_E */ + const char* desc; + } cases[5]; + const byte tDupAttr[] = { 0xA0, 0x00, 0xA0, 0x00 }; + const byte tDupPub[] = { 0xA1, 0x00, 0xA1, 0x00 }; + const byte tOutOfOrder[]= { 0xA1, 0x00, 0xA0, 0x00 }; + const byte tUnknown[] = { 0xA2, 0x00 }; + const byte tValidAttr[] = { 0xA0, 0x00 }; + + cases[0].trailing = tDupAttr; + cases[0].trailingLen = (word32)sizeof(tDupAttr); + cases[0].expectAccept = 0; + cases[0].desc = "duplicate [0] attributes"; + cases[1].trailing = tDupPub; + cases[1].trailingLen = (word32)sizeof(tDupPub); + cases[1].expectAccept = 0; + cases[1].desc = "duplicate [1] publicKey"; + cases[2].trailing = tOutOfOrder; + cases[2].trailingLen = (word32)sizeof(tOutOfOrder); + cases[2].expectAccept = 0; + cases[2].desc = "[1] before [0]"; + cases[3].trailing = tUnknown; + cases[3].trailingLen = (word32)sizeof(tUnknown); + cases[3].expectAccept = 0; + cases[3].desc = "unknown context tag [2]"; + /* Sanity: a single [0] is permitted -- if this rejects, the + * tightening above is overzealous and the four rejection cases + * are testing nothing useful. */ + cases[4].trailing = tValidAttr; + cases[4].trailingLen = (word32)sizeof(tValidAttr); + cases[4].expectAccept = 1; + cases[4].desc = "single [0] attributes (accepted)"; + + XMEMSET(&srcKey, 0, sizeof(srcKey)); + XMEMSET(&rng, 0, sizeof(rng)); + ExpectIntEQ(wc_InitRng(&rng), 0); + ExpectIntEQ(wc_SlhDsaKey_Init(&srcKey, SLHDSA_SHAKE128S, NULL, + INVALID_DEVID), 0); + ExpectIntEQ(wc_SlhDsaKey_MakeKey(&srcKey, &rng), 0); + ExpectIntGT(goodLen = wc_SlhDsaKey_KeyToDer(&srcKey, goodDer, + sizeof(goodDer)), 0); + + /* The mutator below tweaks goodDer[1] (length byte) in place, + * which only works if the encoder used short-form SEQUENCE + * length. SHAKE128S body is ~82 bytes so this holds, but assert + * it so a future encoder change surfaces here rather than + * silently producing buffers that decode despite the mutation. */ + ExpectIntEQ((int)goodDer[0], 0x30); + ExpectIntLT((int)goodDer[1], 0x80); + ExpectIntLT((int)goodDer[1] + 4, 0x80); + + for (i = 0; i < sizeof(cases)/sizeof(cases[0]); i++) { + byte mut[260]; + word32 mutLen; + word32 idx2 = 0; + SlhDsaKey k; + int decRet; + XMEMSET(&k, 0, sizeof(k)); + XMEMCPY(mut, goodDer, (size_t)goodLen); + XMEMCPY(mut + goodLen, cases[i].trailing, cases[i].trailingLen); + mutLen = (word32)goodLen + cases[i].trailingLen; + mut[1] = (byte)(goodDer[1] + cases[i].trailingLen); + ExpectIntEQ(wc_SlhDsaKey_Init(&k, SLHDSA_SHAKE128S, NULL, + INVALID_DEVID), 0); + decRet = wc_SlhDsaKey_PrivateKeyDecode(mut, &idx2, &k, mutLen); + if (cases[i].expectAccept) { + ExpectIntEQ(decRet, 0); + } + else { + ExpectIntEQ(decRet, WC_NO_ERR_TRACE(ASN_PARSE_E)); + } + (void)cases[i].desc; + wc_SlhDsaKey_Free(&k); + } + + wc_SlhDsaKey_Free(&srcKey); + wc_FreeRng(&rng); + } +#endif /* WC_ENABLE_ASYM_KEY_EXPORT && !VERIFY_ONLY && PARAM_128S */ + +#endif /* WOLFSSL_HAVE_SLHDSA */ + return EXPECT_RESULT(); +} + +#if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) && \ + !defined(NO_FILESYSTEM) +/* Load an RFC 9909 compliant DER file from disk and confirm that + * wc_SlhDsaKey_PrivateKeyDecode accepts it, auto-detects the parameter + * set from the OID, and produces a usable signing key. This test + * exercises the on-disk certs/slhdsa/ fixtures - any future file-format + * drift (nested wrapper, seed-only, wrong length) will be caught here. */ +/* doSign=0 skips the sign/verify smoke check; the 192s and 256s parameter + * sets are slow enough (multi-second per Sign) that running them on every + * make-check would balloon test time. The decoder is still exercised. */ +static int slhdsa_decode_file_one(const char *path, enum SlhDsaParam expected, + int doSign) +{ + EXPECT_DECLS; + XFILE f = XBADFILE; + byte der[256]; + int derSz = 0; + SlhDsaKey key; + WC_RNG rng; + word32 idx = 0; + byte sig[WC_SLHDSA_MAX_SIG_LEN]; + word32 sigLen = (word32)sizeof(sig); + static const byte msg[] = "slhdsa decode-file test"; + + XMEMSET(&key, 0, sizeof(key)); + XMEMSET(&rng, 0, sizeof(rng)); + + ExpectTrue((f = XFOPEN(path, "rb")) != XBADFILE); + if (f != XBADFILE) { + ExpectIntGT(derSz = (int)XFREAD(der, 1, sizeof(der), f), 0); + XFCLOSE(f); + } + + /* Pick a seed param different from `expected` when more than one + * variant is built. The decoder always overwrites this from the OID + * in the DER, so a different placeholder actually tests the auto- + * detect contract on disk-loaded fixtures (mirroring the helper + * logic in slhdsa_der_roundtrip_one). Falls back to `expected` when + * no alternative variant is available. */ + { + static const enum SlhDsaParam candidates[] = { + SLHDSA_SHAKE128S, SLHDSA_SHAKE128F, SLHDSA_SHAKE192S, + SLHDSA_SHAKE192F, SLHDSA_SHAKE256S, SLHDSA_SHAKE256F, + #ifdef WOLFSSL_SLHDSA_SHA2 + SLHDSA_SHA2_128S, SLHDSA_SHA2_128F, SLHDSA_SHA2_192S, + SLHDSA_SHA2_192F, SLHDSA_SHA2_256S, SLHDSA_SHA2_256F, + #endif + }; + enum SlhDsaParam placeholder = expected; + size_t cIdx; + for (cIdx = 0; cIdx < sizeof(candidates)/sizeof(candidates[0]); + cIdx++) { + SlhDsaKey probe; + if (candidates[cIdx] == expected) continue; + XMEMSET(&probe, 0, sizeof(probe)); + if (wc_SlhDsaKey_Init(&probe, candidates[cIdx], NULL, + INVALID_DEVID) == 0) { + placeholder = candidates[cIdx]; + wc_SlhDsaKey_Free(&probe); + break; + } + } + ExpectIntEQ(wc_SlhDsaKey_Init(&key, placeholder, NULL, INVALID_DEVID), + 0); + } + + ExpectIntEQ(wc_SlhDsaKey_PrivateKeyDecode(der, &idx, &key, (word32)derSz), + 0); + ExpectNotNull(key.params); + if (key.params != NULL) { + ExpectIntEQ((int)key.params->param, (int)expected); + } + + if (doSign) { + /* Sanity: signing works with the decoded key. */ + ExpectIntEQ(wc_InitRng(&rng), 0); + ExpectIntEQ(wc_SlhDsaKey_Sign(&key, NULL, 0, msg, (word32)sizeof(msg), + sig, &sigLen, &rng), 0); + ExpectIntEQ(wc_SlhDsaKey_Verify(&key, NULL, 0, msg, + (word32)sizeof(msg), sig, sigLen), 0); + wc_FreeRng(&rng); + } + else { + /* Cheap structural validation when the full sign/verify is + * skipped (slow 192s/256s variants): catches an uninitialised SK + * half or a botched SHA-2 precompute without paying the + * multi-second cost of an actual Sign. */ + ExpectIntEQ(wc_SlhDsaKey_CheckKey(&key), 0); + } + + wc_SlhDsaKey_Free(&key); + return EXPECT_RESULT(); +} +#endif + +/* Load each checked-in bench_slhdsa_shake*_key.der fixture and confirm it + * decodes via wc_SlhDsaKey_PrivateKeyDecode with correct auto-detection. + * These fixtures are RFC 9909 compliant (bare OCTET STRING, 4*n bytes) - + * this test would fail if the files drift to a non-compliant encoding + * (e.g. nested OCTET STRING, seed-only). */ +int test_wc_slhdsa_der_decode_files(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) && \ + !defined(NO_FILESYSTEM) +#ifdef WOLFSSL_SLHDSA_PARAM_128S + ExpectIntEQ(slhdsa_decode_file_one( + "./certs/slhdsa/bench_slhdsa_shake128s_key.der", SLHDSA_SHAKE128S, 1), + TEST_SUCCESS); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_128F + ExpectIntEQ(slhdsa_decode_file_one( + "./certs/slhdsa/bench_slhdsa_shake128f_key.der", SLHDSA_SHAKE128F, 1), + TEST_SUCCESS); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_192S + ExpectIntEQ(slhdsa_decode_file_one( + "./certs/slhdsa/bench_slhdsa_shake192s_key.der", SLHDSA_SHAKE192S, 0), + TEST_SUCCESS); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_192F + ExpectIntEQ(slhdsa_decode_file_one( + "./certs/slhdsa/bench_slhdsa_shake192f_key.der", SLHDSA_SHAKE192F, 1), + TEST_SUCCESS); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_256S + ExpectIntEQ(slhdsa_decode_file_one( + "./certs/slhdsa/bench_slhdsa_shake256s_key.der", SLHDSA_SHAKE256S, 0), + TEST_SUCCESS); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_256F + ExpectIntEQ(slhdsa_decode_file_one( + "./certs/slhdsa/bench_slhdsa_shake256f_key.der", SLHDSA_SHAKE256F, 1), + TEST_SUCCESS); +#endif +#ifdef WOLFSSL_SLHDSA_SHA2 +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128S + ExpectIntEQ(slhdsa_decode_file_one( + "./certs/slhdsa/bench_slhdsa_sha2_128s_key.der", SLHDSA_SHA2_128S, 1), + TEST_SUCCESS); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128F + ExpectIntEQ(slhdsa_decode_file_one( + "./certs/slhdsa/bench_slhdsa_sha2_128f_key.der", SLHDSA_SHA2_128F, 1), + TEST_SUCCESS); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192S + ExpectIntEQ(slhdsa_decode_file_one( + "./certs/slhdsa/bench_slhdsa_sha2_192s_key.der", SLHDSA_SHA2_192S, 0), + TEST_SUCCESS); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192F + ExpectIntEQ(slhdsa_decode_file_one( + "./certs/slhdsa/bench_slhdsa_sha2_192f_key.der", SLHDSA_SHA2_192F, 1), + TEST_SUCCESS); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256S + ExpectIntEQ(slhdsa_decode_file_one( + "./certs/slhdsa/bench_slhdsa_sha2_256s_key.der", SLHDSA_SHA2_256S, 0), + TEST_SUCCESS); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256F + ExpectIntEQ(slhdsa_decode_file_one( + "./certs/slhdsa/bench_slhdsa_sha2_256f_key.der", SLHDSA_SHA2_256F, 1), + TEST_SUCCESS); +#endif +#endif /* WOLFSSL_SLHDSA_SHA2 */ +#endif + return EXPECT_RESULT(); +} + +#if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) +/* Regression: wolfssl_x509_make_der and ConfirmSignature both pass the + * raw 2*n public-key bytes (the BIT STRING contents stashed by StoreKey + * into cert->publicKey) to wc_SlhDsaKey_PublicKeyDecode. Before the + * raw-first fast path landed, that call returned ASN_PARSE_E because + * DecodeAsymKeyPublic_Assign requires an SPKI SEQUENCE. This test pins + * the new contract: when key->params is already set, raw bytes decode + * directly, mirroring wc_Falcon_PublicKeyDecode and + * wc_Dilithium_PublicKeyDecode. */ +static int slhdsa_raw_public_decode_one(enum SlhDsaParam param) +{ + EXPECT_DECLS; + SlhDsaKey src; + SlhDsaKey dst; + byte pub[WC_SLHDSA_MAX_PUB_LEN]; + word32 pubLen = (word32)sizeof(pub); + word32 idx = 0; + WC_RNG rng; + + XMEMSET(&src, 0, sizeof(src)); + XMEMSET(&dst, 0, sizeof(dst)); + XMEMSET(&rng, 0, sizeof(rng)); + + ExpectIntEQ(wc_InitRng(&rng), 0); + ExpectIntEQ(wc_SlhDsaKey_Init(&src, param, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_SlhDsaKey_MakeKey(&src, &rng), 0); + ExpectIntEQ(wc_SlhDsaKey_ExportPublic(&src, pub, &pubLen), 0); + + /* Decode the raw public-key bytes via PublicKeyDecode. The fast + * path triggers because key->params is set by Init. */ + ExpectIntEQ(wc_SlhDsaKey_Init(&dst, param, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_SlhDsaKey_PublicKeyDecode(pub, &idx, &dst, pubLen), 0); + ExpectIntEQ((int)idx, (int)pubLen); + ExpectNotNull(dst.params); + if (dst.params != NULL) { + ExpectIntEQ((int)dst.params->param, (int)param); + } + + wc_SlhDsaKey_Free(&dst); + wc_SlhDsaKey_Free(&src); + wc_FreeRng(&rng); + return EXPECT_RESULT(); +} +#endif /* WOLFSSL_HAVE_SLHDSA && !WOLFSSL_SLHDSA_VERIFY_ONLY */ + +int test_wc_slhdsa_x509_i2d_roundtrip(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) + /* Exercise the raw public-key fast path for every compiled-in variant + * so a regression in n-dependent buffer math (32/48/64-byte keys) + * fails the test even in restricted builds where SHAKE128S / + * SHA2_128S happen to be excluded. */ +#ifdef WOLFSSL_SLHDSA_PARAM_128S + ExpectIntEQ(slhdsa_raw_public_decode_one(SLHDSA_SHAKE128S), TEST_SUCCESS); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_128F + ExpectIntEQ(slhdsa_raw_public_decode_one(SLHDSA_SHAKE128F), TEST_SUCCESS); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_192S + ExpectIntEQ(slhdsa_raw_public_decode_one(SLHDSA_SHAKE192S), TEST_SUCCESS); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_192F + ExpectIntEQ(slhdsa_raw_public_decode_one(SLHDSA_SHAKE192F), TEST_SUCCESS); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_256S + ExpectIntEQ(slhdsa_raw_public_decode_one(SLHDSA_SHAKE256S), TEST_SUCCESS); +#endif +#ifdef WOLFSSL_SLHDSA_PARAM_256F + ExpectIntEQ(slhdsa_raw_public_decode_one(SLHDSA_SHAKE256F), TEST_SUCCESS); +#endif +#ifdef WOLFSSL_SLHDSA_SHA2 + #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128S + ExpectIntEQ(slhdsa_raw_public_decode_one(SLHDSA_SHA2_128S), TEST_SUCCESS); + #endif + #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_128F + ExpectIntEQ(slhdsa_raw_public_decode_one(SLHDSA_SHA2_128F), TEST_SUCCESS); + #endif + #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192S + ExpectIntEQ(slhdsa_raw_public_decode_one(SLHDSA_SHA2_192S), TEST_SUCCESS); + #endif + #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_192F + ExpectIntEQ(slhdsa_raw_public_decode_one(SLHDSA_SHA2_192F), TEST_SUCCESS); + #endif + #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256S + ExpectIntEQ(slhdsa_raw_public_decode_one(SLHDSA_SHA2_256S), TEST_SUCCESS); + #endif + #ifdef WOLFSSL_SLHDSA_PARAM_SHA2_256F + ExpectIntEQ(slhdsa_raw_public_decode_one(SLHDSA_SHA2_256F), TEST_SUCCESS); + #endif +#endif /* WOLFSSL_SLHDSA_SHA2 */ +#endif + return EXPECT_RESULT(); +} + +#if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) && \ + defined(WC_ENABLE_ASYM_KEY_EXPORT) +/* Build a DER blob using an enabled SLH-DSA variant and patch the + * AlgorithmIdentifier OID's trailing byte to point at a *disabled* + * variant, then push it through the decoders. The contract being + * pinned is that wc_SlhDsaKey_PrivateKeyDecode / PublicKeyDecode pass + * the wc_SlhDsaOidToParam NOT_COMPILED_IN result through verbatim + * rather than collapsing it to ASN_PARSE_E -- if that breaks, x509 / + * TLS lose the precise "variant unavailable" diagnostic and silently + * report malformed-DER instead. + * + * All SLH-DSA OIDs share the prefix 2.16.840.1.101.3.4.3.X with X<128, + * so DER encoding lengths match exactly and the trailing byte is the + * sole discriminator -- patching it in place produces a structurally + * valid SPKI/PKCS#8 buffer that only fails at the OID-lookup step. + * + * @param src Enabled parameter set used to generate real DER. + * @param targetOidByte Trailing OID byte of the disabled variant. + */ +/* Marked WC_MAYBE_UNUSED because every call site below is gated on a + * per-variant disable macro -- builds that leave every variant enabled + * (e.g. --enable-fips=ready) preprocess all callers away. */ +static WC_MAYBE_UNUSED int slhdsa_decode_disabled_oid_one(enum SlhDsaParam src, + byte targetOidByte) +{ + EXPECT_DECLS; + /* OID prefix common to every SLH-DSA variant. */ + static const byte oidPrefix[] = { + 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03 + }; + SlhDsaKey srcKey; + SlhDsaKey dstKey; + WC_RNG rng; + byte* derBuf = NULL; + const word32 derBufSz = 16 * 1024; + int derLen = 0; + word32 idx; + word32 j; + int patched; + + XMEMSET(&srcKey, 0, sizeof(srcKey)); + XMEMSET(&dstKey, 0, sizeof(dstKey)); + XMEMSET(&rng, 0, sizeof(rng)); + + derBuf = (byte*)XMALLOC(derBufSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + ExpectNotNull(derBuf); + ExpectIntEQ(wc_InitRng(&rng), 0); + ExpectIntEQ(wc_SlhDsaKey_Init(&srcKey, src, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_SlhDsaKey_MakeKey(&srcKey, &rng), 0); + + /* Public-key path: build SPKI, patch the variant byte, decode. */ + ExpectIntGT(derLen = wc_SlhDsaKey_PublicKeyToDer(&srcKey, derBuf, derBufSz, + 1), 0); + patched = 0; + for (j = 0; derLen > (int)sizeof(oidPrefix) && + j + sizeof(oidPrefix) < (word32)derLen; j++) { + if (XMEMCMP(derBuf + j, oidPrefix, sizeof(oidPrefix)) == 0) { + derBuf[j + sizeof(oidPrefix)] = targetOidByte; + patched = 1; + break; + } + } + ExpectIntEQ(patched, 1); + /* dstKey is zeroed (no params) so the raw fast path is skipped and + * SPKI parsing surfaces the OID-lookup result. */ + idx = 0; + ExpectIntEQ(wc_SlhDsaKey_PublicKeyDecode(derBuf, &idx, &dstKey, + (word32)derLen), WC_NO_ERR_TRACE(NOT_COMPILED_IN)); + + /* Private-key path: same scheme using the PKCS#8 wrapper. */ + ExpectIntGT(derLen = wc_SlhDsaKey_KeyToDer(&srcKey, derBuf, derBufSz), 0); + patched = 0; + for (j = 0; derLen > (int)sizeof(oidPrefix) && + j + sizeof(oidPrefix) < (word32)derLen; j++) { + if (XMEMCMP(derBuf + j, oidPrefix, sizeof(oidPrefix)) == 0) { + derBuf[j + sizeof(oidPrefix)] = targetOidByte; + patched = 1; + break; + } + } + ExpectIntEQ(patched, 1); + /* Free any state PublicKeyDecode may have established before the + * second decode call reuses the key slot. */ + wc_SlhDsaKey_Free(&dstKey); + XMEMSET(&dstKey, 0, sizeof(dstKey)); + idx = 0; + ExpectIntEQ(wc_SlhDsaKey_PrivateKeyDecode(derBuf, &idx, &dstKey, + (word32)derLen), WC_NO_ERR_TRACE(NOT_COMPILED_IN)); + + wc_SlhDsaKey_Free(&dstKey); + wc_SlhDsaKey_Free(&srcKey); + wc_FreeRng(&rng); + XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return EXPECT_RESULT(); +} + +/* Round-trip variant: same patcher path but the targetOidByte must equal + * the source's own OID byte, so the decode is expected to succeed. Used + * as an unconditional smoke check so test_wc_slhdsa_decoder_disabled_oid + * exercises the patcher infrastructure even on builds with no per-variant + * disable, where every disabled-branch in the caller is #if'd out. */ +static int slhdsa_decode_disabled_oid_one_roundtrip(enum SlhDsaParam src, + byte targetOidByte) +{ + EXPECT_DECLS; + static const byte oidPrefix[] = { + 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03 + }; + SlhDsaKey srcKey; + SlhDsaKey dstKey; + WC_RNG rng; + byte* derBuf = NULL; + const word32 derBufSz = 16 * 1024; + int derLen = 0; + word32 idx; + word32 j; + int patched; + + XMEMSET(&srcKey, 0, sizeof(srcKey)); + XMEMSET(&dstKey, 0, sizeof(dstKey)); + XMEMSET(&rng, 0, sizeof(rng)); + + derBuf = (byte*)XMALLOC(derBufSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + ExpectNotNull(derBuf); + ExpectIntEQ(wc_InitRng(&rng), 0); + ExpectIntEQ(wc_SlhDsaKey_Init(&srcKey, src, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_SlhDsaKey_MakeKey(&srcKey, &rng), 0); + + ExpectIntGT(derLen = wc_SlhDsaKey_PublicKeyToDer(&srcKey, derBuf, derBufSz, + 1), 0); + patched = 0; + for (j = 0; derLen > (int)sizeof(oidPrefix) && + j + sizeof(oidPrefix) < (word32)derLen; j++) { + if (XMEMCMP(derBuf + j, oidPrefix, sizeof(oidPrefix)) == 0) { + derBuf[j + sizeof(oidPrefix)] = targetOidByte; + patched = 1; + break; + } + } + ExpectIntEQ(patched, 1); + idx = 0; + ExpectIntEQ(wc_SlhDsaKey_PublicKeyDecode(derBuf, &idx, &dstKey, + (word32)derLen), 0); + + wc_SlhDsaKey_Free(&dstKey); + wc_SlhDsaKey_Free(&srcKey); + wc_FreeRng(&rng); + XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return EXPECT_RESULT(); +} + +/* Probe candidate parameter sets in priority order and return the first + * one whose backend is built in. Used to source a real DER buffer for + * slhdsa_decode_disabled_oid_one regardless of which variants the + * current build excluded. Returns 1 on success, 0 if no variant is + * available (which the build's #error guard makes impossible in + * practice but the test handles defensively). */ +static int slhdsa_pick_enabled_param(enum SlhDsaParam* out) +{ + static const enum SlhDsaParam candidates[] = { + SLHDSA_SHAKE128S, SLHDSA_SHAKE128F, SLHDSA_SHAKE192S, + SLHDSA_SHAKE192F, SLHDSA_SHAKE256S, SLHDSA_SHAKE256F, + #ifdef WOLFSSL_SLHDSA_SHA2 + SLHDSA_SHA2_128S, SLHDSA_SHA2_128F, SLHDSA_SHA2_192S, + SLHDSA_SHA2_192F, SLHDSA_SHA2_256S, SLHDSA_SHA2_256F, + #endif + }; + size_t i; + + for (i = 0; i < sizeof(candidates)/sizeof(candidates[0]); i++) { + SlhDsaKey probe; + XMEMSET(&probe, 0, sizeof(probe)); + if (wc_SlhDsaKey_Init(&probe, candidates[i], NULL, + INVALID_DEVID) == 0) { + wc_SlhDsaKey_Free(&probe); + *out = candidates[i]; + return 1; + } + } + return 0; +} +#endif /* WOLFSSL_HAVE_SLHDSA && !VERIFY_ONLY && WC_ENABLE_ASYM_KEY_EXPORT */ + +/* Pin the per-variant disable contract: every parameter set whose enum + * value is visible (so the test compiles) but whose backend is excluded + * by a WOLFSSL_SLHDSA_PARAM_NO_* / WOLFSSL_SLHDSA_NO_* macro must surface + * NOT_COMPILED_IN from wc_SlhDsaKey_Init instead of silently succeeding + * or returning a generic error. + * + * This is the only API-level test for the granular disable surface and + * also locks in the contract that wc_SlhDsaOidToParam/CertType in asn.c + * piggyback on -- if Init drifts away from NOT_COMPILED_IN here, the + * mapping helpers will likewise diverge and certificate handling will + * lose its "variant unavailable" diagnostic. */ +int test_wc_slhdsa_param_disabled(void) +{ + EXPECT_DECLS; +#ifdef WOLFSSL_HAVE_SLHDSA + SlhDsaKey key; + enum SlhDsaParam enabledProbe = SLHDSA_SHAKE128S; + int haveEnabled; + + XMEMSET(&key, 0, sizeof(key)); + + /* Positive smoke check: at least one variant must initialise. Without + * this the disabled-variant branches below can all be #if'd out and + * the test would silently pass on default builds, defeating its + * documented purpose. The probe also validates the contract from the + * other side -- Init must succeed for an enabled param. */ + haveEnabled = 0; +#if defined(WOLFSSL_SLHDSA_PARAM_128S) + enabledProbe = SLHDSA_SHAKE128S; haveEnabled = 1; +#elif defined(WOLFSSL_SLHDSA_PARAM_128F) + enabledProbe = SLHDSA_SHAKE128F; haveEnabled = 1; +#elif defined(WOLFSSL_SLHDSA_PARAM_192S) + enabledProbe = SLHDSA_SHAKE192S; haveEnabled = 1; +#elif defined(WOLFSSL_SLHDSA_PARAM_192F) + enabledProbe = SLHDSA_SHAKE192F; haveEnabled = 1; +#elif defined(WOLFSSL_SLHDSA_PARAM_256S) + enabledProbe = SLHDSA_SHAKE256S; haveEnabled = 1; +#elif defined(WOLFSSL_SLHDSA_PARAM_256F) + enabledProbe = SLHDSA_SHAKE256F; haveEnabled = 1; +#elif defined(WOLFSSL_SLHDSA_SHA2) && defined(WOLFSSL_SLHDSA_PARAM_SHA2_128S) + enabledProbe = SLHDSA_SHA2_128S; haveEnabled = 1; +#endif + ExpectIntEQ(haveEnabled, 1); + if (haveEnabled) { + ExpectIntEQ(wc_SlhDsaKey_Init(&key, enabledProbe, NULL, + INVALID_DEVID), 0); + wc_SlhDsaKey_Free(&key); + XMEMSET(&key, 0, sizeof(key)); + } + +#if defined(WOLFSSL_SLHDSA_PARAM_NO_128S) || \ + defined(WOLFSSL_SLHDSA_NO_128) || \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SMALL) + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128S, NULL, INVALID_DEVID), + WC_NO_ERR_TRACE(NOT_COMPILED_IN)); +#endif +#if defined(WOLFSSL_SLHDSA_PARAM_NO_128F) || \ + defined(WOLFSSL_SLHDSA_NO_128) || \ + defined(WOLFSSL_SLHDSA_PARAM_NO_FAST) + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE128F, NULL, INVALID_DEVID), + WC_NO_ERR_TRACE(NOT_COMPILED_IN)); +#endif +#if defined(WOLFSSL_SLHDSA_PARAM_NO_192S) || \ + defined(WOLFSSL_SLHDSA_NO_192) || \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SMALL) + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE192S, NULL, INVALID_DEVID), + WC_NO_ERR_TRACE(NOT_COMPILED_IN)); +#endif +#if defined(WOLFSSL_SLHDSA_PARAM_NO_192F) || \ + defined(WOLFSSL_SLHDSA_NO_192) || \ + defined(WOLFSSL_SLHDSA_PARAM_NO_FAST) + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE192F, NULL, INVALID_DEVID), + WC_NO_ERR_TRACE(NOT_COMPILED_IN)); +#endif +#if defined(WOLFSSL_SLHDSA_PARAM_NO_256S) || \ + defined(WOLFSSL_SLHDSA_NO_256) || \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SMALL) + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE256S, NULL, INVALID_DEVID), + WC_NO_ERR_TRACE(NOT_COMPILED_IN)); +#endif +#if defined(WOLFSSL_SLHDSA_PARAM_NO_256F) || \ + defined(WOLFSSL_SLHDSA_NO_256) || \ + defined(WOLFSSL_SLHDSA_PARAM_NO_FAST) + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHAKE256F, NULL, INVALID_DEVID), + WC_NO_ERR_TRACE(NOT_COMPILED_IN)); +#endif + +#ifdef WOLFSSL_SLHDSA_SHA2 + /* SHA-2 enum values are only declared when WOLFSSL_SLHDSA_SHA2 is set; + * each per-variant disable below is checked under that gate. */ + #ifdef WOLFSSL_SLHDSA_PARAM_NO_SHA2_128S + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_128S, NULL, INVALID_DEVID), + WC_NO_ERR_TRACE(NOT_COMPILED_IN)); + #endif + #ifdef WOLFSSL_SLHDSA_PARAM_NO_SHA2_128F + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_128F, NULL, INVALID_DEVID), + WC_NO_ERR_TRACE(NOT_COMPILED_IN)); + #endif + #ifdef WOLFSSL_SLHDSA_PARAM_NO_SHA2_192S + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_192S, NULL, INVALID_DEVID), + WC_NO_ERR_TRACE(NOT_COMPILED_IN)); + #endif + #ifdef WOLFSSL_SLHDSA_PARAM_NO_SHA2_192F + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_192F, NULL, INVALID_DEVID), + WC_NO_ERR_TRACE(NOT_COMPILED_IN)); + #endif + #ifdef WOLFSSL_SLHDSA_PARAM_NO_SHA2_256S + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_256S, NULL, INVALID_DEVID), + WC_NO_ERR_TRACE(NOT_COMPILED_IN)); + #endif + #ifdef WOLFSSL_SLHDSA_PARAM_NO_SHA2_256F + ExpectIntEQ(wc_SlhDsaKey_Init(&key, SLHDSA_SHA2_256F, NULL, INVALID_DEVID), + WC_NO_ERR_TRACE(NOT_COMPILED_IN)); + #endif +#endif /* WOLFSSL_SLHDSA_SHA2 */ + + (void)key; +#endif /* WOLFSSL_HAVE_SLHDSA */ + return EXPECT_RESULT(); +} + +/* Decoder-level companion to test_wc_slhdsa_param_disabled: feed DER for + * each disabled SLH-DSA OID into PrivateKeyDecode/PublicKeyDecode and + * confirm they pass NOT_COMPILED_IN through verbatim. The Init-level + * test above proves the mapping helper is correct; this one proves the + * decoders honour it instead of collapsing the result to ASN_PARSE_E. */ +int test_wc_slhdsa_decoder_disabled_oid(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) && \ + defined(WC_ENABLE_ASYM_KEY_EXPORT) + enum SlhDsaParam src = SLHDSA_SHAKE128S; + int haveSrc = slhdsa_pick_enabled_param(&src); + ExpectIntEQ(haveSrc, 1); + + if (haveSrc) { + /* Positive smoke check: feed src's own OID through the patcher + * (round-trip) and expect a clean decode, so the decoder path + * actually exercises here even when no per-variant disable is + * active. The trailing OID byte for SHAKE128S is 0x1A; we look + * up the byte for `src` from a small table because src may not + * be SHAKE128S in restricted builds. */ + { + byte srcOidByte = 0; + switch (src) { + case SLHDSA_SHAKE128S: srcOidByte = 0x1A; break; + case SLHDSA_SHAKE128F: srcOidByte = 0x1B; break; + case SLHDSA_SHAKE192S: srcOidByte = 0x1C; break; + case SLHDSA_SHAKE192F: srcOidByte = 0x1D; break; + case SLHDSA_SHAKE256S: srcOidByte = 0x1E; break; + case SLHDSA_SHAKE256F: srcOidByte = 0x1F; break; + #ifdef WOLFSSL_SLHDSA_SHA2 + case SLHDSA_SHA2_128S: srcOidByte = 0x14; break; + case SLHDSA_SHA2_128F: srcOidByte = 0x15; break; + case SLHDSA_SHA2_192S: srcOidByte = 0x16; break; + case SLHDSA_SHA2_192F: srcOidByte = 0x17; break; + case SLHDSA_SHA2_256S: srcOidByte = 0x18; break; + case SLHDSA_SHA2_256F: srcOidByte = 0x19; break; + #endif + default: break; + } + ExpectIntGT((int)srcOidByte, 0); + /* Round-trip: patching src's OID to itself must still decode + * successfully -- this fires unconditionally and validates + * the patcher infrastructure even when no disable branch + * below applies. */ + ExpectIntEQ(slhdsa_decode_disabled_oid_one_roundtrip(src, + srcOidByte), TEST_SUCCESS); + } + + /* SHAKE family: trailing OID byte = 0x1A..0x1F. */ + #if defined(WOLFSSL_SLHDSA_PARAM_NO_128S) || \ + defined(WOLFSSL_SLHDSA_NO_128) || \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SMALL) + ExpectIntEQ(slhdsa_decode_disabled_oid_one(src, 0x1A), TEST_SUCCESS); + #endif + #if defined(WOLFSSL_SLHDSA_PARAM_NO_128F) || \ + defined(WOLFSSL_SLHDSA_NO_128) || \ + defined(WOLFSSL_SLHDSA_PARAM_NO_FAST) + ExpectIntEQ(slhdsa_decode_disabled_oid_one(src, 0x1B), TEST_SUCCESS); + #endif + #if defined(WOLFSSL_SLHDSA_PARAM_NO_192S) || \ + defined(WOLFSSL_SLHDSA_NO_192) || \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SMALL) + ExpectIntEQ(slhdsa_decode_disabled_oid_one(src, 0x1C), TEST_SUCCESS); + #endif + #if defined(WOLFSSL_SLHDSA_PARAM_NO_192F) || \ + defined(WOLFSSL_SLHDSA_NO_192) || \ + defined(WOLFSSL_SLHDSA_PARAM_NO_FAST) + ExpectIntEQ(slhdsa_decode_disabled_oid_one(src, 0x1D), TEST_SUCCESS); + #endif + #if defined(WOLFSSL_SLHDSA_PARAM_NO_256S) || \ + defined(WOLFSSL_SLHDSA_NO_256) || \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SMALL) + ExpectIntEQ(slhdsa_decode_disabled_oid_one(src, 0x1E), TEST_SUCCESS); + #endif + #if defined(WOLFSSL_SLHDSA_PARAM_NO_256F) || \ + defined(WOLFSSL_SLHDSA_NO_256) || \ + defined(WOLFSSL_SLHDSA_PARAM_NO_FAST) + ExpectIntEQ(slhdsa_decode_disabled_oid_one(src, 0x1F), TEST_SUCCESS); + #endif + + /* SHA-2 family: trailing OID byte = 0x14..0x19. The whole + * family is also disabled when WOLFSSL_SLHDSA_SHA2 is unset. */ + #if !defined(WOLFSSL_SLHDSA_SHA2) || \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128S) + ExpectIntEQ(slhdsa_decode_disabled_oid_one(src, 0x14), TEST_SUCCESS); + #endif + #if !defined(WOLFSSL_SLHDSA_SHA2) || \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128F) + ExpectIntEQ(slhdsa_decode_disabled_oid_one(src, 0x15), TEST_SUCCESS); + #endif + #if !defined(WOLFSSL_SLHDSA_SHA2) || \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192S) + ExpectIntEQ(slhdsa_decode_disabled_oid_one(src, 0x16), TEST_SUCCESS); + #endif + #if !defined(WOLFSSL_SLHDSA_SHA2) || \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192F) + ExpectIntEQ(slhdsa_decode_disabled_oid_one(src, 0x17), TEST_SUCCESS); + #endif + #if !defined(WOLFSSL_SLHDSA_SHA2) || \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256S) + ExpectIntEQ(slhdsa_decode_disabled_oid_one(src, 0x18), TEST_SUCCESS); + #endif + #if !defined(WOLFSSL_SLHDSA_SHA2) || \ + defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256F) + ExpectIntEQ(slhdsa_decode_disabled_oid_one(src, 0x19), TEST_SUCCESS); + #endif + } +#endif + return EXPECT_RESULT(); +} + +#ifdef TEST_SLHDSA_DEFAULT_PARAM + #undef TEST_SLHDSA_DEFAULT_PARAM + #undef TEST_SLHDSA_DEFAULT_SIG_LEN + #undef TEST_SLHDSA_DEFAULT_PRIV_LEN + #undef TEST_SLHDSA_DEFAULT_PUB_LEN + #undef TEST_SLHDSA_DEFAULT_SEED_LEN +#endif diff --git a/tests/api/test_slhdsa.h b/tests/api/test_slhdsa.h index c0d909b7aa..8eed0b8669 100644 --- a/tests/api/test_slhdsa.h +++ b/tests/api/test_slhdsa.h @@ -33,6 +33,12 @@ int test_wc_slhdsa_sign_vfy(void); int test_wc_slhdsa_sign_hash(void); int test_wc_slhdsa_export_import(void); int test_wc_slhdsa_check_key(void); +int test_wc_slhdsa_der_roundtrip(void); +int test_wc_slhdsa_der_negative(void); +int test_wc_slhdsa_der_decode_files(void); +int test_wc_slhdsa_x509_i2d_roundtrip(void); +int test_wc_slhdsa_param_disabled(void); +int test_wc_slhdsa_decoder_disabled_oid(void); #define TEST_SLHDSA_DECLS \ TEST_DECL_GROUP("slhdsa", test_wc_slhdsa), \ @@ -43,6 +49,12 @@ int test_wc_slhdsa_check_key(void); TEST_DECL_GROUP("slhdsa", test_wc_slhdsa_sign_vfy), \ TEST_DECL_GROUP("slhdsa", test_wc_slhdsa_sign_hash), \ TEST_DECL_GROUP("slhdsa", test_wc_slhdsa_export_import), \ - TEST_DECL_GROUP("slhdsa", test_wc_slhdsa_check_key) + TEST_DECL_GROUP("slhdsa", test_wc_slhdsa_check_key), \ + TEST_DECL_GROUP("slhdsa", test_wc_slhdsa_der_roundtrip), \ + TEST_DECL_GROUP("slhdsa", test_wc_slhdsa_der_negative), \ + TEST_DECL_GROUP("slhdsa", test_wc_slhdsa_der_decode_files), \ + TEST_DECL_GROUP("slhdsa", test_wc_slhdsa_x509_i2d_roundtrip), \ + TEST_DECL_GROUP("slhdsa", test_wc_slhdsa_param_disabled), \ + TEST_DECL_GROUP("slhdsa", test_wc_slhdsa_decoder_disabled_oid) #endif /* WOLFCRYPT_TEST_SLHDSA_H */ diff --git a/tests/include.am b/tests/include.am index fc1359d3d5..845808d616 100644 --- a/tests/include.am +++ b/tests/include.am @@ -36,6 +36,9 @@ EXTRA_DIST += tests/unit.h \ tests/test-tls13-pq-standalone.conf \ tests/test-tls13-pq-hybrid.conf \ tests/test-tls13-pq-hybrid-extra.conf \ + tests/test-tls13-slhdsa-shake.conf \ + tests/test-tls13-slhdsa-sha2.conf \ + tests/test-tls13-slhdsa-fail.conf \ tests/test-dtls13-pq-standalone.conf \ tests/test-dtls13-pq-standalone-frag.conf \ tests/test-dtls13-pq-hybrid-frag.conf \ diff --git a/tests/suites.c b/tests/suites.c index 0da168ee1d..3192e5070c 100644 --- a/tests/suites.c +++ b/tests/suites.c @@ -1262,6 +1262,50 @@ int SuiteTest(int argc, char** argv) goto exit; } #endif +#if defined(WOLFSSL_HAVE_SLHDSA) && defined(HAVE_DILITHIUM) && \ + defined(WOLFSSL_SLHDSA_PARAM_128S) && \ + defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_ML_DSA_44) + /* SLH-DSA-SHAKE-128s root + ML-DSA-44 entity cert tests (TLS 1.3) */ + XSTRLCPY(argv0[1], "tests/test-tls13-slhdsa-shake.conf", + sizeof(argv0[1])); + printf("starting TLSv13 SLH-DSA-SHAKE-128s root + ML-DSA-44 entity tests\n"); + test_harness(&args); + if (args.return_code != 0) { + printf("error from script %d\n", args.return_code); + args.return_code = EXIT_FAILURE; + goto exit; + } + + /* Negative: client trusting an unrelated CA must reject the + * SLH-DSA-rooted server chain. */ + args.argc = 3; + XSTRLCPY(argv0[1], "tests/test-tls13-slhdsa-fail.conf", + sizeof(argv0[1])); + XSTRLCPY(argv0[2], "expFail", sizeof(argv0[2])); + printf("starting TLSv13 SLH-DSA wrong-CA tests that expect failure\n"); + test_harness(&args); + if (args.return_code != 0) { + printf("error from script %d\n", args.return_code); + args.return_code = EXIT_FAILURE; + goto exit; + } + XSTRLCPY(argv0[2], "", sizeof(argv0[2])); + args.argc = 2; +#endif +#if defined(WOLFSSL_HAVE_SLHDSA) && defined(WOLFSSL_SLHDSA_SHA2) && \ + defined(WOLFSSL_SLHDSA_PARAM_SHA2_128S) && defined(HAVE_DILITHIUM) && \ + defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_ML_DSA_44) + /* SLH-DSA-SHA2-128s root + ML-DSA-44 entity cert tests (TLS 1.3) */ + XSTRLCPY(argv0[1], "tests/test-tls13-slhdsa-sha2.conf", + sizeof(argv0[1])); + printf("starting TLSv13 SLH-DSA-SHA2-128s root + ML-DSA-44 entity tests\n"); + test_harness(&args); + if (args.return_code != 0) { + printf("error from script %d\n", args.return_code); + args.return_code = EXIT_FAILURE; + goto exit; + } +#endif #if defined(HAVE_ECC) && defined(WOLFSSL_SHA512) && \ (defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)) /* add P-521 certificate cipher suite tests */ diff --git a/tests/test-tls13-slhdsa-fail.conf b/tests/test-tls13-slhdsa-fail.conf new file mode 100644 index 0000000000..dff546894c --- /dev/null +++ b/tests/test-tls13-slhdsa-fail.conf @@ -0,0 +1,18 @@ +# Negative test: client trusts an unrelated CA (not the SLH-DSA root used to +# sign the server's chain), so the SLH-DSA root signature on the server's +# certificate path must not chain to a trusted issuer and the handshake +# must fail. Run with `expFail` so the harness expects each scenario here +# to fail rather than succeed. + +# server TLSv1.3 — serves chain rooted at SLH-DSA-SHAKE-128s +-v 4 +-l TLS13-AES128-GCM-SHA256 +-c ./certs/slhdsa/server-mldsa44-shake.pem +-k ./certs/slhdsa/server-mldsa44-priv.pem +-d +-x + +# client TLSv1.3 — trusts an unrelated RSA CA, must reject the server chain +-v 4 +-l TLS13-AES128-GCM-SHA256 +-A ./certs/ca-cert.pem diff --git a/tests/test-tls13-slhdsa-sha2.conf b/tests/test-tls13-slhdsa-sha2.conf new file mode 100644 index 0000000000..76833ff308 --- /dev/null +++ b/tests/test-tls13-slhdsa-sha2.conf @@ -0,0 +1,40 @@ +# SLH-DSA-SHA2-128s root, ML-DSA-44 entity certs (TLS 1.3 only). +# +# Requires the SHA2 SLH-DSA family to be enabled at build time, e.g.: +# ./configure --enable-slhdsa=yes,sha2 --enable-mldsa +# Plain `--enable-slhdsa` enables only the SHAKE family, in which case +# the dispatch in tests/suites.c gates this file out and it is not run. +# +# Server-auth scenario. + +# server TLSv1.3 TLS13-AES128-GCM-SHA256 +-v 4 +-l TLS13-AES128-GCM-SHA256 +-c ./certs/slhdsa/server-mldsa44-sha2.pem +-k ./certs/slhdsa/server-mldsa44-priv.pem +-d + +# client TLSv1.3 TLS13-AES128-GCM-SHA256 +-v 4 +-l TLS13-AES128-GCM-SHA256 +-A ./certs/slhdsa/root-slhdsa-sha2-128s.pem +-C + +# Mutual-auth scenario. + +# server TLSv1.3 TLS13-AES128-GCM-SHA256 +-v 4 +-l TLS13-AES128-GCM-SHA256 +-c ./certs/slhdsa/server-mldsa44-sha2.pem +-k ./certs/slhdsa/server-mldsa44-priv.pem +-A ./certs/slhdsa/root-slhdsa-sha2-128s.pem +-V +# Remove -V when CRL for SLH-DSA root certificates available. + +# client TLSv1.3 TLS13-AES128-GCM-SHA256 +-v 4 +-l TLS13-AES128-GCM-SHA256 +-c ./certs/slhdsa/client-mldsa44-sha2.pem +-k ./certs/slhdsa/client-mldsa44-priv.pem +-A ./certs/slhdsa/root-slhdsa-sha2-128s.pem +-C diff --git a/tests/test-tls13-slhdsa-shake.conf b/tests/test-tls13-slhdsa-shake.conf new file mode 100644 index 0000000000..0c908ea889 --- /dev/null +++ b/tests/test-tls13-slhdsa-shake.conf @@ -0,0 +1,35 @@ +# SLH-DSA-SHAKE-128s root, ML-DSA-44 entity certs (TLS 1.3 only). +# +# Server-auth scenario. + +# server TLSv1.3 TLS13-AES128-GCM-SHA256 +-v 4 +-l TLS13-AES128-GCM-SHA256 +-c ./certs/slhdsa/server-mldsa44-shake.pem +-k ./certs/slhdsa/server-mldsa44-priv.pem +-d + +# client TLSv1.3 TLS13-AES128-GCM-SHA256 +-v 4 +-l TLS13-AES128-GCM-SHA256 +-A ./certs/slhdsa/root-slhdsa-shake-128s.pem +-C + +# Mutual-auth scenario. + +# server TLSv1.3 TLS13-AES128-GCM-SHA256 +-v 4 +-l TLS13-AES128-GCM-SHA256 +-c ./certs/slhdsa/server-mldsa44-shake.pem +-k ./certs/slhdsa/server-mldsa44-priv.pem +-A ./certs/slhdsa/root-slhdsa-shake-128s.pem +-V +# Remove -V when CRL for SLH-DSA root certificates available. + +# client TLSv1.3 TLS13-AES128-GCM-SHA256 +-v 4 +-l TLS13-AES128-GCM-SHA256 +-c ./certs/slhdsa/client-mldsa44-shake.pem +-k ./certs/slhdsa/client-mldsa44-priv.pem +-A ./certs/slhdsa/root-slhdsa-shake-128s.pem +-C diff --git a/wolfcrypt/benchmark/benchmark.c b/wolfcrypt/benchmark/benchmark.c index 360e2ad461..8f421542fd 100644 --- a/wolfcrypt/benchmark/benchmark.c +++ b/wolfcrypt/benchmark/benchmark.c @@ -193,9 +193,6 @@ #if defined(HAVE_DILITHIUM) #include #endif -#if defined(HAVE_SPHINCS) - #include -#endif #ifdef WOLF_CRYPTO_CB #include @@ -929,13 +926,6 @@ static WC_INLINE void bench_append_memory_info(char* buffer, size_t size, BENCH_ML_DSA_65_SIGN | \ BENCH_ML_DSA_87_SIGN) -/* Post-Quantum Asymmetric algorithms. (Part 2) */ -#define BENCH_SPHINCS_FAST_LEVEL1_SIGN 0x00000001 -#define BENCH_SPHINCS_FAST_LEVEL3_SIGN 0x00000002 -#define BENCH_SPHINCS_FAST_LEVEL5_SIGN 0x00000004 -#define BENCH_SPHINCS_SMALL_LEVEL1_SIGN 0x00000008 -#define BENCH_SPHINCS_SMALL_LEVEL3_SIGN 0x00000010 -#define BENCH_SPHINCS_SMALL_LEVEL5_SIGN 0x00000020 /* Post-Quantum Stateful Hash-Based sig algorithms. */ #define BENCH_LMS_HSS 0x00000001 @@ -1031,8 +1021,6 @@ static word32 bench_kdf_algs = 0; static word32 bench_asym_algs = 0; /* Post-Quantum Asymmetric algorithms to benchmark. */ static word32 bench_pq_asym_algs = 0; -/* Post-Quantum Asymmetric algorithms to benchmark. (Part 2)*/ -static word32 bench_pq_asym_algs2 = 0; /* Other cryptographic algorithms to benchmark. */ static word32 bench_other_algs = 0; /* Post-Quantum Stateful Hash-Based sig algorithms to benchmark. */ @@ -1371,7 +1359,7 @@ static const bench_pq_hash_sig_alg bench_pq_hash_sig_opt[] = { #if !defined(WOLFSSL_BENCHMARK_ALL) && !defined(MAIN_NO_ARGS) #if defined(WOLFSSL_HAVE_MLKEM) || defined(HAVE_FALCON) || \ - defined(HAVE_DILITHIUM) || defined(HAVE_SPHINCS) + defined(HAVE_DILITHIUM) /* The post-quantum-specific mapping of command line option to bit values and * OQS name. */ typedef struct bench_pq_alg { @@ -1410,21 +1398,6 @@ static const bench_pq_alg bench_pq_asym_opt[] = { #endif { NULL, 0 } }; - -#if defined(HAVE_SPHINCS) -/* All recognized post-quantum asymmetric algorithm choosing command line - * options. (Part 2) */ -static const bench_pq_alg bench_pq_asym_opt2[] = { - { "-pq", 0xffffffff }, - { "-sphincs_fast_level1", BENCH_SPHINCS_FAST_LEVEL1_SIGN }, - { "-sphincs_fast_level3", BENCH_SPHINCS_FAST_LEVEL3_SIGN }, - { "-sphincs_fast_level5", BENCH_SPHINCS_FAST_LEVEL5_SIGN }, - { "-sphincs_small_level1", BENCH_SPHINCS_SMALL_LEVEL1_SIGN }, - { "-sphincs_small_level3", BENCH_SPHINCS_SMALL_LEVEL3_SIGN }, - { "-sphincs_small_level5", BENCH_SPHINCS_SMALL_LEVEL5_SIGN }, - { NULL, 0, } -}; -#endif /* HAVE_SPHINCS */ #endif #endif @@ -4754,20 +4727,6 @@ static void* benchmarks_do(void* args) bench_dilithiumKeySign(5); #endif #endif -#ifdef HAVE_SPHINCS - if (bench_all || (bench_pq_asym_algs2 & BENCH_SPHINCS_FAST_LEVEL1_SIGN)) - bench_sphincsKeySign(1, FAST_VARIANT); - if (bench_all || (bench_pq_asym_algs2 & BENCH_SPHINCS_FAST_LEVEL3_SIGN)) - bench_sphincsKeySign(3, FAST_VARIANT); - if (bench_all || (bench_pq_asym_algs2 & BENCH_SPHINCS_FAST_LEVEL5_SIGN)) - bench_sphincsKeySign(5, FAST_VARIANT); - if (bench_all || (bench_pq_asym_algs2 & BENCH_SPHINCS_SMALL_LEVEL1_SIGN)) - bench_sphincsKeySign(1, SMALL_VARIANT); - if (bench_all || (bench_pq_asym_algs2 & BENCH_SPHINCS_SMALL_LEVEL3_SIGN)) - bench_sphincsKeySign(3, SMALL_VARIANT); - if (bench_all || (bench_pq_asym_algs2 & BENCH_SPHINCS_SMALL_LEVEL5_SIGN)) - bench_sphincsKeySign(5, SMALL_VARIANT); -#endif #ifndef WC_NO_RNG if (bench_all || (bench_other_algs & BENCH_RNG_INIT)) @@ -4803,7 +4762,6 @@ exit: (void)bench_asym_algs; (void)bench_other_algs; (void)bench_pq_asym_algs; - (void)bench_pq_asym_algs2; return NULL; } @@ -12615,7 +12573,7 @@ void bench_xmss(int hash) #endif /* if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) */ #if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) -void bench_slhdsa(enum SlhDsaParam param) +void bench_slhdsa(int param) { int ret = 0, count = 0; double start = 0; @@ -12644,22 +12602,25 @@ void bench_slhdsa(enum SlhDsaParam param) WC_ALLOC_VAR_EX(sig, byte, WC_SLHDSA_MAX_SIG_LEN, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER, goto exit); - ret = wc_SlhDsaKey_Init(key, param, NULL, INVALID_DEVID); + ret = wc_SlhDsaKey_Init(key, (enum SlhDsaParam)param, NULL, INVALID_DEVID); if (ret != 0) { goto exit; } len = wc_SlhDsaKey_PublicSize(key) / 2 * 8; - if (SLHDSA_IS_SHA2(param)) { + if (SLHDSA_IS_SHA2((enum SlhDsaParam)param)) { XMEMCPY(name, "SLH-DSA-SHA2-S", 15); if ((param & 1) == 1) { name[13] = 'F'; } } else { - XMEMCPY(name, "SLH-DSA-S", 10); + /* SHAKE family: include the SHAKE token explicitly so output rows + * are symmetric with the SHA2 branch (e.g. "SLH-DSA-SHAKE-S" / + * "SLH-DSA-SHAKE-F" rather than the previous "SLH-DSA-S"). */ + XMEMCPY(name, "SLH-DSA-SHAKE-S", 16); if ((param & 1) == 1) { - name[8] = 'F'; + name[14] = 'F'; } } @@ -12703,7 +12664,7 @@ void bench_slhdsa(enum SlhDsaParam param) goto exit; } - ret = wc_SlhDsaKey_Init(key_vfy, param, NULL, INVALID_DEVID); + ret = wc_SlhDsaKey_Init(key_vfy, (enum SlhDsaParam)param, NULL, INVALID_DEVID); if (ret != 0) { goto exit; } @@ -16353,165 +16314,6 @@ out: } #endif /* HAVE_DILITHIUM && !WC_NO_RNG */ -#ifdef HAVE_SPHINCS -void bench_sphincsKeySign(byte level, byte optim) -{ - int ret = 0; - sphincs_key key; - double start; - int i, count; - byte sig[SPHINCS_MAX_SIG_SIZE]; - byte msg[512]; - word32 x = 0; - const char**desc = bench_desc_words[lng_index]; - DECLARE_MULTI_VALUE_STATS_VARS() - - bench_stats_prepare(); - - ret = wc_sphincs_init(&key); - if (ret != 0) { - printf("wc_sphincs_init failed %d\n", ret); - return; - } - - ret = wc_sphincs_set_level_and_optim(&key, level, optim); - if (ret != 0) { - printf("wc_sphincs_set_level_and_optim() failed %d\n", ret); - } - - if (ret == 0) { - ret = -1; - if ((level == 1) && (optim == FAST_VARIANT)) { - ret = wc_sphincs_import_private_key(bench_sphincs_fast_level1_key, - sizeof_bench_sphincs_fast_level1_key, NULL, 0, &key); - } - else if ((level == 3) && (optim == FAST_VARIANT)) { - ret = wc_sphincs_import_private_key(bench_sphincs_fast_level3_key, - sizeof_bench_sphincs_fast_level3_key, NULL, 0, &key); - } - else if ((level == 5) && (optim == FAST_VARIANT)) { - ret = wc_sphincs_import_private_key(bench_sphincs_fast_level5_key, - sizeof_bench_sphincs_fast_level5_key, NULL, 0, &key); - } - else if ((level == 1) && (optim == SMALL_VARIANT)) { - ret = wc_sphincs_import_private_key( - bench_sphincs_small_level1_key, - sizeof_bench_sphincs_small_level1_key, NULL, 0, &key); - } - else if ((level == 3) && (optim == SMALL_VARIANT)) { - ret = wc_sphincs_import_private_key( - bench_sphincs_small_level3_key, - sizeof_bench_sphincs_small_level3_key, NULL, 0, &key); - } - else if ((level == 5) && (optim == SMALL_VARIANT)) { - ret = wc_sphincs_import_private_key( - bench_sphincs_small_level5_key, - sizeof_bench_sphincs_small_level5_key, NULL, 0, &key); - } - - if (ret != 0) { - printf("wc_sphincs_import_private_key failed %d\n", ret); - } - } - - /* make dummy msg */ - for (i = 0; i < (int)sizeof(msg); i++) { - msg[i] = (byte)i; - } - - bench_stats_start(&count, &start); - do { - for (i = 0; i < agreeTimes; i++) { - if (ret == 0) { - if ((level == 1) && (optim == FAST_VARIANT)) { - x = SPHINCS_FAST_LEVEL1_SIG_SIZE; - } - else if ((level == 3) && (optim == FAST_VARIANT)) { - x = SPHINCS_FAST_LEVEL3_SIG_SIZE; - } - else if ((level == 5) && (optim == FAST_VARIANT)) { - x = SPHINCS_FAST_LEVEL5_SIG_SIZE; - } - else if ((level == 1) && (optim == SMALL_VARIANT)) { - x = SPHINCS_SMALL_LEVEL1_SIG_SIZE; - } - else if ((level == 3) && (optim == SMALL_VARIANT)) { - x = SPHINCS_SMALL_LEVEL3_SIG_SIZE; - } - else if ((level == 5) && (optim == SMALL_VARIANT)) { - x = SPHINCS_SMALL_LEVEL5_SIG_SIZE; - } - - ret = wc_sphincs_sign_msg(msg, sizeof(msg), sig, &x, &key, GLOBAL_RNG); - if (ret != 0) { - printf("wc_sphincs_sign_msg failed\n"); - } - } - RECORD_MULTI_VALUE_STATS(); - } - count += i; - } while (bench_stats_check(start) -#ifdef MULTI_VALUE_STATISTICS - || runs < minimum_runs -#endif - ); - - if (ret == 0) { - if (optim == FAST_VARIANT) { - bench_stats_asym_finish("SPHINCS-FAST", level, desc[4], 0, count, - start, ret); - } - else { - bench_stats_asym_finish("SPHINCS-SMALL", level, desc[4], 0, count, - start, ret); - } - #ifdef MULTI_VALUE_STATISTICS - bench_multi_value_stats(max, min, sum, squareSum, runs); - #endif - } - - RESET_MULTI_VALUE_STATS_VARS(); - - bench_stats_start(&count, &start); - do { - for (i = 0; i < agreeTimes; i++) { - if (ret == 0) { - int verify = 0; - ret = wc_sphincs_verify_msg(sig, x, msg, sizeof(msg), &verify, - &key); - - if (ret != 0 || verify != 1) { - printf("wc_sphincs_verify_msg failed %d, verify %d\n", - ret, verify); - ret = -1; - } - } - RECORD_MULTI_VALUE_STATS(); - } - count += i; - } while (bench_stats_check(start) -#ifdef MULTI_VALUE_STATISTICS - || runs < minimum_runs -#endif - ); - - if (ret == 0) { - if (optim == FAST_VARIANT) { - bench_stats_asym_finish("SPHINCS-FAST", level, desc[5], 0, count, - start, ret); - } - else { - bench_stats_asym_finish("SPHINCS-SMALL", level, desc[5], 0, count, - start, ret); - } - #ifdef MULTI_VALUE_STATISTICS - bench_multi_value_stats(max, min, sum, squareSum, runs); - #endif - } - - wc_sphincs_free(&key); -} -#endif /* HAVE_SPHINCS */ #if defined(_WIN32) && !defined(INTIME_RTOS) @@ -17155,13 +16957,9 @@ static void Usage(void) for (i=0; bench_other_opt[i].str != NULL; i++) print_alg(bench_other_opt[i].str, &line); #if defined(WOLFSSL_HAVE_MLKEM) || defined(HAVE_FALCON) || \ - defined(HAVE_DILITHIUM) || defined(HAVE_SPHINCS) + defined(HAVE_DILITHIUM) for (i=0; bench_pq_asym_opt[i].str != NULL; i++) print_alg(bench_pq_asym_opt[i].str, &line); -#if defined(HAVE_SPHINCS) - for (i=0; bench_pq_asym_opt2[i].str != NULL; i++) - print_alg(bench_pq_asym_opt2[i].str, &line); -#endif /* HAVE_SPHINCS */ #endif #if defined(BENCH_PQ_STATEFUL_HBS) for (i=0; bench_pq_hash_sig_opt[i].str != NULL; i++) @@ -17460,7 +17258,7 @@ int wolfcrypt_benchmark_main(int argc, char** argv) } } #if defined(WOLFSSL_HAVE_MLKEM) || defined(HAVE_FALCON) || \ - defined(HAVE_DILITHIUM) || defined(HAVE_SPHINCS) + defined(HAVE_DILITHIUM) /* Known asymmetric post-quantum algorithms */ for (i=0; !optMatched && bench_pq_asym_opt[i].str != NULL; i++) { if (string_matches(argv[1], bench_pq_asym_opt[i].str)) { @@ -17469,25 +17267,6 @@ int wolfcrypt_benchmark_main(int argc, char** argv) optMatched = 1; } } - #ifdef HAVE_SPHINCS - /* Both bench_pq_asym_opt and bench_pq_asym_opt2 are looking for - * -pq, so we need to do a special case for -pq since optMatched - * was set to 1 just above. */ - if ((bench_pq_asym_opt[0].str != NULL) && - string_matches(argv[1], bench_pq_asym_opt[0].str)) - { - bench_pq_asym_algs2 |= bench_pq_asym_opt2[0].val; - bench_all = 0; - optMatched = 1; - } - for (i=1; !optMatched && bench_pq_asym_opt2[i].str != NULL; i++) { - if (string_matches(argv[1], bench_pq_asym_opt2[i].str)) { - bench_pq_asym_algs2 |= bench_pq_asym_opt2[i].val; - bench_all = 0; - optMatched = 1; - } - } - #endif #endif /* Other known cryptographic algorithms */ for (i=0; !optMatched && bench_other_opt[i].str != NULL; i++) { diff --git a/wolfcrypt/benchmark/benchmark.h b/wolfcrypt/benchmark/benchmark.h index 7b291b2588..2ea0fc06e2 100644 --- a/wolfcrypt/benchmark/benchmark.h +++ b/wolfcrypt/benchmark/benchmark.h @@ -105,9 +105,7 @@ void bench_dh(int useDeviceID); void bench_mlkem(int type); void bench_lms(void); void bench_xmss(int hash); -#ifdef WOLFSSL_HAVE_SLHDSA -void bench_slhdsa(enum SlhDsaParam param); -#endif +void bench_slhdsa(int param); void bench_ecc_curve(int curveId); void bench_eccMakeKey(int useDeviceID, int curveId); void bench_ecc(int useDeviceID, int curveId); @@ -143,7 +141,6 @@ void bench_ascon_hash(void); void bench_pbkdf2(void); void bench_falconKeySign(byte level); void bench_dilithiumKeySign(byte level); -void bench_sphincsKeySign(byte level, byte optim); void bench_stats_print(void); diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 90b964c217..1960a9a957 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -191,7 +191,7 @@ ASN Options: * WOLFSSL_DILITHIUM_NO_SIGN: Disable Dilithium signing * WOLFSSL_DILITHIUM_NO_VERIFY: Disable Dilithium verify * HAVE_FALCON: Enable Falcon ASN support - * HAVE_SPHINCS: Enable SPHINCS+ ASN support + * WOLFSSL_HAVE_SLHDSA: Enable SLH-DSA ASN support * * Key Import/Export: * WC_ENABLE_ASYM_KEY_IMPORT: Enable asymmetric key import @@ -277,8 +277,8 @@ ASN Options: #if defined(HAVE_DILITHIUM) #include #endif -#if defined(HAVE_SPHINCS) - #include +#if defined(WOLFSSL_HAVE_SLHDSA) + #include #endif #ifdef WOLFSSL_QNX_CAAM @@ -4403,9 +4403,9 @@ static int EncodeName(EncodedName* name, const char* nameStr, byte nameTag, byte #endif #ifdef WOLFSSL_CERT_GEN static int SetValidity(byte* output, int daysValid); -static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey, ecc_key* eccKey, WC_RNG* rng, DsaKey* dsaKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, dilithium_key* dilithiumKey, sphincs_key* sphincsKey); +static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey, ecc_key* eccKey, WC_RNG* rng, DsaKey* dsaKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, dilithium_key* dilithiumKey, SlhDsaKey* slhDsaKey); #ifdef WOLFSSL_CERT_REQ -static int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey, DsaKey* dsaKey, ecc_key* eccKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, dilithium_key* dilithiumKey, sphincs_key* sphincsKey); +static int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey, DsaKey* dsaKey, ecc_key* eccKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, dilithium_key* dilithiumKey, SlhDsaKey* slhDsaKey); #endif #endif #endif @@ -4610,31 +4610,32 @@ static int ParseCRL_Extensions(DecodedCRL* dcrl, const byte* buf, word32* inOutI static const byte sigMlDsa_Level5Oid[] = {96, 134, 72, 1, 101, 3, 4, 3, 19}; #endif /* HAVE_DILITHIUM */ -#ifdef HAVE_SPHINCS - /* Sphincs Fast Level 1: 1 3 9999 6 7 4 */ - static const byte sigSphincsFast_Level1Oid[] = - {43, 206, 15, 6, 7, 4}; - - /* Sphincs Fast Level 3: 1 3 9999 6 8 3 */ - static const byte sigSphincsFast_Level3Oid[] = - {43, 206, 15, 6, 8, 3}; - - /* Sphincs Fast Level 5: 1 3 9999 6 9 3 */ - static const byte sigSphincsFast_Level5Oid[] = - {43, 206, 15, 6, 9, 3}; - - /* Sphincs Small Level 1: 1 3 9999 6 7 10 */ - static const byte sigSphincsSmall_Level1Oid[] = - {43, 206, 15, 6, 7, 10}; - - /* Sphincs Small Level 3: 1 3 9999 6 8 7 */ - static const byte sigSphincsSmall_Level3Oid[] = - {43, 206, 15, 6, 8, 7}; - - /* Sphincs Small Level 5: 1 3 9999 6 9 7 */ - static const byte sigSphincsSmall_Level5Oid[] = - {43, 206, 15, 6, 9, 7}; -#endif /* HAVE_SPHINCS */ +#ifdef WOLFSSL_HAVE_SLHDSA + /* SLH-DSA-SHA2-128s: 2.16.840.1.101.3.4.3.20 */ + static const byte sigSlhDsa_Sha2_128sOid[] = {96, 134, 72, 1, 101, 3, 4, 3, 20}; + /* SLH-DSA-SHA2-128f: 2.16.840.1.101.3.4.3.21 */ + static const byte sigSlhDsa_Sha2_128fOid[] = {96, 134, 72, 1, 101, 3, 4, 3, 21}; + /* SLH-DSA-SHA2-192s: 2.16.840.1.101.3.4.3.22 */ + static const byte sigSlhDsa_Sha2_192sOid[] = {96, 134, 72, 1, 101, 3, 4, 3, 22}; + /* SLH-DSA-SHA2-192f: 2.16.840.1.101.3.4.3.23 */ + static const byte sigSlhDsa_Sha2_192fOid[] = {96, 134, 72, 1, 101, 3, 4, 3, 23}; + /* SLH-DSA-SHA2-256s: 2.16.840.1.101.3.4.3.24 */ + static const byte sigSlhDsa_Sha2_256sOid[] = {96, 134, 72, 1, 101, 3, 4, 3, 24}; + /* SLH-DSA-SHA2-256f: 2.16.840.1.101.3.4.3.25 */ + static const byte sigSlhDsa_Sha2_256fOid[] = {96, 134, 72, 1, 101, 3, 4, 3, 25}; + /* SLH-DSA-SHAKE-128s: 2.16.840.1.101.3.4.3.26 */ + static const byte sigSlhDsa_Shake_128sOid[] = {96, 134, 72, 1, 101, 3, 4, 3, 26}; + /* SLH-DSA-SHAKE-128f: 2.16.840.1.101.3.4.3.27 */ + static const byte sigSlhDsa_Shake_128fOid[] = {96, 134, 72, 1, 101, 3, 4, 3, 27}; + /* SLH-DSA-SHAKE-192s: 2.16.840.1.101.3.4.3.28 */ + static const byte sigSlhDsa_Shake_192sOid[] = {96, 134, 72, 1, 101, 3, 4, 3, 28}; + /* SLH-DSA-SHAKE-192f: 2.16.840.1.101.3.4.3.29 */ + static const byte sigSlhDsa_Shake_192fOid[] = {96, 134, 72, 1, 101, 3, 4, 3, 29}; + /* SLH-DSA-SHAKE-256s: 2.16.840.1.101.3.4.3.30 */ + static const byte sigSlhDsa_Shake_256sOid[] = {96, 134, 72, 1, 101, 3, 4, 3, 30}; + /* SLH-DSA-SHAKE-256f: 2.16.840.1.101.3.4.3.31 */ + static const byte sigSlhDsa_Shake_256fOid[] = {96, 134, 72, 1, 101, 3, 4, 3, 31}; +#endif /* WOLFSSL_HAVE_SLHDSA */ /* keyType */ #ifndef NO_DSA @@ -4698,31 +4699,274 @@ static int ParseCRL_Extensions(DecodedCRL* dcrl, const byte* buf, word32* inOutI static const byte keyMlDsa_Level5Oid[] = {96, 134, 72, 1, 101, 3, 4, 3, 19}; #endif /* HAVE_DILITHIUM */ -#ifdef HAVE_SPHINCS - /* Sphincs Fast Level 1: 1 3 9999 6 7 4 */ - static const byte keySphincsFast_Level1Oid[] = - {43, 206, 15, 6, 7, 4}; +#ifdef WOLFSSL_HAVE_SLHDSA + /* SLH-DSA-SHA2-128s: 2.16.840.1.101.3.4.3.20 */ + static const byte keySlhDsa_Sha2_128sOid[] = {96, 134, 72, 1, 101, 3, 4, 3, 20}; + /* SLH-DSA-SHA2-128f: 2.16.840.1.101.3.4.3.21 */ + static const byte keySlhDsa_Sha2_128fOid[] = {96, 134, 72, 1, 101, 3, 4, 3, 21}; + /* SLH-DSA-SHA2-192s: 2.16.840.1.101.3.4.3.22 */ + static const byte keySlhDsa_Sha2_192sOid[] = {96, 134, 72, 1, 101, 3, 4, 3, 22}; + /* SLH-DSA-SHA2-192f: 2.16.840.1.101.3.4.3.23 */ + static const byte keySlhDsa_Sha2_192fOid[] = {96, 134, 72, 1, 101, 3, 4, 3, 23}; + /* SLH-DSA-SHA2-256s: 2.16.840.1.101.3.4.3.24 */ + static const byte keySlhDsa_Sha2_256sOid[] = {96, 134, 72, 1, 101, 3, 4, 3, 24}; + /* SLH-DSA-SHA2-256f: 2.16.840.1.101.3.4.3.25 */ + static const byte keySlhDsa_Sha2_256fOid[] = {96, 134, 72, 1, 101, 3, 4, 3, 25}; + /* SLH-DSA-SHAKE-128s: 2.16.840.1.101.3.4.3.26 */ + static const byte keySlhDsa_Shake_128sOid[] = {96, 134, 72, 1, 101, 3, 4, 3, 26}; + /* SLH-DSA-SHAKE-128f: 2.16.840.1.101.3.4.3.27 */ + static const byte keySlhDsa_Shake_128fOid[] = {96, 134, 72, 1, 101, 3, 4, 3, 27}; + /* SLH-DSA-SHAKE-192s: 2.16.840.1.101.3.4.3.28 */ + static const byte keySlhDsa_Shake_192sOid[] = {96, 134, 72, 1, 101, 3, 4, 3, 28}; + /* SLH-DSA-SHAKE-192f: 2.16.840.1.101.3.4.3.29 */ + static const byte keySlhDsa_Shake_192fOid[] = {96, 134, 72, 1, 101, 3, 4, 3, 29}; + /* SLH-DSA-SHAKE-256s: 2.16.840.1.101.3.4.3.30 */ + static const byte keySlhDsa_Shake_256sOid[] = {96, 134, 72, 1, 101, 3, 4, 3, 30}; + /* SLH-DSA-SHAKE-256f: 2.16.840.1.101.3.4.3.31 */ + static const byte keySlhDsa_Shake_256fOid[] = {96, 134, 72, 1, 101, 3, 4, 3, 31}; - /* Sphincs Fast Level 3: 1 3 9999 6 8 3 */ - static const byte keySphincsFast_Level3Oid[] = - {43, 206, 15, 6, 8, 3}; +/* Single source of truth for all SLH-DSA OID/param/cert-type mappings. + * + * Replaces the five parallel switches that each had to be kept in lockstep + * with the same set of WOLFSSL_SLHDSA_PARAM_NO_* macros. The `builtIn` + * column is the only place those macros appear now, so adding or + * disabling a variant is a one-line change. + * + * Rows for unbuilt variants are kept (with builtIn=0) so OID-keyed + * lookups can distinguish "known SLH-DSA OID, variant disabled" + * (NOT_COMPILED_IN) from "OID not recognised" (-1). Param-keyed lookups + * filter on builtIn=1 so disabled-variant params never escape. + * + * The certKeyType column carries cert_enums values (SLH_DSA_*_KEY) which + * are declared in asn.h only under WOLFSSL_CERT_GEN; the column and its + * single reader (SlhDsaParamToKeyType) are gated accordingly. + */ +typedef struct { + int param; /* enum SlhDsaParam (held as int for uniformity). */ + int oidKeySum; /* SLH_DSA_*k from oid_sum.h. */ +#ifdef WOLFSSL_CERT_GEN + int certKeyType; /* SLH_DSA_*_KEY from cert_enums; cert generation only. */ +#endif + int certType; /* SLH_DSA_*_TYPE from CertType (asn_public.h). */ + int builtIn; /* 1 if this variant is compiled in. */ +} SlhDsaOidMap; - /* Sphincs Fast Level 5: 1 3 9999 6 9 3 */ - static const byte keySphincsFast_Level5Oid[] = - {43, 206, 15, 6, 9, 3}; +#if !defined(WOLFSSL_SLHDSA_PARAM_NO_128S) + #define SLHDSA_BUILT_128S 1 +#else + #define SLHDSA_BUILT_128S 0 +#endif +#if !defined(WOLFSSL_SLHDSA_PARAM_NO_128F) + #define SLHDSA_BUILT_128F 1 +#else + #define SLHDSA_BUILT_128F 0 +#endif +#if !defined(WOLFSSL_SLHDSA_PARAM_NO_192S) + #define SLHDSA_BUILT_192S 1 +#else + #define SLHDSA_BUILT_192S 0 +#endif +#if !defined(WOLFSSL_SLHDSA_PARAM_NO_192F) + #define SLHDSA_BUILT_192F 1 +#else + #define SLHDSA_BUILT_192F 0 +#endif +#if !defined(WOLFSSL_SLHDSA_PARAM_NO_256S) + #define SLHDSA_BUILT_256S 1 +#else + #define SLHDSA_BUILT_256S 0 +#endif +#if !defined(WOLFSSL_SLHDSA_PARAM_NO_256F) + #define SLHDSA_BUILT_256F 1 +#else + #define SLHDSA_BUILT_256F 0 +#endif - /* Sphincs Small Level 1: 1 3 9999 6 7 10 */ - static const byte keySphincsSmall_Level1Oid[] = - {43, 206, 15, 6, 7, 10}; +#if defined(WOLFSSL_SLHDSA_SHA2) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128S) + #define SLHDSA_BUILT_SHA2_128S 1 +#else + #define SLHDSA_BUILT_SHA2_128S 0 +#endif +#if defined(WOLFSSL_SLHDSA_SHA2) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_128F) + #define SLHDSA_BUILT_SHA2_128F 1 +#else + #define SLHDSA_BUILT_SHA2_128F 0 +#endif +#if defined(WOLFSSL_SLHDSA_SHA2) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192S) + #define SLHDSA_BUILT_SHA2_192S 1 +#else + #define SLHDSA_BUILT_SHA2_192S 0 +#endif +#if defined(WOLFSSL_SLHDSA_SHA2) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_192F) + #define SLHDSA_BUILT_SHA2_192F 1 +#else + #define SLHDSA_BUILT_SHA2_192F 0 +#endif +#if defined(WOLFSSL_SLHDSA_SHA2) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256S) + #define SLHDSA_BUILT_SHA2_256S 1 +#else + #define SLHDSA_BUILT_SHA2_256S 0 +#endif +#if defined(WOLFSSL_SLHDSA_SHA2) && \ + !defined(WOLFSSL_SLHDSA_PARAM_NO_SHA2_256F) + #define SLHDSA_BUILT_SHA2_256F 1 +#else + #define SLHDSA_BUILT_SHA2_256F 0 +#endif - /* Sphincs Small Level 3: 1 3 9999 6 8 7 */ - static const byte keySphincsSmall_Level3Oid[] = - {43, 206, 15, 6, 8, 7}; +/* Helper to keep the row literals readable while certKeyType is + * conditional on WOLFSSL_CERT_GEN. */ +#ifdef WOLFSSL_CERT_GEN + #define SLHDSA_OID_ROW(p, k, certK, t, b) { (p), (k), (certK), (t), (b) } +#else + #define SLHDSA_OID_ROW(p, k, certK, t, b) { (p), (k), (t), (b) } +#endif - /* Sphincs Small Level 5: 1 3 9999 6 9 7 */ - static const byte keySphincsSmall_Level5Oid[] = - {43, 206, 15, 6, 9, 7}; -#endif /* HAVE_SPHINCS */ +/* SHA2 rows: in non-SHA2 builds the public enum SlhDsaParam doesn't + * declare SLHDSA_SHA2_*, so substitute -1 (a value no real param can + * take) for the param column and discard the macro arg. The OID is still + * present, so wc_SlhDsaOidToParam(SLH_DSA_SHA2_*k) returns NOT_COMPILED_IN + * (via builtIn=0) instead of -1 (unknown). The sentinel never escapes + * because lookups by param go through builtIn=1 rows only. */ +#ifdef WOLFSSL_SLHDSA_SHA2 + #define SLHDSA_SHA2_OID_ROW(p, k, certK, t, b) \ + SLHDSA_OID_ROW(p, k, certK, t, b) +#else + #define SLHDSA_SHA2_OID_ROW(p, k, certK, t, b) \ + SLHDSA_OID_ROW(-1, k, certK, t, b) +#endif + +static const SlhDsaOidMap slhDsaOidMap[] = { + SLHDSA_OID_ROW(SLHDSA_SHAKE128S, SLH_DSA_SHAKE_128Sk, + SLH_DSA_SHAKE_128S_KEY, SLH_DSA_SHAKE_128S_TYPE, SLHDSA_BUILT_128S), + SLHDSA_OID_ROW(SLHDSA_SHAKE128F, SLH_DSA_SHAKE_128Fk, + SLH_DSA_SHAKE_128F_KEY, SLH_DSA_SHAKE_128F_TYPE, SLHDSA_BUILT_128F), + SLHDSA_OID_ROW(SLHDSA_SHAKE192S, SLH_DSA_SHAKE_192Sk, + SLH_DSA_SHAKE_192S_KEY, SLH_DSA_SHAKE_192S_TYPE, SLHDSA_BUILT_192S), + SLHDSA_OID_ROW(SLHDSA_SHAKE192F, SLH_DSA_SHAKE_192Fk, + SLH_DSA_SHAKE_192F_KEY, SLH_DSA_SHAKE_192F_TYPE, SLHDSA_BUILT_192F), + SLHDSA_OID_ROW(SLHDSA_SHAKE256S, SLH_DSA_SHAKE_256Sk, + SLH_DSA_SHAKE_256S_KEY, SLH_DSA_SHAKE_256S_TYPE, SLHDSA_BUILT_256S), + SLHDSA_OID_ROW(SLHDSA_SHAKE256F, SLH_DSA_SHAKE_256Fk, + SLH_DSA_SHAKE_256F_KEY, SLH_DSA_SHAKE_256F_TYPE, SLHDSA_BUILT_256F), + SLHDSA_SHA2_OID_ROW(SLHDSA_SHA2_128S, SLH_DSA_SHA2_128Sk, + SLH_DSA_SHA2_128S_KEY, SLH_DSA_SHA2_128S_TYPE, SLHDSA_BUILT_SHA2_128S), + SLHDSA_SHA2_OID_ROW(SLHDSA_SHA2_128F, SLH_DSA_SHA2_128Fk, + SLH_DSA_SHA2_128F_KEY, SLH_DSA_SHA2_128F_TYPE, SLHDSA_BUILT_SHA2_128F), + SLHDSA_SHA2_OID_ROW(SLHDSA_SHA2_192S, SLH_DSA_SHA2_192Sk, + SLH_DSA_SHA2_192S_KEY, SLH_DSA_SHA2_192S_TYPE, SLHDSA_BUILT_SHA2_192S), + SLHDSA_SHA2_OID_ROW(SLHDSA_SHA2_192F, SLH_DSA_SHA2_192Fk, + SLH_DSA_SHA2_192F_KEY, SLH_DSA_SHA2_192F_TYPE, SLHDSA_BUILT_SHA2_192F), + SLHDSA_SHA2_OID_ROW(SLHDSA_SHA2_256S, SLH_DSA_SHA2_256Sk, + SLH_DSA_SHA2_256S_KEY, SLH_DSA_SHA2_256S_TYPE, SLHDSA_BUILT_SHA2_256S), + SLHDSA_SHA2_OID_ROW(SLHDSA_SHA2_256F, SLH_DSA_SHA2_256Fk, + SLH_DSA_SHA2_256F_KEY, SLH_DSA_SHA2_256F_TYPE, SLHDSA_BUILT_SHA2_256F) +}; + +#define SLHDSA_OID_MAP_LEN \ + ((int)(sizeof(slhDsaOidMap) / sizeof(slhDsaOidMap[0]))) + +/* Map SLH-DSA OID key type (SLH_DSA_*k) to enum SlhDsaParam. + * + * A known OID whose parameter set is disabled returns NOT_COMPILED_IN so + * callers can render a "variant unavailable" diagnostic; an unknown OID + * returns -1. */ +int wc_SlhDsaOidToParam(int oid) +{ + int i; + for (i = 0; i < SLHDSA_OID_MAP_LEN; i++) { + if (slhDsaOidMap[i].oidKeySum == oid) { + return slhDsaOidMap[i].builtIn ? slhDsaOidMap[i].param + : NOT_COMPILED_IN; + } + } + return -1; +} + +/* Map SLH-DSA OID key type (SLH_DSA_*k) to CertType (SLH_DSA_*_TYPE). + * + * Returns NOT_COMPILED_IN for a known but disabled OID; -1 for unknown. */ +int wc_SlhDsaOidToCertType(int oid) +{ + int i; + for (i = 0; i < SLHDSA_OID_MAP_LEN; i++) { + if (slhDsaOidMap[i].oidKeySum == oid) { + return slhDsaOidMap[i].builtIn ? slhDsaOidMap[i].certType + : NOT_COMPILED_IN; + } + } + return -1; +} + +/* True if oid is any SLH-DSA OID, even one whose parameter set is not + * built. The x509 dispatch uses this to route to the SLH-DSA branch so + * unbuilt-variant errors surface as NOT_COMPILED_IN rather than the + * generic "No public key found" diagnostic. */ +int wc_IsSlhDsaOid(int oid) +{ + int i; + for (i = 0; i < SLHDSA_OID_MAP_LEN; i++) { + if (slhDsaOidMap[i].oidKeySum == oid) { + return 1; + } + } + return 0; +} + +/* Map enum SlhDsaParam to its OID Key_Sum identifier (SLH_DSA_*k). + * + * Symmetric with wc_SlhDsaOidToParam: a known SLH-DSA param whose + * variant is disabled returns NOT_COMPILED_IN; an unknown / out-of-range + * value returns BAD_FUNC_ARG. */ +int wc_SlhDsaParamToOid(enum SlhDsaParam param) +{ + int i; + for (i = 0; i < SLHDSA_OID_MAP_LEN; i++) { + if (slhDsaOidMap[i].param == (int)param) { + return slhDsaOidMap[i].builtIn ? slhDsaOidMap[i].oidKeySum + : NOT_COMPILED_IN; + } + } + return BAD_FUNC_ARG; +} + +#if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_REQ) +/* True if certType (SLH_DSA_*_TYPE) is any built-in SLH-DSA cert key + * type. */ +static int IsSlhDsaKeyType(int certType) +{ + int i; + for (i = 0; i < SLHDSA_OID_MAP_LEN; i++) { + if (slhDsaOidMap[i].builtIn && + slhDsaOidMap[i].certType == certType) { + return 1; + } + } + return 0; +} +#endif /* WOLFSSL_CERT_GEN || WOLFSSL_CERT_REQ */ + +#ifdef WOLFSSL_CERT_GEN +/* Map enum SlhDsaParam to Cert keyType identifier (SLH_DSA_*_KEY), or 0 + * on unknown / unbuilt. */ +static int SlhDsaParamToKeyType(enum SlhDsaParam param) +{ + int i; + for (i = 0; i < SLHDSA_OID_MAP_LEN; i++) { + if (slhDsaOidMap[i].builtIn && + slhDsaOidMap[i].param == (int)param) { + return slhDsaOidMap[i].certKeyType; + } + } + return 0; +} +#endif /* WOLFSSL_CERT_GEN */ +#endif /* WOLFSSL_HAVE_SLHDSA */ /* curveType */ #ifdef HAVE_ECC @@ -5565,32 +5809,56 @@ const byte* OidFromId(word32 id, word32 type, word32* oidSz) *oidSz = sizeof(sigMlDsa_Level5Oid); break; #endif /* HAVE_DILITHIUM */ - #ifdef HAVE_SPHINCS - case CTC_SPHINCS_FAST_LEVEL1: - oid = sigSphincsFast_Level1Oid; - *oidSz = sizeof(sigSphincsFast_Level1Oid); + #ifdef WOLFSSL_HAVE_SLHDSA + case CTC_SLH_DSA_SHA2_128S: + oid = sigSlhDsa_Sha2_128sOid; + *oidSz = sizeof(sigSlhDsa_Sha2_128sOid); break; - case CTC_SPHINCS_FAST_LEVEL3: - oid = sigSphincsFast_Level3Oid; - *oidSz = sizeof(sigSphincsFast_Level3Oid); + case CTC_SLH_DSA_SHA2_128F: + oid = sigSlhDsa_Sha2_128fOid; + *oidSz = sizeof(sigSlhDsa_Sha2_128fOid); break; - case CTC_SPHINCS_FAST_LEVEL5: - oid = sigSphincsFast_Level5Oid; - *oidSz = sizeof(sigSphincsFast_Level5Oid); + case CTC_SLH_DSA_SHA2_192S: + oid = sigSlhDsa_Sha2_192sOid; + *oidSz = sizeof(sigSlhDsa_Sha2_192sOid); break; - case CTC_SPHINCS_SMALL_LEVEL1: - oid = sigSphincsSmall_Level1Oid; - *oidSz = sizeof(sigSphincsSmall_Level1Oid); + case CTC_SLH_DSA_SHA2_192F: + oid = sigSlhDsa_Sha2_192fOid; + *oidSz = sizeof(sigSlhDsa_Sha2_192fOid); break; - case CTC_SPHINCS_SMALL_LEVEL3: - oid = sigSphincsSmall_Level3Oid; - *oidSz = sizeof(sigSphincsSmall_Level3Oid); + case CTC_SLH_DSA_SHA2_256S: + oid = sigSlhDsa_Sha2_256sOid; + *oidSz = sizeof(sigSlhDsa_Sha2_256sOid); break; - case CTC_SPHINCS_SMALL_LEVEL5: - oid = sigSphincsSmall_Level5Oid; - *oidSz = sizeof(sigSphincsSmall_Level5Oid); + case CTC_SLH_DSA_SHA2_256F: + oid = sigSlhDsa_Sha2_256fOid; + *oidSz = sizeof(sigSlhDsa_Sha2_256fOid); break; - #endif /* HAVE_SPHINCS */ + case CTC_SLH_DSA_SHAKE_128S: + oid = sigSlhDsa_Shake_128sOid; + *oidSz = sizeof(sigSlhDsa_Shake_128sOid); + break; + case CTC_SLH_DSA_SHAKE_128F: + oid = sigSlhDsa_Shake_128fOid; + *oidSz = sizeof(sigSlhDsa_Shake_128fOid); + break; + case CTC_SLH_DSA_SHAKE_192S: + oid = sigSlhDsa_Shake_192sOid; + *oidSz = sizeof(sigSlhDsa_Shake_192sOid); + break; + case CTC_SLH_DSA_SHAKE_192F: + oid = sigSlhDsa_Shake_192fOid; + *oidSz = sizeof(sigSlhDsa_Shake_192fOid); + break; + case CTC_SLH_DSA_SHAKE_256S: + oid = sigSlhDsa_Shake_256sOid; + *oidSz = sizeof(sigSlhDsa_Shake_256sOid); + break; + case CTC_SLH_DSA_SHAKE_256F: + oid = sigSlhDsa_Shake_256fOid; + *oidSz = sizeof(sigSlhDsa_Shake_256fOid); + break; + #endif /* WOLFSSL_HAVE_SLHDSA */ default: break; } @@ -5690,32 +5958,56 @@ const byte* OidFromId(word32 id, word32 type, word32* oidSz) *oidSz = sizeof(keyMlDsa_Level5Oid); break; #endif /* HAVE_DILITHIUM */ - #ifdef HAVE_SPHINCS - case SPHINCS_FAST_LEVEL1k: - oid = keySphincsFast_Level1Oid; - *oidSz = sizeof(keySphincsFast_Level1Oid); + #ifdef WOLFSSL_HAVE_SLHDSA + case SLH_DSA_SHA2_128Sk: + oid = keySlhDsa_Sha2_128sOid; + *oidSz = sizeof(keySlhDsa_Sha2_128sOid); break; - case SPHINCS_FAST_LEVEL3k: - oid = keySphincsFast_Level3Oid; - *oidSz = sizeof(keySphincsFast_Level3Oid); + case SLH_DSA_SHA2_128Fk: + oid = keySlhDsa_Sha2_128fOid; + *oidSz = sizeof(keySlhDsa_Sha2_128fOid); break; - case SPHINCS_FAST_LEVEL5k: - oid = keySphincsFast_Level5Oid; - *oidSz = sizeof(keySphincsFast_Level5Oid); + case SLH_DSA_SHA2_192Sk: + oid = keySlhDsa_Sha2_192sOid; + *oidSz = sizeof(keySlhDsa_Sha2_192sOid); break; - case SPHINCS_SMALL_LEVEL1k: - oid = keySphincsSmall_Level1Oid; - *oidSz = sizeof(keySphincsSmall_Level1Oid); + case SLH_DSA_SHA2_192Fk: + oid = keySlhDsa_Sha2_192fOid; + *oidSz = sizeof(keySlhDsa_Sha2_192fOid); break; - case SPHINCS_SMALL_LEVEL3k: - oid = keySphincsSmall_Level3Oid; - *oidSz = sizeof(keySphincsSmall_Level3Oid); + case SLH_DSA_SHA2_256Sk: + oid = keySlhDsa_Sha2_256sOid; + *oidSz = sizeof(keySlhDsa_Sha2_256sOid); break; - case SPHINCS_SMALL_LEVEL5k: - oid = keySphincsSmall_Level5Oid; - *oidSz = sizeof(keySphincsSmall_Level5Oid); + case SLH_DSA_SHA2_256Fk: + oid = keySlhDsa_Sha2_256fOid; + *oidSz = sizeof(keySlhDsa_Sha2_256fOid); break; - #endif /* HAVE_SPHINCS */ + case SLH_DSA_SHAKE_128Sk: + oid = keySlhDsa_Shake_128sOid; + *oidSz = sizeof(keySlhDsa_Shake_128sOid); + break; + case SLH_DSA_SHAKE_128Fk: + oid = keySlhDsa_Shake_128fOid; + *oidSz = sizeof(keySlhDsa_Shake_128fOid); + break; + case SLH_DSA_SHAKE_192Sk: + oid = keySlhDsa_Shake_192sOid; + *oidSz = sizeof(keySlhDsa_Shake_192sOid); + break; + case SLH_DSA_SHAKE_192Fk: + oid = keySlhDsa_Shake_192fOid; + *oidSz = sizeof(keySlhDsa_Shake_192fOid); + break; + case SLH_DSA_SHAKE_256Sk: + oid = keySlhDsa_Shake_256sOid; + *oidSz = sizeof(keySlhDsa_Shake_256sOid); + break; + case SLH_DSA_SHAKE_256Fk: + oid = keySlhDsa_Shake_256fOid; + *oidSz = sizeof(keySlhDsa_Shake_256fOid); + break; + #endif /* WOLFSSL_HAVE_SLHDSA */ default: break; } @@ -7262,7 +7554,7 @@ static int GetOID(const byte* input, word32* inOutIdx, word32* oid, word32 checkOidSz; #endif /* NO_VERIFY_OID */ #ifdef WOLFSSL_OLD_OID_SUM -#if defined(HAVE_SPHINCS) || defined(WOLFSSL_FPKI) +#if defined(WOLFSSL_FPKI) word32 found_collision = 0; #endif #endif @@ -7275,24 +7567,6 @@ static int GetOID(const byte* input, word32* inOutIdx, word32* oid, actualOidSz = (word32)length; #endif /* NO_VERIFY_OID */ -#ifdef WOLFSSL_OLD_OID_SUM -#if defined(HAVE_SPHINCS) - /* Since we are summing it up, there could be collisions...and indeed there - * are: SPHINCS_FAST_LEVEL1 and SPHINCS_FAST_LEVEL3. - * - * We will look for the special case of SPHINCS_FAST_LEVEL3 and set *oid to - * 283 instead of 281; 282 is taken. - * - * These hacks will hopefully disappear when new standardized OIDs appear. - */ - if (idx + (word32)sizeof(sigSphincsFast_Level3Oid) < (word32)length && - XMEMCMP(&input[idx], sigSphincsFast_Level3Oid, - sizeof(sigSphincsFast_Level3Oid)) == 0) { - found_collision = SPHINCS_FAST_LEVEL3k; - } -#endif /* HAVE_SPHINCS */ -#endif - *oid = wc_oid_sum(actualOid, (int)actualOidSz); idx += actualOidSz; @@ -7306,11 +7580,11 @@ static int GetOID(const byte* input, word32* inOutIdx, word32* oid, } #endif -#if defined(HAVE_SPHINCS) || defined(WOLFSSL_FPKI) +#if defined(WOLFSSL_FPKI) if (found_collision) { *oid = found_collision; } -#endif /* HAVE_SPHINCS */ +#endif /* WOLFSSL_FPKI */ #endif /* Return the index after the OID data. */ @@ -8595,7 +8869,7 @@ int ToTraditionalInline_ex2(const byte* input, word32* inOutIdx, word32 sz, break; #endif /* DSAk not supported. */ - /* Falcon, Dilithium and Sphincs not supported. */ + /* Falcon, Dilithium and SLH-DSA not supported. */ /* Ignore OID lookup failures. */ default: break; @@ -9127,63 +9401,45 @@ int wc_CheckPrivateKey(const byte* privKey, word32 privKeySz, } else #endif /* HAVE_DILITHIUM && !WOLFSSL_DILITHIUM_VERIFY_ONLY */ - #if defined(HAVE_SPHINCS) - if ((ks == SPHINCS_FAST_LEVEL1k) || - (ks == SPHINCS_FAST_LEVEL3k) || - (ks == SPHINCS_FAST_LEVEL5k) || - (ks == SPHINCS_SMALL_LEVEL1k) || - (ks == SPHINCS_SMALL_LEVEL3k) || - (ks == SPHINCS_SMALL_LEVEL5k)) { - WC_DECLARE_VAR(key_pair, sphincs_key, 1, 0); +#if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) + if (wc_IsSlhDsaOid(ks)) { + WC_DECLARE_VAR(key_pair, SlhDsaKey, 1, 0); word32 keyIdx = 0; + int slhDsaParam; - WC_ALLOC_VAR_EX(key_pair, sphincs_key, 1, NULL, DYNAMIC_TYPE_SPHINCS, + WC_ALLOC_VAR_EX(key_pair, SlhDsaKey, 1, NULL, DYNAMIC_TYPE_SLHDSA, return MEMORY_E); - ret = wc_sphincs_init(key_pair); + + slhDsaParam = wc_SlhDsaOidToParam(ks); + + if (slhDsaParam < 0) { + WC_FREE_VAR_EX(key_pair, NULL, DYNAMIC_TYPE_SLHDSA); + return NOT_COMPILED_IN; + } + + ret = wc_SlhDsaKey_Init(key_pair, (enum SlhDsaParam)slhDsaParam, + NULL, INVALID_DEVID); if (ret < 0) { - WC_FREE_VAR_EX(key_pair, NULL, DYNAMIC_TYPE_SPHINCS); + WC_FREE_VAR_EX(key_pair, NULL, DYNAMIC_TYPE_SLHDSA); return ret; } - if (ks == SPHINCS_FAST_LEVEL1k) { - ret = wc_sphincs_set_level_and_optim(key_pair, 1, FAST_VARIANT); - } - else if (ks == SPHINCS_FAST_LEVEL3k) { - ret = wc_sphincs_set_level_and_optim(key_pair, 3, FAST_VARIANT); - } - else if (ks == SPHINCS_FAST_LEVEL5k) { - ret = wc_sphincs_set_level_and_optim(key_pair, 5, FAST_VARIANT); - } - else if (ks == SPHINCS_SMALL_LEVEL1k) { - ret = wc_sphincs_set_level_and_optim(key_pair, 1, SMALL_VARIANT); - } - else if (ks == SPHINCS_SMALL_LEVEL3k) { - ret = wc_sphincs_set_level_and_optim(key_pair, 3, SMALL_VARIANT); - } - else if (ks == SPHINCS_SMALL_LEVEL5k) { - ret = wc_sphincs_set_level_and_optim(key_pair, 5, SMALL_VARIANT); - } - - if (ret < 0) { - WC_FREE_VAR_EX(key_pair, NULL, DYNAMIC_TYPE_SPHINCS); - return ret; - } - if ((ret = wc_Sphincs_PrivateKeyDecode(privKey, &keyIdx, key_pair, + if ((ret = wc_SlhDsaKey_PrivateKeyDecode(privKey, &keyIdx, key_pair, privKeySz)) == 0) { - WOLFSSL_MSG("Checking Sphincs key pair"); + WOLFSSL_MSG("Checking SLH-DSA key pair"); keyIdx = 0; - if ((ret = wc_sphincs_import_public(pubKey, pubKeySz, - key_pair)) == 0) { + if ((ret = wc_SlhDsaKey_ImportPublic(key_pair, pubKey, + pubKeySz)) == 0) { /* Public and private extracted successfully. Sanity check. */ - if ((ret = wc_sphincs_check_key(key_pair)) == 0) + if ((ret = wc_SlhDsaKey_CheckKey(key_pair)) == 0) ret = 1; } } - wc_sphincs_free(key_pair); - WC_FREE_VAR_EX(key_pair, NULL, DYNAMIC_TYPE_SPHINCS); + wc_SlhDsaKey_Free(key_pair); + WC_FREE_VAR_EX(key_pair, NULL, DYNAMIC_TYPE_SLHDSA); } else - #endif /* HAVE_SPHINCS */ +#endif /* WOLFSSL_HAVE_SLHDSA && !WOLFSSL_SLHDSA_VERIFY_ONLY */ { ret = 0; } @@ -9627,83 +9883,112 @@ int wc_GetKeyOID(byte* key, word32 keySz, const byte** curveOID, word32* oidSz, XFREE(dilithium, heap, DYNAMIC_TYPE_TMP_BUFFER); } #endif /* HAVE_DILITHIUM && !WOLFSSL_DILITHIUM_VERIFY_ONLY */ -#if defined(HAVE_SPHINCS) +#if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) if (*algoID == 0) { - sphincs_key *sphincs = (sphincs_key *)XMALLOC(sizeof(*sphincs), + enum SlhDsaParam placeholder; + SlhDsaKey *slhDsa = (SlhDsaKey *)XMALLOC(sizeof(*slhDsa), heap, DYNAMIC_TYPE_TMP_BUFFER); - if (sphincs == NULL) + if (slhDsa == NULL) return MEMORY_E; - if (wc_sphincs_init(sphincs) == 0) { + /* wc_SlhDsaKey_PrivateKeyDecode auto-detects the parameter set from + * the OID in the DER encoding, so a single call handles all twelve + * SLH-DSA variants. The initial parameter is only a placeholder; + * it is overwritten by the decoder. Pick whichever variant is + * compiled in so wc_SlhDsaKey_Init does not fail with + * NOT_COMPILED_IN when a specific variant (like 128F) is disabled. */ + #if defined(WOLFSSL_SLHDSA_PARAM_128F) + placeholder = SLHDSA_SHAKE128F; + #elif defined(WOLFSSL_SLHDSA_PARAM_128S) + placeholder = SLHDSA_SHAKE128S; + #elif defined(WOLFSSL_SLHDSA_PARAM_192F) + placeholder = SLHDSA_SHAKE192F; + #elif defined(WOLFSSL_SLHDSA_PARAM_192S) + placeholder = SLHDSA_SHAKE192S; + #elif defined(WOLFSSL_SLHDSA_PARAM_256F) + placeholder = SLHDSA_SHAKE256F; + #elif defined(WOLFSSL_SLHDSA_PARAM_256S) + placeholder = SLHDSA_SHAKE256S; + #elif defined(WOLFSSL_SLHDSA_SHA2) && \ + defined(WOLFSSL_SLHDSA_PARAM_SHA2_128F) + placeholder = SLHDSA_SHA2_128F; + #elif defined(WOLFSSL_SLHDSA_SHA2) && \ + defined(WOLFSSL_SLHDSA_PARAM_SHA2_128S) + placeholder = SLHDSA_SHA2_128S; + #elif defined(WOLFSSL_SLHDSA_SHA2) && \ + defined(WOLFSSL_SLHDSA_PARAM_SHA2_192F) + placeholder = SLHDSA_SHA2_192F; + #elif defined(WOLFSSL_SLHDSA_SHA2) && \ + defined(WOLFSSL_SLHDSA_PARAM_SHA2_192S) + placeholder = SLHDSA_SHA2_192S; + #elif defined(WOLFSSL_SLHDSA_SHA2) && \ + defined(WOLFSSL_SLHDSA_PARAM_SHA2_256F) + placeholder = SLHDSA_SHA2_256F; + #elif defined(WOLFSSL_SLHDSA_SHA2) && \ + defined(WOLFSSL_SLHDSA_PARAM_SHA2_256S) + placeholder = SLHDSA_SHA2_256S; + #else + #error "WOLFSSL_HAVE_SLHDSA requires at least one parameter set" + #endif + if (wc_SlhDsaKey_Init(slhDsa, placeholder, NULL, INVALID_DEVID) == 0) { tmpIdx = 0; - if (wc_sphincs_set_level_and_optim(sphincs, 1, FAST_VARIANT) - == 0) { - if (wc_Sphincs_PrivateKeyDecode(key, &tmpIdx, sphincs, + if (wc_SlhDsaKey_PrivateKeyDecode(key, &tmpIdx, slhDsa, keySz) == 0) { - *algoID = SPHINCS_FAST_LEVEL1k; - } - else { - WOLFSSL_MSG("Not Sphincs-fast Level 1 DER key"); - } - } - else if (wc_sphincs_set_level_and_optim(sphincs, 3, FAST_VARIANT) - == 0) { - if (wc_Sphincs_PrivateKeyDecode(key, &tmpIdx, sphincs, - keySz) == 0) { - *algoID = SPHINCS_FAST_LEVEL3k; - } - else { - WOLFSSL_MSG("Not Sphincs-fast Level 3 DER key"); - } - } - else if (wc_sphincs_set_level_and_optim(sphincs, 5, FAST_VARIANT) - == 0) { - if (wc_Sphincs_PrivateKeyDecode(key, &tmpIdx, sphincs, - keySz) == 0) { - *algoID = SPHINCS_FAST_LEVEL5k; - } - else { - WOLFSSL_MSG("Not Sphincs-fast Level 5 DER key"); - } - } - else if (wc_sphincs_set_level_and_optim(sphincs, 1, SMALL_VARIANT) - == 0) { - if (wc_Sphincs_PrivateKeyDecode(key, &tmpIdx, sphincs, - keySz) == 0) { - *algoID = SPHINCS_SMALL_LEVEL1k; - } - else { - WOLFSSL_MSG("Not Sphincs-small Level 1 DER key"); - } - } - else if (wc_sphincs_set_level_and_optim(sphincs, 3, SMALL_VARIANT) - == 0) { - if (wc_Sphincs_PrivateKeyDecode(key, &tmpIdx, sphincs, - keySz) == 0) { - *algoID = SPHINCS_SMALL_LEVEL3k; - } - else { - WOLFSSL_MSG("Not Sphincs-small Level 3 DER key"); - } - } - else if (wc_sphincs_set_level_and_optim(sphincs, 5, SMALL_VARIANT) - == 0) { - if (wc_Sphincs_PrivateKeyDecode(key, &tmpIdx, sphincs, - keySz) == 0) { - *algoID = SPHINCS_SMALL_LEVEL5k; - } - else { - WOLFSSL_MSG("Not Sphincs-small Level 5 DER key"); + switch (slhDsa->params->param) { + case SLHDSA_SHAKE128S: + *algoID = SLH_DSA_SHAKE_128Sk; + break; + case SLHDSA_SHAKE128F: + *algoID = SLH_DSA_SHAKE_128Fk; + break; + case SLHDSA_SHAKE192S: + *algoID = SLH_DSA_SHAKE_192Sk; + break; + case SLHDSA_SHAKE192F: + *algoID = SLH_DSA_SHAKE_192Fk; + break; + case SLHDSA_SHAKE256S: + *algoID = SLH_DSA_SHAKE_256Sk; + break; + case SLHDSA_SHAKE256F: + *algoID = SLH_DSA_SHAKE_256Fk; + break; + #ifdef WOLFSSL_SLHDSA_SHA2 + case SLHDSA_SHA2_128S: + *algoID = SLH_DSA_SHA2_128Sk; + break; + case SLHDSA_SHA2_128F: + *algoID = SLH_DSA_SHA2_128Fk; + break; + case SLHDSA_SHA2_192S: + *algoID = SLH_DSA_SHA2_192Sk; + break; + case SLHDSA_SHA2_192F: + *algoID = SLH_DSA_SHA2_192Fk; + break; + case SLHDSA_SHA2_256S: + *algoID = SLH_DSA_SHA2_256Sk; + break; + case SLHDSA_SHA2_256F: + *algoID = SLH_DSA_SHA2_256Fk; + break; + #endif + default: + WOLFSSL_MSG("Unexpected SLH-DSA parameter set"); + break; } } else { - WOLFSSL_MSG("GetKeyOID sphincs initialization failed"); + WOLFSSL_MSG("Not an SLH-DSA DER key"); } - wc_sphincs_free(sphincs); + wc_SlhDsaKey_Free(slhDsa); } - XFREE(sphincs, heap, DYNAMIC_TYPE_TMP_BUFFER); + else { + WOLFSSL_MSG("GetKeyOID SLH-DSA initialization failed"); + } + XFREE(slhDsa, heap, DYNAMIC_TYPE_TMP_BUFFER); } -#endif /* HAVE_SPHINCS */ +#endif /* WOLFSSL_HAVE_SLHDSA && !WOLFSSL_SLHDSA_VERIFY_ONLY */ /* if flag is not set then this is not a key that we understand. */ if (*algoID == 0) { @@ -12166,7 +12451,7 @@ void wc_FreeDecodedCert(DecodedCert* cert) } #if defined(HAVE_ED25519) || defined(HAVE_ED448) || defined(HAVE_FALCON) || \ - defined(HAVE_DILITHIUM) || defined(HAVE_SPHINCS) + defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_SLHDSA) /* Store the key data under the BIT_STRING in dynamically allocated data. * * @param [in, out] cert Certificate object. @@ -12465,7 +12750,7 @@ int wc_EccPublicKeyDerSize(ecc_key* key, int with_AlgCurve) #ifdef WOLFSSL_ASN_TEMPLATE #if defined(WC_ENABLE_ASYM_KEY_EXPORT) || defined(WC_ENABLE_ASYM_KEY_IMPORT) /* ASN.1 template for the SubjectPublicKeyInfo of a general asymmetric key. - * Used with Ed448/Ed25519, Curve448/Curve25519, SPHINCS+, falcon, dilithium, + * Used with Ed448/Ed25519, Curve448/Curve25519, SLH-DSA, falcon, dilithium, * etc. * * X.509: RFC 5280, 4.1 - SubjectPublicKeyInfo @@ -13070,32 +13355,23 @@ static int GetCertKey(DecodedCert* cert, const byte* source, word32* inOutIdx, ret = StoreKey(cert, source, &srcIdx, maxIdx); break; #endif /* HAVE_DILITHIUM */ - #ifdef HAVE_SPHINCS - case SPHINCS_FAST_LEVEL1k: - cert->pkCurveOID = SPHINCS_FAST_LEVEL1k; + #ifdef WOLFSSL_HAVE_SLHDSA + case SLH_DSA_SHAKE_128Fk: + case SLH_DSA_SHAKE_192Fk: + case SLH_DSA_SHAKE_256Fk: + case SLH_DSA_SHAKE_128Sk: + case SLH_DSA_SHAKE_192Sk: + case SLH_DSA_SHAKE_256Sk: + case SLH_DSA_SHA2_128Fk: + case SLH_DSA_SHA2_192Fk: + case SLH_DSA_SHA2_256Fk: + case SLH_DSA_SHA2_128Sk: + case SLH_DSA_SHA2_192Sk: + case SLH_DSA_SHA2_256Sk: + cert->pkCurveOID = cert->keyOID; ret = StoreKey(cert, source, &srcIdx, maxIdx); break; - case SPHINCS_FAST_LEVEL3k: - cert->pkCurveOID = SPHINCS_FAST_LEVEL3k; - ret = StoreKey(cert, source, &srcIdx, maxIdx); - break; - case SPHINCS_FAST_LEVEL5k: - cert->pkCurveOID = SPHINCS_FAST_LEVEL5k; - ret = StoreKey(cert, source, &srcIdx, maxIdx); - break; - case SPHINCS_SMALL_LEVEL1k: - cert->pkCurveOID = SPHINCS_SMALL_LEVEL1k; - ret = StoreKey(cert, source, &srcIdx, maxIdx); - break; - case SPHINCS_SMALL_LEVEL3k: - cert->pkCurveOID = SPHINCS_SMALL_LEVEL3k; - ret = StoreKey(cert, source, &srcIdx, maxIdx); - break; - case SPHINCS_SMALL_LEVEL5k: - cert->pkCurveOID = SPHINCS_SMALL_LEVEL5k; - ret = StoreKey(cert, source, &srcIdx, maxIdx); - break; - #endif /* HAVE_SPHINCS */ + #endif /* WOLFSSL_HAVE_SLHDSA */ #ifndef NO_DSA case DSAk: cert->publicKey = source + pubIdx; @@ -15559,13 +15835,19 @@ static WC_INLINE int IsSigAlgoECC(word32 algoOID) || (algoOID == ML_DSA_LEVEL3k) || (algoOID == ML_DSA_LEVEL5k) #endif - #ifdef HAVE_SPHINCS - || (algoOID == SPHINCS_FAST_LEVEL1k) - || (algoOID == SPHINCS_FAST_LEVEL3k) - || (algoOID == SPHINCS_FAST_LEVEL5k) - || (algoOID == SPHINCS_SMALL_LEVEL1k) - || (algoOID == SPHINCS_SMALL_LEVEL3k) - || (algoOID == SPHINCS_SMALL_LEVEL5k) + #ifdef WOLFSSL_HAVE_SLHDSA + || (algoOID == SLH_DSA_SHAKE_128Fk) + || (algoOID == SLH_DSA_SHAKE_192Fk) + || (algoOID == SLH_DSA_SHAKE_256Fk) + || (algoOID == SLH_DSA_SHAKE_128Sk) + || (algoOID == SLH_DSA_SHAKE_192Sk) + || (algoOID == SLH_DSA_SHAKE_256Sk) + || (algoOID == SLH_DSA_SHA2_128Fk) + || (algoOID == SLH_DSA_SHA2_192Fk) + || (algoOID == SLH_DSA_SHA2_256Fk) + || (algoOID == SLH_DSA_SHA2_128Sk) + || (algoOID == SLH_DSA_SHA2_192Sk) + || (algoOID == SLH_DSA_SHA2_256Sk) #endif ); } @@ -15900,20 +16182,28 @@ void FreeSignatureCtx(SignatureCtx* sigCtx) #endif break; #endif /* HAVE_DILITHIUM */ - #if defined(HAVE_SPHINCS) - case SPHINCS_FAST_LEVEL1k: - case SPHINCS_FAST_LEVEL3k: - case SPHINCS_FAST_LEVEL5k: - case SPHINCS_SMALL_LEVEL1k: - case SPHINCS_SMALL_LEVEL3k: - case SPHINCS_SMALL_LEVEL5k: - wc_sphincs_free(sigCtx->key.sphincs); + #if defined(WOLFSSL_HAVE_SLHDSA) + case SLH_DSA_SHAKE_128Fk: + case SLH_DSA_SHAKE_192Fk: + case SLH_DSA_SHAKE_256Fk: + case SLH_DSA_SHAKE_128Sk: + case SLH_DSA_SHAKE_192Sk: + case SLH_DSA_SHAKE_256Sk: + #ifdef WOLFSSL_SLHDSA_SHA2 + case SLH_DSA_SHA2_128Fk: + case SLH_DSA_SHA2_192Fk: + case SLH_DSA_SHA2_256Fk: + case SLH_DSA_SHA2_128Sk: + case SLH_DSA_SHA2_192Sk: + case SLH_DSA_SHA2_256Sk: + #endif + wc_SlhDsaKey_Free(sigCtx->key.slhdsa); #ifndef WOLFSSL_NO_MALLOC - XFREE(sigCtx->key.sphincs, sigCtx->heap, DYNAMIC_TYPE_SPHINCS); - sigCtx->key.sphincs = NULL; + XFREE(sigCtx->key.slhdsa, sigCtx->heap, DYNAMIC_TYPE_SLHDSA); + sigCtx->key.slhdsa = NULL; #endif break; - #endif /* HAVE_SPHINCS */ + #endif /* WOLFSSL_HAVE_SLHDSA */ default: break; } /* switch (keyOID) */ @@ -16096,13 +16386,19 @@ static int HashForSignature(const byte* buf, word32 bufSz, word32 sigOID, /* Hashes done in signing operation. */ break; #endif - #ifdef HAVE_SPHINCS - case CTC_SPHINCS_FAST_LEVEL1: - case CTC_SPHINCS_FAST_LEVEL3: - case CTC_SPHINCS_FAST_LEVEL5: - case CTC_SPHINCS_SMALL_LEVEL1: - case CTC_SPHINCS_SMALL_LEVEL3: - case CTC_SPHINCS_SMALL_LEVEL5: + #ifdef WOLFSSL_HAVE_SLHDSA + case CTC_SLH_DSA_SHA2_128S: + case CTC_SLH_DSA_SHA2_128F: + case CTC_SLH_DSA_SHA2_192S: + case CTC_SLH_DSA_SHA2_192F: + case CTC_SLH_DSA_SHA2_256S: + case CTC_SLH_DSA_SHA2_256F: + case CTC_SLH_DSA_SHAKE_128S: + case CTC_SLH_DSA_SHAKE_128F: + case CTC_SLH_DSA_SHAKE_192S: + case CTC_SLH_DSA_SHAKE_192F: + case CTC_SLH_DSA_SHAKE_256S: + case CTC_SLH_DSA_SHAKE_256F: /* Hashes done in signing operation. */ break; #endif @@ -16277,19 +16573,31 @@ static int SigOidMatchesKeyOid(word32 sigOID, word32 keyOID) case ML_DSA_LEVEL5k: return (sigOID == CTC_ML_DSA_LEVEL5); #endif - #if defined(HAVE_SPHINCS) - case SPHINCS_FAST_LEVEL1k: - return (sigOID == CTC_SPHINCS_FAST_LEVEL1); - case SPHINCS_FAST_LEVEL3k: - return (sigOID == CTC_SPHINCS_FAST_LEVEL3); - case SPHINCS_FAST_LEVEL5k: - return (sigOID == CTC_SPHINCS_FAST_LEVEL5); - case SPHINCS_SMALL_LEVEL1k: - return (sigOID == CTC_SPHINCS_SMALL_LEVEL1); - case SPHINCS_SMALL_LEVEL3k: - return (sigOID == CTC_SPHINCS_SMALL_LEVEL3); - case SPHINCS_SMALL_LEVEL5k: - return (sigOID == CTC_SPHINCS_SMALL_LEVEL5); + #if defined(WOLFSSL_HAVE_SLHDSA) + case SLH_DSA_SHAKE_128Fk: + return (sigOID == CTC_SLH_DSA_SHAKE_128F); + case SLH_DSA_SHAKE_192Fk: + return (sigOID == CTC_SLH_DSA_SHAKE_192F); + case SLH_DSA_SHAKE_256Fk: + return (sigOID == CTC_SLH_DSA_SHAKE_256F); + case SLH_DSA_SHAKE_128Sk: + return (sigOID == CTC_SLH_DSA_SHAKE_128S); + case SLH_DSA_SHAKE_192Sk: + return (sigOID == CTC_SLH_DSA_SHAKE_192S); + case SLH_DSA_SHAKE_256Sk: + return (sigOID == CTC_SLH_DSA_SHAKE_256S); + case SLH_DSA_SHA2_128Fk: + return (sigOID == CTC_SLH_DSA_SHA2_128F); + case SLH_DSA_SHA2_192Fk: + return (sigOID == CTC_SLH_DSA_SHA2_192F); + case SLH_DSA_SHA2_256Fk: + return (sigOID == CTC_SLH_DSA_SHA2_256F); + case SLH_DSA_SHA2_128Sk: + return (sigOID == CTC_SLH_DSA_SHA2_128S); + case SLH_DSA_SHA2_192Sk: + return (sigOID == CTC_SLH_DSA_SHA2_192S); + case SLH_DSA_SHA2_256Sk: + return (sigOID == CTC_SLH_DSA_SHA2_256S); #endif } @@ -16746,177 +17054,79 @@ int ConfirmSignature(SignatureCtx* sigCtx, break; } #endif /* HAVE_DILITHIUM */ - #if defined(HAVE_SPHINCS) - case SPHINCS_FAST_LEVEL1k: + #if defined(WOLFSSL_HAVE_SLHDSA) + #ifndef WOLFSSL_SLHDSA_SHA2 + /* SHA-2 OIDs recognised but backend not built; emit a + * specific NOT_COMPILED_IN so callers can render a + * "variant unavailable" diagnostic instead of the + * generic ASN_UNKNOWN_OID_E for "malformed DER". */ + case SLH_DSA_SHA2_128Fk: + case SLH_DSA_SHA2_192Fk: + case SLH_DSA_SHA2_256Fk: + case SLH_DSA_SHA2_128Sk: + case SLH_DSA_SHA2_192Sk: + case SLH_DSA_SHA2_256Sk: + WOLFSSL_MSG("SHA2-SLH-DSA recognised but not compiled in"); + ERROR_OUT(NOT_COMPILED_IN, exit_cs); + #else + case SLH_DSA_SHA2_128Fk: + case SLH_DSA_SHA2_192Fk: + case SLH_DSA_SHA2_256Fk: + case SLH_DSA_SHA2_128Sk: + case SLH_DSA_SHA2_192Sk: + case SLH_DSA_SHA2_256Sk: + #endif + case SLH_DSA_SHAKE_128Fk: + case SLH_DSA_SHAKE_192Fk: + case SLH_DSA_SHAKE_256Fk: + case SLH_DSA_SHAKE_128Sk: + case SLH_DSA_SHAKE_192Sk: + case SLH_DSA_SHAKE_256Sk: { - word32 idx = 0; + int slhDsaParam = wc_SlhDsaOidToParam(keyOID); sigCtx->verify = 0; - #ifndef WOLFSSL_NO_MALLOC - sigCtx->key.sphincs = - (sphincs_key*)XMALLOC(sizeof(sphincs_key), - sigCtx->heap, - DYNAMIC_TYPE_SPHINCS); - if (sigCtx->key.sphincs == NULL) { - ERROR_OUT(MEMORY_E, exit_cs); - } - #endif - if ((ret = wc_sphincs_init(sigCtx->key.sphincs)) < 0) { - goto exit_cs; + /* Mirror PrivateKeyDecode/PublicKeyDecode: a recognised + * SLH-DSA OID with a per-variant disable returns + * NOT_COMPILED_IN; pass it through so callers can render + * a "variant unavailable" diagnostic instead of the + * malformed-DER ASN_UNKNOWN_OID_E. */ + if (slhDsaParam == WC_NO_ERR_TRACE(NOT_COMPILED_IN)) { + WOLFSSL_MSG("SLH-DSA variant not compiled in"); + ERROR_OUT(NOT_COMPILED_IN, exit_cs); } - if ((ret = wc_sphincs_set_level_and_optim( - sigCtx->key.sphincs, 1, FAST_VARIANT)) - < 0) { - goto exit_cs; + if (slhDsaParam < 0) { + ERROR_OUT(ASN_UNKNOWN_OID_E, exit_cs); } - if ((ret = wc_Sphincs_PublicKeyDecode(key, &idx, - sigCtx->key.sphincs, keySz)) < 0) { - WOLFSSL_MSG("ASN Key import err: Sphincs-fast Level1"); - goto exit_cs; - } - break; - } - case SPHINCS_FAST_LEVEL3k: - { - word32 idx = 0; - sigCtx->verify = 0; + #ifndef WOLFSSL_NO_MALLOC - sigCtx->key.sphincs = - (sphincs_key*)XMALLOC(sizeof(sphincs_key), + sigCtx->key.slhdsa = + (SlhDsaKey*)XMALLOC(sizeof(SlhDsaKey), sigCtx->heap, - DYNAMIC_TYPE_SPHINCS); - if (sigCtx->key.sphincs == NULL) { + DYNAMIC_TYPE_SLHDSA); + if (sigCtx->key.slhdsa == NULL) { ERROR_OUT(MEMORY_E, exit_cs); } #endif - if ((ret = wc_sphincs_init(sigCtx->key.sphincs)) < 0) { + if ((ret = wc_SlhDsaKey_Init(sigCtx->key.slhdsa, + (enum SlhDsaParam)slhDsaParam, + NULL, INVALID_DEVID)) < 0) { + WOLFSSL_MSG("ASN Key init err: SLH-DSA"); goto exit_cs; } - if ((ret = wc_sphincs_set_level_and_optim( - sigCtx->key.sphincs, 3, FAST_VARIANT)) - < 0) { - goto exit_cs; - } - if ((ret = wc_Sphincs_PublicKeyDecode(key, &idx, - sigCtx->key.sphincs, keySz)) < 0) { - WOLFSSL_MSG("ASN Key import err: Sphincs-fast Level3"); + /* StoreKey() stashes the BIT STRING contents (raw + * public-key bytes) in cert->publicKey, not the + * SPKI envelope. Use ImportPublic which accepts + * raw bytes; _PublicKeyDecode would expect an SPKI + * SEQUENCE and fail with ASN_PARSE_E. */ + if ((ret = wc_SlhDsaKey_ImportPublic(sigCtx->key.slhdsa, + key, keySz)) < 0) { + WOLFSSL_MSG("ASN Key import err: SLH-DSA"); goto exit_cs; } break; } - case SPHINCS_FAST_LEVEL5k: - { - word32 idx = 0; - sigCtx->verify = 0; - #ifndef WOLFSSL_NO_MALLOC - sigCtx->key.sphincs = - (sphincs_key*)XMALLOC(sizeof(sphincs_key), - sigCtx->heap, - DYNAMIC_TYPE_SPHINCS); - if (sigCtx->key.sphincs == NULL) { - ERROR_OUT(MEMORY_E, exit_cs); - } - #endif - if ((ret = wc_sphincs_init(sigCtx->key.sphincs)) < 0) { - goto exit_cs; - } - if ((ret = wc_sphincs_set_level_and_optim( - sigCtx->key.sphincs, 5, FAST_VARIANT)) - < 0) { - goto exit_cs; - } - if ((ret = wc_Sphincs_PublicKeyDecode(key, &idx, - sigCtx->key.sphincs, keySz)) < 0) { - WOLFSSL_MSG("ASN Key import err: Sphincs-fast Level5"); - goto exit_cs; - } - break; - } - case SPHINCS_SMALL_LEVEL1k: - { - word32 idx = 0; - sigCtx->verify = 0; - #ifndef WOLFSSL_NO_MALLOC - sigCtx->key.sphincs = - (sphincs_key*)XMALLOC(sizeof(sphincs_key), - sigCtx->heap, - DYNAMIC_TYPE_SPHINCS); - if (sigCtx->key.sphincs == NULL) { - ERROR_OUT(MEMORY_E, exit_cs); - } - #endif - if ((ret = wc_sphincs_init(sigCtx->key.sphincs)) < 0) { - goto exit_cs; - } - if ((ret = wc_sphincs_set_level_and_optim( - sigCtx->key.sphincs, 1, SMALL_VARIANT)) - < 0) { - goto exit_cs; - } - if ((ret = wc_Sphincs_PublicKeyDecode(key, &idx, - sigCtx->key.sphincs, keySz)) < 0) { - WOLFSSL_MSG("ASN Key import err: Sphincs-fast Level1"); - goto exit_cs; - } - break; - } - case SPHINCS_SMALL_LEVEL3k: - { - word32 idx = 0; - sigCtx->verify = 0; - #ifndef WOLFSSL_NO_MALLOC - sigCtx->key.sphincs = - (sphincs_key*)XMALLOC(sizeof(sphincs_key), - sigCtx->heap, - DYNAMIC_TYPE_SPHINCS); - if (sigCtx->key.sphincs == NULL) { - ERROR_OUT(MEMORY_E, exit_cs); - } - #endif - if ((ret = wc_sphincs_init(sigCtx->key.sphincs)) < 0) { - goto exit_cs; - } - if ((ret = wc_sphincs_set_level_and_optim( - sigCtx->key.sphincs, 3, SMALL_VARIANT)) - < 0) { - goto exit_cs; - } - if ((ret = wc_Sphincs_PublicKeyDecode(key, &idx, - sigCtx->key.sphincs, keySz)) < 0) { - WOLFSSL_MSG("ASN Key import err: Sphincs-fast Level3"); - goto exit_cs; - } - break; - } - case SPHINCS_SMALL_LEVEL5k: - { - word32 idx = 0; - sigCtx->verify = 0; - #ifndef WOLFSSL_NO_MALLOC - sigCtx->key.sphincs = - (sphincs_key*)XMALLOC(sizeof(sphincs_key), - sigCtx->heap, - DYNAMIC_TYPE_SPHINCS); - if (sigCtx->key.sphincs == NULL) { - ERROR_OUT(MEMORY_E, exit_cs); - } - #endif - if ((ret = wc_sphincs_init(sigCtx->key.sphincs)) < 0) { - goto exit_cs; - } - if ((ret = wc_sphincs_set_level_and_optim( - sigCtx->key.sphincs, 5, SMALL_VARIANT)) - < 0) { - goto exit_cs; - } - if ((ret = wc_Sphincs_PublicKeyDecode(key, &idx, - sigCtx->key.sphincs, keySz)) < 0) { - WOLFSSL_MSG("ASN Key import err: Sphincs-fast Level5"); - goto exit_cs; - } - break; - } - #endif /* HAVE_SPHINCS */ + #endif /* WOLFSSL_HAVE_SLHDSA */ default: WOLFSSL_MSG("Verify Key type unknown"); ret = ASN_UNKNOWN_OID_E; @@ -17104,20 +17314,31 @@ int ConfirmSignature(SignatureCtx* sigCtx, break; } #endif /* HAVE_DILITHIUM */ - #if defined(HAVE_SPHINCS) - case SPHINCS_FAST_LEVEL1k: - case SPHINCS_FAST_LEVEL3k: - case SPHINCS_FAST_LEVEL5k: - case SPHINCS_SMALL_LEVEL1k: - case SPHINCS_SMALL_LEVEL3k: - case SPHINCS_SMALL_LEVEL5k: + #if defined(WOLFSSL_HAVE_SLHDSA) + #ifdef WOLFSSL_SLHDSA_SHA2 + case SLH_DSA_SHA2_128Fk: + case SLH_DSA_SHA2_192Fk: + case SLH_DSA_SHA2_256Fk: + case SLH_DSA_SHA2_128Sk: + case SLH_DSA_SHA2_192Sk: + case SLH_DSA_SHA2_256Sk: + #endif + case SLH_DSA_SHAKE_128Fk: + case SLH_DSA_SHAKE_192Fk: + case SLH_DSA_SHAKE_256Fk: + case SLH_DSA_SHAKE_128Sk: + case SLH_DSA_SHAKE_192Sk: + case SLH_DSA_SHAKE_256Sk: { - ret = wc_sphincs_verify_msg(sig, sigSz, buf, bufSz, - &sigCtx->verify, - sigCtx->key.sphincs); + ret = wc_SlhDsaKey_Verify(sigCtx->key.slhdsa, + NULL, 0, buf, bufSz, + sig, sigSz); + if (ret == 0) { + sigCtx->verify = 1; + } break; } - #endif /* HAVE_SPHINCS */ + #endif /* WOLFSSL_HAVE_SLHDSA */ default: break; } /* switch (keyOID) */ @@ -17314,74 +17535,32 @@ int ConfirmSignature(SignatureCtx* sigCtx, } break; #endif /* HAVE_DILITHIUM */ - #ifdef HAVE_SPHINCS - case SPHINCS_FAST_LEVEL1k: + #ifdef WOLFSSL_HAVE_SLHDSA + #ifdef WOLFSSL_SLHDSA_SHA2 + case SLH_DSA_SHA2_128Fk: + case SLH_DSA_SHA2_192Fk: + case SLH_DSA_SHA2_256Fk: + case SLH_DSA_SHA2_128Sk: + case SLH_DSA_SHA2_192Sk: + case SLH_DSA_SHA2_256Sk: + #endif + case SLH_DSA_SHAKE_128Fk: + case SLH_DSA_SHAKE_192Fk: + case SLH_DSA_SHAKE_256Fk: + case SLH_DSA_SHAKE_128Sk: + case SLH_DSA_SHAKE_192Sk: + case SLH_DSA_SHAKE_256Sk: { if (sigCtx->verify == 1) { ret = 0; } else { - WOLFSSL_MSG("SPHINCS_FAST_LEVEL1 Verify didn't match"); + WOLFSSL_MSG("SLH-DSA Verify didn't match"); ret = ASN_SIG_CONFIRM_E; } break; } - case SPHINCS_FAST_LEVEL3k: - { - if (sigCtx->verify == 1) { - ret = 0; - } - else { - WOLFSSL_MSG("SPHINCS_FAST_LEVEL3 Verify didn't match"); - ret = ASN_SIG_CONFIRM_E; - } - break; - } - case SPHINCS_FAST_LEVEL5k: - { - if (sigCtx->verify == 1) { - ret = 0; - } - else { - WOLFSSL_MSG("SPHINCS_FAST_LEVEL5 Verify didn't match"); - ret = ASN_SIG_CONFIRM_E; - } - break; - } - case SPHINCS_SMALL_LEVEL1k: - { - if (sigCtx->verify == 1) { - ret = 0; - } - else { - WOLFSSL_MSG("SPHINCS_SMALL_LEVEL1 Verify didn't match"); - ret = ASN_SIG_CONFIRM_E; - } - break; - } - case SPHINCS_SMALL_LEVEL3k: - { - if (sigCtx->verify == 1) { - ret = 0; - } - else { - WOLFSSL_MSG("SPHINCS_SMALL_LEVEL3 Verify didn't match"); - ret = ASN_SIG_CONFIRM_E; - } - break; - } - case SPHINCS_SMALL_LEVEL5k: - { - if (sigCtx->verify == 1) { - ret = 0; - } - else { - WOLFSSL_MSG("SPHINCS_SMALL_LEVEL5 Verify didn't match"); - ret = ASN_SIG_CONFIRM_E; - } - break; - } - #endif /* HAVE_SPHINCS */ + #endif /* WOLFSSL_HAVE_SLHDSA */ default: break; } /* switch (keyOID) */ @@ -23347,21 +23526,36 @@ static wcchar END_PUB_KEY = "-----END PUBLIC KEY-----"; static wcchar BEGIN_ML_DSA_LEVEL5_PRIV = "-----BEGIN ML_DSA_LEVEL5 PRIVATE KEY-----"; static wcchar END_ML_DSA_LEVEL5_PRIV = "-----END ML_DSA_LEVEL5 PRIVATE KEY-----"; #endif /* HAVE_DILITHIUM */ -#if defined(HAVE_SPHINCS) - static wcchar BEGIN_SPHINCS_FAST_LEVEL1_PRIV = "-----BEGIN SPHINCS_FAST_LEVEL1 PRIVATE KEY-----"; - static wcchar END_SPHINCS_FAST_LEVEL1_PRIV = "-----END SPHINCS_FAST_LEVEL1 PRIVATE KEY-----"; - static wcchar BEGIN_SPHINCS_FAST_LEVEL3_PRIV = "-----BEGIN SPHINCS_FAST_LEVEL3 PRIVATE KEY-----"; - static wcchar END_SPHINCS_FAST_LEVEL3_PRIV = "-----END SPHINCS_FAST_LEVEL3 PRIVATE KEY-----"; - static wcchar BEGIN_SPHINCS_FAST_LEVEL5_PRIV = "-----BEGIN SPHINCS_FAST_LEVEL5 PRIVATE KEY-----"; - static wcchar END_SPHINCS_FAST_LEVEL5_PRIV = "-----END SPHINCS_FAST_LEVEL5 PRIVATE KEY-----"; +#if defined(WOLFSSL_HAVE_SLHDSA) + static wcchar BEGIN_SLH_DSA_SHAKE_128F_PRIV = "-----BEGIN SLH_DSA_SHAKE_128F PRIVATE KEY-----"; + static wcchar END_SLH_DSA_SHAKE_128F_PRIV = "-----END SLH_DSA_SHAKE_128F PRIVATE KEY-----"; + static wcchar BEGIN_SLH_DSA_SHAKE_192F_PRIV = "-----BEGIN SLH_DSA_SHAKE_192F PRIVATE KEY-----"; + static wcchar END_SLH_DSA_SHAKE_192F_PRIV = "-----END SLH_DSA_SHAKE_192F PRIVATE KEY-----"; + static wcchar BEGIN_SLH_DSA_SHAKE_256F_PRIV = "-----BEGIN SLH_DSA_SHAKE_256F PRIVATE KEY-----"; + static wcchar END_SLH_DSA_SHAKE_256F_PRIV = "-----END SLH_DSA_SHAKE_256F PRIVATE KEY-----"; - static wcchar BEGIN_SPHINCS_SMALL_LEVEL1_PRIV = "-----BEGIN SPHINCS_SMALL_LEVEL1 PRIVATE KEY-----"; - static wcchar END_SPHINCS_SMALL_LEVEL1_PRIV = "-----END SPHINCS_SMALL_LEVEL1 PRIVATE KEY-----"; - static wcchar BEGIN_SPHINCS_SMALL_LEVEL3_PRIV = "-----BEGIN SPHINCS_SMALL_LEVEL3 PRIVATE KEY-----"; - static wcchar END_SPHINCS_SMALL_LEVEL3_PRIV = "-----END SPHINCS_SMALL_LEVEL3 PRIVATE KEY-----"; - static wcchar BEGIN_SPHINCS_SMALL_LEVEL5_PRIV = "-----BEGIN SPHINCS_SMALL_LEVEL5 PRIVATE KEY-----"; - static wcchar END_SPHINCS_SMALL_LEVEL5_PRIV = "-----END SPHINCS_SMALL_LEVEL5 PRIVATE KEY-----"; -#endif /* HAVE_SPHINCS */ + static wcchar BEGIN_SLH_DSA_SHAKE_128S_PRIV = "-----BEGIN SLH_DSA_SHAKE_128S PRIVATE KEY-----"; + static wcchar END_SLH_DSA_SHAKE_128S_PRIV = "-----END SLH_DSA_SHAKE_128S PRIVATE KEY-----"; + static wcchar BEGIN_SLH_DSA_SHAKE_192S_PRIV = "-----BEGIN SLH_DSA_SHAKE_192S PRIVATE KEY-----"; + static wcchar END_SLH_DSA_SHAKE_192S_PRIV = "-----END SLH_DSA_SHAKE_192S PRIVATE KEY-----"; + static wcchar BEGIN_SLH_DSA_SHAKE_256S_PRIV = "-----BEGIN SLH_DSA_SHAKE_256S PRIVATE KEY-----"; + static wcchar END_SLH_DSA_SHAKE_256S_PRIV = "-----END SLH_DSA_SHAKE_256S PRIVATE KEY-----"; +#ifdef WOLFSSL_SLHDSA_SHA2 + static wcchar BEGIN_SLH_DSA_SHA2_128F_PRIV = "-----BEGIN SLH_DSA_SHA2_128F PRIVATE KEY-----"; + static wcchar END_SLH_DSA_SHA2_128F_PRIV = "-----END SLH_DSA_SHA2_128F PRIVATE KEY-----"; + static wcchar BEGIN_SLH_DSA_SHA2_192F_PRIV = "-----BEGIN SLH_DSA_SHA2_192F PRIVATE KEY-----"; + static wcchar END_SLH_DSA_SHA2_192F_PRIV = "-----END SLH_DSA_SHA2_192F PRIVATE KEY-----"; + static wcchar BEGIN_SLH_DSA_SHA2_256F_PRIV = "-----BEGIN SLH_DSA_SHA2_256F PRIVATE KEY-----"; + static wcchar END_SLH_DSA_SHA2_256F_PRIV = "-----END SLH_DSA_SHA2_256F PRIVATE KEY-----"; + + static wcchar BEGIN_SLH_DSA_SHA2_128S_PRIV = "-----BEGIN SLH_DSA_SHA2_128S PRIVATE KEY-----"; + static wcchar END_SLH_DSA_SHA2_128S_PRIV = "-----END SLH_DSA_SHA2_128S PRIVATE KEY-----"; + static wcchar BEGIN_SLH_DSA_SHA2_192S_PRIV = "-----BEGIN SLH_DSA_SHA2_192S PRIVATE KEY-----"; + static wcchar END_SLH_DSA_SHA2_192S_PRIV = "-----END SLH_DSA_SHA2_192S PRIVATE KEY-----"; + static wcchar BEGIN_SLH_DSA_SHA2_256S_PRIV = "-----BEGIN SLH_DSA_SHA2_256S PRIVATE KEY-----"; + static wcchar END_SLH_DSA_SHA2_256S_PRIV = "-----END SLH_DSA_SHA2_256S PRIVATE KEY-----"; +#endif /* WOLFSSL_SLHDSA_SHA2 */ +#endif /* WOLFSSL_HAVE_SLHDSA */ const int pem_struct_min_sz = XSTR_SIZEOF("-----BEGIN X509 CRL-----" "-----END X509 CRL-----"); @@ -23529,38 +23723,70 @@ int wc_PemGetHeaderFooter(int type, const char** header, const char** footer) ret = 0; break; #endif /* HAVE_DILITHIUM */ -#ifdef HAVE_SPHINCS - case SPHINCS_FAST_LEVEL1_TYPE: - if (header) *header = BEGIN_SPHINCS_FAST_LEVEL1_PRIV; - if (footer) *footer = END_SPHINCS_FAST_LEVEL1_PRIV; +#ifdef WOLFSSL_HAVE_SLHDSA + case SLH_DSA_SHAKE_128F_TYPE: + if (header) *header = BEGIN_SLH_DSA_SHAKE_128F_PRIV; + if (footer) *footer = END_SLH_DSA_SHAKE_128F_PRIV; ret = 0; break; - case SPHINCS_FAST_LEVEL3_TYPE: - if (header) *header = BEGIN_SPHINCS_FAST_LEVEL3_PRIV; - if (footer) *footer = END_SPHINCS_FAST_LEVEL3_PRIV; + case SLH_DSA_SHAKE_192F_TYPE: + if (header) *header = BEGIN_SLH_DSA_SHAKE_192F_PRIV; + if (footer) *footer = END_SLH_DSA_SHAKE_192F_PRIV; ret = 0; break; - case SPHINCS_FAST_LEVEL5_TYPE: - if (header) *header = BEGIN_SPHINCS_FAST_LEVEL5_PRIV; - if (footer) *footer = END_SPHINCS_FAST_LEVEL5_PRIV; + case SLH_DSA_SHAKE_256F_TYPE: + if (header) *header = BEGIN_SLH_DSA_SHAKE_256F_PRIV; + if (footer) *footer = END_SLH_DSA_SHAKE_256F_PRIV; ret = 0; break; - case SPHINCS_SMALL_LEVEL1_TYPE: - if (header) *header = BEGIN_SPHINCS_SMALL_LEVEL1_PRIV; - if (footer) *footer = END_SPHINCS_SMALL_LEVEL1_PRIV; + case SLH_DSA_SHAKE_128S_TYPE: + if (header) *header = BEGIN_SLH_DSA_SHAKE_128S_PRIV; + if (footer) *footer = END_SLH_DSA_SHAKE_128S_PRIV; ret = 0; break; - case SPHINCS_SMALL_LEVEL3_TYPE: - if (header) *header = BEGIN_SPHINCS_SMALL_LEVEL3_PRIV; - if (footer) *footer = END_SPHINCS_SMALL_LEVEL3_PRIV; + case SLH_DSA_SHAKE_192S_TYPE: + if (header) *header = BEGIN_SLH_DSA_SHAKE_192S_PRIV; + if (footer) *footer = END_SLH_DSA_SHAKE_192S_PRIV; ret = 0; break; - case SPHINCS_SMALL_LEVEL5_TYPE: - if (header) *header = BEGIN_SPHINCS_SMALL_LEVEL5_PRIV; - if (footer) *footer = END_SPHINCS_SMALL_LEVEL5_PRIV; + case SLH_DSA_SHAKE_256S_TYPE: + if (header) *header = BEGIN_SLH_DSA_SHAKE_256S_PRIV; + if (footer) *footer = END_SLH_DSA_SHAKE_256S_PRIV; ret = 0; break; -#endif /* HAVE_SPHINCS */ + #ifdef WOLFSSL_SLHDSA_SHA2 + case SLH_DSA_SHA2_128F_TYPE: + if (header) *header = BEGIN_SLH_DSA_SHA2_128F_PRIV; + if (footer) *footer = END_SLH_DSA_SHA2_128F_PRIV; + ret = 0; + break; + case SLH_DSA_SHA2_192F_TYPE: + if (header) *header = BEGIN_SLH_DSA_SHA2_192F_PRIV; + if (footer) *footer = END_SLH_DSA_SHA2_192F_PRIV; + ret = 0; + break; + case SLH_DSA_SHA2_256F_TYPE: + if (header) *header = BEGIN_SLH_DSA_SHA2_256F_PRIV; + if (footer) *footer = END_SLH_DSA_SHA2_256F_PRIV; + ret = 0; + break; + case SLH_DSA_SHA2_128S_TYPE: + if (header) *header = BEGIN_SLH_DSA_SHA2_128S_PRIV; + if (footer) *footer = END_SLH_DSA_SHA2_128S_PRIV; + ret = 0; + break; + case SLH_DSA_SHA2_192S_TYPE: + if (header) *header = BEGIN_SLH_DSA_SHA2_192S_PRIV; + if (footer) *footer = END_SLH_DSA_SHA2_192S_PRIV; + ret = 0; + break; + case SLH_DSA_SHA2_256S_TYPE: + if (header) *header = BEGIN_SLH_DSA_SHA2_256S_PRIV; + if (footer) *footer = END_SLH_DSA_SHA2_256S_PRIV; + ret = 0; + break; + #endif /* WOLFSSL_SLHDSA_SHA2 */ +#endif /* WOLFSSL_HAVE_SLHDSA */ case PUBLICKEY_TYPE: case ECC_PUBLICKEY_TYPE: if (header) *header = BEGIN_PUB_KEY; @@ -26407,7 +26633,7 @@ static int EncodePublicKey(int keyType, byte* output, int outLen, RsaKey* rsaKey, ecc_key* eccKey, ed25519_key* ed25519Key, ed448_key* ed448Key, DsaKey* dsaKey, falcon_key* falconKey, - dilithium_key* dilithiumKey, sphincs_key* sphincsKey) + dilithium_key* dilithiumKey, SlhDsaKey* slhDsaKey) { int ret = 0; @@ -26419,7 +26645,7 @@ static int EncodePublicKey(int keyType, byte* output, int outLen, (void)dsaKey; (void)falconKey; (void)dilithiumKey; - (void)sphincsKey; + (void)slhDsaKey; switch (keyType) { #ifndef NO_RSA @@ -26481,20 +26707,28 @@ static int EncodePublicKey(int keyType, byte* output, int outLen, } break; #endif /* HAVE_DILITHIUM */ - #if defined(HAVE_SPHINCS) - case SPHINCS_FAST_LEVEL1_KEY: - case SPHINCS_FAST_LEVEL3_KEY: - case SPHINCS_FAST_LEVEL5_KEY: - case SPHINCS_SMALL_LEVEL1_KEY: - case SPHINCS_SMALL_LEVEL3_KEY: - case SPHINCS_SMALL_LEVEL5_KEY: - ret = wc_Sphincs_PublicKeyToDer(sphincsKey, output, + #if defined(WOLFSSL_HAVE_SLHDSA) + case SLH_DSA_SHAKE_128F_KEY: + case SLH_DSA_SHAKE_192F_KEY: + case SLH_DSA_SHAKE_256F_KEY: + case SLH_DSA_SHAKE_128S_KEY: + case SLH_DSA_SHAKE_192S_KEY: + case SLH_DSA_SHAKE_256S_KEY: + #ifdef WOLFSSL_SLHDSA_SHA2 + case SLH_DSA_SHA2_128F_KEY: + case SLH_DSA_SHA2_192F_KEY: + case SLH_DSA_SHA2_256F_KEY: + case SLH_DSA_SHA2_128S_KEY: + case SLH_DSA_SHA2_192S_KEY: + case SLH_DSA_SHA2_256S_KEY: + #endif + ret = wc_SlhDsaKey_PublicKeyToDer(slhDsaKey, output, (word32)outLen, 1); if (ret <= 0) { ret = PUBLIC_KEY_E; } break; - #endif /* HAVE_SPHINCS */ + #endif /* WOLFSSL_HAVE_SLHDSA */ default: ret = PUBLIC_KEY_E; break; @@ -27268,16 +27502,13 @@ static int InternalSignCb(const byte* in, word32 inLen, } else #endif /* HAVE_DILITHIUM && !WOLFSSL_DILITHIUM_NO_SIGN */ -#if defined(HAVE_SPHINCS) - if ((keyType == SPHINCS_FAST_LEVEL1_TYPE || keyType == SPHINCS_FAST_LEVEL3_TYPE || - keyType == SPHINCS_FAST_LEVEL5_TYPE || keyType == SPHINCS_SMALL_LEVEL1_TYPE || - keyType == SPHINCS_SMALL_LEVEL3_TYPE || keyType == SPHINCS_SMALL_LEVEL5_TYPE) && - signCtx->key) { - /* Sphincs signs messages, not hashes - cannot use callback path */ +#if defined(WOLFSSL_HAVE_SLHDSA) + if (IsSlhDsaKeyType(keyType) && signCtx->key) { + /* SLH-DSA signs messages, not hashes - cannot use callback path */ ret = SIG_TYPE_E; } else -#endif /* HAVE_SPHINCS */ +#endif /* WOLFSSL_HAVE_SLHDSA */ { /* Unhandled key type */ (void)in; @@ -27300,7 +27531,7 @@ static int InternalSignCb(const byte* in, word32 inLen, static int MakeSignature(CertSignCtx* certSignCtx, const byte* buf, word32 sz, byte* sig, word32 sigSz, RsaKey* rsaKey, ecc_key* eccKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, - dilithium_key* dilithiumKey, sphincs_key* sphincsKey, WC_RNG* rng, + dilithium_key* dilithiumKey, SlhDsaKey* slhDsaKey, WC_RNG* rng, word32 sigAlgoType, void* heap) { int ret = 0; @@ -27313,7 +27544,7 @@ static int MakeSignature(CertSignCtx* certSignCtx, const byte* buf, word32 sz, (void)ed448Key; (void)falconKey; (void)dilithiumKey; - (void)sphincsKey; + (void)slhDsaKey; (void)rng; (void)heap; @@ -27398,14 +27629,14 @@ static int MakeSignature(CertSignCtx* certSignCtx, const byte* buf, word32 sz, } #endif /* HAVE_DILITHIUM && !WOLFSSL_DILITHIUM_NO_SIGN */ -#if defined(HAVE_SPHINCS) - if (sphincsKey) { +#if defined(WOLFSSL_HAVE_SLHDSA) && !defined(WOLFSSL_SLHDSA_VERIFY_ONLY) + if (slhDsaKey) { word32 outSz = sigSz; - ret = wc_sphincs_sign_msg(buf, sz, sig, &outSz, sphincsKey, rng); + ret = wc_SlhDsaKey_Sign(slhDsaKey, NULL, 0, buf, sz, sig, &outSz, rng); if (ret == 0) ret = outSz; } -#endif /* HAVE_SPHINCS */ +#endif /* WOLFSSL_HAVE_SLHDSA && !WOLFSSL_SLHDSA_VERIFY_ONLY */ if (ret == -1) ret = ALGO_ID_E; @@ -27554,7 +27785,7 @@ static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey, ecc_key* eccKey, WC_RNG* rng, DsaKey* dsaKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, - dilithium_key* dilithiumKey, sphincs_key* sphincsKey) + dilithium_key* dilithiumKey, SlhDsaKey* slhDsaKey) { /* TODO: issRaw and sbjRaw should be NUL terminated. */ DECL_ASNSETDATA(dataASN, x509CertASN_Length); @@ -27567,10 +27798,10 @@ static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, word32 issRawLen = 0; word32 sbjRawLen = 0; - /* Unused without OQS */ + /* Unused without PQC */ (void)falconKey; (void)dilithiumKey; - (void)sphincsKey; + (void)slhDsaKey; CALLOC_ASNSETDATA(dataASN, x509CertASN_Length, ret, cert->heap); @@ -27627,32 +27858,17 @@ static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, cert->keyType = ML_DSA_LEVEL5_KEY; } #endif /* HAVE_DILITHIUM */ -#ifdef HAVE_SPHINCS - else if ((sphincsKey != NULL) && (sphincsKey->level == 1) - && (sphincsKey->optim == FAST_VARIANT)) { - cert->keyType = SPHINCS_FAST_LEVEL1_KEY; +#ifdef WOLFSSL_HAVE_SLHDSA + else if ((slhDsaKey != NULL) && (slhDsaKey->params != NULL)) { + int slhdsaKt = SlhDsaParamToKeyType(slhDsaKey->params->param); + if (slhdsaKt != 0) { + cert->keyType = slhdsaKt; + } + else { + ret = BAD_FUNC_ARG; + } } - else if ((sphincsKey != NULL) && (sphincsKey->level == 3) - && (sphincsKey->optim == FAST_VARIANT)) { - cert->keyType = SPHINCS_FAST_LEVEL3_KEY; - } - else if ((sphincsKey != NULL) && (sphincsKey->level == 5) - && (sphincsKey->optim == FAST_VARIANT)) { - cert->keyType = SPHINCS_FAST_LEVEL5_KEY; - } - else if ((sphincsKey != NULL) && (sphincsKey->level == 1) - && (sphincsKey->optim == SMALL_VARIANT)) { - cert->keyType = SPHINCS_SMALL_LEVEL1_KEY; - } - else if ((sphincsKey != NULL) && (sphincsKey->level == 3) - && (sphincsKey->optim == SMALL_VARIANT)) { - cert->keyType = SPHINCS_SMALL_LEVEL3_KEY; - } - else if ((sphincsKey != NULL) && (sphincsKey->level == 5) - && (sphincsKey->optim == SMALL_VARIANT)) { - cert->keyType = SPHINCS_SMALL_LEVEL5_KEY; - } -#endif /* HAVE_SPHINCS */ +#endif /* WOLFSSL_HAVE_SLHDSA */ else { ret = BAD_FUNC_ARG; } @@ -27701,7 +27917,7 @@ static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, /* Calculate public key encoding size. */ ret = EncodePublicKey(cert->keyType, NULL, 0, rsaKey, eccKey, ed25519Key, ed448Key, dsaKey, falconKey, - dilithiumKey, sphincsKey); + dilithiumKey, slhDsaKey); publicKeySz = (word32)ret; } if (ret >= 0) { @@ -27888,7 +28104,7 @@ static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, (int)dataASN[X509CERTASN_IDX_TBS_SPUBKEYINFO_SEQ] .data.buffer.length, rsaKey, eccKey, ed25519Key, ed448Key, dsaKey, - falconKey, dilithiumKey, sphincsKey); + falconKey, dilithiumKey, slhDsaKey); } if ((ret >= 0) && (!dataASN[X509CERTASN_IDX_TBS_EXT_SEQ].noOut)) { /* Encode extensions into buffer. */ @@ -27932,7 +28148,7 @@ int wc_MakeCert_ex(Cert* cert, byte* derBuffer, word32 derSz, int keyType, ed448_key* ed448Key = NULL; falcon_key* falconKey = NULL; dilithium_key* dilithiumKey = NULL; - sphincs_key* sphincsKey = NULL; + SlhDsaKey* slhDsaKey = NULL; if (keyType == RSA_TYPE) rsaKey = (RsaKey*)key; @@ -27962,22 +28178,14 @@ int wc_MakeCert_ex(Cert* cert, byte* derBuffer, word32 derSz, int keyType, dilithiumKey = (dilithium_key*)key; else if (keyType == ML_DSA_LEVEL5_TYPE) dilithiumKey = (dilithium_key*)key; - else if (keyType == SPHINCS_FAST_LEVEL1_TYPE) - sphincsKey = (sphincs_key*)key; - else if (keyType == SPHINCS_FAST_LEVEL3_TYPE) - sphincsKey = (sphincs_key*)key; - else if (keyType == SPHINCS_FAST_LEVEL5_TYPE) - sphincsKey = (sphincs_key*)key; - else if (keyType == SPHINCS_SMALL_LEVEL1_TYPE) - sphincsKey = (sphincs_key*)key; - else if (keyType == SPHINCS_SMALL_LEVEL3_TYPE) - sphincsKey = (sphincs_key*)key; - else if (keyType == SPHINCS_SMALL_LEVEL5_TYPE) - sphincsKey = (sphincs_key*)key; +#ifdef WOLFSSL_HAVE_SLHDSA + else if (IsSlhDsaKeyType(keyType)) + slhDsaKey = (SlhDsaKey*)key; +#endif return MakeAnyCert(cert, derBuffer, derSz, rsaKey, eccKey, rng, dsaKey, ed25519Key, ed448Key, falconKey, dilithiumKey, - sphincsKey); + slhDsaKey); } /* Make an x509 Certificate v3 RSA or ECC from cert input, write to buffer */ @@ -28054,7 +28262,7 @@ static int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey, DsaKey* dsaKey, ecc_key* eccKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, dilithium_key* dilithiumKey, - sphincs_key* sphincsKey) + SlhDsaKey* slhDsaKey) { DECL_ASNSETDATA(dataASN, certReqBodyASN_Length); word32 publicKeySz = 0; @@ -28066,10 +28274,10 @@ static int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, word32 sbjRawSz = 0; #endif - /* Unused without OQS */ + /* Unused without PQC */ (void)falconKey; (void)dilithiumKey; - (void)sphincsKey; + (void)slhDsaKey; CALLOC_ASNSETDATA(dataASN, certReqBodyASN_Length, ret, cert->heap); @@ -28126,32 +28334,17 @@ static int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, cert->keyType = ML_DSA_LEVEL5_KEY; } #endif /* HAVE_DILITHIUM */ -#ifdef HAVE_SPHINCS - else if ((sphincsKey != NULL) && (sphincsKey->level == 1) - && (sphincsKey->optim == FAST_VARIANT)) { - cert->keyType = SPHINCS_FAST_LEVEL1_KEY; +#ifdef WOLFSSL_HAVE_SLHDSA + else if ((slhDsaKey != NULL) && (slhDsaKey->params != NULL)) { + int slhdsaKt = SlhDsaParamToKeyType(slhDsaKey->params->param); + if (slhdsaKt != 0) { + cert->keyType = slhdsaKt; + } + else { + ret = BAD_FUNC_ARG; + } } - else if ((sphincsKey != NULL) && (sphincsKey->level == 3) - && (sphincsKey->optim == FAST_VARIANT)) { - cert->keyType = SPHINCS_FAST_LEVEL3_KEY; - } - else if ((sphincsKey != NULL) && (sphincsKey->level == 5) - && (sphincsKey->optim == FAST_VARIANT)) { - cert->keyType = SPHINCS_FAST_LEVEL5_KEY; - } - else if ((sphincsKey != NULL) && (sphincsKey->level == 1) - && (sphincsKey->optim == SMALL_VARIANT)) { - cert->keyType = SPHINCS_SMALL_LEVEL1_KEY; - } - else if ((sphincsKey != NULL) && (sphincsKey->level == 3) - && (sphincsKey->optim == SMALL_VARIANT)) { - cert->keyType = SPHINCS_SMALL_LEVEL3_KEY; - } - else if ((sphincsKey != NULL) && (sphincsKey->level == 5) - && (sphincsKey->optim == SMALL_VARIANT)) { - cert->keyType = SPHINCS_SMALL_LEVEL5_KEY; - } -#endif /* HAVE_SPHINCS */ +#endif /* WOLFSSL_HAVE_SLHDSA */ else { ret = BAD_FUNC_ARG; } @@ -28174,7 +28367,7 @@ static int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, /* Determine encode public key size. */ ret = EncodePublicKey(cert->keyType, NULL, 0, rsaKey, eccKey, ed25519Key, ed448Key, dsaKey, falconKey, - dilithiumKey, sphincsKey); + dilithiumKey, slhDsaKey); publicKeySz = (word32)ret; } if (ret >= 0) { @@ -28294,7 +28487,7 @@ static int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, dataASN[CERTREQBODYASN_IDX_SPUBKEYINFO_SEQ].data.buffer.data, (int)dataASN[CERTREQBODYASN_IDX_SPUBKEYINFO_SEQ].data.buffer.length, rsaKey, eccKey, ed25519Key, ed448Key, dsaKey, falconKey, - dilithiumKey, sphincsKey); + dilithiumKey, slhDsaKey); } if ((ret >= 0 && derBuffer != NULL) && (!dataASN[CERTREQBODYASN_IDX_EXT_BODY].noOut)) { @@ -28327,7 +28520,7 @@ int wc_MakeCertReq_ex(Cert* cert, byte* derBuffer, word32 derSz, int keyType, ed448_key* ed448Key = NULL; falcon_key* falconKey = NULL; dilithium_key* dilithiumKey = NULL; - sphincs_key* sphincsKey = NULL; + SlhDsaKey* slhDsaKey = NULL; if (keyType == RSA_TYPE) rsaKey = (RsaKey*)key; @@ -28357,22 +28550,14 @@ int wc_MakeCertReq_ex(Cert* cert, byte* derBuffer, word32 derSz, int keyType, dilithiumKey = (dilithium_key*)key; else if (keyType == ML_DSA_LEVEL5_TYPE) dilithiumKey = (dilithium_key*)key; - else if (keyType == SPHINCS_FAST_LEVEL1_TYPE) - sphincsKey = (sphincs_key*)key; - else if (keyType == SPHINCS_FAST_LEVEL3_TYPE) - sphincsKey = (sphincs_key*)key; - else if (keyType == SPHINCS_FAST_LEVEL5_TYPE) - sphincsKey = (sphincs_key*)key; - else if (keyType == SPHINCS_SMALL_LEVEL1_TYPE) - sphincsKey = (sphincs_key*)key; - else if (keyType == SPHINCS_SMALL_LEVEL3_TYPE) - sphincsKey = (sphincs_key*)key; - else if (keyType == SPHINCS_SMALL_LEVEL5_TYPE) - sphincsKey = (sphincs_key*)key; +#ifdef WOLFSSL_HAVE_SLHDSA + else if (IsSlhDsaKeyType(keyType)) + slhDsaKey = (SlhDsaKey*)key; +#endif return MakeCertReq(cert, derBuffer, derSz, rsaKey, dsaKey, eccKey, ed25519Key, ed448Key, falconKey, dilithiumKey, - sphincsKey); + slhDsaKey); } WOLFSSL_ABI @@ -28526,7 +28711,7 @@ exit_ms: static int SignCert(int requestSz, int sType, byte* buf, word32 buffSz, RsaKey* rsaKey, ecc_key* eccKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, - dilithium_key* dilithiumKey, sphincs_key* sphincsKey, + dilithium_key* dilithiumKey, SlhDsaKey* slhDsaKey, WC_RNG* rng) { int sigSz = 0; @@ -28572,7 +28757,7 @@ static int SignCert(int requestSz, int sType, byte* buf, word32 buffSz, sigSz = MakeSignature(certSignCtx, buf, (word32)requestSz, certSignCtx->sig, MAX_ENCODED_SIG_SZ, rsaKey, eccKey, ed25519Key, ed448Key, - falconKey, dilithiumKey, sphincsKey, rng, (word32)sType, heap); + falconKey, dilithiumKey, slhDsaKey, rng, (word32)sType, heap); #ifdef WOLFSSL_ASYNC_CRYPT if (sigSz == WC_NO_ERR_TRACE(WC_PENDING_E)) { /* Not free'ing certSignCtx->sig here because it could still be in use @@ -28622,7 +28807,7 @@ int wc_MakeSigWithBitStr(byte *sig, int sigSz, int sType, byte* buf, ed448_key* ed448Key = NULL; falcon_key* falconKey = NULL; dilithium_key* dilithiumKey = NULL; - sphincs_key* sphincsKey = NULL; + SlhDsaKey* slhDsaKey = NULL; int ret = 0; int headerSz; void* heap = NULL; @@ -28665,13 +28850,21 @@ int wc_MakeSigWithBitStr(byte *sig, int sigSz, int sType, byte* buf, case ML_DSA_LEVEL5_TYPE: dilithiumKey = (dilithium_key*)key; break; - case SPHINCS_FAST_LEVEL1_TYPE: - case SPHINCS_FAST_LEVEL3_TYPE: - case SPHINCS_FAST_LEVEL5_TYPE: - case SPHINCS_SMALL_LEVEL1_TYPE: - case SPHINCS_SMALL_LEVEL3_TYPE: - case SPHINCS_SMALL_LEVEL5_TYPE: - sphincsKey = (sphincs_key*)key; + case SLH_DSA_SHAKE_128F_TYPE: + case SLH_DSA_SHAKE_192F_TYPE: + case SLH_DSA_SHAKE_256F_TYPE: + case SLH_DSA_SHAKE_128S_TYPE: + case SLH_DSA_SHAKE_192S_TYPE: + case SLH_DSA_SHAKE_256S_TYPE: + #ifdef WOLFSSL_SLHDSA_SHA2 + case SLH_DSA_SHA2_128F_TYPE: + case SLH_DSA_SHA2_192F_TYPE: + case SLH_DSA_SHA2_256F_TYPE: + case SLH_DSA_SHA2_128S_TYPE: + case SLH_DSA_SHA2_192S_TYPE: + case SLH_DSA_SHA2_256S_TYPE: + #endif + slhDsaKey = (SlhDsaKey*)key; break; default: return BAD_FUNC_ARG; @@ -28710,7 +28903,7 @@ int wc_MakeSigWithBitStr(byte *sig, int sigSz, int sType, byte* buf, ret = MakeSignature(certSignCtx, buf, (word32)bufSz, certSignCtx->sig, MAX_ENCODED_SIG_SZ, rsaKey, eccKey, ed25519Key, ed448Key, - falconKey, dilithiumKey, sphincsKey, rng, (word32)sType, heap); + falconKey, dilithiumKey, slhDsaKey, rng, (word32)sType, heap); #ifdef WOLFSSL_ASYNC_CRYPT if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) { /* Not free'ing certSignCtx->sig here because it could still be in use @@ -28769,7 +28962,7 @@ int wc_SignCert_ex(int requestSz, int sType, byte* buf, word32 buffSz, ed448_key* ed448Key = NULL; falcon_key* falconKey = NULL; dilithium_key* dilithiumKey = NULL; - sphincs_key* sphincsKey = NULL; + SlhDsaKey* slhDsaKey = NULL; if (keyType == RSA_TYPE) rsaKey = (RsaKey*)key; @@ -28797,21 +28990,13 @@ int wc_SignCert_ex(int requestSz, int sType, byte* buf, word32 buffSz, dilithiumKey = (dilithium_key*)key; else if (keyType == ML_DSA_LEVEL5_TYPE) dilithiumKey = (dilithium_key*)key; - else if (keyType == SPHINCS_FAST_LEVEL1_TYPE) - sphincsKey = (sphincs_key*)key; - else if (keyType == SPHINCS_FAST_LEVEL3_TYPE) - sphincsKey = (sphincs_key*)key; - else if (keyType == SPHINCS_FAST_LEVEL5_TYPE) - sphincsKey = (sphincs_key*)key; - else if (keyType == SPHINCS_SMALL_LEVEL1_TYPE) - sphincsKey = (sphincs_key*)key; - else if (keyType == SPHINCS_SMALL_LEVEL3_TYPE) - sphincsKey = (sphincs_key*)key; - else if (keyType == SPHINCS_SMALL_LEVEL5_TYPE) - sphincsKey = (sphincs_key*)key; +#ifdef WOLFSSL_HAVE_SLHDSA + else if (IsSlhDsaKeyType(keyType)) + slhDsaKey = (SlhDsaKey*)key; +#endif return SignCert(requestSz, sType, buf, buffSz, rsaKey, eccKey, ed25519Key, - ed448Key, falconKey, dilithiumKey, sphincsKey, rng); + ed448Key, falconKey, dilithiumKey, slhDsaKey, rng); } int wc_SignCert(int requestSz, int sType, byte* buf, word32 buffSz, @@ -28967,7 +29152,7 @@ static int SetKeyIdFromPublicKey(Cert *cert, RsaKey *rsakey, ecc_key *eckey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, dilithium_key* dilithiumKey, - sphincs_key *sphincsKey, int kid_type) + SlhDsaKey *slhDsaKey, int kid_type) { byte *buf; int bufferSz, ret; @@ -28975,7 +29160,7 @@ static int SetKeyIdFromPublicKey(Cert *cert, RsaKey *rsakey, ecc_key *eckey, if (cert == NULL || (rsakey == NULL && eckey == NULL && ed25519Key == NULL && ed448Key == NULL && falconKey == NULL && dilithiumKey == NULL && - sphincsKey == NULL) || + slhDsaKey == NULL) || (kid_type != SKID_TYPE && kid_type != AKID_TYPE)) return BAD_FUNC_ARG; @@ -29020,9 +29205,9 @@ static int SetKeyIdFromPublicKey(Cert *cert, RsaKey *rsakey, ecc_key *eckey, MAX_PUBLIC_KEY_SZ, 0); } #endif -#if defined(HAVE_SPHINCS) - if (sphincsKey != NULL) { - bufferSz = wc_Sphincs_PublicKeyToDer(sphincsKey, buf, +#if defined(WOLFSSL_HAVE_SLHDSA) + if (slhDsaKey != NULL) { + bufferSz = wc_SlhDsaKey_PublicKeyToDer(slhDsaKey, buf, MAX_PUBLIC_KEY_SZ, 0); } #endif @@ -29064,7 +29249,7 @@ int wc_SetSubjectKeyIdFromPublicKey_ex(Cert *cert, int keyType, void* key) ed448_key* ed448Key = NULL; falcon_key* falconKey = NULL; dilithium_key* dilithiumKey = NULL; - sphincs_key* sphincsKey = NULL; + SlhDsaKey* slhDsaKey = NULL; if (keyType == RSA_TYPE) rsaKey = (RsaKey*)key; @@ -29092,21 +29277,13 @@ int wc_SetSubjectKeyIdFromPublicKey_ex(Cert *cert, int keyType, void* key) dilithiumKey = (dilithium_key*)key; else if (keyType == ML_DSA_LEVEL5_TYPE) dilithiumKey = (dilithium_key*)key; - else if (keyType == SPHINCS_FAST_LEVEL1_TYPE) - sphincsKey = (sphincs_key*)key; - else if (keyType == SPHINCS_FAST_LEVEL3_TYPE) - sphincsKey = (sphincs_key*)key; - else if (keyType == SPHINCS_FAST_LEVEL5_TYPE) - sphincsKey = (sphincs_key*)key; - else if (keyType == SPHINCS_SMALL_LEVEL1_TYPE) - sphincsKey = (sphincs_key*)key; - else if (keyType == SPHINCS_SMALL_LEVEL3_TYPE) - sphincsKey = (sphincs_key*)key; - else if (keyType == SPHINCS_SMALL_LEVEL5_TYPE) - sphincsKey = (sphincs_key*)key; +#ifdef WOLFSSL_HAVE_SLHDSA + else if (IsSlhDsaKeyType(keyType)) + slhDsaKey = (SlhDsaKey*)key; +#endif return SetKeyIdFromPublicKey(cert, rsaKey, eccKey, ed25519Key, ed448Key, - falconKey, dilithiumKey, sphincsKey, + falconKey, dilithiumKey, slhDsaKey, SKID_TYPE); } @@ -29125,7 +29302,7 @@ int wc_SetAuthKeyIdFromPublicKey_ex(Cert *cert, int keyType, void* key) ed448_key* ed448Key = NULL; falcon_key* falconKey = NULL; dilithium_key* dilithiumKey = NULL; - sphincs_key* sphincsKey = NULL; + SlhDsaKey* slhDsaKey = NULL; if (keyType == RSA_TYPE) rsaKey = (RsaKey*)key; @@ -29153,21 +29330,13 @@ int wc_SetAuthKeyIdFromPublicKey_ex(Cert *cert, int keyType, void* key) dilithiumKey = (dilithium_key*)key; else if (keyType == ML_DSA_LEVEL5_TYPE) dilithiumKey = (dilithium_key*)key; - else if (keyType == SPHINCS_FAST_LEVEL1_TYPE) - sphincsKey = (sphincs_key*)key; - else if (keyType == SPHINCS_FAST_LEVEL3_TYPE) - sphincsKey = (sphincs_key*)key; - else if (keyType == SPHINCS_FAST_LEVEL5_TYPE) - sphincsKey = (sphincs_key*)key; - else if (keyType == SPHINCS_SMALL_LEVEL1_TYPE) - sphincsKey = (sphincs_key*)key; - else if (keyType == SPHINCS_SMALL_LEVEL3_TYPE) - sphincsKey = (sphincs_key*)key; - else if (keyType == SPHINCS_SMALL_LEVEL5_TYPE) - sphincsKey = (sphincs_key*)key; +#ifdef WOLFSSL_HAVE_SLHDSA + else if (IsSlhDsaKeyType(keyType)) + slhDsaKey = (SlhDsaKey*)key; +#endif return SetKeyIdFromPublicKey(cert, rsaKey, eccKey, ed25519Key, ed448Key, - falconKey, dilithiumKey, sphincsKey, + falconKey, dilithiumKey, slhDsaKey, AKID_TYPE); } @@ -31144,7 +31313,7 @@ enum { || (defined(HAVE_CURVE25519) && defined(HAVE_CURVE25519_KEY_IMPORT)) \ || (defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT)) \ || (defined(HAVE_CURVE448) && defined(HAVE_CURVE448_KEY_IMPORT)) \ - || defined(HAVE_FALCON) || defined(HAVE_DILITHIUM) || defined(HAVE_SPHINCS)) + || defined(HAVE_FALCON) || defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_SLHDSA)) int DecodeAsymKey_Assign(const byte* input, word32* inOutIdx, word32 inSz, @@ -31504,7 +31673,7 @@ int DecodeAsymKeyPublic(const byte* input, word32* inOutIdx, word32 inSz, return ret; } -#endif /* HAVE_ED25519 || etc... || HAVE_DILITHIUM || HAVE_SPHINCS */ +#endif /* HAVE_ED25519 || etc... || HAVE_DILITHIUM || WOLFSSL_HAVE_SLHDSA */ #endif /* WC_ENABLE_ASYM_KEY_IMPORT */ #if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_IMPORT) diff --git a/wolfcrypt/src/asn_orig.c b/wolfcrypt/src/asn_orig.c index b39417c60e..3abc341798 100644 --- a/wolfcrypt/src/asn_orig.c +++ b/wolfcrypt/src/asn_orig.c @@ -5981,7 +5981,7 @@ static int SetValidity(byte* output, int daysValid) static int EncodeCert(Cert* cert, DerCert* der, RsaKey* rsaKey, ecc_key* eccKey, WC_RNG* rng, DsaKey* dsaKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, - dilithium_key* dilithiumKey, sphincs_key* sphincsKey) + dilithium_key* dilithiumKey, SlhDsaKey* slhDsaKey) { int ret; @@ -5991,7 +5991,7 @@ static int EncodeCert(Cert* cert, DerCert* der, RsaKey* rsaKey, ecc_key* eccKey, /* make sure at least one key type is provided */ if (rsaKey == NULL && eccKey == NULL && ed25519Key == NULL && dsaKey == NULL && ed448Key == NULL && falconKey == NULL && - dilithiumKey == NULL && sphincsKey == NULL) { + dilithiumKey == NULL && slhDsaKey == NULL) { return PUBLIC_KEY_E; } @@ -6097,21 +6097,30 @@ static int EncodeCert(Cert* cert, DerCert* der, RsaKey* rsaKey, ecc_key* eccKey, (word32)sizeof(der->publicKey), 1); } #endif /* HAVE_DILITHIUM */ -#if defined(HAVE_SPHINCS) - if ((cert->keyType == SPHINCS_FAST_LEVEL1_KEY) || - (cert->keyType == SPHINCS_FAST_LEVEL3_KEY) || - (cert->keyType == SPHINCS_FAST_LEVEL5_KEY) || - (cert->keyType == SPHINCS_SMALL_LEVEL1_KEY) || - (cert->keyType == SPHINCS_SMALL_LEVEL3_KEY) || - (cert->keyType == SPHINCS_SMALL_LEVEL5_KEY)) { - if (sphincsKey == NULL) +#if defined(WOLFSSL_HAVE_SLHDSA) + if ((cert->keyType == SLH_DSA_SHAKE_128F_KEY) || + (cert->keyType == SLH_DSA_SHAKE_192F_KEY) || + (cert->keyType == SLH_DSA_SHAKE_256F_KEY) || + (cert->keyType == SLH_DSA_SHAKE_128S_KEY) || + (cert->keyType == SLH_DSA_SHAKE_192S_KEY) || + (cert->keyType == SLH_DSA_SHAKE_256S_KEY) + #ifdef WOLFSSL_SLHDSA_SHA2 + || (cert->keyType == SLH_DSA_SHA2_128F_KEY) || + (cert->keyType == SLH_DSA_SHA2_192F_KEY) || + (cert->keyType == SLH_DSA_SHA2_256F_KEY) || + (cert->keyType == SLH_DSA_SHA2_128S_KEY) || + (cert->keyType == SLH_DSA_SHA2_192S_KEY) || + (cert->keyType == SLH_DSA_SHA2_256S_KEY) + #endif + ) { + if (slhDsaKey == NULL) return PUBLIC_KEY_E; der->publicKeySz = - wc_Sphincs_PublicKeyToDer(sphincsKey, der->publicKey, + wc_SlhDsaKey_PublicKeyToDer(slhDsaKey, der->publicKey, (word32)sizeof(der->publicKey), 1); } -#endif /* HAVE_SPHINCS */ +#endif /* WOLFSSL_HAVE_SLHDSA */ if (der->publicKeySz <= 0) return PUBLIC_KEY_E; @@ -6571,7 +6580,7 @@ static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey, ecc_key* eccKey, WC_RNG* rng, DsaKey* dsaKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, - dilithium_key* dilithiumKey, sphincs_key* sphincsKey) + dilithium_key* dilithiumKey, SlhDsaKey* slhDsaKey) { int ret; WC_DECLARE_VAR(der, DerCert, 1, 0); @@ -6623,26 +6632,12 @@ static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, cert->keyType = ML_DSA_LEVEL5_KEY; } #endif /* HAVE_DILITHIUM */ -#ifdef HAVE_SPHINCS - else if ((sphincsKey != NULL) && (sphincsKey->level == 1) - && (sphincsKey->optim == FAST_VARIANT)) - cert->keyType = SPHINCS_FAST_LEVEL1_KEY; - else if ((sphincsKey != NULL) && (sphincsKey->level == 3) - && (sphincsKey->optim == FAST_VARIANT)) - cert->keyType = SPHINCS_FAST_LEVEL3_KEY; - else if ((sphincsKey != NULL) && (sphincsKey->level == 5) - && (sphincsKey->optim == FAST_VARIANT)) - cert->keyType = SPHINCS_FAST_LEVEL5_KEY; - else if ((sphincsKey != NULL) && (sphincsKey->level == 1) - && (sphincsKey->optim == SMALL_VARIANT)) - cert->keyType = SPHINCS_SMALL_LEVEL1_KEY; - else if ((sphincsKey != NULL) && (sphincsKey->level == 3) - && (sphincsKey->optim == SMALL_VARIANT)) - cert->keyType = SPHINCS_SMALL_LEVEL3_KEY; - else if ((sphincsKey != NULL) && (sphincsKey->level == 5) - && (sphincsKey->optim == SMALL_VARIANT)) - cert->keyType = SPHINCS_SMALL_LEVEL5_KEY; -#endif /* HAVE_SPHINCS */ +#ifdef WOLFSSL_HAVE_SLHDSA + else if ((slhDsaKey != NULL) && (slhDsaKey->params != NULL) && + (SlhDsaParamToKeyType(slhDsaKey->params->param) != 0)) { + cert->keyType = SlhDsaParamToKeyType(slhDsaKey->params->param); + } +#endif /* WOLFSSL_HAVE_SLHDSA */ else return BAD_FUNC_ARG; @@ -6650,7 +6645,7 @@ static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, return MEMORY_E); ret = EncodeCert(cert, der, rsaKey, eccKey, rng, dsaKey, ed25519Key, - ed448Key, falconKey, dilithiumKey, sphincsKey); + ed448Key, falconKey, dilithiumKey, slhDsaKey); if (ret == 0) { if (der->total + MAX_SEQ_SZ * 2 > (int)derSz) ret = BUFFER_E; @@ -6826,7 +6821,7 @@ static int EncodeCertReq(Cert* cert, DerCert* der, RsaKey* rsaKey, DsaKey* dsaKey, ecc_key* eccKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, dilithium_key* dilithiumKey, - sphincs_key* sphincsKey) + SlhDsaKey* slhDsaKey) { int ret; @@ -6835,14 +6830,14 @@ static int EncodeCertReq(Cert* cert, DerCert* der, RsaKey* rsaKey, (void)ed448Key; (void)falconKey; (void)dilithiumKey; - (void)sphincsKey; + (void)slhDsaKey; if (cert == NULL || der == NULL) return BAD_FUNC_ARG; if (rsaKey == NULL && eccKey == NULL && ed25519Key == NULL && dsaKey == NULL && ed448Key == NULL && falconKey == NULL && - dilithiumKey == NULL && sphincsKey == NULL) { + dilithiumKey == NULL && slhDsaKey == NULL) { return PUBLIC_KEY_E; } @@ -6949,16 +6944,25 @@ static int EncodeCertReq(Cert* cert, DerCert* der, RsaKey* rsaKey, der->publicKey, (word32)sizeof(der->publicKey), 1); } #endif -#if defined(HAVE_SPHINCS) - if ((cert->keyType == SPHINCS_FAST_LEVEL1_KEY) || - (cert->keyType == SPHINCS_FAST_LEVEL3_KEY) || - (cert->keyType == SPHINCS_FAST_LEVEL5_KEY) || - (cert->keyType == SPHINCS_SMALL_LEVEL1_KEY) || - (cert->keyType == SPHINCS_SMALL_LEVEL3_KEY) || - (cert->keyType == SPHINCS_SMALL_LEVEL5_KEY)) { - if (sphincsKey == NULL) +#if defined(WOLFSSL_HAVE_SLHDSA) + if ((cert->keyType == SLH_DSA_SHAKE_128F_KEY) || + (cert->keyType == SLH_DSA_SHAKE_192F_KEY) || + (cert->keyType == SLH_DSA_SHAKE_256F_KEY) || + (cert->keyType == SLH_DSA_SHAKE_128S_KEY) || + (cert->keyType == SLH_DSA_SHAKE_192S_KEY) || + (cert->keyType == SLH_DSA_SHAKE_256S_KEY) + #ifdef WOLFSSL_SLHDSA_SHA2 + || (cert->keyType == SLH_DSA_SHA2_128F_KEY) || + (cert->keyType == SLH_DSA_SHA2_192F_KEY) || + (cert->keyType == SLH_DSA_SHA2_256F_KEY) || + (cert->keyType == SLH_DSA_SHA2_128S_KEY) || + (cert->keyType == SLH_DSA_SHA2_192S_KEY) || + (cert->keyType == SLH_DSA_SHA2_256S_KEY) + #endif + ) { + if (slhDsaKey == NULL) return PUBLIC_KEY_E; - der->publicKeySz = wc_Sphincs_PublicKeyToDer(sphincsKey, + der->publicKeySz = wc_SlhDsaKey_PublicKeyToDer(slhDsaKey, der->publicKey, (word32)sizeof(der->publicKey), 1); } #endif @@ -7209,7 +7213,7 @@ static int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey, DsaKey* dsaKey, ecc_key* eccKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, dilithium_key* dilithiumKey, - sphincs_key* sphincsKey) + SlhDsaKey* slhDsaKey) { int ret; WC_DECLARE_VAR(der, DerCert, 1, 0); @@ -7258,26 +7262,12 @@ static int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, cert->keyType = ML_DSA_LEVEL5_KEY; } #endif /* HAVE_DILITHIUM */ -#ifdef HAVE_SPHINCS - else if ((sphincsKey != NULL) && (sphincsKey->level == 1) - && (sphincsKey->optim == FAST_VARIANT)) - cert->keyType = SPHINCS_FAST_LEVEL1_KEY; - else if ((sphincsKey != NULL) && (sphincsKey->level == 3) - && (sphincsKey->optim == FAST_VARIANT)) - cert->keyType = SPHINCS_FAST_LEVEL3_KEY; - else if ((sphincsKey != NULL) && (sphincsKey->level == 5) - && (sphincsKey->optim == FAST_VARIANT)) - cert->keyType = SPHINCS_FAST_LEVEL5_KEY; - else if ((sphincsKey != NULL) && (sphincsKey->level == 1) - && (sphincsKey->optim == SMALL_VARIANT)) - cert->keyType = SPHINCS_SMALL_LEVEL1_KEY; - else if ((sphincsKey != NULL) && (sphincsKey->level == 3) - && (sphincsKey->optim == SMALL_VARIANT)) - cert->keyType = SPHINCS_SMALL_LEVEL3_KEY; - else if ((sphincsKey != NULL) && (sphincsKey->level == 5) - && (sphincsKey->optim == SMALL_VARIANT)) - cert->keyType = SPHINCS_SMALL_LEVEL5_KEY; -#endif /* HAVE_SPHINCS */ +#ifdef WOLFSSL_HAVE_SLHDSA + else if ((slhDsaKey != NULL) && (slhDsaKey->params != NULL) && + (SlhDsaParamToKeyType(slhDsaKey->params->param) != 0)) { + cert->keyType = SlhDsaParamToKeyType(slhDsaKey->params->param); + } +#endif /* WOLFSSL_HAVE_SLHDSA */ else return BAD_FUNC_ARG; @@ -7285,7 +7275,7 @@ static int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, return MEMORY_E); ret = EncodeCertReq(cert, der, rsaKey, dsaKey, eccKey, ed25519Key, ed448Key, - falconKey, dilithiumKey, sphincsKey); + falconKey, dilithiumKey, slhDsaKey); if (ret == 0) { if (der->total + MAX_SEQ_SZ * 2 > (int)derSz) diff --git a/wolfcrypt/src/sphincs.c b/wolfcrypt/src/sphincs.c deleted file mode 100644 index 61d858e3e7..0000000000 --- a/wolfcrypt/src/sphincs.c +++ /dev/null @@ -1,1057 +0,0 @@ -/* sphincs.c - * - * Copyright (C) 2006-2026 wolfSSL Inc. - * - * This file is part of wolfSSL. - * - * wolfSSL is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * wolfSSL is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA - */ - -#include - -/* Based on dilithium.c and Reworked for Sphincs by Anthony Hu. */ - -#include - -#if defined(HAVE_SPHINCS) - -#ifdef HAVE_LIBOQS -#include -#endif - -#include -#ifdef NO_INLINE - #include -#else - #define WOLFSSL_MISC_INCLUDED - #include -#endif - -/* Sign the message using the sphincs private key. - * - * in [in] Message to sign. - * inLen [in] Length of the message in bytes. - * out [in] Buffer to write signature into. - * outLen [in/out] On in, size of buffer. - * On out, the length of the signature in bytes. - * key [in] Sphincs key to use when signing - * returns BAD_FUNC_ARG when a parameter is NULL or public key not set, - * BUFFER_E when outLen is less than SPHINCS_FAST_LEVEL1_SIG_SIZE, - * 0 otherwise. - */ -int wc_sphincs_sign_msg(const byte* in, word32 inLen, byte* out, word32 *outLen, - sphincs_key* key, WC_RNG* rng) -{ - int ret = 0; -#ifdef HAVE_LIBOQS - OQS_SIG *oqssig = NULL; - size_t localOutLen = 0; - - /* sanity check on arguments */ - if ((in == NULL) || (out == NULL) || (outLen == NULL) || (key == NULL)) { - ret = BAD_FUNC_ARG; - } - - if ((ret == 0) && (!key->prvKeySet)) { - ret = BAD_FUNC_ARG; - } - - if (ret == 0) { - if ((key->optim == FAST_VARIANT) && (key->level == 1)) { - oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake_128f_simple); - } - else if ((key->optim == FAST_VARIANT) && (key->level == 3)) { - oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake_192f_simple); - } - else if ((key->optim == FAST_VARIANT) && (key->level == 5)) { - oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake_256f_simple); - } - else if ((key->optim == SMALL_VARIANT) && (key->level == 1)) { - oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake_128s_simple); - } - else if ((key->optim == SMALL_VARIANT) && (key->level == 3)) { - oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake_192s_simple); - } - else if ((key->optim == SMALL_VARIANT) && (key->level == 5)) { - oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake_256s_simple); - } - - if (oqssig == NULL) { - ret = SIG_TYPE_E; - } - } - - /* check and set up out length */ - if (ret == 0) { - if ((key->level == 1) && (key->optim == FAST_VARIANT) && - (*outLen < SPHINCS_FAST_LEVEL1_SIG_SIZE)) { - *outLen = SPHINCS_FAST_LEVEL1_SIG_SIZE; - ret = BUFFER_E; - } - else if ((key->level == 3) && (key->optim == FAST_VARIANT) && - (*outLen < SPHINCS_FAST_LEVEL3_SIG_SIZE)) { - *outLen = SPHINCS_FAST_LEVEL3_SIG_SIZE; - ret = BUFFER_E; - } - else if ((key->level == 5) && (key->optim == FAST_VARIANT) && - (*outLen < SPHINCS_FAST_LEVEL5_SIG_SIZE)) { - *outLen = SPHINCS_FAST_LEVEL5_SIG_SIZE; - ret = BUFFER_E; - } - else if ((key->level == 1) && (key->optim == SMALL_VARIANT) && - (*outLen < SPHINCS_SMALL_LEVEL1_SIG_SIZE)) { - *outLen = SPHINCS_SMALL_LEVEL1_SIG_SIZE; - ret = BUFFER_E; - } - else if ((key->level == 3) && (key->optim == SMALL_VARIANT) && - (*outLen < SPHINCS_SMALL_LEVEL3_SIG_SIZE)) { - *outLen = SPHINCS_SMALL_LEVEL3_SIG_SIZE; - ret = BUFFER_E; - } - else if ((key->level == 5) && (key->optim == SMALL_VARIANT) && - (*outLen < SPHINCS_SMALL_LEVEL5_SIG_SIZE)) { - *outLen = SPHINCS_SMALL_LEVEL5_SIG_SIZE; - ret = BUFFER_E; - } - - localOutLen = *outLen; - } - - if (ret == 0) { - ret = wolfSSL_liboqsRngMutexLock(rng); - if (ret == 0) { - if (OQS_SIG_sign(oqssig, out, &localOutLen, in, inLen, key->k) - == OQS_ERROR) { - ret = BAD_FUNC_ARG; - } - } - if (ret == 0) { - *outLen = (word32)localOutLen; - } - wolfSSL_liboqsRngMutexUnlock(); - } - - if (oqssig != NULL) { - OQS_SIG_free(oqssig); - } -#else - ret = NOT_COMPILED_IN; -#endif - return ret; -} - -/* Verify the message using the sphincs public key. - * - * sig [in] Signature to verify. - * sigLen [in] Size of signature in bytes. - * msg [in] Message to verify. - * msgLen [in] Length of the message in bytes. - * res [out] *res is set to 1 on successful verification. - * key [in] Sphincs key to use to verify. - * returns BAD_FUNC_ARG when a parameter is NULL or contextLen is zero when and - * BUFFER_E when sigLen is less than SPHINCS_FAST_LEVEL1_SIG_SIZE, - * 0 otherwise. - */ -int wc_sphincs_verify_msg(const byte* sig, word32 sigLen, const byte* msg, - word32 msgLen, int* res, sphincs_key* key) -{ - int ret = 0; -#ifdef HAVE_LIBOQS - OQS_SIG *oqssig = NULL; - - if (key == NULL || sig == NULL || msg == NULL || res == NULL) { - ret = BAD_FUNC_ARG; - } - - if ((ret == 0) && (!key->pubKeySet)) { - ret = BAD_FUNC_ARG; - } - - if (ret == 0) { - if ((key->optim == FAST_VARIANT) && (key->level == 1)) { - oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake_128f_simple); - } - else if ((key->optim == FAST_VARIANT) && (key->level == 3)) { - oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake_192f_simple); - } - else if ((key->optim == FAST_VARIANT) && (key->level == 5)) { - oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake_256f_simple); - } - else if ((key->optim == SMALL_VARIANT) && (key->level == 1)) { - oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake_128s_simple); - } - else if ((key->optim == SMALL_VARIANT) && (key->level == 3)) { - oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake_192s_simple); - } - else if ((key->optim == SMALL_VARIANT) && (key->level == 5)) { - oqssig = OQS_SIG_new(OQS_SIG_alg_sphincs_shake_256s_simple); - } - - if (oqssig == NULL) { - ret = SIG_TYPE_E; - } - } - - if ((ret == 0) && - (OQS_SIG_verify(oqssig, msg, msgLen, sig, sigLen, key->p) - == OQS_ERROR)) { - ret = SIG_VERIFY_E; - } - - if (ret == 0) { - *res = 1; - } - - if (oqssig != NULL) { - OQS_SIG_free(oqssig); - } -#else - ret = NOT_COMPILED_IN; -#endif - - return ret; -} - -/* Initialize the sphincs private/public key. - * - * key [in] Sphincs key. - * returns BAD_FUNC_ARG when key is NULL - */ -int wc_sphincs_init(sphincs_key* key) -{ - if (key == NULL) { - return BAD_FUNC_ARG; - } - - ForceZero(key, sizeof(*key)); - return 0; -} - -/* Set the level of the sphincs private/public key. - * - * key [out] Sphincs key. - * level [in] Either 1, 3 or 5. - * optim [in] Either FAST_VARIANT or SMALL_VARIANT. - * returns BAD_FUNC_ARG when key is NULL or level or optim are bad values. - */ -int wc_sphincs_set_level_and_optim(sphincs_key* key, byte level, byte optim) -{ - if (key == NULL) { - return BAD_FUNC_ARG; - } - - if (level != 1 && level != 3 && level != 5) { - return BAD_FUNC_ARG; - } - - if (optim != FAST_VARIANT && optim != SMALL_VARIANT) { - return BAD_FUNC_ARG; - } - - key->level = level; - key->optim = optim; - key->pubKeySet = 0; - key->prvKeySet = 0; - return 0; -} - -/* Get the level and optimization variant of the sphincs private/public key. - * - * key [in] Sphincs key. - * level [out] The level. - * optim [out] The optimization variant. FAST_VARIANT or SMALL_VARIANT. - * returns BAD_FUNC_ARG when key is NULL or level has not been set. - */ -int wc_sphincs_get_level_and_optim(sphincs_key* key, byte* level, byte* optim) -{ - if (key == NULL || level == NULL) { - return BAD_FUNC_ARG; - } - - if (key->level != 1 && key->level != 3 && key->level != 5) { - return BAD_FUNC_ARG; - } - - if (key->optim != FAST_VARIANT && key->optim != SMALL_VARIANT) { - return BAD_FUNC_ARG; - } - - *level = key->level; - *optim = key->optim; - return 0; -} - -/* Clears the sphincs key data - * - * key [in] Sphincs key. - */ -void wc_sphincs_free(sphincs_key* key) -{ - if (key != NULL) { - ForceZero(key, sizeof(*key)); - } -} - -/* Export the sphincs public key. - * - * key [in] Sphincs public key. - * out [in] Array to hold public key. - * outLen [in/out] On in, the number of bytes in array. - * On out, the number bytes put into array. - * returns BAD_FUNC_ARG when a parameter is NULL, - * BUFFER_E when outLen is less than SPHINCS_FAST_LEVEL1_PUB_KEY_SIZE, - * 0 otherwise. - */ -int wc_sphincs_export_public(sphincs_key* key, - byte* out, word32* outLen) -{ - /* sanity check on arguments */ - if ((key == NULL) || (out == NULL) || (outLen == NULL)) { - return BAD_FUNC_ARG; - } - - if ((key->level != 1) && (key->level != 5)) { - return BAD_FUNC_ARG; - } - - if (!key->pubKeySet) { - return BAD_FUNC_ARG; - } - - /* check and set up out length */ - if ((key->level == 1) && (*outLen < SPHINCS_LEVEL1_PUB_KEY_SIZE)) { - *outLen = SPHINCS_LEVEL1_PUB_KEY_SIZE; - return BUFFER_E; - } - else if ((key->level == 3) && (*outLen < SPHINCS_LEVEL3_PUB_KEY_SIZE)) { - *outLen = SPHINCS_LEVEL3_PUB_KEY_SIZE; - return BUFFER_E; - } - else if ((key->level == 5) && (*outLen < SPHINCS_LEVEL5_PUB_KEY_SIZE)) { - *outLen = SPHINCS_LEVEL5_PUB_KEY_SIZE; - return BUFFER_E; - } - - if (key->level == 1) { - *outLen = SPHINCS_LEVEL1_PUB_KEY_SIZE; - XMEMCPY(out, key->p, SPHINCS_LEVEL1_PUB_KEY_SIZE); - } - else if (key->level == 3) { - *outLen = SPHINCS_LEVEL3_PUB_KEY_SIZE; - XMEMCPY(out, key->p, SPHINCS_LEVEL3_PUB_KEY_SIZE); - } - else if (key->level == 5) { - *outLen = SPHINCS_LEVEL5_PUB_KEY_SIZE; - XMEMCPY(out, key->p, SPHINCS_LEVEL5_PUB_KEY_SIZE); - } - - return 0; -} - -/* Import a sphincs public key from a byte array. - * Public key encoded in big-endian. - * - * in [in] Array holding public key. - * inLen [in] Number of bytes of data in array. - * key [in] Sphincs public key. - * returns BAD_FUNC_ARG when a parameter is NULL or key format is not supported, - * 0 otherwise. - */ -int wc_sphincs_import_public(const byte* in, word32 inLen, - sphincs_key* key) -{ - /* sanity check on arguments */ - if ((in == NULL) || (key == NULL)) { - return BAD_FUNC_ARG; - } - - if ((key->level != 1) && (key->level != 3) && (key->level != 5)) { - return BAD_FUNC_ARG; - } - - if ((key->optim != FAST_VARIANT) && (key->optim != SMALL_VARIANT)) { - return BAD_FUNC_ARG; - } - - if ((key->level == 1) && (inLen != SPHINCS_LEVEL1_PUB_KEY_SIZE)) { - return BAD_FUNC_ARG; - } - else if ((key->level == 3) && (inLen != SPHINCS_LEVEL3_PUB_KEY_SIZE)) { - return BAD_FUNC_ARG; - } - else if ((key->level == 5) && (inLen != SPHINCS_LEVEL5_PUB_KEY_SIZE)) { - return BAD_FUNC_ARG; - } - - XMEMCPY(key->p, in, inLen); - key->pubKeySet = 1; - - return 0; -} - -static int parse_private_key(const byte* priv, word32 privSz, - byte** out, word32 *outSz, - sphincs_key* key) { - word32 idx = 0; - int ret = 0; - int length = 0; - - /* sanity check on arguments */ - if ((priv == NULL) || (key == NULL)) { - return BAD_FUNC_ARG; - } - - if ((key->level != 1) && (key->level != 3) && (key->level != 5)) { - return BAD_FUNC_ARG; - } - - if ((key->optim != FAST_VARIANT) && (key->optim != SMALL_VARIANT)) { - return BAD_FUNC_ARG; - } - - /* At this point, it is still a PKCS8 private key. */ - if ((ret = ToTraditionalInline(priv, &idx, privSz)) < 0) { - /* ignore error, did not have PKCS8 header */ - (void)ret; - } - - /* Now it is a octet_string(concat(priv,pub)) */ - if ((ret = GetOctetString(priv, &idx, &length, privSz)) < 0) { - return ret; - } - - *out = (byte *)priv + idx; - *outSz = privSz - idx; - - /* And finally it is concat(priv,pub). Key size check. */ - if ((key->level == 1) && (*outSz != SPHINCS_LEVEL1_KEY_SIZE + - SPHINCS_LEVEL1_PUB_KEY_SIZE)) { - return BAD_FUNC_ARG; - } - else if ((key->level == 3) && (*outSz != SPHINCS_LEVEL3_KEY_SIZE + - SPHINCS_LEVEL3_PUB_KEY_SIZE)) { - return BAD_FUNC_ARG; - } - else if ((key->level == 5) && (*outSz != SPHINCS_LEVEL5_KEY_SIZE + - SPHINCS_LEVEL5_PUB_KEY_SIZE)) { - return BAD_FUNC_ARG; - } - - return 0; -} - -/* Import a sphincs private key from a byte array. - * - * priv [in] Array holding private key. - * privSz [in] Number of bytes of data in array. - * key [in] Sphincs private key. - * returns BAD_FUNC_ARG when a parameter is NULL or privSz is less than - * SPHINCS_LEVEL1_KEY_SIZE, - * 0 otherwise. - */ -int wc_sphincs_import_private_only(const byte* priv, word32 privSz, - sphincs_key* key) -{ - int ret = 0; - byte *newPriv = NULL; - word32 newPrivSz = 0; - - if ((ret = parse_private_key(priv, privSz, &newPriv, &newPrivSz, key)) - != 0) { - return ret; - } - - if (key->level == 1) { - XMEMCPY(key->k, newPriv, SPHINCS_LEVEL1_KEY_SIZE); - } - else if (key->level == 3) { - XMEMCPY(key->k, newPriv, SPHINCS_LEVEL3_KEY_SIZE); - } - else if (key->level == 5) { - XMEMCPY(key->k, newPriv, SPHINCS_LEVEL5_KEY_SIZE); - } - key->prvKeySet = 1; - - return 0; -} - -/* Import a sphincs private and public keys from byte array(s). - * - * priv [in] Array holding private key or private+public keys - * privSz [in] Number of bytes of data in private key array. - * pub [in] Array holding public key (or NULL). - * pubSz [in] Number of bytes of data in public key array (or 0). - * key [in] Sphincs private/public key. - * returns BAD_FUNC_ARG when a required parameter is NULL or an invalid - * combination of keys/lengths is supplied, 0 otherwise. - */ -int wc_sphincs_import_private_key(const byte* priv, word32 privSz, - const byte* pub, word32 pubSz, - sphincs_key* key) -{ - int ret = 0; - byte *newPriv = NULL; - word32 newPrivSz = 0; - - if ((ret = parse_private_key(priv, privSz, &newPriv, &newPrivSz, key)) - != 0) { - return ret; - } - - if (pub == NULL) { - if (pubSz != 0) { - return BAD_FUNC_ARG; - } - - if ((newPrivSz != SPHINCS_LEVEL1_PRV_KEY_SIZE) && - (newPrivSz != SPHINCS_LEVEL3_PRV_KEY_SIZE) && - (newPrivSz != SPHINCS_LEVEL5_PRV_KEY_SIZE)) { - return BAD_FUNC_ARG; - } - - if (key->level == 1) { - pub = newPriv + SPHINCS_LEVEL1_KEY_SIZE; - pubSz = SPHINCS_LEVEL1_PUB_KEY_SIZE; - } - else if (key->level == 3) { - pub = newPriv + SPHINCS_LEVEL3_KEY_SIZE; - pubSz = SPHINCS_LEVEL3_PUB_KEY_SIZE; - } - else if (key->level == 5) { - pub = newPriv + SPHINCS_LEVEL5_KEY_SIZE; - pubSz = SPHINCS_LEVEL5_PUB_KEY_SIZE; - } - } - else if ((pubSz != SPHINCS_LEVEL1_PUB_KEY_SIZE) && - (pubSz != SPHINCS_LEVEL3_PUB_KEY_SIZE) && - (pubSz != SPHINCS_LEVEL5_PUB_KEY_SIZE)) { - return BAD_FUNC_ARG; - } - - /* import public key */ - ret = wc_sphincs_import_public(pub, pubSz, key); - - if (ret == 0) { - /* make the private key (priv + pub) */ - if (key->level == 1) { - XMEMCPY(key->k, newPriv, SPHINCS_LEVEL1_KEY_SIZE); - } - else if (key->level == 3) { - XMEMCPY(key->k, newPriv, SPHINCS_LEVEL3_KEY_SIZE); - } - else if (key->level == 5) { - XMEMCPY(key->k, newPriv, SPHINCS_LEVEL5_KEY_SIZE); - } - key->prvKeySet = 1; - } - - return ret; -} - -/* Export the sphincs private key. - * - * key [in] Sphincs private key. - * out [in] Array to hold private key. - * outLen [in/out] On in, the number of bytes in array. - * On out, the number bytes put into array. - * returns BAD_FUNC_ARG when a parameter is NULL, - * BUFFER_E when outLen is less than SPHINCS_LEVEL1_KEY_SIZE, - * 0 otherwise. - */ -int wc_sphincs_export_private_only(sphincs_key* key, byte* out, word32* outLen) -{ - /* sanity checks on arguments */ - if ((key == NULL) || (out == NULL) || (outLen == NULL)) { - return BAD_FUNC_ARG; - } - - if ((key->level != 1) && (key->level != 3) && (key->level != 5)) { - return BAD_FUNC_ARG; - } - - if ((key->optim != FAST_VARIANT) && (key->optim != SMALL_VARIANT)) { - return BAD_FUNC_ARG; - } - - /* check and set up out length */ - if ((key->level == 1) && (*outLen < SPHINCS_LEVEL1_KEY_SIZE)) { - *outLen = SPHINCS_LEVEL1_KEY_SIZE; - return BUFFER_E; - } - else if ((key->level == 3) && (*outLen < SPHINCS_LEVEL3_KEY_SIZE)) { - *outLen = SPHINCS_LEVEL3_KEY_SIZE; - return BUFFER_E; - } - else if ((key->level == 5) && (*outLen < SPHINCS_LEVEL5_KEY_SIZE)) { - *outLen = SPHINCS_LEVEL5_KEY_SIZE; - return BUFFER_E; - } - - if (key->level == 1) { - *outLen = SPHINCS_LEVEL1_KEY_SIZE; - } - else if (key->level == 3) { - *outLen = SPHINCS_LEVEL3_KEY_SIZE; - } - else if (key->level == 5) { - *outLen = SPHINCS_LEVEL5_KEY_SIZE; - } - - XMEMCPY(out, key->k, *outLen); - - return 0; -} - -/* Export the sphincs private and public key. - * - * key [in] Sphincs private/public key. - * out [in] Array to hold private and public key. - * outLen [in/out] On in, the number of bytes in array. - * On out, the number bytes put into array. - * returns BAD_FUNC_ARG when a parameter is NULL, - * BUFFER_E when outLen is less than required, 0 otherwise. - */ -int wc_sphincs_export_private(sphincs_key* key, byte* out, word32* outLen) -{ - /* sanity checks on arguments */ - if ((key == NULL) || (out == NULL) || (outLen == NULL)) { - return BAD_FUNC_ARG; - } - - if ((key->level != 1) && (key->level != 3) && (key->level != 5)) { - return BAD_FUNC_ARG; - } - - if ((key->optim != FAST_VARIANT) && (key->optim != SMALL_VARIANT)) { - return BAD_FUNC_ARG; - } - - if ((key->level == 1) && (*outLen < SPHINCS_LEVEL1_PRV_KEY_SIZE)) { - *outLen = SPHINCS_LEVEL1_PRV_KEY_SIZE; - return BUFFER_E; - } - else if ((key->level == 3) && (*outLen < SPHINCS_LEVEL3_PRV_KEY_SIZE)) { - *outLen = SPHINCS_LEVEL3_PRV_KEY_SIZE; - return BUFFER_E; - } - else if ((key->level == 5) && (*outLen < SPHINCS_LEVEL5_PRV_KEY_SIZE)) { - *outLen = SPHINCS_LEVEL5_PRV_KEY_SIZE; - return BUFFER_E; - } - - - if (key->level == 1) { - *outLen = SPHINCS_LEVEL1_PRV_KEY_SIZE; - XMEMCPY(out, key->k, SPHINCS_LEVEL1_PRV_KEY_SIZE); - XMEMCPY(out + SPHINCS_LEVEL1_PRV_KEY_SIZE, key->p, - SPHINCS_LEVEL1_PUB_KEY_SIZE); - } - else if (key->level == 3) { - *outLen = SPHINCS_LEVEL3_PRV_KEY_SIZE; - XMEMCPY(out, key->k, SPHINCS_LEVEL3_PRV_KEY_SIZE); - XMEMCPY(out + SPHINCS_LEVEL3_PRV_KEY_SIZE, key->p, - SPHINCS_LEVEL3_PUB_KEY_SIZE); - } - else if (key->level == 5) { - *outLen = SPHINCS_LEVEL5_PRV_KEY_SIZE; - XMEMCPY(out, key->k, SPHINCS_LEVEL5_PRV_KEY_SIZE); - XMEMCPY(out + SPHINCS_LEVEL5_PRV_KEY_SIZE, key->p, - SPHINCS_LEVEL5_PUB_KEY_SIZE); - } - - return 0; -} - -/* Export the sphincs private and public key. - * - * key [in] Sphincs private/public key. - * priv [in] Array to hold private key. - * privSz [in/out] On in, the number of bytes in private key array. - * pub [in] Array to hold public key. - * pubSz [in/out] On in, the number of bytes in public key array. - * On out, the number bytes put into array. - * returns BAD_FUNC_ARG when a parameter is NULL, - * BUFFER_E when privSz is or pubSz is less than required, - * 0 otherwise. - */ -int wc_sphincs_export_key(sphincs_key* key, byte* priv, word32 *privSz, - byte* pub, word32 *pubSz) -{ - int ret = 0; - - /* export private part */ - ret = wc_sphincs_export_private(key, priv, privSz); - if (ret == 0) { - /* export public part */ - ret = wc_sphincs_export_public(key, pub, pubSz); - } - - return ret; -} - -/* Check the public key of the sphincs key matches the private key. - * - * key [in] Sphincs private/public key. - * returns BAD_FUNC_ARG when key is NULL, - * PUBLIC_KEY_E when the public key is not set or doesn't match, - * other -ve value on hash failure, - * 0 otherwise. - */ -int wc_sphincs_check_key(sphincs_key* key) -{ - if (key == NULL) { - return BAD_FUNC_ARG; - } - - /* Assume everything is fine. */ - return 0; -} - -/* Returns the size of a sphincs private key. - * - * key [in] Sphincs private/public key. - * returns BAD_FUNC_ARG when key is NULL, - * SPHINCS_LEVELn_KEY_SIZE otherwise. - */ -int wc_sphincs_size(sphincs_key* key) -{ - if (key == NULL) { - return BAD_FUNC_ARG; - } - - if (key->level == 1) { - return SPHINCS_LEVEL1_KEY_SIZE; - } - else if (key->level == 3) { - return SPHINCS_LEVEL3_KEY_SIZE; - } - else if (key->level == 5) { - return SPHINCS_LEVEL5_KEY_SIZE; - } - - return BAD_FUNC_ARG; -} - -/* Returns the size of a sphincs private plus public key. - * - * key [in] Sphincs private/public key. - * returns BAD_FUNC_ARG when key is NULL, - * SPHINCS_LEVELn_PRV_KEY_SIZE otherwise. - */ -int wc_sphincs_priv_size(sphincs_key* key) -{ - if (key == NULL) { - return BAD_FUNC_ARG; - } - - if (key->level == 1) { - return SPHINCS_LEVEL1_PRV_KEY_SIZE; - } - else if (key->level == 3) { - return SPHINCS_LEVEL3_PRV_KEY_SIZE; - } - else if (key->level == 5) { - return SPHINCS_LEVEL5_PRV_KEY_SIZE; - } - - return BAD_FUNC_ARG; -} - -/* Returns the size of a sphincs public key. - * - * key [in] Sphincs private/public key. - * returns BAD_FUNC_ARG when key is NULL, - * SPHINCS_FAST_LEVEL1_PUB_KEY_SIZE otherwise. - */ -int wc_sphincs_pub_size(sphincs_key* key) -{ - if (key == NULL) { - return BAD_FUNC_ARG; - } - - if (key->level == 1) { - return SPHINCS_LEVEL1_PUB_KEY_SIZE; - } - else if (key->level == 3) { - return SPHINCS_LEVEL3_PUB_KEY_SIZE; - } - else if (key->level == 5) { - return SPHINCS_LEVEL5_PUB_KEY_SIZE; - } - - return BAD_FUNC_ARG; -} - -/* Returns the size of a sphincs signature. - * - * key [in] Sphincs private/public key. - * returns BAD_FUNC_ARG when key is NULL, - * SPHINCS_FAST_LEVEL1_SIG_SIZE otherwise. - */ -int wc_sphincs_sig_size(sphincs_key* key) -{ - if (key == NULL) { - return BAD_FUNC_ARG; - } - - if ((key->level == 1) && (key->optim == FAST_VARIANT)) { - return SPHINCS_FAST_LEVEL1_SIG_SIZE; - } - else if ((key->level == 3) && (key->optim == FAST_VARIANT)) { - return SPHINCS_FAST_LEVEL3_SIG_SIZE; - } - else if ((key->level == 5) && (key->optim == FAST_VARIANT)) { - return SPHINCS_FAST_LEVEL5_SIG_SIZE; - } - else if ((key->level == 1) && (key->optim == SMALL_VARIANT)) { - return SPHINCS_SMALL_LEVEL1_SIG_SIZE; - } - else if ((key->level == 3) && (key->optim == SMALL_VARIANT)) { - return SPHINCS_SMALL_LEVEL3_SIG_SIZE; - } - else if ((key->level == 5) && (key->optim == SMALL_VARIANT)) { - return SPHINCS_SMALL_LEVEL5_SIG_SIZE; - } - - return BAD_FUNC_ARG; -} - -int wc_Sphincs_PrivateKeyDecode(const byte* input, word32* inOutIdx, - sphincs_key* key, word32 inSz) -{ - int ret = 0; - byte privKey[SPHINCS_MAX_KEY_SIZE], pubKey[SPHINCS_MAX_PUB_KEY_SIZE]; - word32 privKeyLen = (word32)sizeof(privKey); - word32 pubKeyLen = (word32)sizeof(pubKey); - int keytype = 0; - - if (input == NULL || inOutIdx == NULL || key == NULL || inSz == 0) { - return BAD_FUNC_ARG; - } - - if ((key->level == 1) && (key->optim == FAST_VARIANT)) { - keytype = SPHINCS_FAST_LEVEL1k; - } - else if ((key->level == 3) && (key->optim == FAST_VARIANT)) { - keytype = SPHINCS_FAST_LEVEL3k; - } - else if ((key->level == 5) && (key->optim == FAST_VARIANT)) { - keytype = SPHINCS_FAST_LEVEL5k; - } - else if ((key->level == 1) && (key->optim == SMALL_VARIANT)) { - keytype = SPHINCS_SMALL_LEVEL1k; - } - else if ((key->level == 3) && (key->optim == SMALL_VARIANT)) { - keytype = SPHINCS_SMALL_LEVEL3k; - } - else if ((key->level == 5) && (key->optim == SMALL_VARIANT)) { - keytype = SPHINCS_SMALL_LEVEL5k; - } - else { - return BAD_FUNC_ARG; - } - - ret = DecodeAsymKey(input, inOutIdx, inSz, privKey, &privKeyLen, - pubKey, &pubKeyLen, keytype); - if (ret == 0) { - if (pubKeyLen == 0) { - ret = wc_sphincs_import_private_only(input, inSz, key); - } - else { - ret = wc_sphincs_import_private_key(privKey, privKeyLen, - pubKey, pubKeyLen, key); - } - } - return ret; -} - -int wc_Sphincs_PublicKeyDecode(const byte* input, word32* inOutIdx, - sphincs_key* key, word32 inSz) -{ - int ret = 0; - byte pubKey[SPHINCS_MAX_PUB_KEY_SIZE]; - word32 pubKeyLen = (word32)sizeof(pubKey); - int keytype = 0; - - if (input == NULL || inOutIdx == NULL || key == NULL || inSz == 0) { - return BAD_FUNC_ARG; - } - - ret = wc_sphincs_import_public(input, inSz, key); - if (ret == 0) { - return 0; - } - - if ((key->level == 1) && (key->optim == FAST_VARIANT)) { - keytype = SPHINCS_FAST_LEVEL1k; - } - else if ((key->level == 3) && (key->optim == FAST_VARIANT)) { - keytype = SPHINCS_FAST_LEVEL3k; - } - else if ((key->level == 5) && (key->optim == FAST_VARIANT)) { - keytype = SPHINCS_FAST_LEVEL5k; - } - else if ((key->level == 1) && (key->optim == SMALL_VARIANT)) { - keytype = SPHINCS_SMALL_LEVEL1k; - } - else if ((key->level == 3) && (key->optim == SMALL_VARIANT)) { - keytype = SPHINCS_SMALL_LEVEL3k; - } - else if ((key->level == 5) && (key->optim == SMALL_VARIANT)) { - keytype = SPHINCS_SMALL_LEVEL5k; - } - else { - return BAD_FUNC_ARG; - } - - ret = DecodeAsymKeyPublic(input, inOutIdx, inSz, pubKey, &pubKeyLen, - keytype); - if (ret == 0) { - ret = wc_sphincs_import_public(pubKey, pubKeyLen, key); - } - return ret; -} - -#ifdef WC_ENABLE_ASYM_KEY_EXPORT -/* Encode the public part of an Sphincs key in DER. - * - * Pass NULL for output to get the size of the encoding. - * - * @param [in] key Sphincs key object. - * @param [out] output Buffer to put encoded data in. - * @param [in] outLen Size of buffer in bytes. - * @param [in] withAlg Whether to use SubjectPublicKeyInfo format. - * @return Size of encoded data in bytes on success. - * @return BAD_FUNC_ARG when key is NULL. - * @return MEMORY_E when dynamic memory allocation failed. - */ -int wc_Sphincs_PublicKeyToDer(sphincs_key* key, byte* output, word32 inLen, - int withAlg) -{ - int ret; - byte pubKey[SPHINCS_MAX_PUB_KEY_SIZE]; - word32 pubKeyLen = (word32)sizeof(pubKey); - int keytype = 0; - - if (key == NULL) { - return BAD_FUNC_ARG; - } - - if ((key->level == 1) && (key->optim == FAST_VARIANT)) { - keytype = SPHINCS_FAST_LEVEL1k; - } - else if ((key->level == 3) && (key->optim == FAST_VARIANT)) { - keytype = SPHINCS_FAST_LEVEL3k; - } - else if ((key->level == 5) && (key->optim == FAST_VARIANT)) { - keytype = SPHINCS_FAST_LEVEL5k; - } - else if ((key->level == 1) && (key->optim == SMALL_VARIANT)) { - keytype = SPHINCS_SMALL_LEVEL1k; - } - else if ((key->level == 3) && (key->optim == SMALL_VARIANT)) { - keytype = SPHINCS_SMALL_LEVEL3k; - } - else if ((key->level == 5) && (key->optim == SMALL_VARIANT)) { - keytype = SPHINCS_SMALL_LEVEL5k; - } - else { - return BAD_FUNC_ARG; - } - - ret = wc_sphincs_export_public(key, pubKey, &pubKeyLen); - if (ret == 0) { - ret = SetAsymKeyDerPublic(pubKey, pubKeyLen, output, inLen, keytype, - withAlg); - } - - return ret; -} -#endif - -int wc_Sphincs_KeyToDer(sphincs_key* key, byte* output, word32 inLen) -{ - if (key == NULL) { - return BAD_FUNC_ARG; - } - - if ((key->level == 1) && (key->optim == FAST_VARIANT)) { - return SetAsymKeyDer(key->k, SPHINCS_LEVEL1_KEY_SIZE, key->p, - SPHINCS_LEVEL1_KEY_SIZE, output, inLen, - SPHINCS_FAST_LEVEL1k); - } - else if ((key->level == 3) && (key->optim == FAST_VARIANT)) { - return SetAsymKeyDer(key->k, SPHINCS_LEVEL3_KEY_SIZE, key->p, - SPHINCS_LEVEL3_KEY_SIZE, output, inLen, - SPHINCS_FAST_LEVEL3k); - } - else if ((key->level == 5) && (key->optim == FAST_VARIANT)) { - return SetAsymKeyDer(key->k, SPHINCS_LEVEL5_KEY_SIZE, key->p, - SPHINCS_LEVEL5_KEY_SIZE, output, inLen, - SPHINCS_FAST_LEVEL5k); - } - else if ((key->level == 1) && (key->optim == SMALL_VARIANT)) { - return SetAsymKeyDer(key->k, SPHINCS_LEVEL1_KEY_SIZE, key->p, - SPHINCS_LEVEL1_KEY_SIZE, output, inLen, - SPHINCS_SMALL_LEVEL1k); - } - else if ((key->level == 3) && (key->optim == SMALL_VARIANT)) { - return SetAsymKeyDer(key->k, SPHINCS_LEVEL3_KEY_SIZE, key->p, - SPHINCS_LEVEL3_KEY_SIZE, output, inLen, - SPHINCS_SMALL_LEVEL3k); - } - else if ((key->level == 5) && (key->optim == SMALL_VARIANT)) { - return SetAsymKeyDer(key->k, SPHINCS_LEVEL5_KEY_SIZE, key->p, - SPHINCS_LEVEL5_KEY_SIZE, output, inLen, - SPHINCS_SMALL_LEVEL5k); - } - - return BAD_FUNC_ARG; -} - -int wc_Sphincs_PrivateKeyToDer(sphincs_key* key, byte* output, word32 inLen) -{ - if (key == NULL) { - return BAD_FUNC_ARG; - } - - if ((key->level == 1) && (key->optim == FAST_VARIANT)) { - return SetAsymKeyDer(key->k, SPHINCS_LEVEL1_KEY_SIZE, NULL, 0, output, - inLen, SPHINCS_FAST_LEVEL1k); - } - else if ((key->level == 3) && (key->optim == FAST_VARIANT)) { - return SetAsymKeyDer(key->k, SPHINCS_LEVEL3_KEY_SIZE, NULL, 0, output, - inLen, SPHINCS_FAST_LEVEL3k); - } - else if ((key->level == 5) && (key->optim == FAST_VARIANT)) { - return SetAsymKeyDer(key->k, SPHINCS_LEVEL5_KEY_SIZE, NULL, 0, output, - inLen, SPHINCS_FAST_LEVEL5k); - } - else if ((key->level == 1) && (key->optim == SMALL_VARIANT)) { - return SetAsymKeyDer(key->k, SPHINCS_LEVEL1_KEY_SIZE, NULL, 0, output, - inLen, SPHINCS_SMALL_LEVEL1k); - } - else if ((key->level == 3) && (key->optim == SMALL_VARIANT)) { - return SetAsymKeyDer(key->k, SPHINCS_LEVEL3_KEY_SIZE, NULL, 0, output, - inLen, SPHINCS_SMALL_LEVEL3k); - } - else if ((key->level == 5) && (key->optim == SMALL_VARIANT)) { - return SetAsymKeyDer(key->k, SPHINCS_LEVEL5_KEY_SIZE, NULL, 0, output, - inLen, SPHINCS_SMALL_LEVEL5k); - } - - return BAD_FUNC_ARG; -} -#endif /* HAVE_SPHINCS */ diff --git a/wolfcrypt/src/wc_slhdsa.c b/wolfcrypt/src/wc_slhdsa.c index af1a864eb5..3909bbb653 100644 --- a/wolfcrypt/src/wc_slhdsa.c +++ b/wolfcrypt/src/wc_slhdsa.c @@ -30,6 +30,7 @@ #ifdef WOLFSSL_HAVE_SLHDSA +#include #include #include #ifdef NO_INLINE @@ -8201,7 +8202,7 @@ int wc_SlhDsaKey_ImportPublic(SlhDsaKey* key, const byte* pub, word32 pubLen) else { /* Copy public key data into SLH-DSA key object. */ XMEMCPY(key->sk + 2 * key->params->n, pub, 2 * key->params->n); - key->flags = WC_SLHDSA_FLAG_PUBLIC; + key->flags |= WC_SLHDSA_FLAG_PUBLIC; #ifdef WOLFSSL_SLHDSA_SHA2 if (SLHDSA_IS_SHA2(key->params->param)) { ret = slhdsakey_precompute_sha2_midstates(key); @@ -8564,5 +8565,457 @@ int wc_SlhDsaKey_SigSizeFromParam(enum SlhDsaParam param) return ret; } + +/* Find SlhDsaParameters entry for a given param enum. */ +static const SlhDsaParameters* slhdsa_find_params(enum SlhDsaParam param) +{ + int i; + for (i = 0; i < SLHDSA_PARAM_LEN; i++) { + if (SlhDsaParams[i].param == param) { + return &SlhDsaParams[i]; + } + } + return NULL; +} + +#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY +/* Decode a DER-encoded SLH-DSA private key (PKCS#8 / OneAsymmetricKey). + * + * RFC 9909 Section 6: The privateKey OCTET STRING contains the raw + * concatenation SK.seed || SK.prf || PK.seed || PK.root (4*n bytes) + * directly, without a nested OCTET STRING wrapper. This differs from + * Ed25519/Ed448 which wrap the key in an additional OCTET STRING. + * + * The parameter set is detected from the AlgorithmIdentifier OID. + * On success, key->params is updated to match the detected parameter set. + * + * @param [in] input DER-encoded key data. + * @param [in, out] inOutIdx Index into input, updated on return. + * @param [in, out] key SLH-DSA key. Parameter set is auto-detected. + * @param [in] inSz Size of input in bytes. + * @return 0 on success. + * @return BAD_FUNC_ARG when input, inOutIdx, or key is NULL. + * @return ASN_PARSE_E when the DER cannot be parsed as an SLH-DSA key. + */ +int wc_SlhDsaKey_PrivateKeyDecode(const byte* input, word32* inOutIdx, + SlhDsaKey* key, word32 inSz) +{ + int ret = 0; + int length; + int version; + word32 oid = 0; + word32 seqEnd; + word32 savedIdx; + int privSz; + int paramId; + const SlhDsaParameters* params; + + if ((input == NULL) || (inOutIdx == NULL) || (key == NULL) || (inSz == 0)) { + return BAD_FUNC_ARG; + } + + /* Snapshot the caller's index so failures restore it -- mirrors + * wc_SlhDsaKey_PublicKeyDecode and lets callers chain parsers or + * retry on the same buffer without recomputing the offset. */ + savedIdx = *inOutIdx; + + /* Parse PKCS#8 OneAsymmetricKey wrapper: + * SEQUENCE { version, AlgorithmIdentifier { OID }, OCTET STRING { key }, + * [0] attributes OPTIONAL, [1] publicKey OPTIONAL } + */ + if (GetSequence(input, inOutIdx, &length, inSz) < 0) { + *inOutIdx = savedIdx; + return ASN_PARSE_E; + } + seqEnd = *inOutIdx + (word32)length; + + if (GetMyVersion(input, inOutIdx, &version, inSz) < 0) { + *inOutIdx = savedIdx; + return ASN_PARSE_E; + } + if (version != 0 && version != 1) { + *inOutIdx = savedIdx; + return ASN_PARSE_E; + } + + if (GetAlgoId(input, inOutIdx, &oid, oidKeyType, inSz) < 0) { + *inOutIdx = savedIdx; + return ASN_PARSE_E; + } + + /* Map the OID to an SLH-DSA parameter set. Pass through NOT_COMPILED_IN + * so callers can distinguish "variant present but not built in" from + * "malformed DER". */ + paramId = wc_SlhDsaOidToParam((int)oid); + if (paramId == WC_NO_ERR_TRACE(NOT_COMPILED_IN)) { + *inOutIdx = savedIdx; + return NOT_COMPILED_IN; + } + if (paramId < 0) { + *inOutIdx = savedIdx; + return ASN_PARSE_E; + } + params = slhdsa_find_params((enum SlhDsaParam)paramId); + if (params == NULL) { + *inOutIdx = savedIdx; + return ASN_PARSE_E; + } + + /* RFC 9909: privateKey is a single OCTET STRING containing the raw key + * (4*n bytes). Unlike Ed25519/Ed448, there is no nested inner OCTET + * STRING wrapping. */ + if (GetOctetString(input, inOutIdx, &privSz, inSz) < 0) { + *inOutIdx = savedIdx; + return ASN_PARSE_E; + } + + if (privSz != params->n * 4) { + *inOutIdx = savedIdx; + return ASN_PARSE_E; + } + + { + const SlhDsaParameters* oldParams = key->params; + byte oldFlags = key->flags; + + /* Update the key's parameter set to the detected one. */ + key->params = params; + + /* Import the raw private key: SK.seed || SK.prf || PK.seed || PK.root */ + ret = wc_SlhDsaKey_ImportPrivate(key, input + *inOutIdx, + (word32)privSz); + if (ret == 0) { + /* Validate trailing fields per RFC 5958 OneAsymmetricKey: + * [0] IMPLICIT Attributes OPTIONAL -- at most once + * [1] IMPLICIT PublicKey OPTIONAL -- at most once, + * must follow [0] + * Reject duplicates, out-of-order tags, and any other tag. + * The previous code accepted any number of either tag in any + * order. */ + const byte tagAttrs = ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 0; + const byte tagPub = ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 1; + int seenAttrs = 0; + int seenPub = 0; + *inOutIdx += (word32)privSz; + while (ret == 0 && *inOutIdx < seqEnd) { + byte tlvTag; + int tlvLen; + if (GetASNTag(input, inOutIdx, &tlvTag, inSz) < 0) { + ret = ASN_PARSE_E; + break; + } + if (tlvTag == tagAttrs) { + /* attributes must precede publicKey and appear once */ + if (seenAttrs || seenPub) { + ret = ASN_PARSE_E; + break; + } + seenAttrs = 1; + } + else if (tlvTag == tagPub) { + /* publicKey may appear at most once */ + if (seenPub) { + ret = ASN_PARSE_E; + break; + } + seenPub = 1; + } + else { + ret = ASN_PARSE_E; + break; + } + if (GetLength(input, inOutIdx, &tlvLen, inSz) < 0) { + ret = ASN_PARSE_E; + break; + } + /* Length must stay within the outer SEQUENCE. */ + if (*inOutIdx + (word32)tlvLen > seqEnd) { + ret = ASN_PARSE_E; + break; + } + *inOutIdx += (word32)tlvLen; + } + if (ret == 0 && *inOutIdx != seqEnd) { + ret = ASN_PARSE_E; + } + if (ret != 0) { + /* Trailing-field validation failed after ImportPrivate + * already populated key->sk. Scrub the imported material + * and roll back state so the caller sees the failure as + * if the import never happened. */ + ForceZero(key->sk, (word32)(4 * params->n)); + key->params = oldParams; + key->flags = oldFlags; + *inOutIdx = savedIdx; + } + } + else { + /* On failure, restore params/flags. ImportPrivate writes the + * full sk[0..4*n] (private + public material) before any + * SHA-2 precompute step, so a precompute failure can leave + * the entire sk dirty -- clear it. BAD_LENGTH_E is detected + * before any write, so no zeroing is needed in that case. */ + if (ret != WC_NO_ERR_TRACE(BAD_LENGTH_E)) { + ForceZero(key->sk, (word32)(4 * params->n)); + } + key->params = oldParams; + key->flags = oldFlags; + *inOutIdx = savedIdx; + } + } + + return ret; +} +#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ + +/* Decode a DER-encoded SLH-DSA public key (SubjectPublicKeyInfo). + * + * The parameter set is detected from the AlgorithmIdentifier OID. + * On success, key->params is updated to match the detected parameter set. + * + * @param [in] input DER-encoded key data. + * @param [in, out] inOutIdx Index into input, updated on return. + * @param [in, out] key SLH-DSA key. Parameter set is auto-detected. + * @param [in] inSz Size of input in bytes. + * @return 0 on success. + * @return BAD_FUNC_ARG when input, inOutIdx, or key is NULL. + * @return ASN_PARSE_E when the DER cannot be parsed as an SLH-DSA key. + */ +int wc_SlhDsaKey_PublicKeyDecode(const byte* input, word32* inOutIdx, + SlhDsaKey* key, word32 inSz) +{ + int ret; + int keytype = ANONk; + int paramId; + const SlhDsaParameters* params; + const SlhDsaParameters* oldParams; + const byte* pubKeyPtr = NULL; + word32 pubKeyLen = 0; + word32 savedIdx; + byte oldFlags; + + if ((input == NULL) || (inOutIdx == NULL) || (key == NULL) || (inSz == 0)) { + return BAD_FUNC_ARG; + } + + savedIdx = *inOutIdx; + + /* Fast path: if the caller initialised the key with a parameter set, + * treat the entire window from *inOutIdx to inSz as a candidate raw + * public key and let wc_SlhDsaKey_ImportPublic decide via its length + * check. The window must contain exactly 2*n bytes for the configured + * parameter set -- callers chaining decoders must pass inSz scoped to + * just the public-key buffer or the import will reject the length and + * fall through to SPKI parsing. Mirrors the raw-first fallback in + * wc_Dilithium_PublicKeyDecode and wc_Falcon_PublicKeyDecode so all PQ + * public-key decoders accept either raw bytes or SPKI. + * + * The length check in ImportPublic is the disambiguator: a real SPKI + * for any SLH-DSA variant carries ~19 bytes of AlgorithmIdentifier and + * BIT STRING overhead on top of the 2*n public bytes, so SPKI input + * never collides with the 2*n raw length and falls through cleanly. */ + if (key->params != NULL && savedIdx < inSz) { + word32 windowSz = inSz - savedIdx; + int n = key->params->n; + oldFlags = key->flags; + ret = wc_SlhDsaKey_ImportPublic(key, input + savedIdx, windowSz); + if (ret == 0) { + *inOutIdx += windowSz; + return 0; + } + /* Fall through to SPKI parsing. BAD_LENGTH_E is detected before + * any write (typical SPKI input), so there is nothing to scrub. + * On SHA-2 precompute failure ImportPublic has written only the + * public half at sk[2*n .. 4*n] - leave the private half + * sk[0 .. 2*n] untouched in case the caller imported it earlier. */ + if (ret != WC_NO_ERR_TRACE(BAD_LENGTH_E)) { + ForceZero(key->sk + 2 * n, (word32)(2 * n)); + } + key->flags = oldFlags; + } + + /* Use ANONk to auto-detect the OID from the SPKI AlgorithmIdentifier + * in a single parse. (PrivateKeyDecode parses each DER element + * manually because the PKCS#8 OneAsymmetricKey layout differs from + * SPKI and has no matching helper.) */ + ret = DecodeAsymKeyPublic_Assign(input, inOutIdx, inSz, &pubKeyPtr, + &pubKeyLen, &keytype); + if (ret != 0) { + return ret; + } + + /* Map the detected OID key type to an SLH-DSA parameter set. Pass + * through NOT_COMPILED_IN so callers see the specific reason + * (unsupported variant) rather than a generic parse error. */ + paramId = wc_SlhDsaOidToParam(keytype); + if (paramId == WC_NO_ERR_TRACE(NOT_COMPILED_IN)) { + *inOutIdx = savedIdx; + return NOT_COMPILED_IN; + } + if (paramId < 0) { + *inOutIdx = savedIdx; + return ASN_PARSE_E; + } + params = slhdsa_find_params((enum SlhDsaParam)paramId); + if (params == NULL) { + *inOutIdx = savedIdx; + return ASN_PARSE_E; + } + + oldFlags = key->flags; + oldParams = key->params; + key->params = params; + ret = wc_SlhDsaKey_ImportPublic(key, pubKeyPtr, pubKeyLen); + if (ret != 0) { + /* Restore params/flags/inOutIdx. ImportPublic writes only the + * public half (sk[2*n .. 4*n]) and only after the length check + * passes; preserve any prior private bytes the caller may have + * imported into sk[0 .. 2*n]. */ + if (ret != WC_NO_ERR_TRACE(BAD_LENGTH_E)) { + ForceZero(key->sk + 2 * params->n, (word32)(2 * params->n)); + } + key->params = oldParams; + key->flags = oldFlags; + *inOutIdx = savedIdx; + } + + return ret; +} + +#ifdef WC_ENABLE_ASYM_KEY_EXPORT +/* Encode an SLH-DSA public key to DER. + * + * Pass NULL for output to get the size of the encoding. + * + * @param [in] key SLH-DSA key object. + * @param [out] output Buffer to put encoded data in. + * @param [in] inLen Size of buffer in bytes. + * @param [in] withAlg Whether to use SubjectPublicKeyInfo format. + * @return Size of encoded data in bytes on success. + * @return BAD_FUNC_ARG when key/key->params is NULL or param is unknown. + * @return NOT_COMPILED_IN when key->params names a known SLH-DSA variant + * whose parameter set isn't compiled in. In practice unreachable + * because SlhDsaParams[] is itself gated on the build, but the + * contract matches wc_SlhDsaOidToParam for forward compatibility. + */ +int wc_SlhDsaKey_PublicKeyToDer(SlhDsaKey* key, byte* output, word32 inLen, + int withAlg) +{ + int ret; + byte pubKey[WC_SLHDSA_MAX_PUB_LEN]; + word32 pubKeyLen = (word32)sizeof(pubKey); + int keytype; + + if ((key == NULL) || (key->params == NULL)) { + return BAD_FUNC_ARG; + } + + keytype = wc_SlhDsaParamToOid(key->params->param); + if (keytype < 0) { + return keytype; + } + + ret = wc_SlhDsaKey_ExportPublic(key, pubKey, &pubKeyLen); + if (ret == 0) { + ret = SetAsymKeyDerPublic(pubKey, pubKeyLen, output, inLen, keytype, + withAlg); + } + + return ret; +} + +#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY +/* Encode an SLH-DSA private key to DER (PKCS#8 / OneAsymmetricKey). + * + * RFC 9909: The privateKey OCTET STRING contains the raw 4*n bytes + * (SK.seed || SK.prf || PK.seed || PK.root) directly, without a nested + * OCTET STRING wrapper. This differs from Ed25519/Ed448 which use a + * double OCTET STRING wrapping. + * + * Pass NULL for output to get the required buffer size. + * + * @param [in] key SLH-DSA key object. + * @param [out] output Buffer to put encoded data in (or NULL for size). + * @param [in] inLen Size of buffer in bytes. + * @return Size of encoded data in bytes on success. + * @return BAD_FUNC_ARG when key/key->params is NULL or param is unknown. + * @return NOT_COMPILED_IN when key->params names a known SLH-DSA variant + * whose parameter set isn't compiled in (in practice unreachable; + * SlhDsaParams[] is itself gated on the build). + * @return MISSING_KEY when private key not set. + * @return BUFFER_E when output buffer is too small. + */ +int wc_SlhDsaKey_KeyToDer(SlhDsaKey* key, byte* output, word32 inLen) +{ + int keytype; + int n; + word32 privSz, algoSz, verSz, seqSz, sz; + + if ((key == NULL) || (key->params == NULL)) { + return BAD_FUNC_ARG; + } + if ((key->flags & WC_SLHDSA_FLAG_PRIVATE) == 0) { + return MISSING_KEY; + } + + keytype = wc_SlhDsaParamToOid(key->params->param); + if (keytype < 0) { + return keytype; + } + + n = key->params->n; + /* RFC 9909: bare OCTET STRING containing 4*n raw key bytes */ + privSz = SetOctetString((word32)(n * 4), NULL) + (word32)(n * 4); + algoSz = SetAlgoID(keytype, NULL, oidKeyType, 0); + verSz = 3; /* ASN_INTEGER(1) + length(1) + version_byte(1) */ + seqSz = SetSequence(verSz + algoSz + privSz, NULL); + sz = seqSz + verSz + algoSz + privSz; + + if (output == NULL) { + return (int)sz; + } + if (sz > inLen) { + return BUFFER_E; + } + + { + word32 idx = 0; + int actualVerSz; + idx += SetSequence(verSz + algoSz + privSz, output + idx); + actualVerSz = SetMyVersion(0, output + idx, FALSE); + if (actualVerSz != (int)verSz) { + return BUFFER_E; + } + idx += (word32)actualVerSz; + idx += SetAlgoID(keytype, output + idx, oidKeyType, 0); + idx += SetOctetString((word32)(n * 4), output + idx); + XMEMCPY(output + idx, key->sk, (word32)(n * 4)); + idx += (word32)(n * 4); + return (int)idx; + } +} + +/* Encode an SLH-DSA private key to DER (PKCS#8 / OneAsymmetricKey). + * + * For SLH-DSA, RFC 9909 packs SK.seed || SK.prf || PK.seed || PK.root into + * a single OCTET STRING, so there is no separate "private-only" encoding. + * This function is intentionally an alias of wc_SlhDsaKey_KeyToDer, kept + * for API parity with Ed25519/Ed448 which do have a distinct private form. + * + * @param [in] key SLH-DSA key object. + * @param [out] output Buffer to put encoded data in (or NULL for size). + * @param [in] inLen Size of buffer in bytes. + * @return Size of encoded data in bytes on success. + * @return BAD_FUNC_ARG when key is NULL. + * @return MISSING_KEY when private key not set. + * @return BUFFER_E when output buffer is too small. + */ +int wc_SlhDsaKey_PrivateKeyToDer(SlhDsaKey* key, byte* output, word32 inLen) +{ + return wc_SlhDsaKey_KeyToDer(key, output, inLen); +} +#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ +#endif /* WC_ENABLE_ASYM_KEY_EXPORT */ + #endif /* WOLFSSL_HAVE_SLHDSA */ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 757bd737ee..32b6abb875 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -54195,6 +54195,28 @@ out: } #endif +/* True iff slhdsa_test() actually emits at least one `goto out;` / + * ERROR_OUT(..., out). The SHAKE128S block has a couple of ERROR_OUTs + * gated only on PARAM_128S; everything else (other SHAKE variants, all + * SHA-2 KATs, slhdsa_test_param dispatch) lives inside `#ifndef + * WOLFSSL_SLHDSA_VERIFY_ONLY`. So the label is needed when 128S is + * built, OR when any other variant is built without VERIFY_ONLY. */ +#if defined(WOLFSSL_SLHDSA_PARAM_128S) || \ + (!defined(WOLFSSL_SLHDSA_VERIFY_ONLY) && \ + (defined(WOLFSSL_SLHDSA_PARAM_128F) || \ + defined(WOLFSSL_SLHDSA_PARAM_192S) || \ + defined(WOLFSSL_SLHDSA_PARAM_192F) || \ + defined(WOLFSSL_SLHDSA_PARAM_256S) || \ + defined(WOLFSSL_SLHDSA_PARAM_256F) || \ + defined(WOLFSSL_SLHDSA_PARAM_SHA2_128S) || \ + defined(WOLFSSL_SLHDSA_PARAM_SHA2_128F) || \ + defined(WOLFSSL_SLHDSA_PARAM_SHA2_192S) || \ + defined(WOLFSSL_SLHDSA_PARAM_SHA2_192F) || \ + defined(WOLFSSL_SLHDSA_PARAM_SHA2_256S) || \ + defined(WOLFSSL_SLHDSA_PARAM_SHA2_256F))) + #define SLHDSA_TEST_HAVE_ANY_PARAM +#endif + wc_test_ret_t slhdsa_test(void) { int ret = 0; @@ -56006,11 +56028,8 @@ wc_test_ret_t slhdsa_test(void) #endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ -#if defined(WOLFSSL_SLHDSA_VERIFY_ONLY) || \ - defined(WOLFSSL_SLHDSA_PARAM_128S) - +#ifdef SLHDSA_TEST_HAVE_ANY_PARAM out: - #endif #ifdef WOLFSSL_SLHDSA_PARAM_128S @@ -56021,7 +56040,9 @@ out: wc_SlhDsaKey_Free(key_vfy); } WC_FREE_VAR_EX(key_vfy, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); -#endif + /* key, sig, sk, pk are declared inside #ifdef WOLFSSL_SLHDSA_PARAM_128S + * (alongside the SHAKE-128s test data) so they only exist when 128S is + * built. Their cleanup must match. */ #ifndef WOLFSSL_SLHDSA_VERIFY_ONLY #ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC if (key) @@ -56034,6 +56055,7 @@ out: WC_FREE_VAR_EX(sk, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); WC_FREE_VAR_EX(pk, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); #endif +#endif /* WOLFSSL_SLHDSA_PARAM_128S */ return ret; } diff --git a/wolfssl-VS2022.vcxproj b/wolfssl-VS2022.vcxproj index 7bb1661a1b..a2c001ca8a 100644 --- a/wolfssl-VS2022.vcxproj +++ b/wolfssl-VS2022.vcxproj @@ -459,7 +459,6 @@ - @@ -469,6 +468,7 @@ + diff --git a/wolfssl.vcproj b/wolfssl.vcproj index a35cff8c7a..1bcc024863 100644 --- a/wolfssl.vcproj +++ b/wolfssl.vcproj @@ -371,10 +371,6 @@ RelativePath=".\wolfcrypt\src\sha512.c" > - - @@ -415,6 +411,10 @@ RelativePath=".\wolfcrypt\src\wc_port.c" > + + diff --git a/wolfssl.vcxproj b/wolfssl.vcxproj index c0cab55b3b..acc663d6a2 100644 --- a/wolfssl.vcxproj +++ b/wolfssl.vcxproj @@ -459,7 +459,6 @@ - @@ -469,6 +468,7 @@ + diff --git a/wolfssl/certs_test.h b/wolfssl/certs_test.h index 3b01e501ac..42b849f4ca 100644 --- a/wolfssl/certs_test.h +++ b/wolfssl/certs_test.h @@ -5911,148 +5911,6 @@ static const unsigned char bench_dilithium_level5_pubkey[] = { #endif /* HAVE_DILITHIUM */ -#if defined(HAVE_SPHINCS) - -/* certs/sphincs/bench_sphincs_fast_level1_key.der */ -static const unsigned char bench_sphincs_fast_level1_key[] = -{ - 0x30, 0x71, 0x02, 0x01, 0x00, 0x30, 0x08, 0x06, 0x06, 0x2B, - 0xCE, 0x0F, 0x06, 0x07, 0x0D, 0x04, 0x62, 0x04, 0x60, 0xD8, - 0xC4, 0x6E, 0x8D, 0x3B, 0xB7, 0xE7, 0x48, 0x8D, 0x6F, 0x0C, - 0x3D, 0xDF, 0xAB, 0x79, 0xB6, 0x62, 0xAE, 0x89, 0x19, 0x6F, - 0x5E, 0xF9, 0xD3, 0x3A, 0x69, 0xBA, 0xFF, 0x4C, 0x46, 0xDE, - 0xAA, 0x7C, 0x40, 0x79, 0x8C, 0xE1, 0xE5, 0x30, 0xE6, 0xDF, - 0x4E, 0x23, 0x5E, 0x14, 0xDB, 0x0A, 0x48, 0x4E, 0xF6, 0x57, - 0xCE, 0x45, 0x8F, 0x8B, 0x1D, 0x68, 0x63, 0xAA, 0x24, 0xA4, - 0xE1, 0x0D, 0xFB, 0x7C, 0x40, 0x79, 0x8C, 0xE1, 0xE5, 0x30, - 0xE6, 0xDF, 0x4E, 0x23, 0x5E, 0x14, 0xDB, 0x0A, 0x48, 0x4E, - 0xF6, 0x57, 0xCE, 0x45, 0x8F, 0x8B, 0x1D, 0x68, 0x63, 0xAA, - 0x24, 0xA4, 0xE1, 0x0D, 0xFB -}; -#define sizeof_bench_sphincs_fast_level1_key (sizeof(bench_sphincs_fast_level1_key)) - -/* certs/sphincs/bench_sphincs_fast_level3_key.der */ -static const unsigned char bench_sphincs_fast_level3_key[] = -{ - 0x30, 0x81, 0xA3, 0x02, 0x01, 0x00, 0x30, 0x08, 0x06, 0x06, - 0x2B, 0xCE, 0x0F, 0x06, 0x08, 0x0A, 0x04, 0x81, 0x93, 0x04, - 0x81, 0x90, 0xB2, 0x3A, 0x67, 0xA6, 0x4B, 0x8E, 0xB9, 0xEF, - 0xAD, 0x99, 0xE4, 0x3D, 0x65, 0xE8, 0xEE, 0xCF, 0xAC, 0xCF, - 0x2F, 0xDE, 0xBC, 0x11, 0x67, 0x8D, 0x8F, 0x8D, 0x3E, 0x99, - 0x31, 0x67, 0xED, 0x31, 0x6A, 0x05, 0x47, 0xC1, 0xDA, 0xC5, - 0x14, 0x17, 0xA1, 0x93, 0x83, 0x44, 0x58, 0x09, 0x80, 0x3A, - 0x47, 0x67, 0x42, 0x6D, 0x4C, 0xB7, 0xC8, 0x7D, 0x37, 0xF3, - 0x90, 0xF7, 0x46, 0x92, 0xB6, 0x26, 0xF7, 0x4E, 0x0D, 0x8D, - 0xB8, 0xCA, 0x8B, 0xA8, 0x20, 0x5D, 0x67, 0x85, 0xD2, 0x83, - 0x2C, 0x2A, 0x38, 0x1F, 0x57, 0x89, 0x76, 0x8C, 0x6D, 0x88, - 0xCE, 0x18, 0x4F, 0xA7, 0x88, 0x48, 0x7C, 0x0D, 0x47, 0x67, - 0x42, 0x6D, 0x4C, 0xB7, 0xC8, 0x7D, 0x37, 0xF3, 0x90, 0xF7, - 0x46, 0x92, 0xB6, 0x26, 0xF7, 0x4E, 0x0D, 0x8D, 0xB8, 0xCA, - 0x8B, 0xA8, 0x20, 0x5D, 0x67, 0x85, 0xD2, 0x83, 0x2C, 0x2A, - 0x38, 0x1F, 0x57, 0x89, 0x76, 0x8C, 0x6D, 0x88, 0xCE, 0x18, - 0x4F, 0xA7, 0x88, 0x48, 0x7C, 0x0D -}; -#define sizeof_bench_sphincs_fast_level3_key (sizeof(bench_sphincs_fast_level3_key)) - -/* certs/sphincs/bench_sphincs_fast_level5_key.der */ -static const unsigned char bench_sphincs_fast_level5_key[] = -{ - 0x30, 0x81, 0xD3, 0x02, 0x01, 0x00, 0x30, 0x08, 0x06, 0x06, - 0x2B, 0xCE, 0x0F, 0x06, 0x09, 0x0A, 0x04, 0x81, 0xC3, 0x04, - 0x81, 0xC0, 0xAB, 0xD3, 0xFD, 0x3B, 0x17, 0x00, 0xCD, 0xD5, - 0xB2, 0xEE, 0xD2, 0x36, 0xE5, 0xF7, 0x1D, 0xDC, 0xC8, 0x42, - 0xDB, 0x53, 0x6A, 0x8A, 0x0D, 0x6D, 0xD2, 0x3C, 0x1C, 0x7C, - 0x98, 0x4D, 0x73, 0xC8, 0xAB, 0x2E, 0xAA, 0x7A, 0xC0, 0x26, - 0xC4, 0x0D, 0x7E, 0xB4, 0xD3, 0xBB, 0x13, 0xF4, 0x6E, 0xFE, - 0x0E, 0xA5, 0xA4, 0x58, 0x57, 0xA2, 0xDD, 0x99, 0x62, 0xB9, - 0xBA, 0xC2, 0x5B, 0x26, 0xED, 0x6E, 0x99, 0xFA, 0x11, 0x0E, - 0xCF, 0x33, 0x54, 0x85, 0x56, 0x0C, 0xEB, 0x2A, 0xB0, 0xAA, - 0xEB, 0x74, 0x14, 0x89, 0x1A, 0xB9, 0x38, 0xF5, 0x29, 0x66, - 0x28, 0x28, 0x17, 0xF5, 0x72, 0x42, 0xEE, 0xC0, 0x14, 0x59, - 0xA0, 0x72, 0x9B, 0x9B, 0x1E, 0x7F, 0x70, 0x70, 0xBB, 0x89, - 0x0C, 0x7E, 0x87, 0x8B, 0x83, 0x80, 0x2B, 0x66, 0x58, 0x64, - 0x1D, 0x94, 0xAF, 0x58, 0xB5, 0x23, 0x2C, 0xA1, 0xE9, 0x95, - 0x99, 0xFA, 0x11, 0x0E, 0xCF, 0x33, 0x54, 0x85, 0x56, 0x0C, - 0xEB, 0x2A, 0xB0, 0xAA, 0xEB, 0x74, 0x14, 0x89, 0x1A, 0xB9, - 0x38, 0xF5, 0x29, 0x66, 0x28, 0x28, 0x17, 0xF5, 0x72, 0x42, - 0xEE, 0xC0, 0x14, 0x59, 0xA0, 0x72, 0x9B, 0x9B, 0x1E, 0x7F, - 0x70, 0x70, 0xBB, 0x89, 0x0C, 0x7E, 0x87, 0x8B, 0x83, 0x80, - 0x2B, 0x66, 0x58, 0x64, 0x1D, 0x94, 0xAF, 0x58, 0xB5, 0x23, - 0x2C, 0xA1, 0xE9, 0x95 -}; -#define sizeof_bench_sphincs_fast_level5_key (sizeof(bench_sphincs_fast_level5_key)) - -/* certs/sphincs/bench_sphincs_small_level1_key.der */ -static const unsigned char bench_sphincs_small_level1_key[] = -{ - 0x30, 0x71, 0x02, 0x01, 0x00, 0x30, 0x08, 0x06, 0x06, 0x2B, - 0xCE, 0x0F, 0x06, 0x07, 0x10, 0x04, 0x62, 0x04, 0x60, 0xFF, - 0x26, 0x56, 0x65, 0xAC, 0x6C, 0x0B, 0x72, 0x2D, 0x8D, 0xB8, - 0x29, 0x4A, 0x15, 0x7E, 0xEF, 0x55, 0xFD, 0xBE, 0xF4, 0xC0, - 0xE6, 0x6F, 0x2B, 0x7A, 0x97, 0x60, 0x51, 0x1C, 0xCB, 0x82, - 0x43, 0x44, 0xDE, 0x14, 0x3D, 0x4F, 0xE7, 0x3C, 0x1C, 0xB3, - 0xBB, 0x9F, 0xE8, 0x9F, 0x8F, 0xA4, 0xAD, 0xB9, 0x52, 0xC1, - 0x31, 0xF7, 0xC1, 0x86, 0x7E, 0x73, 0xFB, 0x9E, 0x72, 0x57, - 0x8A, 0xD7, 0x44, 0x44, 0xDE, 0x14, 0x3D, 0x4F, 0xE7, 0x3C, - 0x1C, 0xB3, 0xBB, 0x9F, 0xE8, 0x9F, 0x8F, 0xA4, 0xAD, 0xB9, - 0x52, 0xC1, 0x31, 0xF7, 0xC1, 0x86, 0x7E, 0x73, 0xFB, 0x9E, - 0x72, 0x57, 0x8A, 0xD7, 0x44 -}; -#define sizeof_bench_sphincs_small_level1_key (sizeof(bench_sphincs_small_level1_key)) - -/* certs/sphincs/bench_sphincs_small_level3_key.der */ -static const unsigned char bench_sphincs_small_level3_key[] = -{ - 0x30, 0x81, 0xA3, 0x02, 0x01, 0x00, 0x30, 0x08, 0x06, 0x06, - 0x2B, 0xCE, 0x0F, 0x06, 0x08, 0x0C, 0x04, 0x81, 0x93, 0x04, - 0x81, 0x90, 0x59, 0xC1, 0x44, 0x8A, 0x5F, 0xF3, 0xF1, 0xB3, - 0xB8, 0xFF, 0x98, 0x7F, 0x86, 0x4A, 0x4C, 0x19, 0xFC, 0x51, - 0xB8, 0x12, 0x87, 0x9C, 0x52, 0xD6, 0x7F, 0xD6, 0xB0, 0xA9, - 0xF7, 0xED, 0x44, 0x26, 0xAF, 0xC2, 0xCE, 0x47, 0xD9, 0xE3, - 0x95, 0x1A, 0xE6, 0x11, 0xC1, 0x37, 0x67, 0xA5, 0x89, 0xDD, - 0x37, 0x6A, 0xE9, 0xC3, 0x8C, 0x9B, 0x3E, 0xBA, 0xB1, 0x76, - 0x4A, 0x5A, 0xEE, 0xCD, 0x96, 0x66, 0xF2, 0x53, 0xDA, 0x8C, - 0x89, 0x69, 0xBF, 0xBF, 0xF9, 0xA5, 0xBC, 0x7D, 0x80, 0xA8, - 0x97, 0x63, 0x90, 0x55, 0x58, 0x6C, 0x0A, 0x52, 0x61, 0x0B, - 0xF3, 0xBC, 0xE1, 0x1F, 0xB4, 0xA6, 0x5F, 0x9F, 0x37, 0x6A, - 0xE9, 0xC3, 0x8C, 0x9B, 0x3E, 0xBA, 0xB1, 0x76, 0x4A, 0x5A, - 0xEE, 0xCD, 0x96, 0x66, 0xF2, 0x53, 0xDA, 0x8C, 0x89, 0x69, - 0xBF, 0xBF, 0xF9, 0xA5, 0xBC, 0x7D, 0x80, 0xA8, 0x97, 0x63, - 0x90, 0x55, 0x58, 0x6C, 0x0A, 0x52, 0x61, 0x0B, 0xF3, 0xBC, - 0xE1, 0x1F, 0xB4, 0xA6, 0x5F, 0x9F -}; -#define sizeof_bench_sphincs_small_level3_key (sizeof(bench_sphincs_small_level3_key)) - -/* certs/sphincs/bench_sphincs_small_level5_key.der */ -static const unsigned char bench_sphincs_small_level5_key[] = -{ - 0x30, 0x81, 0xD3, 0x02, 0x01, 0x00, 0x30, 0x08, 0x06, 0x06, - 0x2B, 0xCE, 0x0F, 0x06, 0x09, 0x0C, 0x04, 0x81, 0xC3, 0x04, - 0x81, 0xC0, 0x53, 0xE5, 0x25, 0x41, 0x1C, 0xCB, 0x8F, 0xAF, - 0x83, 0xBE, 0x64, 0x43, 0x70, 0x4E, 0x1D, 0x86, 0xF8, 0xFA, - 0xEA, 0x65, 0x9B, 0x45, 0xBC, 0xF1, 0x79, 0x57, 0x87, 0x51, - 0x2F, 0x6D, 0x50, 0xB8, 0x0D, 0x9A, 0x9F, 0x8C, 0xE8, 0x9B, - 0xE8, 0xFA, 0x1E, 0xF0, 0xA1, 0x98, 0xCA, 0x8B, 0x34, 0xD4, - 0x71, 0x53, 0xF0, 0xA7, 0x1D, 0xD6, 0x0D, 0xDF, 0x63, 0x61, - 0xA7, 0x12, 0x80, 0x64, 0xF7, 0x73, 0x14, 0x03, 0xD4, 0x54, - 0x01, 0x9D, 0x9D, 0x5D, 0x42, 0xC1, 0x2B, 0x91, 0xC3, 0xA2, - 0xD3, 0x12, 0x67, 0x35, 0x3B, 0xD7, 0x67, 0x31, 0xD5, 0xDC, - 0xDF, 0x4C, 0x4C, 0xAA, 0x45, 0xA8, 0x5D, 0x1E, 0xFB, 0x9E, - 0x34, 0x5D, 0x4B, 0x83, 0x77, 0xBF, 0x52, 0x8A, 0xDB, 0x67, - 0x7A, 0x52, 0xA4, 0x02, 0x29, 0xEB, 0x34, 0x9A, 0x4E, 0x86, - 0x25, 0x66, 0xFF, 0xA0, 0x79, 0x47, 0xBE, 0x94, 0xC2, 0x69, - 0x14, 0x03, 0xD4, 0x54, 0x01, 0x9D, 0x9D, 0x5D, 0x42, 0xC1, - 0x2B, 0x91, 0xC3, 0xA2, 0xD3, 0x12, 0x67, 0x35, 0x3B, 0xD7, - 0x67, 0x31, 0xD5, 0xDC, 0xDF, 0x4C, 0x4C, 0xAA, 0x45, 0xA8, - 0x5D, 0x1E, 0xFB, 0x9E, 0x34, 0x5D, 0x4B, 0x83, 0x77, 0xBF, - 0x52, 0x8A, 0xDB, 0x67, 0x7A, 0x52, 0xA4, 0x02, 0x29, 0xEB, - 0x34, 0x9A, 0x4E, 0x86, 0x25, 0x66, 0xFF, 0xA0, 0x79, 0x47, - 0xBE, 0x94, 0xC2, 0x69 -}; -#define sizeof_bench_sphincs_small_level5_key (sizeof(bench_sphincs_small_level5_key)) - -#endif /* HAVE_SPHINCS */ - #if defined(HAVE_ECC) && defined(USE_CERT_BUFFERS_256) /* ./certs/ecc-client-key.der, ECC */ diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index abdfa953f9..915a6c9559 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -67,8 +67,8 @@ that can be serialized and deserialized in a cross-platform way. #ifdef HAVE_ED448 #include #endif -#ifdef HAVE_SPHINCS - #include +#ifdef WOLFSSL_HAVE_SLHDSA + #include #endif #ifdef HAVE_FALCON #include @@ -1542,7 +1542,7 @@ struct SignatureCtx { #endif #if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) || \ !defined(NO_DSA) || defined(HAVE_DILITHIUM) || defined(HAVE_FALCON) || \ - defined(HAVE_SPHINCS) + defined(WOLFSSL_HAVE_SLHDSA) int verify; #endif union { @@ -1595,11 +1595,11 @@ struct SignatureCtx { struct dilithium_key* dilithium; #endif #endif - #ifdef HAVE_SPHINCS + #ifdef WOLFSSL_HAVE_SLHDSA #ifdef WOLFSSL_NO_MALLOC - struct sphincs_key sphincs[1]; + SlhDsaKey slhdsa[1]; #else - struct sphincs_key* sphincs; + SlhDsaKey* slhdsa; #endif #endif #ifndef WOLFSSL_NO_MALLOC @@ -1856,13 +1856,14 @@ struct DecodedCert { #endif /* WOLFSSL_SUBJ_INFO_ACC */ #if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) || \ - defined(HAVE_DILITHIUM) || defined(HAVE_FALCON) || defined(HAVE_SPHINCS) + defined(HAVE_DILITHIUM) || defined(HAVE_FALCON) || \ + defined(WOLFSSL_HAVE_SLHDSA) word32 pkCurveOID; /* Public Key's curve OID */ #ifdef WOLFSSL_CUSTOM_CURVES int pkCurveSize; /* Public Key's curve size */ #endif #endif /* HAVE_ECC || HAVE_ED25519 || HAVE_ED448 || HAVE_DILITHIUM || - * HAVE_FALCON || HAVE_SPHINCS */ + * HAVE_FALCON || WOLFSSL_HAVE_SLHDSA */ const byte* beforeDate; int beforeDateLen; const byte* afterDate; @@ -2690,12 +2691,18 @@ enum cert_enums { ML_DSA_LEVEL2_KEY = 21, ML_DSA_LEVEL3_KEY = 22, ML_DSA_LEVEL5_KEY = 23, - SPHINCS_FAST_LEVEL1_KEY = 24, - SPHINCS_FAST_LEVEL3_KEY = 25, - SPHINCS_FAST_LEVEL5_KEY = 26, - SPHINCS_SMALL_LEVEL1_KEY = 27, - SPHINCS_SMALL_LEVEL3_KEY = 28, - SPHINCS_SMALL_LEVEL5_KEY = 29 + SLH_DSA_SHA2_128S_KEY = 24, + SLH_DSA_SHA2_128F_KEY = 25, + SLH_DSA_SHA2_192S_KEY = 26, + SLH_DSA_SHA2_192F_KEY = 27, + SLH_DSA_SHA2_256S_KEY = 28, + SLH_DSA_SHA2_256F_KEY = 29, + SLH_DSA_SHAKE_128S_KEY = 30, + SLH_DSA_SHAKE_128F_KEY = 31, + SLH_DSA_SHAKE_192S_KEY = 32, + SLH_DSA_SHAKE_192F_KEY = 33, + SLH_DSA_SHAKE_256S_KEY = 34, + SLH_DSA_SHAKE_256F_KEY = 35 }; #endif /* WOLFSSL_CERT_GEN */ @@ -3133,7 +3140,7 @@ WOLFSSL_TEST_VIS int wolfssl_local_MatchIpSubnet(const byte* ip, int ipSz, || (defined(HAVE_CURVE25519) && defined(HAVE_CURVE25519_KEY_IMPORT)) \ || (defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT)) \ || (defined(HAVE_CURVE448) && defined(HAVE_CURVE448_KEY_IMPORT)) \ - || defined(HAVE_FALCON) || defined(HAVE_DILITHIUM) || defined(HAVE_SPHINCS)) + || defined(HAVE_FALCON) || defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_SLHDSA)) WOLFSSL_LOCAL int DecodeAsymKey_Assign(const byte* input, word32* inOutIdx, word32 inSz, const byte** seed, word32* seedLen, const byte** privKey, word32* privKeyLen, const byte** pubKey, word32* pubKeyLen, @@ -3150,6 +3157,16 @@ WOLFSSL_TEST_VIS int SetAsymKeyDer(const byte* privKey, word32 privKeyLen, int keyType); #endif +#ifdef WOLFSSL_HAVE_SLHDSA +/* SLH-DSA OID mapping helpers shared with x509.c, ssl.c, wc_slhdsa.c, etc. + * All four are backed by a single static map in asn.c so the per-variant + * gating (WOLFSSL_SLHDSA_PARAM_NO_*) lives in one place. */ +WOLFSSL_LOCAL int wc_SlhDsaOidToParam(int oid); +WOLFSSL_LOCAL int wc_SlhDsaOidToCertType(int oid); +WOLFSSL_LOCAL int wc_IsSlhDsaOid(int oid); +WOLFSSL_LOCAL int wc_SlhDsaParamToOid(enum SlhDsaParam param); +#endif + #endif /* !NO_ASN */ #if !defined(NO_ASN) || !defined(NO_PWDBASED) diff --git a/wolfssl/wolfcrypt/asn_public.h b/wolfssl/wolfcrypt/asn_public.h index 15359ae835..bb85d51b0e 100644 --- a/wolfssl/wolfcrypt/asn_public.h +++ b/wolfssl/wolfcrypt/asn_public.h @@ -81,9 +81,9 @@ This library defines the interface APIs for X509 certificates. typedef struct dilithium_key dilithium_key; #define WC_DILITHIUMKEY_TYPE_DEFINED #endif -#ifndef WC_SPHINCSKEY_TYPE_DEFINED - typedef struct sphincs_key sphincs_key; - #define WC_SPHINCSKEY_TYPE_DEFINED +#ifndef WC_SLHDSAKEY_TYPE_DEFINED + typedef struct SlhDsaKey SlhDsaKey; + #define WC_SLHDSAKEY_TYPE_DEFINED #endif enum EncPkcs8Types { @@ -143,12 +143,18 @@ enum CertType { ML_DSA_LEVEL2_TYPE, ML_DSA_LEVEL3_TYPE, ML_DSA_LEVEL5_TYPE, - SPHINCS_FAST_LEVEL1_TYPE, - SPHINCS_FAST_LEVEL3_TYPE, - SPHINCS_FAST_LEVEL5_TYPE, - SPHINCS_SMALL_LEVEL1_TYPE, - SPHINCS_SMALL_LEVEL3_TYPE, - SPHINCS_SMALL_LEVEL5_TYPE, + SLH_DSA_SHA2_128S_TYPE, + SLH_DSA_SHA2_128F_TYPE, + SLH_DSA_SHA2_192S_TYPE, + SLH_DSA_SHA2_192F_TYPE, + SLH_DSA_SHA2_256S_TYPE, + SLH_DSA_SHA2_256F_TYPE, + SLH_DSA_SHAKE_128S_TYPE, + SLH_DSA_SHAKE_128F_TYPE, + SLH_DSA_SHAKE_192S_TYPE, + SLH_DSA_SHAKE_192F_TYPE, + SLH_DSA_SHAKE_256S_TYPE, + SLH_DSA_SHAKE_256F_TYPE, ECC_PARAM_TYPE, CHAIN_CERT_TYPE, PKCS7_TYPE, diff --git a/wolfssl/wolfcrypt/include.am b/wolfssl/wolfcrypt/include.am index 9ef11785fc..a4c703c455 100644 --- a/wolfssl/wolfcrypt/include.am +++ b/wolfssl/wolfcrypt/include.am @@ -25,7 +25,6 @@ nobase_include_HEADERS+= \ wolfssl/wolfcrypt/ed448.h \ wolfssl/wolfcrypt/falcon.h \ wolfssl/wolfcrypt/dilithium.h \ - wolfssl/wolfcrypt/sphincs.h \ wolfssl/wolfcrypt/fe_448.h \ wolfssl/wolfcrypt/ge_448.h \ wolfssl/wolfcrypt/eccsi.h \ diff --git a/wolfssl/wolfcrypt/oid_sum.h b/wolfssl/wolfcrypt/oid_sum.h index f0d4a2fe30..8df91a8546 100644 --- a/wolfssl/wolfcrypt/oid_sum.h +++ b/wolfssl/wolfcrypt/oid_sum.h @@ -196,18 +196,30 @@ enum Key_Sum { ML_DSA_LEVEL3k = 432, /* 2.16.840.1.101.3.4.3.18 */ /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x13 */ ML_DSA_LEVEL5k = 433, /* 2.16.840.1.101.3.4.3.19 */ - /* 0x2b,0xce,0x0f,0x06,0x07,0x04 */ - SPHINCS_FAST_LEVEL1k = 281, /* 1.3.9999.6.7.4 */ - /* 0x2b,0xce,0x0f,0x06,0x08,0x03 */ - SPHINCS_FAST_LEVEL3k = 283, /* 1.3.9999.6.8.3 */ - /* 0x2b,0xce,0x0f,0x06,0x09,0x03 */ - SPHINCS_FAST_LEVEL5k = 282, /* 1.3.9999.6.9.3 */ - /* 0x2b,0xce,0x0f,0x06,0x07,0x0a */ - SPHINCS_SMALL_LEVEL1k = 287, /* 1.3.9999.6.7.10 */ - /* 0x2b,0xce,0x0f,0x06,0x08,0x07 */ - SPHINCS_SMALL_LEVEL3k = 285, /* 1.3.9999.6.8.7 */ - /* 0x2b,0xce,0x0f,0x06,0x09,0x07 */ - SPHINCS_SMALL_LEVEL5k = 286 /* 1.3.9999.6.9.7 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x14 */ + SLH_DSA_SHA2_128Sk = 434, /* 2.16.840.1.101.3.4.3.20 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x15 */ + SLH_DSA_SHA2_128Fk = 435, /* 2.16.840.1.101.3.4.3.21 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x16 */ + SLH_DSA_SHA2_192Sk = 436, /* 2.16.840.1.101.3.4.3.22 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x17 */ + SLH_DSA_SHA2_192Fk = 437, /* 2.16.840.1.101.3.4.3.23 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x18 */ + SLH_DSA_SHA2_256Sk = 438, /* 2.16.840.1.101.3.4.3.24 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x19 */ + SLH_DSA_SHA2_256Fk = 439, /* 2.16.840.1.101.3.4.3.25 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x1a */ + SLH_DSA_SHAKE_128Sk = 440, /* 2.16.840.1.101.3.4.3.26 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x1b */ + SLH_DSA_SHAKE_128Fk = 441, /* 2.16.840.1.101.3.4.3.27 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x1c */ + SLH_DSA_SHAKE_192Sk = 442, /* 2.16.840.1.101.3.4.3.28 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x1d */ + SLH_DSA_SHAKE_192Fk = 443, /* 2.16.840.1.101.3.4.3.29 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x1e */ + SLH_DSA_SHAKE_256Sk = 444, /* 2.16.840.1.101.3.4.3.30 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x1f */ + SLH_DSA_SHAKE_256Fk = 445 /* 2.16.840.1.101.3.4.3.31 */ #else /* 0x00 */ ANONk = 0x7fffffff, /* 0.0 */ @@ -249,18 +261,30 @@ enum Key_Sum { ML_DSA_LEVEL3k = 0x7db37ae8, /* 2.16.840.1.101.3.4.3.18 */ /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x13 */ ML_DSA_LEVEL5k = 0x7db37ae9, /* 2.16.840.1.101.3.4.3.19 */ - /* 0x2b,0xce,0x0f,0x06,0x07,0x04 */ - SPHINCS_FAST_LEVEL1k = 0x06f0ca2c, /* 1.3.9999.6.7.4 */ - /* 0x2b,0xce,0x0f,0x06,0x08,0x03 */ - SPHINCS_FAST_LEVEL3k = 0x06f0cd23, /* 1.3.9999.6.8.3 */ - /* 0x2b,0xce,0x0f,0x06,0x09,0x03 */ - SPHINCS_FAST_LEVEL5k = 0x06f0cd22, /* 1.3.9999.6.9.3 */ - /* 0x2b,0xce,0x0f,0x06,0x07,0x0a */ - SPHINCS_SMALL_LEVEL1k = 0x06f0c42c, /* 1.3.9999.6.7.10 */ - /* 0x2b,0xce,0x0f,0x06,0x08,0x07 */ - SPHINCS_SMALL_LEVEL3k = 0x06f0c923, /* 1.3.9999.6.8.7 */ - /* 0x2b,0xce,0x0f,0x06,0x09,0x07 */ - SPHINCS_SMALL_LEVEL5k = 0x06f0c922 /* 1.3.9999.6.9.7 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x14 */ + SLH_DSA_SHA2_128Sk = 0x7db37aee, /* 2.16.840.1.101.3.4.3.20 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x15 */ + SLH_DSA_SHA2_128Fk = 0x7db37aef, /* 2.16.840.1.101.3.4.3.21 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x16 */ + SLH_DSA_SHA2_192Sk = 0x7db37aec, /* 2.16.840.1.101.3.4.3.22 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x17 */ + SLH_DSA_SHA2_192Fk = 0x7db37aed, /* 2.16.840.1.101.3.4.3.23 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x18 */ + SLH_DSA_SHA2_256Sk = 0x7db37ae2, /* 2.16.840.1.101.3.4.3.24 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x19 */ + SLH_DSA_SHA2_256Fk = 0x7db37ae3, /* 2.16.840.1.101.3.4.3.25 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x1a */ + SLH_DSA_SHAKE_128Sk = 0x7db37ae0, /* 2.16.840.1.101.3.4.3.26 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x1b */ + SLH_DSA_SHAKE_128Fk = 0x7db37ae1, /* 2.16.840.1.101.3.4.3.27 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x1c */ + SLH_DSA_SHAKE_192Sk = 0x7db37ae6, /* 2.16.840.1.101.3.4.3.28 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x1d */ + SLH_DSA_SHAKE_192Fk = 0x7db37ae7, /* 2.16.840.1.101.3.4.3.29 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x1e */ + SLH_DSA_SHAKE_256Sk = 0x7db37ae4, /* 2.16.840.1.101.3.4.3.30 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x1f */ + SLH_DSA_SHAKE_256Fk = 0x7db37ae5 /* 2.16.840.1.101.3.4.3.31 */ #endif }; @@ -1580,18 +1604,30 @@ enum Ctc_SigType { CTC_ML_DSA_LEVEL3 = 432, /* 2.16.840.1.101.3.4.3.18 */ /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x13 */ CTC_ML_DSA_LEVEL5 = 433, /* 2.16.840.1.101.3.4.3.19 */ - /* 0x2b,0xce,0x0f,0x06,0x07,0x04 */ - CTC_SPHINCS_FAST_LEVEL1 = 281, /* 1.3.9999.6.7.4 */ - /* 0x2b,0xce,0x0f,0x06,0x08,0x03 */ - CTC_SPHINCS_FAST_LEVEL3 = 283, /* 1.3.9999.6.8.3 */ - /* 0x2b,0xce,0x0f,0x06,0x09,0x03 */ - CTC_SPHINCS_FAST_LEVEL5 = 282, /* 1.3.9999.6.9.3 */ - /* 0x2b,0xce,0x0f,0x06,0x07,0x0a */ - CTC_SPHINCS_SMALL_LEVEL1 = 287, /* 1.3.9999.6.7.10 */ - /* 0x2b,0xce,0x0f,0x06,0x08,0x07 */ - CTC_SPHINCS_SMALL_LEVEL3 = 285, /* 1.3.9999.6.8.7 */ - /* 0x2b,0xce,0x0f,0x06,0x09,0x07 */ - CTC_SPHINCS_SMALL_LEVEL5 = 286 /* 1.3.9999.6.9.7 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x14 */ + CTC_SLH_DSA_SHA2_128S = 434, /* 2.16.840.1.101.3.4.3.20 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x15 */ + CTC_SLH_DSA_SHA2_128F = 435, /* 2.16.840.1.101.3.4.3.21 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x16 */ + CTC_SLH_DSA_SHA2_192S = 436, /* 2.16.840.1.101.3.4.3.22 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x17 */ + CTC_SLH_DSA_SHA2_192F = 437, /* 2.16.840.1.101.3.4.3.23 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x18 */ + CTC_SLH_DSA_SHA2_256S = 438, /* 2.16.840.1.101.3.4.3.24 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x19 */ + CTC_SLH_DSA_SHA2_256F = 439, /* 2.16.840.1.101.3.4.3.25 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x1a */ + CTC_SLH_DSA_SHAKE_128S = 440, /* 2.16.840.1.101.3.4.3.26 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x1b */ + CTC_SLH_DSA_SHAKE_128F = 441, /* 2.16.840.1.101.3.4.3.27 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x1c */ + CTC_SLH_DSA_SHAKE_192S = 442, /* 2.16.840.1.101.3.4.3.28 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x1d */ + CTC_SLH_DSA_SHAKE_192F = 443, /* 2.16.840.1.101.3.4.3.29 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x1e */ + CTC_SLH_DSA_SHAKE_256S = 444, /* 2.16.840.1.101.3.4.3.30 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x1f */ + CTC_SLH_DSA_SHAKE_256F = 445 /* 2.16.840.1.101.3.4.3.31 */ #else /* 0x2a,0x86,0x48,0xce,0x38,0x04,0x03 */ CTC_SHAwDSA = 0x314b8212, /* 1.2.840.10040.4.3 */ @@ -1661,18 +1697,30 @@ enum Ctc_SigType { CTC_ML_DSA_LEVEL3 = 0x7db37ae8, /* 2.16.840.1.101.3.4.3.18 */ /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x13 */ CTC_ML_DSA_LEVEL5 = 0x7db37ae9, /* 2.16.840.1.101.3.4.3.19 */ - /* 0x2b,0xce,0x0f,0x06,0x07,0x04 */ - CTC_SPHINCS_FAST_LEVEL1 = 0x06f0ca2c, /* 1.3.9999.6.7.4 */ - /* 0x2b,0xce,0x0f,0x06,0x08,0x03 */ - CTC_SPHINCS_FAST_LEVEL3 = 0x06f0cd23, /* 1.3.9999.6.8.3 */ - /* 0x2b,0xce,0x0f,0x06,0x09,0x03 */ - CTC_SPHINCS_FAST_LEVEL5 = 0x06f0cd22, /* 1.3.9999.6.9.3 */ - /* 0x2b,0xce,0x0f,0x06,0x07,0x0a */ - CTC_SPHINCS_SMALL_LEVEL1 = 0x06f0c42c, /* 1.3.9999.6.7.10 */ - /* 0x2b,0xce,0x0f,0x06,0x08,0x07 */ - CTC_SPHINCS_SMALL_LEVEL3 = 0x06f0c923, /* 1.3.9999.6.8.7 */ - /* 0x2b,0xce,0x0f,0x06,0x09,0x07 */ - CTC_SPHINCS_SMALL_LEVEL5 = 0x06f0c922 /* 1.3.9999.6.9.7 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x14 */ + CTC_SLH_DSA_SHA2_128S = 0x7db37aee, /* 2.16.840.1.101.3.4.3.20 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x15 */ + CTC_SLH_DSA_SHA2_128F = 0x7db37aef, /* 2.16.840.1.101.3.4.3.21 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x16 */ + CTC_SLH_DSA_SHA2_192S = 0x7db37aec, /* 2.16.840.1.101.3.4.3.22 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x17 */ + CTC_SLH_DSA_SHA2_192F = 0x7db37aed, /* 2.16.840.1.101.3.4.3.23 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x18 */ + CTC_SLH_DSA_SHA2_256S = 0x7db37ae2, /* 2.16.840.1.101.3.4.3.24 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x19 */ + CTC_SLH_DSA_SHA2_256F = 0x7db37ae3, /* 2.16.840.1.101.3.4.3.25 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x1a */ + CTC_SLH_DSA_SHAKE_128S = 0x7db37ae0, /* 2.16.840.1.101.3.4.3.26 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x1b */ + CTC_SLH_DSA_SHAKE_128F = 0x7db37ae1, /* 2.16.840.1.101.3.4.3.27 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x1c */ + CTC_SLH_DSA_SHAKE_192S = 0x7db37ae6, /* 2.16.840.1.101.3.4.3.28 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x1d */ + CTC_SLH_DSA_SHAKE_192F = 0x7db37ae7, /* 2.16.840.1.101.3.4.3.29 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x1e */ + CTC_SLH_DSA_SHAKE_256S = 0x7db37ae4, /* 2.16.840.1.101.3.4.3.30 */ + /* 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x1f */ + CTC_SLH_DSA_SHAKE_256F = 0x7db37ae5 /* 2.16.840.1.101.3.4.3.31 */ #endif }; diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 8bb70507c0..ed74bba7b7 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -3292,7 +3292,7 @@ extern void uITRON4_free(void *p) ; (defined(HAVE_ED448) && defined(HAVE_ED448_KEY_EXPORT)) || \ (defined(HAVE_CURVE448) && defined(HAVE_CURVE448_KEY_EXPORT)) || \ defined(HAVE_FALCON) || defined(HAVE_DILITHIUM) || \ - defined(HAVE_SPHINCS) || defined(HAVE_LIBOQS)) + defined(WOLFSSL_HAVE_SLHDSA) || defined(HAVE_LIBOQS)) #define WC_ENABLE_ASYM_KEY_EXPORT #endif @@ -3302,7 +3302,7 @@ extern void uITRON4_free(void *p) ; (defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT)) || \ (defined(HAVE_CURVE448) && defined(HAVE_CURVE448_KEY_IMPORT)) || \ defined(HAVE_FALCON) || defined(HAVE_DILITHIUM) || \ - defined(HAVE_SPHINCS) || defined(HAVE_LIBOQS)) + defined(WOLFSSL_HAVE_SLHDSA) || defined(HAVE_LIBOQS)) #define WC_ENABLE_ASYM_KEY_IMPORT #endif diff --git a/wolfssl/wolfcrypt/sphincs.h b/wolfssl/wolfcrypt/sphincs.h deleted file mode 100644 index a070baf664..0000000000 --- a/wolfssl/wolfcrypt/sphincs.h +++ /dev/null @@ -1,167 +0,0 @@ -/* sphincs.h - * - * Copyright (C) 2006-2026 wolfSSL Inc. - * - * This file is part of wolfSSL. - * - * wolfSSL is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * wolfSSL is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA - */ - -/*! - \file wolfssl/wolfcrypt/sphincs.h -*/ - -/* Interfaces for Sphincs: - * - SPHINCS_FAST_LEVEL1 (AKA SPHINCS+-SHAKE-128f-simple) - * - SPHINCS_FAST_LEVEL3 (AKA SPHINCS+-SHAKE-192f-simple) - * - SPHINCS_FAST_LEVEL5 (AKA SPHINCS+-SHAKE-256f-simple) - * - SPHINCS_SMALL_LEVEL1 (AKA SPHINCS+-SHAKE-128s-simple) - * - SPHINCS_SMALL_LEVEL3 (AKA SPHINCS+-SHAKE-192s-simple) - * - SPHINCS_SMALL_LEVEL5 (AKA SPHINCS+-SHAKE-256s-simple) - */ - -#ifndef WOLF_CRYPT_SPHINCS_H -#define WOLF_CRYPT_SPHINCS_H - -#include - -#if defined(HAVE_SPHINCS) - -#ifdef HAVE_LIBOQS -#include -#include -#endif - -#ifdef __cplusplus - extern "C" { -#endif - -/* Macros Definitions */ - -#ifdef HAVE_LIBOQS - -#define SPHINCS_FAST_LEVEL1_SIG_SIZE OQS_SIG_sphincs_shake_128f_simple_length_signature -#define SPHINCS_FAST_LEVEL3_SIG_SIZE OQS_SIG_sphincs_shake_192f_simple_length_signature -#define SPHINCS_FAST_LEVEL5_SIG_SIZE OQS_SIG_sphincs_shake_256f_simple_length_signature -#define SPHINCS_SMALL_LEVEL1_SIG_SIZE OQS_SIG_sphincs_shake_128s_simple_length_signature -#define SPHINCS_SMALL_LEVEL3_SIG_SIZE OQS_SIG_sphincs_shake_192s_simple_length_signature -#define SPHINCS_SMALL_LEVEL5_SIG_SIZE OQS_SIG_sphincs_shake_256s_simple_length_signature - -#define SPHINCS_LEVEL1_KEY_SIZE OQS_SIG_sphincs_shake_128f_simple_length_secret_key -#define SPHINCS_LEVEL1_PUB_KEY_SIZE OQS_SIG_sphincs_shake_128f_simple_length_public_key -#define SPHINCS_LEVEL1_PRV_KEY_SIZE (SPHINCS_LEVEL1_PUB_KEY_SIZE+SPHINCS_LEVEL1_KEY_SIZE) - -#define SPHINCS_LEVEL3_KEY_SIZE OQS_SIG_sphincs_shake_192f_simple_length_secret_key -#define SPHINCS_LEVEL3_PUB_KEY_SIZE OQS_SIG_sphincs_shake_192f_simple_length_public_key -#define SPHINCS_LEVEL3_PRV_KEY_SIZE (SPHINCS_LEVEL3_PUB_KEY_SIZE+SPHINCS_LEVEL3_KEY_SIZE) - -#define SPHINCS_LEVEL5_KEY_SIZE OQS_SIG_sphincs_shake_256f_simple_length_secret_key -#define SPHINCS_LEVEL5_PUB_KEY_SIZE OQS_SIG_sphincs_shake_256f_simple_length_public_key -#define SPHINCS_LEVEL5_PRV_KEY_SIZE (SPHINCS_LEVEL5_PUB_KEY_SIZE+SPHINCS_LEVEL5_KEY_SIZE) -#endif - -#define SPHINCS_MAX_SIG_SIZE SPHINCS_FAST_LEVEL5_SIG_SIZE -#define SPHINCS_MAX_KEY_SIZE SPHINCS_LEVEL5_PRV_KEY_SIZE -#define SPHINCS_MAX_PUB_KEY_SIZE SPHINCS_LEVEL5_PUB_KEY_SIZE -#define SPHINCS_MAX_PRV_KEY_SIZE SPHINCS_LEVEL5_PRV_KEY_SIZE - -#define FAST_VARIANT 1 -#define SMALL_VARIANT 2 - -/* Structs */ - -struct sphincs_key { - WC_BITFIELD pubKeySet:1; - WC_BITFIELD prvKeySet:1; - byte level; /* 1,3 or 5 */ - byte optim; /* FAST_VARIANT or SMALL_VARIANT */ - byte p[SPHINCS_MAX_PUB_KEY_SIZE]; - byte k[SPHINCS_MAX_PRV_KEY_SIZE]; -}; - -#ifndef WC_SPHINCSKEY_TYPE_DEFINED - typedef struct sphincs_key sphincs_key; - #define WC_SPHINCSKEY_TYPE_DEFINED -#endif - -/* Functions */ - -WOLFSSL_API -int wc_sphincs_sign_msg(const byte* in, word32 inLen, byte* out, word32 *outLen, - sphincs_key* key, WC_RNG* rng); -WOLFSSL_API -int wc_sphincs_verify_msg(const byte* sig, word32 sigLen, const byte* msg, - word32 msgLen, int* res, sphincs_key* key); - -WOLFSSL_API -int wc_sphincs_init(sphincs_key* key); -WOLFSSL_API -int wc_sphincs_set_level_and_optim(sphincs_key* key, byte level, byte optim); -WOLFSSL_API -int wc_sphincs_get_level_and_optim(sphincs_key* key, byte* level, byte *optim); -WOLFSSL_API -void wc_sphincs_free(sphincs_key* key); - -WOLFSSL_API -int wc_sphincs_import_public(const byte* in, word32 inLen, sphincs_key* key); -WOLFSSL_API -int wc_sphincs_import_private_only(const byte* priv, word32 privSz, - sphincs_key* key); -WOLFSSL_API -int wc_sphincs_import_private_key(const byte* priv, word32 privSz, - const byte* pub, word32 pubSz, - sphincs_key* key); - -WOLFSSL_API -int wc_sphincs_export_public(sphincs_key* key, byte* out, word32* outLen); -WOLFSSL_API -int wc_sphincs_export_private_only(sphincs_key* key, byte* out, word32* outLen); -WOLFSSL_API -int wc_sphincs_export_private(sphincs_key* key, byte* out, word32* outLen); -WOLFSSL_API -int wc_sphincs_export_key(sphincs_key* key, byte* priv, word32 *privSz, - byte* pub, word32 *pubSz); - -WOLFSSL_API -int wc_sphincs_check_key(sphincs_key* key); - -WOLFSSL_API -int wc_sphincs_size(sphincs_key* key); -WOLFSSL_API -int wc_sphincs_priv_size(sphincs_key* key); -WOLFSSL_API -int wc_sphincs_pub_size(sphincs_key* key); -WOLFSSL_API -int wc_sphincs_sig_size(sphincs_key* key); - -WOLFSSL_API int wc_Sphincs_PrivateKeyDecode(const byte* input, - word32* inOutIdx, - sphincs_key* key, word32 inSz); -WOLFSSL_API int wc_Sphincs_PublicKeyDecode(const byte* input, - word32* inOutIdx, - sphincs_key* key, word32 inSz); -WOLFSSL_API int wc_Sphincs_KeyToDer(sphincs_key* key, byte* output, - word32 inLen); -WOLFSSL_API int wc_Sphincs_PrivateKeyToDer(sphincs_key* key, byte* output, - word32 inLen); -WOLFSSL_API int wc_Sphincs_PublicKeyToDer(sphincs_key* key, byte* output, - word32 inLen, int withAlg); - -#ifdef __cplusplus - } /* extern "C" */ -#endif - -#endif /* HAVE_SPHINCS */ -#endif /* WOLF_CRYPT_SPHINCS_H */ diff --git a/wolfssl/wolfcrypt/types.h b/wolfssl/wolfcrypt/types.h index b6c8049e48..01e71a3ebb 100644 --- a/wolfssl/wolfcrypt/types.h +++ b/wolfssl/wolfcrypt/types.h @@ -1370,7 +1370,7 @@ enum { DYNAMIC_TYPE_FALCON = 95, DYNAMIC_TYPE_SESSION = 96, DYNAMIC_TYPE_DILITHIUM = 97, - DYNAMIC_TYPE_SPHINCS = 98, + DYNAMIC_TYPE_SPHINCS = 98, /* deprecated: kept for ABI compat */ DYNAMIC_TYPE_SM4_BUFFER = 99, DYNAMIC_TYPE_DEBUG_TAG = 100, DYNAMIC_TYPE_LMS = 101, @@ -2314,7 +2314,9 @@ enum Max_ASN { DSA_INTS = 5, /* DSA ints in private key */ MAX_SALT_SIZE = 64, /* MAX PKCS Salt length */ MAX_IV_SIZE = 64, /* MAX PKCS Iv length */ -#ifdef HAVE_SPHINCS +#ifdef WOLFSSL_HAVE_SLHDSA + /* Largest raw SLH-DSA signature (SHAKE-256f) is 49856 bytes; round up + * to leave headroom for ASN.1 wrapping (BIT STRING tag + length). */ MAX_ENCODED_SIG_SZ = 51200, #elif defined(HAVE_FALCON) || defined(HAVE_DILITHIUM) MAX_ENCODED_SIG_SZ = 5120, @@ -2367,7 +2369,7 @@ enum Max_ASN { /* Maximum DER digest ASN header size */ /* Max X509 header length indicates the * max length + 2 ('\n', '\0') */ -#if defined(HAVE_FALCON) || defined(HAVE_DILITHIUM) || defined(HAVE_SPHINCS) +#if defined(HAVE_FALCON) || defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_SLHDSA) MAX_X509_HEADER_SZ = (48 + 2), /* Maximum PEM Header/Footer Size */ #else MAX_X509_HEADER_SZ = (37 + 2), /* Maximum PEM Header/Footer Size */ diff --git a/wolfssl/wolfcrypt/wc_slhdsa.h b/wolfssl/wolfcrypt/wc_slhdsa.h index eb34c73bd8..715b9af80b 100644 --- a/wolfssl/wolfcrypt/wc_slhdsa.h +++ b/wolfssl/wolfcrypt/wc_slhdsa.h @@ -23,6 +23,13 @@ #define WOLF_CRYPT_WC_SLHDSA_H #include + +#if FIPS_VERSION3_GE(7,0,0) + #include +#endif + +#ifdef WOLFSSL_HAVE_SLHDSA + #include #include @@ -32,12 +39,6 @@ #include #endif -#if FIPS_VERSION3_GE(7,0,0) - #include -#endif - -#ifdef WOLFSSL_HAVE_SLHDSA - /* ======== SHAKE parameter guards ======== */ #ifdef WOLFSSL_SLHDSA_NO_SHAKE @@ -693,6 +694,27 @@ WOLFSSL_API int wc_SlhDsaKey_PrivateSizeFromParam(enum SlhDsaParam param); WOLFSSL_API int wc_SlhDsaKey_PublicSizeFromParam(enum SlhDsaParam param); WOLFSSL_API int wc_SlhDsaKey_SigSizeFromParam(enum SlhDsaParam param); +/* DER encode/decode */ +#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY +WOLFSSL_API int wc_SlhDsaKey_PrivateKeyDecode(const byte* input, + word32* inOutIdx, SlhDsaKey* key, word32 inSz); +#endif +WOLFSSL_API int wc_SlhDsaKey_PublicKeyDecode(const byte* input, + word32* inOutIdx, SlhDsaKey* key, word32 inSz); +#ifdef WC_ENABLE_ASYM_KEY_EXPORT +#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY +WOLFSSL_API int wc_SlhDsaKey_KeyToDer(SlhDsaKey* key, byte* output, + word32 inLen); +/* SLH-DSA has no separate private-only encoding based on RFC 9909. This + * function is an intentional alias of wc_SlhDsaKey_KeyToDer, kept for API + * parity with other algorithms which do have a distinct private form. */ +WOLFSSL_API int wc_SlhDsaKey_PrivateKeyToDer(SlhDsaKey* key, byte* output, + word32 inLen); +#endif +WOLFSSL_API int wc_SlhDsaKey_PublicKeyToDer(SlhDsaKey* key, byte* output, + word32 inLen, int withAlg); +#endif + #endif /* WOLFSSL_HAVE_SLHDSA */ #endif /* WOLF_CRYPT_WC_SLHDSA_H */ diff --git a/wrapper/CSharp/wolfssl.vcxproj b/wrapper/CSharp/wolfssl.vcxproj index 6bb50d9da0..391b5c9eb9 100644 --- a/wrapper/CSharp/wolfssl.vcxproj +++ b/wrapper/CSharp/wolfssl.vcxproj @@ -341,7 +341,6 @@ - @@ -351,6 +350,7 @@ + diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index 9b5ca2097c..7332865b75 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -111,7 +111,6 @@ if(CONFIG_WOLFSSL) zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/sp_dsp32.c) zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/sp_int.c) zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/sp_x86_64.c) - zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/sphincs.c) zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/srp.c) zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/tfm.c) zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/wc_dsp.c) @@ -122,6 +121,7 @@ if(CONFIG_WOLFSSL) zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/wc_lms_impl.c) zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/wc_pkcs11.c) zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/wc_port.c) + zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/wc_slhdsa.c) zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/wolfevent.c) zephyr_library_sources(${ZEPHYR_CURRENT_MODULE_DIR}/wolfcrypt/src/wolfmath.c) From 31ae5d3efd6fec38a2a618fe230f1ef64e5cd1ea Mon Sep 17 00:00:00 2001 From: David Garske Date: Thu, 30 Apr 2026 07:46:19 -0700 Subject: [PATCH 166/167] Add STM32U3 hardware crypto support for AES, Hash and TRNG. Tested on NUCLEO-U385RG-Q. --- .wolfssl_known_macro_extras | 1 + IDE/STM32Cube/README.md | 1 + IDE/STM32Cube/default_conf.ftl | 12 ++++++++++-- wolfssl/wolfcrypt/port/st/stm32.h | 19 ++++++++++--------- wolfssl/wolfcrypt/settings.h | 13 ++++++++----- 5 files changed, 30 insertions(+), 16 deletions(-) diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 4d5c99f71d..cc6ba25169 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -563,6 +563,7 @@ STM32L552xx STM32L562xx STM32MP135Fxx STM32N657xx +STM32U385xx STM32U575xx STM32U585xx STM32U5A9xx diff --git a/IDE/STM32Cube/README.md b/IDE/STM32Cube/README.md index ebce241a08..20ed0b06ea 100644 --- a/IDE/STM32Cube/README.md +++ b/IDE/STM32Cube/README.md @@ -97,6 +97,7 @@ The section for "Hardware platform" may need to be adjusted depending on your pr * To enable STM32WB support define `WOLFSSL_STM32WB`. * To enable STM32WBA support define `WOLFSSL_STM32WBA`. * To enable STM32WL support define `WOLFSSL_STM32WL`. +* To enable STM32U3 support define `WOLFSSL_STM32U3`. * To enable STM32U5 support define `WOLFSSL_STM32U5`. * To enable STM32H5 support define `WOLFSSL_STM32H5`. * To enable STM32MP13 support define `WOLFSSL_STM32MP13`. diff --git a/IDE/STM32Cube/default_conf.ftl b/IDE/STM32Cube/default_conf.ftl index 951e319baf..c494cf9f02 100644 --- a/IDE/STM32Cube/default_conf.ftl +++ b/IDE/STM32Cube/default_conf.ftl @@ -206,6 +206,14 @@ extern ${variable.value} ${variable.name}; #elif defined(STM32G491xx) #define WOLFSSL_STM32G4 #define HAL_CONSOLE_UART hlpuart1 +#elif defined(STM32U385xx) + #define WOLFSSL_STM32U3 + #define STM32_HAL_V2 + #undef NO_STM32_HASH + #undef NO_STM32_CRYPTO + #ifndef HAL_CONSOLE_UART + #define HAL_CONSOLE_UART huart1 + #endif #elif defined(STM32U575xx) || defined(STM32U585xx) || defined(STM32U5A9xx) #define WOLFSSL_STM32U5 #define STM32_HAL_V2 @@ -250,8 +258,8 @@ extern ${variable.value} ${variable.name}; /* You need to define a CPU type, HW crypto and debug UART */ /* CPU Type: WOLFSSL_STM32F1, WOLFSSL_STM32F2, WOLFSSL_STM32F4, WOLFSSL_STM32F7, WOLFSSL_STM32H7, WOLFSSL_STM32L4, WOLFSSL_STM32L5, - WOLFSSL_STM32G0, WOLFSSL_STM32G4, WOLFSSL_STM32WB, WOLFSSL_STM32U5 and - WOLFSSL_STM32MP13 */ + WOLFSSL_STM32G0, WOLFSSL_STM32G4, WOLFSSL_STM32WB, WOLFSSL_STM32U3, + WOLFSSL_STM32U5 and WOLFSSL_STM32MP13 */ #define WOLFSSL_STM32F4 /* Debug UART used for printf */ diff --git a/wolfssl/wolfcrypt/port/st/stm32.h b/wolfssl/wolfcrypt/port/st/stm32.h index e073976619..9aa0d418ae 100644 --- a/wolfssl/wolfcrypt/port/st/stm32.h +++ b/wolfssl/wolfcrypt/port/st/stm32.h @@ -166,9 +166,10 @@ int wc_Stm32_Hmac_Final(STM32_HASH_Context* stmCtx, word32 algo, #if !defined(STM32_CRYPTO_AES_GCM) && (defined(WOLFSSL_STM32F4) || \ defined(WOLFSSL_STM32F7) || defined(WOLFSSL_STM32L4) || \ defined(WOLFSSL_STM32L5) || defined(WOLFSSL_STM32H7) || \ - defined(WOLFSSL_STM32U5) || defined(WOLFSSL_STM32H5) || \ - defined(WOLFSSL_STM32MP13) || defined(WOLFSSL_STM32H7S) || \ - defined(WOLFSSL_STM32N6) || defined(WOLFSSL_STM32G0)) + defined(WOLFSSL_STM32U5) || defined(WOLFSSL_STM32U3) || \ + defined(WOLFSSL_STM32H5) || defined(WOLFSSL_STM32MP13) || \ + defined(WOLFSSL_STM32H7S) || defined(WOLFSSL_STM32N6) || \ + defined(WOLFSSL_STM32G0)) /* Hardware supports AES GCM acceleration */ #define STM32_CRYPTO_AES_GCM #endif @@ -184,10 +185,10 @@ int wc_Stm32_Hmac_Final(STM32_HASH_Context* stmCtx, word32 algo, #define STM32_HAL_V2 #endif #if defined(WOLFSSL_STM32L4) || defined(WOLFSSL_STM32L5) || \ - defined(WOLFSSL_STM32U5) || defined(WOLFSSL_STM32H5) || \ - defined(WOLFSSL_STM32G0) + defined(WOLFSSL_STM32U5) || defined(WOLFSSL_STM32U3) || \ + defined(WOLFSSL_STM32H5) || defined(WOLFSSL_STM32G0) #if defined(WOLFSSL_STM32L4) || defined(WOLFSSL_STM32U5) || \ - defined(WOLFSSL_STM32G0) + defined(WOLFSSL_STM32U3) || defined(WOLFSSL_STM32G0) #define STM32_CRYPTO_AES_ONLY /* crypto engine only supports AES */ #endif #if defined(WOLFSSL_STM32H5) @@ -204,9 +205,9 @@ int wc_Stm32_Hmac_Final(STM32_HASH_Context* stmCtx, word32 algo, #if !defined(STM32_HAL_V2) && defined(CRYP_AES_GCM) && \ (defined(WOLFSSL_STM32F7) || defined(WOLFSSL_STM32L5) || \ defined(WOLFSSL_STM32H7) || defined(WOLFSSL_STM32U5) || \ - defined(WOLFSSL_STM32H5) || defined(WOLFSSL_STM32MP13) || \ - defined(WOLFSSL_STM32H7S) || defined(WOLFSSL_STM32N6) || \ - defined(WOLFSSL_STM32G0)) + defined(WOLFSSL_STM32U3) || defined(WOLFSSL_STM32H5) || \ + defined(WOLFSSL_STM32MP13) || defined(WOLFSSL_STM32H7S) || \ + defined(WOLFSSL_STM32N6) || defined(WOLFSSL_STM32G0)) #define STM32_HAL_V2 #endif diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 32fa66fb62..201982f0db 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -2198,10 +2198,10 @@ extern void uITRON4_free(void *p) ; defined(WOLFSSL_STM32L4) || defined(WOLFSSL_STM32L5) || \ defined(WOLFSSL_STM32WB) || defined(WOLFSSL_STM32H7) || \ defined(WOLFSSL_STM32G0) || defined(WOLFSSL_STM32U5) || \ - defined(WOLFSSL_STM32H5) || defined(WOLFSSL_STM32WL) || \ - defined(WOLFSSL_STM32G4) || defined(WOLFSSL_STM32MP13) || \ - defined(WOLFSSL_STM32H7S) || defined(WOLFSSL_STM32WBA) || \ - defined(WOLFSSL_STM32N6) + defined(WOLFSSL_STM32U3) || defined(WOLFSSL_STM32H5) || \ + defined(WOLFSSL_STM32WL) || defined(WOLFSSL_STM32G4) || \ + defined(WOLFSSL_STM32MP13) || defined(WOLFSSL_STM32H7S) || \ + defined(WOLFSSL_STM32WBA) || defined(WOLFSSL_STM32N6) #define SIZEOF_LONG_LONG 8 #ifndef CHAR_BIT @@ -2222,7 +2222,8 @@ extern void uITRON4_free(void *p) ; #if defined(WOLFSSL_STM32L4) || defined(WOLFSSL_STM32L5) || \ defined(WOLFSSL_STM32WB) || defined(WOLFSSL_STM32U5) || \ - defined(WOLFSSL_STM32WL) || defined(WOLFSSL_STM32WBA) + defined(WOLFSSL_STM32U3) || defined(WOLFSSL_STM32WL) || \ + defined(WOLFSSL_STM32WBA) #define NO_AES_192 /* hardware does not support 192-bit */ #endif #endif @@ -2267,6 +2268,8 @@ extern void uITRON4_free(void *p) ; #include "stm32g4xx_hal.h" #elif defined(WOLFSSL_STM32U5) #include "stm32u5xx_hal.h" + #elif defined(WOLFSSL_STM32U3) + #include "stm32u3xx_hal.h" #elif defined(WOLFSSL_STM32H5) #include "stm32h5xx_hal.h" #elif defined(WOLFSSL_STM32N6) From 70d5d86dda0d78f834549592f3221531bfc9f49c Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Thu, 30 Apr 2026 17:00:40 -0500 Subject: [PATCH 167/167] wolfcrypt/test/test.c: in ecc_test_vector_item(), don't attempt wc_ecc_verify_hash() if the test vector's message (hash) is shorter than WC_MIN_DIGEST_SIZE. --- wolfcrypt/test/test.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 757bd737ee..f88863ee03 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -34832,20 +34832,22 @@ static wc_test_ret_t ecc_test_vector_item(const eccVector* vector) #endif /* !NO_ASN */ #ifdef HAVE_ECC_VERIFY - do { + if (vector->msgLen >= WC_MIN_DIGEST_SIZE) { + do { #if defined(WOLFSSL_ASYNC_CRYPT) - ret = wc_AsyncWait(ret, &userA->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN); + ret = wc_AsyncWait(ret, &userA->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN); #endif - if (ret == 0) - ret = wc_ecc_verify_hash(sig, sigSz, (byte*)vector->msg, - vector->msgLen, &verify, userA); - } while (ret == WC_NO_ERR_TRACE(WC_PENDING_E)); - if (ret != 0) - ERROR_OUT(WC_TEST_RET_ENC_EC(ret), done); - TEST_SLEEP(); + if (ret == 0) + ret = wc_ecc_verify_hash(sig, sigSz, (byte*)vector->msg, + vector->msgLen, &verify, userA); + } while (ret == WC_NO_ERR_TRACE(WC_PENDING_E)); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), done); + TEST_SLEEP(); - if (verify != 1) - ret = WC_TEST_RET_ENC_NC; + if (verify != 1) + ret = WC_TEST_RET_ENC_NC; + } #endif done: