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/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/hostap-files/configs/07c9f183ea744ac04585fb6dd10220c75a5e2e74/tests b/.github/workflows/hostap-files/configs/07c9f183ea744ac04585fb6dd10220c75a5e2e74/tests index 5ebaee3ba5..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 @@ -248,9 +246,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 +644,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 +683,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 +739,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 +891,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..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 @@ -347,7 +346,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 +459,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 +470,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 +571,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-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 diff --git a/.github/workflows/hostap-vm.yml b/.github/workflows/hostap-vm.yml index 627f7184ac..1e609028c9 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 }} @@ -80,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' @@ -100,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' @@ -126,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 @@ -174,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 @@ -219,27 +233,18 @@ 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 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 @@ -258,6 +263,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/.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..e6ff993bdb 100644 --- a/.github/workflows/opensslcoexist.yml +++ b/.github/workflows/opensslcoexist.yml @@ -18,8 +18,8 @@ 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 -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_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/openvpn.yml b/.github/workflows/openvpn.yml index bc38257107..0b793f19ef 100644 --- a/.github/workflows/openvpn.yml +++ b/.github/workflows/openvpn.yml @@ -42,8 +42,6 @@ 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 ] name: ${{ matrix.ref }} if: github.repository_owner == 'wolfssl' diff --git a/.github/workflows/os-check.yml b/.github/workflows/os-check.yml index 871d239a3b..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 -Wno-overlength-strings -Wdeclaration-after-statement -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. @@ -139,9 +118,58 @@ 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 + # 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: | diff --git a/.github/workflows/pq-all.yml b/.github/workflows/pq-all.yml index 305faa5403..c6d4704e99 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 --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 -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"', @@ -43,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 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." 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/.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 diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 3943d47739..99e5990666 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 @@ -219,6 +222,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 +238,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 @@ -279,6 +284,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 @@ -317,6 +323,7 @@ IGNORE_NETSCAPE_CERT_TYPE INCLUDE_uxTaskGetStackHighWaterMark INTEGRITY INTIMEVER +IN_CLOEXEC IOTSAFE_NO_GETDATA IOTSAFE_SIG_8BIT_LENGTH KCAPI_USE_XMALLOC @@ -477,7 +484,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 @@ -520,6 +529,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 @@ -553,6 +563,7 @@ STM32L552xx STM32L562xx STM32MP135Fxx STM32N657xx +STM32U385xx STM32U575xx STM32U585xx STM32U5A9xx @@ -652,6 +663,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 @@ -659,6 +671,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 @@ -732,6 +745,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 @@ -820,7 +834,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 @@ -829,6 +842,8 @@ 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_LMS_SHAKE256_256 WOLFSSL_NO_OCSP_DATE_CHECK WOLFSSL_NO_OCSP_ISSUER_CHAIN_CHECK WOLFSSL_NO_OCSP_OPTIONAL_CERTS @@ -837,7 +852,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 @@ -895,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 @@ -1004,9 +1019,11 @@ __ATOMIC_CONSUME __ATOMIC_RELAXED __AVR_ARCH__ __AVR__ +__AVX512F__ __BCPLUSPLUS__ __BIG_ENDIAN__ __BORLANDC__ +__BSD_VISIBLE __CCRX__ __CC_ARM __COMPILER_VER__ @@ -1121,6 +1138,7 @@ __sun __svr4__ __thumb__ __ti__ +__unix__ __x86_64__ __xtensa__ byte diff --git a/CMakeLists.txt b/CMakeLists.txt index 663c3cf2cc..b4af397e9e 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) @@ -700,10 +701,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") @@ -733,6 +732,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 +757,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 +786,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 @@ -1772,6 +1777,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/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/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/Espressif/ESP-IDF/examples/template/components/wolfssl/component.mk b/IDE/Espressif/ESP-IDF/examples/template/components/wolfssl/component.mk index 6b1c052988..35b3462cdb 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 @@ -245,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 @@ -271,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/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..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 @@ -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 @@ -245,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 @@ -271,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/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..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 @@ -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 @@ -245,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 @@ -271,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/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..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 @@ -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 @@ -245,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 @@ -271,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/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..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 @@ -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 @@ -245,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 @@ -271,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/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/INTIME-RTOS/Makefile b/IDE/INTIME-RTOS/Makefile index 3755c29205..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 *~ @@ -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 \ @@ -320,18 +319,19 @@ 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 \ 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_slhdsa.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 \ @@ -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 3c5bd1d8d5..9564c6ae66 100644 --- a/IDE/INTIME-RTOS/wolfssl-lib.vcxproj +++ b/IDE/INTIME-RTOS/wolfssl-lib.vcxproj @@ -87,8 +87,6 @@ true - - @@ -108,7 +106,6 @@ - @@ -190,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/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/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..486f374266 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 */ @@ -660,9 +668,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/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/IDE/XCODE/wolfssl-FIPS.xcodeproj/project.pbxproj b/IDE/XCODE/wolfssl-FIPS.xcodeproj/project.pbxproj index c96018c5a8..ab2f56cfdb 100644 --- a/IDE/XCODE/wolfssl-FIPS.xcodeproj/project.pbxproj +++ b/IDE/XCODE/wolfssl-FIPS.xcodeproj/project.pbxproj @@ -125,8 +125,8 @@ 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 */; }; + 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 */; }; @@ -145,9 +145,7 @@ 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 */; }; - 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,8 +283,8 @@ 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 */, + 700F0D9A2A2FC11300755BA7 /* wc_slhdsa.h in CopyFiles */, 700F0CFA2A2FC11300755BA7 /* fe_448.h in CopyFiles */, 700F0CFB2A2FC11300755BA7 /* fe_operations.h in CopyFiles */, 700F0CFC2A2FC11300755BA7 /* fips.h in CopyFiles */, @@ -305,9 +303,7 @@ 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 */, - 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,15 +568,14 @@ 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 = ""; }; 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 = ""; }; @@ -593,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 = ""; }; @@ -643,8 +637,8 @@ 700F0CDB2A2FC0D500755BA7 /* eccsi.h */, 700F0CD22A2FC0D500755BA7 /* ed448.h */, 700F0CE12A2FC0D500755BA7 /* ed25519.h */, - 700F0CD52A2FC0D500755BA7 /* ext_mlkem.h */, 700F0CDD2A2FC0D500755BA7 /* falcon.h */, + 700F0D992A2FC0D500755BA7 /* wc_slhdsa.h */, 700F0CDE2A2FC0D500755BA7 /* fe_448.h */, 700F0CC72A2FC0D400755BA7 /* fe_operations.h */, 700F0CCF2A2FC0D500755BA7 /* fips.h */, @@ -663,9 +657,7 @@ 700F0CD42A2FC0D500755BA7 /* siphash.h */, 700F0CDF2A2FC0D500755BA7 /* sp_int.h */, 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..972f46d1cd 100644 --- a/IDE/XCODE/wolfssl.xcodeproj/project.pbxproj +++ b/IDE/XCODE/wolfssl.xcodeproj/project.pbxproj @@ -256,8 +256,8 @@ 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 */; }; + 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 */; }; @@ -275,9 +275,7 @@ 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 */; }; - 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,8 +620,8 @@ 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 */, + 700F0C9A2A2FBC5100755BA7 /* wc_slhdsa.h in CopyFiles */, 700F0C122A2FBC5100755BA7 /* fe_448.h in CopyFiles */, 700F0C132A2FBC5100755BA7 /* fe_operations.h in CopyFiles */, 700F0C142A2FBC5100755BA7 /* fips.h in CopyFiles */, @@ -641,9 +639,7 @@ 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 */, - 700F0C252A2FBC5100755BA7 /* wc_mlkem.h in CopyFiles */, 700F0C262A2FBC5100755BA7 /* wc_pkcs11.h in CopyFiles */, 700F0C272A2FBC5100755BA7 /* wolfevent.h in CopyFiles */, 700F0C282A2FBC5100755BA7 /* kdf.h in CopyFiles */, @@ -975,14 +971,13 @@ 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 = ""; }; 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,16 +992,15 @@ 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 = ""; }; + 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 = ""; }; @@ -1153,8 +1147,8 @@ 700F0BF72A2FBC1600755BA7 /* eccsi.h */, 700F0BF82A2FBC1600755BA7 /* ed448.h */, 700F0BF42A2FBC1600755BA7 /* ed25519.h */, - 700F0BF92A2FBC1600755BA7 /* ext_mlkem.h */, 700F0C022A2FBC1600755BA7 /* falcon.h */, + 700F0C992A2FBC1600755BA7 /* wc_slhdsa.h */, 700F0BEB2A2FBC1500755BA7 /* fe_448.h */, 700F0BF62A2FBC1600755BA7 /* fe_operations.h */, 700F0C002A2FBC1600755BA7 /* fips.h */, @@ -1172,9 +1166,7 @@ 700F0BFE2A2FBC1600755BA7 /* siphash.h */, 700F0BE82A2FBC1500755BA7 /* sp_int.h */, 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..058b5a1edf 100644 --- a/INSTALL +++ b/INSTALL @@ -250,16 +250,16 @@ Congratulations! You have just achieved a fully quantum-safe TLS 1.3 connection! - The following NIST Competition winning algorithms are supported: - - ML-KEM (CRYSTALS-KYBER) (key encapsulation mechanism) - - ML-DSA (CRYSTALS-Dilithium) (signature scheme) + The following NIST Competition winning algorithms are supported by the + native wolfSSL implementation: + - ML-KEM (FIPS 203, CRYSTALS-KYBER) (key encapsulation mechanism) + - ML-DSA (FIPS 204, CRYSTALS-Dilithium) (signature scheme) + - SLH-DSA (FIPS 205, SPHINCS+) (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) - - 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. The following NIST Competition Round 3 finalist algorithms were supported, but have been removed after 5.3.3 @@ -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/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/certs/falcon/bench_falcon_level1_key.der b/certs/falcon/bench_falcon_level1_key.der index 1ff376d0ef..32d0e84e68 100644 Binary files a/certs/falcon/bench_falcon_level1_key.der and b/certs/falcon/bench_falcon_level1_key.der differ diff --git a/certs/falcon/bench_falcon_level5_key.der b/certs/falcon/bench_falcon_level5_key.der index a0eaa2a3b7..15f25b19f6 100644 Binary files a/certs/falcon/bench_falcon_level5_key.der and b/certs/falcon/bench_falcon_level5_key.der differ 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 0000000000..2b58abddcf Binary files /dev/null and b/certs/slhdsa/bench_slhdsa_sha2_128f_key.der differ 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 0000000000..92e8e9bc10 Binary files /dev/null and b/certs/slhdsa/bench_slhdsa_sha2_128s_key.der differ 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 0000000000..f9351012db Binary files /dev/null and b/certs/slhdsa/bench_slhdsa_sha2_192f_key.der differ 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 0000000000..6791ea070c Binary files /dev/null and b/certs/slhdsa/bench_slhdsa_sha2_192s_key.der differ 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 0000000000..772f575dab Binary files /dev/null and b/certs/slhdsa/bench_slhdsa_sha2_256f_key.der differ 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 0000000000..4144e443e8 Binary files /dev/null and b/certs/slhdsa/bench_slhdsa_sha2_256s_key.der differ diff --git a/certs/slhdsa/bench_slhdsa_shake128f_key.der b/certs/slhdsa/bench_slhdsa_shake128f_key.der new file mode 100644 index 0000000000..8be3a1f878 Binary files /dev/null and b/certs/slhdsa/bench_slhdsa_shake128f_key.der differ diff --git a/certs/slhdsa/bench_slhdsa_shake128s_key.der b/certs/slhdsa/bench_slhdsa_shake128s_key.der new file mode 100644 index 0000000000..aa11d8c5b3 Binary files /dev/null and b/certs/slhdsa/bench_slhdsa_shake128s_key.der differ diff --git a/certs/slhdsa/bench_slhdsa_shake192f_key.der b/certs/slhdsa/bench_slhdsa_shake192f_key.der new file mode 100644 index 0000000000..0847ef7cff Binary files /dev/null and b/certs/slhdsa/bench_slhdsa_shake192f_key.der differ diff --git a/certs/slhdsa/bench_slhdsa_shake192s_key.der b/certs/slhdsa/bench_slhdsa_shake192s_key.der new file mode 100644 index 0000000000..e4a3b219e7 Binary files /dev/null and b/certs/slhdsa/bench_slhdsa_shake192s_key.der differ diff --git a/certs/slhdsa/bench_slhdsa_shake256f_key.der b/certs/slhdsa/bench_slhdsa_shake256f_key.der new file mode 100644 index 0000000000..264c2393a7 Binary files /dev/null and b/certs/slhdsa/bench_slhdsa_shake256f_key.der differ diff --git a/certs/slhdsa/bench_slhdsa_shake256s_key.der b/certs/slhdsa/bench_slhdsa_shake256s_key.der new file mode 100644 index 0000000000..712c6b9b34 Binary files /dev/null and b/certs/slhdsa/bench_slhdsa_shake256s_key.der differ 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 0000000000..bdcf1fbd60 Binary files /dev/null and b/certs/slhdsa/client-mldsa44-sha2.der differ 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 +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 +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 0000000000..42f235ca4f Binary files /dev/null and b/certs/slhdsa/client-mldsa44-shake.der differ 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 0000000000..ba68f102d6 Binary files /dev/null and b/certs/slhdsa/root-slhdsa-sha2-128s-priv.der differ 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 0000000000..3b8bce092d Binary files /dev/null and b/certs/slhdsa/root-slhdsa-sha2-128s.der differ 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 0000000000..632893c0ad Binary files /dev/null and b/certs/slhdsa/root-slhdsa-shake-128s-priv.der differ diff --git a/certs/slhdsa/root-slhdsa-shake-128s-priv.pem b/certs/slhdsa/root-slhdsa-shake-128s-priv.pem new file mode 100644 index 0000000000..6903f52deb --- /dev/null +++ b/certs/slhdsa/root-slhdsa-shake-128s-priv.pem @@ -0,0 +1,4 @@ +-----BEGIN PRIVATE KEY----- +MFICAQAwCwYJYIZIAWUDBAMaBEAnqyIgk6VNnF0xM5x6Vbnp9D23c/kPGQeocOR8 +HctLAiqMjF2YEIFMAUeaq+RxTydF4qwQjpWAlJQwoaItuSqz +-----END PRIVATE KEY----- diff --git a/certs/slhdsa/root-slhdsa-shake-128s.der b/certs/slhdsa/root-slhdsa-shake-128s.der new file mode 100644 index 0000000000..34b1bf2881 Binary files /dev/null and b/certs/slhdsa/root-slhdsa-shake-128s.der differ diff --git a/certs/slhdsa/root-slhdsa-shake-128s.pem b/certs/slhdsa/root-slhdsa-shake-128s.pem new file mode 100644 index 0000000000..efbc9ed312 --- /dev/null +++ b/certs/slhdsa/root-slhdsa-shake-128s.pem @@ -0,0 +1,644 @@ +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 +xTmAW4r3ImffkmKGP+WP/g/y6Y9s6nvvLcHbnGvFk+YzcFmbVz4+tA8dl7IlB1sQ +BWDUAk/LXc5pUWmGLnSCwwKdHHcoHbXUoxjGnFnUqB0OOJ+qExDDwjnR4sa3+OPD +aJ47ipFB0JNPYwbP1+JYFRmjyhQL1Z+BLtg1Kcpec3XhuzDViV/8s7XeWoY+H8Bl ++a5zzu96wGhlkV8gItiRz7iurXO/33Hamv4olCY+juhQSoaaDAf7958pxQZLPtEL +Do+k8sDb3NW3np8PUw7+dBPjkaWkQOtMQ3Prt5lP3qHyKbyfHtnz3adgZX7GdCdu ++6li/MmHqrOXtq0iTdNYE6S3LGD68dDZS0PQUzRhXB1IWuQRKhxDTkU6fm7HBQ99 +2PMf4pn5Rd/pWbZlqkF4Oh9ovN48LcMaGnJ9P7QklI6Q+acv4oaHd4iPe5iCHAOZ +ncforWJJ4OVRUJVn16o7Z8RUfGzx/tVNF32MmbRJSlfdm/1GHDOhjz9CvlanBgC+ +iB0BOMUoqLSDSrmEfc06e214Ln+c5EbKGJ+q0v4kduWzpjzer7iirnC3LnYTKR5r +fOtU2CxFd+XGoimmso1U4mD4NCFb7LGYSfsaDs1UY8vjDPw4EWrlSldqld47cMKl +BdAQHOvFOUqw4oGCQZ8Lvo2D+hycgea8htEoaV3MZ1pDhC6db82v8HklY3MKjx0U +nczlZem/Cdn+09xaq9sOAh34z1G+cDLxHskZy1LNy2DL4T2BjbD18rwhw7Jxe0xB +N75DqOPah1+PuSOjjGjXkI66zQVyHDaCe8VUKbBB0aTg+Mg8xfcmUSfCh3EaDoZU +L0jP4fir8Z90Nr7RRSETE07VyJj3UQywQSXkzAQSfQMRRTf5ElGjpvgl2OcZsuUg +N3HjlX0etW646IsFQvfUl1fiPcaOjKmGj1fA2kGJjQeMs87XOZO1buD7Wa92iG+E +X05Ua0LelU8XJlxIv+xl3XOMlsVdGlp5+mcIBclyLxscN94aohfr0WFnKVYAsD+c +17zq3jHtLAlLSqbFUkPVOG+CtLnJnTsaYJGMsJPCkajxnBDzo55Ta+f9hIPsI/ld +BV27whZRrqr0KlM8jF1e983XZMOpzvl7MfXE+2jjl0wIv2R8WG1LEXVvqBNOJHZj +R+/p/70MfMz4XpHpJbaet0KXok3JS/iCEOpFoYFdtw/t4OAn1IjJbj9HuB3XZlHc +D0vMy/uo84VDYHGqZstmVDpjv6zhqskG4Usm9991qL9FcL0Y2JFYu4pRDnlYAT1F +BV6dArR9BkgNWUz6Su7+cloDrVzr5UQEtCCQWnkcL2LVSYlZFsJ1BzUs2vCZPVtJ +s76rHyoAzRhHOiCP5e7UueWbr+82u0L3gAKX4eNKUumV5BXrQMvBoBEXp4iY6zSz +vlbQri2c/jjrUYz7F3Rmt/VXt+/I5aifSoffMIzz8fQzu/tidjZo+FC6jLLrzVyO +CgPVT/qBa2TlW6HxJ5gmCGndIXCd+iQfUaW1okgf/vvOgpPJc8zDWzBit+iMgiZX +4Cmnl8GYxZmE9UqZ0yMdp5EaznHh/b5ZDtqpgiMdS0lfBXwgvP8x8sY7fsc5dDcz +2/B6vQbFa3EBVzYU3YpXqG71Ql8dh4i9cG5vlLuCRKi3pPjDWSV2torjKhWiIjOQ +uribeF3zvya3oEcTMbYA4RmwUyX4KMdgYrktsZeuGp1Bt2bi0AkRY+oDJxvdx9Yg +isOoJ92zWdAOnvevvn4wU1GpeVNAMaxdIEULYpaYGu1XKztlekmFbxVspUtT9UWP +pkbTjZOv0yC+ybn620dIBxTMpx1+ZWZE90LOQO8DGpa9vuHFM47schrKtWTlmClo +KSept3WEodDGO2MY+nfAMQCcj2RqNFTTWkNT0DX14hHPnU6yMwEcSXNWr66rBHLn +2cyMfx0jDn0dRi+npVnVoIwxWwjNOoy0jWjbppQISQIWVeM9Sck19uvgX+e/tmd9 +9TBXYNbwHusNA0Scyz3aof/E7gvyf49NivJHE1UsxarN2Q/HumHzbOP4NRofacYh +lPpbki128XgW6TH9/HezV/WmjI0cVZ7GTojYV0voN9qocpUlY0ZPc75g/1gQNu2Y ++2MH4RmI9HOjs0i9eCKF95awY59jiUY1WrYYYdhnjbqzfoN7uH+U+5PFNLcz2F3X ++taOSmxUPCnliDaMlh07rAhssgXXcRI565BGGP6gRpejAPtDjrRQGrXz4nIk/kU6 +unEjxotbm34X/FI8NOcW9wdsmBsRxYs5K5dZiUsteydUQeu8IAJQcLtsyTRo1mcH +OV5OUN+L9bDKvkLaNGRI8syYkvBmP9Buh09c7/31kbNSOUhw0JmjD2fZ/Zpq81zc +ROCk+FzDzIVkfKxsF38jPH6yEIbFV5QmC2qq+TTXWkGAhev8qf0UlO3JSOTdOKAh +JxLIRPtD/hpKqxMitpwXyX+ZnCL6WVc1pWr3kGdYZbJ8al5DL08a9rFsM0+Eg+/5 +zFwKmi4RJeB3jNMLkBXR/31L0qapuqS/CKNl/7IV07TphnTOXobA8gzQCSdHSKqJ +iOfKRxNP87jX5KqvJ3OTkG5G+5u0PyrXvP4bnjIJtdSsOSCrUqtC0nqJg9nwT4uL +red9UYLDmphWfg5RqRM1pXw2hjbkjunXhNGCnM2tmYsR96dm/jZHVkZnr1l29535 +Ovk/ECInSmzLMitZE/Sg/dY7bGCRvarzpTGN7ho4kBk+o43iEA6zo9p/deJ5vzaG +Fny8lLJ4V8VFAm6Zrc8tIcRsWbKylHroRiwSYZl0Loc+/SViWIkgNaWDPdHVXOIX +WHOc8KmQE++gsDgIqEb5B/G+MZzsrGWCoe79OV17bVMspiNIWSsTYxaTaUZCT5jI +cNwQp/6KKJFvJsuo5SY3dcykzYhJTxANwkZEaHpYgrQVeEfzGnavzYT+4NaTHvkh +G9SiEyk8Gr0q/tTNZeYU4TGCFL2eCeK+uYCPERGVctmkDcRuJDGe6c+eoOL6fUuw +AyWykOZ+CDk3Fzigk/KM/4zuaA4RdO+1t0chMoKbJEfgiL8VYeI+VaaH1vC695l1 +TX4udgaM/J74uzvldHDhMA4GrQGkbUXG9FVHKEXNeo8pdyiao73KLbT/UxChxrdR +WQsE/7pybV9DTt827avZ1km8jI6+U4Qu4wCj6zNJI62umH2lsEkp1NFeWhFeAfT0 +EzFc09a3CNolh321cxJ0Bg2XUn9gCEIqrxT1MIms8zIhLOgW/EUTiShuSpWH/DA2 +VX5lAU9VUjk5JUAhTDDc2WxfWP5XK4PZoNtPs04CSI63cJ/rCphhknKEPlN8xvM+ +P3A8wv+YTBumccEV+OUDT1Ni/uzZLYyD4KNCfdkWUQQtQkgRSmIxBtQCXZMxIapH +2snGSb7kcU5XNkaUv/vjiDtZd20TzzRiNLpGg2QeIhB0GKWy0oMROq24cpNIxGod +tcLZ3S1Pv+vmP5/hhZvxLgNesPXdizPWfF7kNOu9YtyAA8/N7e8pTu3m4O/UHmvU +ob2xI3Nx96x9w+vmN6uNRuEkk5KwjfCEu/f2URlSdpTOtfQ+XgqO450UQzFPFJES +m4F9Uf4ikyjo4deLcpAeRGHSBxf174FpJ7qlpOouz5wEz/0Pwi1NV4BJu6aSvnqO +Spm31NcIY7QsG7+2uzFsE3+EGXrjwFdexV+aJ+2yiyNlltXgWexQDmOo339N3G41 +2DKGlIh6ID1nZwjl7Qj6N36Eb6Ph02Ly9xnx73O1aqgWQi9BeuNmvhSeXCKV9DEX +RKhs6qxs1sapduvJJB6Tdkj0FDoY8jJo+J7LU+GgBAuopkvCP9dNcjp3NOl8thgm +u+Xo1xskhurAyAqB6lBatzzKert6hU8D0n2XRIAMrFhIoDN0YmnbmXW4p33EZC8A +tafB7D1p48Ww5kesG8CyFXV2hKT3Be3+berAL9M3ctyyiyNFHCHxa1yvWRK4kp++ +WbdwaAjW5TCyzBY3NSK3fX1hLvGBowiZzR+2Uvf5U8Lc5E5AVFmaCkv9kmRZcWTd +1JR0rORbyKmtogu8ZkWtMHa7MoEK75IAUHcOsmEOY4qoqNGEiK5SU9ObX674pTW3 +QFGVq27vhMSEDzuPdTMFbUIsqiDaF1y4y80IVGoY0cANfRTl/WQdj+e2q+NLlbyz +l/bnxiOGn5jdCkrL3wJdG2apWPc9suweWVM4ZK0PVxtaEIE9+CJtr7fqCMqxmNZm +iabbOsSANRijfo/MMhbSaxWDaBUV7SN988PfqF67DGEOP4W+30eaWMGEFakUFOXw +ri3I3WQN2+F4YnotTjG75D36ktnKz7PiJXkzstOb9MHb/iTe9UfMm9lHtrI86SU9 +FV/h54Zm8UuMVr+8E9vNQKtFjrrz8GefRsZyxtYzeiY5mGwTzCrPmUTqaJcFjNy5 +RaQQO0NmrxVED1PHdmywWdvFhcJUyVvQrivEVM84YCqspY9lFdQCsaAXS8G1X79s +NCPuM/iCJ12PG1i28LgP3Mt2GektuIVvVRxkNsiM04TEzfelhpNGCnNF4eXMOcX3 +YMzKApBm4Owj6SPAmPt16XQLiZ8yGmiJltvYcFaPheKoOQj7wFOM8q/yeQ2o1/Hj +H/t3tnD5QM/yT1rrvG3p9vH2Af6DH28p0RkQtR43gckPq13WNIDMurwidmzwox7N +bfwbjVjdpgnqOyrsR3u5ruGwUl2GklzRJmZ5WzvnjmFOFQpVI88BrBLnaxNSOiaP +qTR5zNdjFfiaw1xiDv5awoR7af6YmsLK72OThkzfrJUxtO3DPYeHA9o1Xzw4J8Ve +BUpeS+tE7Ju+uXFtY94U3nMOEZCFt45Bkirae2UG/IYBPfC/DUVEUTbFG51mL2Ec +cLGBY0zeEzhqke0yUZGukrxtTXbhFDmIPMUt7pUWtexUQMzhsKtpbj2C3jfStzq+ +iWxnxccrKgTYCE7yoITCbjYgGuZYpVsxyXTOeF9P79INlXX0FqdhhxentpiILosO ++435TmxW3Dhex9sVhtCP4hma4iV2rEYFInenyvGBO/bVHXzp6on+FeprPCh31nnd +lhWJm5cfR+aVwJfkGDsC3U5i4R5reEPlSSCJM1sahB74LhJzYYUJuVQkbsjuufpS +eE4n+zkCWQlG+dC+A3iw8heAciWuoy5DIaNwbOxwK6qaFHiKuWZYM8jsbB9S8Mkg +VdRNiP6V/W/u7CahmA47kyGF9VwkAizunuWuyfZdP6BedWYZOK0NQshJ3yDftqNQ +697uNjEXzMAuz1TRWoxUPZWhbnXC4OH8uoOwBB2+Rjzuz+WhQTdvQXJ6RNI75kLQ +AScUc4Ql4fUZj7KzUyvI+Jx6woch5ORpdhzysPux0vxQ32EURSGgXE0wiVKMUR5q +zwKxFrg7ESTw50Y7RdbX/6z4b9yPlv+oVsvmBcwvzIl9Up0APlaN/a13/wbATeUK +IrJRKvXo4VLUrJnylr2IIoXBzkU8xma2GINy/wM1BPRYnWQxXja5j3PnTYDYhV00 +O2m+9onx4mmKT2dFcvlmvhyPiJio9ori7VDLs2TXUKTul9eupYhzuxAoGEfC4ACO +W+EUxZ+KbptfKTY2YjUPiW3WWxlXjL/RMb7mpPOShry+dfiKo5cnYq62b1QxZIVn +CzV70+b9LWsyey3AxCUqnCbIMXSPoMRLTImscnKL88x0FqGTnDxHN3860GOwALZk +Y1z8i1IN6ipSv7exh/HdMeSXdFIMDy7Eh1Lb/z9FrStlLzvMBVXCQ8ggNJ2akj8P +qQXNs8+WnlFu1gboS6gq5UQCYF0ElJG/7uJirGt1KBPLuPVe/iTjbpZQ+Au4KKSM +HJQkok9X1JMA+fV1poB5oxEAPYM+eHKzuOuauqkOruMAhd4pkQPOM9M6pnQGfd9L +b7LLsP9vmZG7glU604/x6dXs0xXHKo89rWlq03L40lzd5mDENpAr3FtAdfG2URSu +L/g5HOSYz4ZopV9+nRIUVjUpy6BZYdEoM9PmalgvO173rGmZmBqdFaV5qi2vdQQL +QtUuh6ZqanOjdNoRyygJXIOGx2G+Ek431YA4mnyNhHyRjiwyiYa6lLtkLkjs8U7C +w8GeE1dy3bmg9ZpasWUAXgEl9P8wst+ukYT9U7uHbMj+Pl3d5q5XrVypZgsM+cfU +SfoGGdOOiPY2Q8Ny8q0DTDMX7mmlrkwaIUAoVIpm73TIQ5HinG6nsvIT/eCa2J82 +3uZXBhVgxDrX8xXQQLgul2UwxPaIOcRw2IOob715oh2gPBE2VA5n+CdCZpqWePIZ +jX1jBTZLazoeMZrm7cvUsnYPW9p4jUqykDsPhTbHWxYATDjYcIlflEg0+6Z/PpE2 +K1CcqJafsKdAQ7bh8sBs6PLWiq3+EK2f2jiJyL4stce9d/d5D6BSc1rquHKY/nB4 +d7/zp1rZRIUu1Hoh7AfoYcFknz1WXMsuwvd9A3CvPvLVi7f2U4jrjnCjsOumngC3 +rXCY4m5DLcLSCZRkw3Caktl/zD68wFivtSPByqVVakn/DuFpLM1qjeT8AEGAyO6J +6gfFMcJYMYT5nx7OEaynTj3R6krNnekigB0IdNg3vsoVtHq/8IKPYOri6bpxDiCU +irQVoT6Fd7HR8JBbUa2fC/iPQPHievO11puZzqkTa3sKRn2iJ6Fao193L5prY++k +oXBMpisBJAY9DxukUAwoDI9YkJGWJC1/4qpzBpQI4RmfnGS1gmUiiAfXv7ZWPnfl +yL1uj3JDBtQcgbXx7L979KipA/dBVjmCTVsuljJHw76wANrIhkYFi9YgXsU5qWGK +CUCQO3ZlipiP1MSly0Ch48w7JQYevkxdymnmsqoxnAgqs2DbZZDqFpUdFNJjN5eM +8cUaxIYfvmB8FRenJtnw7Nz4e23DMtTefgglLSaqMBq8sF3/RgwY+7/blvXKWaJ2 +AU6CO2MviVMQnaO2V/o5A2PSXc6heYAltxp0nx3TlUilPDnZpyXvYykO/PulaqR+ +YcnDkLz5I4q0aD9fy95MNBCBl82nVGfttUejdQaJ/B9wZYYtlpi5FpLwwr0Boo6s +L9IDaGsA1IF/3KGWfbUPdhawGi96v3xOuKk1ukBes65uiniF+MxkfYjJL1wfXxnr +zi5g6eh3l1tjEeni+4HkAa9UEo2+qilxLVR0wF8HiI46BYYFVj+IOndUyOSUZynE +sEdjC9cplx/WXiJ2oU0vdkMgSHpEq9dSJX+pFOasmDQiXIlvyI0gKs+9xhl6Pxz2 +bwi8Im4LeI+CHCa4grj/7CN7E1yVfaUEP8eH7fLW+6K8oKzyF8TkEVbCL1xkZv0O +wBA4bPdr/2IVJ1VFXfzwjjZoZnKWQBN/srRKypfyP6fsOJV65M/ah7eqglf/fNXc +++KoE5sqpmp8ggu+73Fnkp4Bg0AacWSzY1ecVabu3miFeHCXgvVndNSUsf799E8m +7UlVeFyyvtpd9RhWilhOgr+INIuc1DJJz1aubdBFdp3HF3yQNLn1uqQyknwvd7yD +3wYitPPr0tM2IjK4wUpElrIVE75Ew/pVNPwyNxDyKDnJzdXgsqzRONdxBlAIaMNq +roZ+uag+Klyyb3lk4gC1zdYYYdoLk0wh953K5uhc03VTOMOC5TXnYpVOc2cRJyJs +CqxwidXIqpSxUlu5UTXYKTMWmoOV4mwMuua8trsmWuSSGyGTDANzrpILKzzwbl4g +iAnxB/CNAhXVeE/h1YpCyuEJ/TS1PqQNV1SGQLtaDowrhljy5Z/ztAtBHq1B0Yzr +YOIEHZfUT1NpNHLHvd/Lrik3MWka1LrBVjPq49XynUVmW63nWaM0+4XeMUGf08px +MFvV80as0mDKqMcGNQL6DEmR/aV8IoEu9nSt0Npfgjo95aoFofyqxrtIItoLqH2W +D1R2wXts3y8qdikh94oSCE3R9YAT0rjzemL+8NiB39gy6kUxrGu3WPcpqh9DcyPq +vuLLVjIXI/oli5hRtLFDDQucXufSfBvgTMXfiP23LEoZPzhNbPCrl0Jl30cxjnZL +epoPZWcHx/6Er97pM9OXSp94dKofmY5eFVn0YOU6ViV7UrU+7PIfazyJ3FgBmuzd +8yHGTlfgtoAaAyqfE6mS0zuxa9scnnt5dFlk64qZFi+/eMHeqGFGPZMPEtwPptn/ +rrHCKrOqo2zB+rCoeXMHpC5vrDT0mcMDhiEsF+Cjsna9MjGbmpg11WMIBvE7TtDb +JYdfdRQzunCjqGQwiz7QzFZhxqvMjtv/qTi/kowwCL+EcWEY3xV6Ac/VU230bGRf +gn4UtncX/NVsRAK/Qduu5tg+KVDB175jzJwnJkmPkJvM9MHEgo9UGG70n9mPA18V +d9f+0Kf3Ic4xGgWflVMuz7/s8ryBjQGpR3RxDSPcKEWTt123mHzvJeErJZ7+RzQp +50jblCK7wNUqA3RNEpVB1NzBl6/1jOTh/zmhWz8z3yLd/2cXkqP0wa9q2ScX/4jQ +Ou7Y6TK2g4xGbxNSmPNmkL7o8w0knH3P5GA867N4cKhXxSL+ax7SMbpGYNKuKZxH +/Rsoiar5r/jKxS7iZmf8dS2fbKJI1OqTKyp+pRExZNlXDHV5yw0uvw5pNlGORn5W +361Wcwn4eCnwY7Kmw7byg1TG+nX1JO9aur0Dsuo80NjM0kUAvnU4ukavCaNnUupG +18cBdM0vSN/xH2Qur+WZdrPDPkfIviyKH+xM6hb4CbF4MpDddb/bzs7Zln6FrMal +uclI3xHT6wVZByykrAbYb7OwCZsLxMpliIkedvoSu2bM+H/RkEJs+blfLZpiAJYu +77JcFlLXLrDmUvC21cLV6XPEoULFVTRVOnXFYQmsqS1w08fHSMiLDC52+3wb4ioe +DthqlbAsLI9DE1Zo1qCFZp1IdeBGiTuwsV0/jqjS2641K42zEXeqxqUR6DrUa7pF +v0TnnmNtbBFYwXp00n2FeO3unt3FB7H1yZ7Q1taeL4l/Z0fhUXly8Span33GiqOa +hyYACgYqCpXwX26B4XHPr7M/kxsjR9MojYz2wcwSA8NP3dXlqYcqH8D/Cml+c1XX +h3mfff308Ut5SdlTjFgi4E8hv9ZWy72zqqi00pNgrPPNV4AnEe6Y6MKTEranDaFc +4GQtjdcJcKyzxCFEdgRd9cvsFbq2HGbFcj0HLrcmriaMwAFGfMeFYzVsjUe/ImCz +QOn6BQZ9YSbt7fKwov3Q5RurCo4B35NQiXa27klBJOZBzRCxSHPzY3xyQYMjicvc +r/ecf51VaPfYx6ZXdTgLIbY3sOzsBeb5A7eyxP7T0ikpqV1UztRyT1G3oPRFlfN6 +LzOkPrA09f9oHEpq2mLNHf6nzlq163kIzcJ403i/BK9/EqJbr8CyZ75EZLbXE4bi +vxnG5PbgTyEfaB13P28I+lTMp7Vqb/2nnWE3WpRGr3EqvIpeRNdxy0nC/VH/2Ks1 +IxqER06gr+VVzr1Jdlc1T4uQI6TQEajJvX5/5dLJwE+wlRMlrq9Ud7HgEjRZJdGN +jzYvKqwwOD5OADZDdhKI89TB+nPlhCfAV5RMNANVzP9uo8LF0y8trHwrdDofQHTf +kmDUZLS7bCY+iG0dluPGRAFaYR+fgZkydy7upoWcmaW5DeMxmKk4vO7PZQeFXnfe +t7T4kR3KRUcAuIDvZiDL8RAP2JUiwf3BmCkepkTWK3PZczH9nfrysRvrfjqj+sSL +1klUySsc5xQA7DA0T8DPEFoYJ/rG/yERa1X/1oQL5McPYFtZ2IRyWZ/ni3CPP1yI +GT61J7dF6mVtfXyGVX7hqfNa9D8Rzc6QyPLZpi0E7fGJQB9/TqTm1rmv5UDptog4 +F+NJmLaeroR+WvoDhX+hn7MaOe58f+Ei45/s95QVeKGooRCPKXMoqcDfIS+gVl7q +/J97wpZMeFZ5s77eVIAEoK9/9GNS6zC623mjnTYSOnkDdm3qZdK4s6t1tgruCb79 +I+kydk0AeDWhtOVL1qM0Fxb9np3VdY47sYSLS4r85ppKeWSwDE1c8LKMsCzTdNsY +LRh7g1d8/B0JnrsO30LQi05ef+6fvyzZOSN74aFHtW/En2KF5w== +-----END CERTIFICATE----- diff --git a/certs/slhdsa/server-mldsa44-priv.pem b/certs/slhdsa/server-mldsa44-priv.pem new file mode 100644 index 0000000000..834879dd43 --- /dev/null +++ b/certs/slhdsa/server-mldsa44-priv.pem @@ -0,0 +1,56 @@ +-----BEGIN PRIVATE KEY----- +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 +-----END PRIVATE KEY----- diff --git a/certs/slhdsa/server-mldsa44-sha2.der b/certs/slhdsa/server-mldsa44-sha2.der new file mode 100644 index 0000000000..8f2c51341d Binary files /dev/null and b/certs/slhdsa/server-mldsa44-sha2.der differ 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 0000000000..2a5d3ea75b Binary files /dev/null and b/certs/slhdsa/server-mldsa44-shake.der differ diff --git a/certs/slhdsa/server-mldsa44-shake.pem b/certs/slhdsa/server-mldsa44-shake.pem new file mode 100644 index 0000000000..ad0f166425 --- /dev/null +++ b/certs/slhdsa/server-mldsa44-shake.pem @@ -0,0 +1,1404 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + 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=Server-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: + 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: + 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 Server Authentication + Netscape Cert Type: + SSL Server + Signature Algorithm: SLH-DSA-SHAKE-128s + Signature Value: + 82:c0:62:f7:8b:4e:5e:5f:90:88:4f:38:4c:f2:07:77:91:32: + 5e:bb:81:16:17:48:51:1b:fe:b6:60:79:d4:76:0d:61:3c:71: + f6:18:05:45:d3:70:43:5a:17:06:ef:da:15:dc:5b:77:49:ef: + 48:bb:9c:60:1f:16:ca:15:c8:bc:92:d3:d5:3e:8e:8d:aa:e8: + 57:9d:cd:b8:7f:14:14:c1:b5:62:6d:f5:28:0f:52:fe:af:cb: + ad:65:93:66:f6:97:0f:3b:bb:ff:90:29:d1:f8:9f:df:63:e3: + f7:06:e5:bf:9f:93:b6:fa:71:f6:b8:59:66:4b:4b:5f:2c:a3: + 7f:23:c0:97:ba:34:1c:89:7a:ac:39:50:d3:b0:90:dc:fe:15: + 0a:0d:6c:5d:68:60:86:8d:fa:4e:e1:e7:ed:ae:95:7c:6f:fa: + f4:42:78:ae:c4:fe:d3:66:c4:33:97:04:f0:8d:72:35:68:b9: + bd:b4:b0:d5:2f:91:7b:d7:14:d6:e8:a4:b8:f7:eb:8b:b2:8e: + c0:1f:89:66:79:5f:ec:88:11:78:5e:68:7d:c5:63:c8:b9:ae: + 1c:b1:7e:95:59:9f:65:61:ba:27:8d:81:0b:a9:82:c7:83:2a: + a1:6e:56:a4:4f:8a:e7:1f:63:96:8a:c7:6f:3f:39:8a:19:4f: + 00:6a:4f:b5:2d:09:04:3c:2c:3a:e4:c7:dd:e1:e3:10:ed:7b: + d8:57:4a:14:c3:0d:2a:99:f5:85:e8:43:e1:95:fc:aa:96:21: + 43:98:66:39:ba:72:0b:59:9a:26:11:f8:eb:d1:a1:36:28:78: + 7b:a6:3b:cc:f9:cd:7a:1f:d1:08:e4:93:1b:7e:6c:3e:dd:1c: + b0:70:87:52:14:fd:f5:c9:9e:8e:0f:5c:6c:70:5f:47:d5:ca: + 27:5c:90:88:da:60:f6:d1:96:84:57:9a:95:3a:2b:2a:09:c9: + e8:c0:21:44:c2:c6:a4:b6:16:c2:32:63:d9:ee:42:6a:c2:7a: + cd:bf:47:3e:72:38:74:a7:35:7b:4f:8b:2f:bb:ba:77:ec:6e: + f7:1b:8b:4f:07:0f:02:07:a2:98:f2:ac:e3:8d:fa:7c:f4:51: + d6:7c:5d:bf:e5:6c:a7:b8:47:38:93:cf:8e:8c:d3:48:64:1b: + 42:db:e3:f3:19:6c:28:dd:f5:57:19:10:76:95:60:52:84:6d: + a8:37:7f:84:2c:86:7b:73:3d:91:d3:c2:a4:6a:ea:e6:af:d0: + 80:a6:29:ab:6d:31:c9:91:da:7e:ee:44:60:43:9e:38:0b:47: + 09:c5:5a:5c:f0:0e:47:87:8b:46:3f:b8:c5:83:5f:c1:74:5b: + 27:de:c5:a0:ed:5b:35:8b:41:96:88:e5:64:8f:39:09:92:d1: + 39:ba:d8:a2:c7:cf:6b:bd:68:3a:4c:e6:98:9e:35:b8:6d:2a: + 4b:4f:80:9a:94:bf:8b:de:43:99:0e:67:73:03:c3:8f:55:48: + d0:e8:d7:70:fb:ea:b5:9a:1f:67:d0:3d:de:c9:7a:f2:cb:c2: + 81:9d:f2:bc:45:c5:e5:f7:0b:81:32:b6:83:49:d6:67:10:cf: + d3:d0:f5:00:29:6b:28:f5:8f:e7:3f:14:10:63:a1:9d:72:64: + 16:91:13:ac:ce:8a:a1:56:41:b4:d1:78:a4:10:1f:28:81:57: + f7:fc:1b:28:ee:7d:41:6f:71:08:a2:5d:2a:62:91:c2:a0:e2: + e1:57:5e:d3:16:6f:c6:78:cd:ce:ff:ba:7e:0c:35:ed:a2:09: + 2f:ae:3b:d6:bd:71:77:4d:8e:35:e3:32:21:8d:9b:77:3a:06: + 70:52:df:d5:cc:61:06:7b:bd:ee:bc:04:eb:4c:49:8a:05:a0: + 2a:c3:49:25:3e:2f:a7:f3:47:41:70:ab:df:9f:bb:2d:d4:81: + e4:93:84:72:89:af:0a:18:90:41:47:f5:d3:75:0c:c2:0c:c6: + 07:f7:80:59:96:b2:1b:0b:37:be:39:62:b2:9a:5e:be:c6:36: + 7f:55:b5:5b:7f:4a:d0:fb:16:19:3d:44:8a:b5:90:8d:7e:23: + c2:5a:70:04:ba:18:e1:99:07:d3:8b:2f:3f:b0:51:af:31:09: + bd:39:53:db:bb:f5:fa:89:6e:61:f9:e1:b3:75:d5:9d:23:9e: + a4:7a:a5:38:ce:0e:65:dd:6f:ab:7d:e2:f6:11:23:37:67:ce: + 5e:c7:9e:72:4e:87:5b:37:29:d7:9b:5d:39:da:44:d3:53:58: + c3:a9:a3:1d:14:b1:18:fd:63:bc:86:fe:0a:3e:f6:bd:1f:0f: + 2b:00:bd:40:71:46:63:8d:73:b2:0d:34:47:e1:e1:e8:5f:38: + 52:8a:de:45:1a:98:66:a9:1b:d8:32:7a:28:9e:bd:ad:e7:30: + 19:e6:c7:86:ee:83:6e:1b:8b:13:6f:07:50:4c:ca:3f:52:d7: + d2:7a:dd:93:6a:f9:4c:13:c0:91:2c:39:26:92:fe:8b:ae:39: + bf:9f:af:32:da:66:59:17:aa:d6:5b:5e:8f:51:7b:f8:52:58: + 93:ab:13:d3:3a:b7:1a:49:6c:d0:68:99:39:01:29:54:be:46: + 1a:7e:d0:db:df:c7:72:2f:b6:05:d2:d4:34:63:27:5f:11:c7: + 9d:67:26:f1:6e:97:65:ee:50:2f:b8:c6:6c:8d:b2:d4:81:5a: + 13:6f:e7:e0:65:12:a7:33:c4:d9:46:35:15:3e:64:0c:4e:07: + f4:fb:b8:0d:5c:0f:3b:98:b0:58:59:a3:fb:5b:27:d8:31:b4: + 04:0f:42:b5:13:f3:af:64:7d:46:2e:77:a3:0f:f3:c2:42:ed: + 13:23:0e:44:5c:7e:e8:e6:15:48:0e:60:3a:d2:22:92:bc:97: + 54:c6:31:11:af:b3:7c:97:a1:10:b7:f9:9e:55:a1:45:4b:4d: + d0:eb:40:cb:31:98:8b:62:87:21:cd:05:12:2d:76:6b:4a:93: + 12:76:b3:04:79:96:39:16:d0:c1:67:e6:88:68:3a:3d:50:28: + e1:5d:87:23:7c:5f:4b:4a:5c:99:97:f0:0e:87:c8:16:35:71: + cd:74:d4:7d:99:b1:ef:86:15:17:9c:bd:fc:35:7c:c8:68:b9: + 92:65:db:56:bb:5d:3a:ee:0e:8a:7e:14:f8:1c:1b:b6:11:4a: + 7d:7a:77:6c:74:ba:30:3f:68:fe:04:05:1b:c4:3d:7d:9e:c5: + 33:79:fa:3a:c5:7f:39:d8:83:11:d9:6a:3d:06:0e:fe:72:af: + 9d:27:b5:2f:b1:71:d6:02:d2:14:a6:d4:fb:7c:7c:22:83:a3: + 4d:26:0d:86:24:66:de:67:d9:02:7a:7c:75:6d:eb:c8:06:07: + 10:60:b8:5c:a8:50:27:02:14:18:d3:2f:38:d1:89:26:a7:bb: + a6:04:20:55:0f:9a:b9:c9:d0:56:2e:96:09:a9:62:c2:1f:da: + 04:d1:ba:d3:59:fd:fc:d0:4d:a7:fb:ff:46:e0:83:7f:b4:1c: + b3:b2:b6:fd:1d:cd:b0:72:cf:ff:10:3c:ac:01:b5:00:e8:db: + fa:5a:8a:50:bc:71:8b:fa:15:d3:ce:77:9b:30:38:60:54:1b: + fe:9f:4e:7a:91:b6:72:91:2f:93:c7:2d:6f:11:c0:1f:91:96: + 4e:e5:48:dc:61:93:7c:44:81:7e:6d:76:6f:1d:cc:a1:d2:a0: + 81:f9:df:d6:58:2a:19:7a:49:9e:00:69:ec:53:e7:91:98:b4: + 65:d7:ab:9f:6b:dc:9d:e0:c0:01:19:cf:36:0b:d0:f5:b6:13: + d9:ce:34:57:99:da:12:9d:bf:60:9a:5d:f3:e8:7f:e5:e1:0f: + 23:2b:a0:6e:b6:27:18:e9:ae:2d:18:e7:2f:5c:8d:85:9c:2d: + b4:32:7c:c3:5e:9a:b7:c9:5a:5a:a8:28:e7:ae:c4:79:13:4b: + 2b:94:ac:3b:1e:2b:0a:6b:df:a1:7c:4b:bf:3c:ca:51:5c:d6: + 1f:48:0a:e7:50:f7:a5:34:04:bb:d0:10:3f:80:e2:3f:b7:55: + fc:3b:a2:fb:68:4c:be:03:f9:12:7b:f2:72:26:81:82:4d:80: + 95:9c:2c:87:19:f9:46:6e:9b:97:ce:f7:15:6e:c2:83:cc:48: + f5:7f:71:98:12:1b:8a:2e:ed:d1:34:69:da:5c:08:83:d8:06: + a5:af:85:60:35:9a:ae:3f:b0:61:f0:9c:9f:93:89:56:b8:55: + f8:ae:f0:3b:b6:53:d8:4a:ec:a6:c8:93:e6:02:61:8d:e7:97: + 07:e1:6d:c4:1d:23:50:e7:28:74:ab:e1:f3:4f:ab:01:95:88: + 79:15:17:6c:d8:ba:73:47:9f:4d:68:18:12:66:f3:7a:09:34: + 04:ab:96:4c:a2:43:2c:8d:f3:dd:aa:df:33:05:7b:c4:ca:2f: + e8:f8:49:0e:17:06:87:6b:bd:4c:da:a4:f3:f8:a5:40:ce:9f: + 23:af:d9:65:25:25:ad:c4:fc:89:f3:8e:2e:69:6a:5d:b7:ed: + 67:1f:d5:45:1b:39:cd:27:40:0d:52:6d:a2:4a:78:29:51:ff: + c6:40:ef:e1:f0:e4:28:a0:ba:8e:0a:ef:7f:89:04:83:0a:a7: + df:5e:19:69:9f:63:7a:11:49:21:16:2d:0d:e0:03:34:f8:23: + b4:ba:e3:aa:5f:5b:43:05:6f:e1:18:a5:7c:9a:d0:5c:52:a0: + dc:9f:67:0a:39:6a:1d:85:5e:77:9f:71:54:1b:74:f5:98:16: + f2:fc:67:92:39:b8:9d:39:51:7b:28:df:59:11:ee:3d:6f:fc: + 5e:3c:78:9b:2c:01:25:39:f7:52:a7:44:6b:91:6f:48:ab:6d: + 49:b4:88:57:23:29:9b:fc:73:51:49:fa:4e:96:c4:48:66:ff: + 18:9e:1d:08:b3:18:af:d5:38:59:48:75:38:39:86:f0:12:39: + 17:bc:bb:45:e0:c2:f0:49:c6:07:18:ea:41:4d:d7:c1:52:6e: + 37:5d:aa:c5:10:04:99:cc:48:b6:45:41:da:4b:a1:8d:a0:5c: + a2:10:29:c0:54:f4:88:bf:3d:29:54:96:8f:15:75:f0:b7:d1: + 17:45:a3:36:a0:33:a3:3a:fe:9a:95:29:d1:82:53:68:bc:2a: + ee:2d:29:c8:b3:22:60:5d:a2:38:c9:83:89:89:05:72:1b:d0: + 60:28:75:ff:74:8e:54:8e:b6:af:fb:4b:b8:22:c7:19:43:ef: + 0d:e3:85:01:98:03:72:66:b8:19:3a:ca:b9:36:ff:66:78:5a: + 4c:d2:75:29:5b:d1:a7:28:9f:2e:9c:6d:3f:73:63:4c:e0:1c: + ee:84:5f:8f:1c:3d:34:da:5d:bd:aa:c9:30:f9:07:c0:9b:34: + 66:bd:b8:d5:44:ed:43:ce:1f:fc:50:16:20:68:aa:cc:a1:be: + 4a:38:0b:39:72:bf:99:67:ab:62:13:9b:18:06:05:d9:4b:69: + 38:9c:7a:61:69:de:33:b2:0d:a5:28:3c:43:6f:ce:e7:c6:3c: + b5:34:38:01:44:f3:bc:cc:f4:ea:c3:88:35:79:4d:70:c4:74: + 3c:b1:1a:78:89:1e:21:1d:92:d9:01:df:93:f5:97:1c:bc:ca: + b4:25:04:c9:5f:2f:5e:54:d8:ef:a8:5d:fa:f5:ff:7b:b1:4c: + 6b:d3:01:30:e3:65:2b:7e:d4:4e:e1:e9:60:df:3f:7a:82:24: + 41:e8:ba:a4:5d:ee:6a:09:69:b4:b2:8f:e8:8c:4c:9c:b1:ab: + 6b:1c:7f:db:e6:82:8b:c7:e4:76:36:a2:58:c6:ad:d0:db:e3: + 9a:88:7f:dc:12:61:3b:c2:f6:02:d1:4e:83:ad:d5:e9:21:8c: + 3d:2c:0b:7a:3d:5f:f0:d8:ae:3e:e0:f6:e5:af:ab:96:1d:c0: + f8:5d:d5:6a:4b:7f:a3:71:b3:4d:04:c7:b0:cd:c4:52:ce:b2: + 53:19:c4:da:3b:9a:8a:e5:6d:bc:32:cf:5d:6c:ae:66:16:67: + be:53:e6:81:7d:db:c8:95:08:e9:8a:3e:55:e8:4e:69:8c:8d: + 80:09:7c:3c:e9:0e:5d:49:33:11:de:0d:8c:b4:df:45:40:8b: + 27:d1:56:74:dc:7f:e1:e8:04:dc:f5:ca:29:a5:cd:51:3f:f9: + 08:2a:8a:f5:4a:9d:4e:a0:e2:18:c0:79:8b:cb:0f:0b:25:55: + 9e:e6:06:38:a9:35:78:5e:b9:48:10:39:d2:72:00:99:55:a4: + cd:df:ef:c4:b4:88:4e:14:52:89:1a:74:b3:92:a8:82:9a:34: + f6:81:87:b1:e3:73:6c:8a:3c:4e:18:ad:6a:02:b3:34:79:f2: + 85:80:2b:8e:ee:19:56:48:dc:cd:64:a4:65:a4:1e:3e:09:16: + 63:f6:aa:38:ca:62:4f:d8:8d:56:47:1c:f0:34:c5:c1:b4:46: + 1f:8b:f5:45:1d:64:72:d1:04:c6:87:eb:a9:d4:1a:2b:7a:e8: + 61:b2:36:ae:48:55:38:a4:74:05:eb:05:d1:2b:9e:85:0b:11: + 64:7a:e9:ee:a0:75:65:94:36:6f:2d:ea:93:01:8b:78:03:45: + 38:25:0c:ac:0f:08:3e:9b:b2:5a:c1:f8:c8:95:0f:35:b6:8d: + 3f:cb:3e:ad:bf:7f:1e:80:67:66:13:20:e1:e9:0a:3d:b8:94: + 42:67:e6:2c:5f:6c:e4:9d:70:3b:e3:c1:42:44:a9:39:8c:09: + 69:42:ab:5a:4c:12:cd:ee:2c:c9:3f:19:08:3b:37:6a:a9:f5: + 2d:15:c6:17:b9:72:40:5b:6d:32:13:71:4c:b0:5c:36:9c:64: + 6f:42:81:5e:5b:78:55:7a:d6:e6:2c:29:31:39:d7:01:24:2e: + fa:98:c6:b5:97:4e:75:6f:3e:ec:8f:f5:77:82:99:e0:27:91: + c7:82:8a:b5:8a:30:5d:a3:1e:10:37:0b:87:72:45:27:88:e0: + 76:a8:85:c7:ec:f1:68:bd:05:dc:0a:87:7f:d2:26:74:03:b9: + 2b:a4:2d:08:ba:81:ad:f3:81:a4:e7:bb:90:42:19:c1:87:87: + 74:0f:30:8f:6f:5c:62:cf:d5:79:39:54:b7:2f:40:70:82:70: + 35:d1:fa:c4:aa:e5:ca:3f:bc:0c:76:0b:8c:ad:f1:39:9a:f1: + c3:9e:93:de:4a:9d:99:3b:7b:3e:47:f0:63:e5:75:96:b1:c7: + 81:7d:e4:a2:0b:18:77:f9:17:ab:88:40:ea:de:22:9e:6d:e1: + 47:88:f9:66:3c:ba:9a:5f:bc:03:e0:b7:12:06:17:98:9b:cf: + 12:08:47:85:01:df:bd:23:29:82:ea:27:18:36:86:1b:1a:1f: + c7:80:13:01:0d:c8:49:56:cd:b8:ca:e4:a7:35:aa:0a:fb:95: + b2:ae:7b:a1:56:a9:33:b9:74:09:7f:39:f0:45:ac:5b:a9:9e: + 70:39:47:05:9e:50:03:74:37:63:d5:d5:c4:98:dd:19:a3:7d: + b8:8d:c4:ee:d8:56:ed:ee:0b:a9:53:e3:50:a5:dd:4f:12:74: + 23:ef:dc:be:75:eb:24:c9:0b:d2:d8:71:e9:6c:ee:98:53:a4: + b0:73:55:3f:e4:5c:da:9a:9c:ae:40:05:87:5c:21:0a:e4:a8: + 8b:40:fc:69:74:87:9f:15:03:39:92:22:3c:47:f2:13:6f:d0: + 82:0d:cf:3b:db:ca:92:2d:99:54:d7:b6:46:a6:b4:3f:d8:82: + ef:02:24:e7:80:d7:38:0b:92:b3:9a:57:51:d6:46:8f:18:b0: + 16:b8:ec:0f:4c:0b:9f:a2:1b:8c:68:4c:c8:60:dc:b7:af:33: + 2f:a7:60:f8:48:9b:84:2c:83:93:1b:e8:2b:c3:a5:63:64:1f: + ce:e4:aa:ec:07:8f:87:c6:60:94:7c:04:8a:d4:f5:e0:06:de: + 42:7c:2d:d2:e5:e2:0d:3a:0f:e1:ef:40:33:42:94:e8:3e:df: + 85:fb:d3:04:15:b5:56:5a:35:10:f1:68:ec:d5:6b:ad:ca:7c: + d5:4e:4d:58:9f:2f:d5:8a:c0:e3:2a:8f:6e:e8:8f:e6:17:89: + 95:37:28:ca:d5:cf:a9:f0:c4:94:44:f4:6b:28:5d:50:e3:f2: + 91:50:e3:07:2c:26:50:29:71:d8:29:41:ef:8c:7a:15:f6:c0: + 0f:b5:31:45:d3:05:96:fa:52:96:e1:20:63:e9:16:03:b6:46: + 75:fe:a4:88:53:97:53:e5:e9:67:0a:58:91:6d:24:22:f2:d4: + 97:55:65:f1:72:4d:30:f5:80:01:3e:ca:f6:59:5f:22:48:b2: + ee:79:02:32:3f:7f:f1:f6:b5:80:a0:79:6d:15:b3:1c:fd:90: + 66:9c:a0:90:41:e8:c6:cd:6f:a2:96:63:e7:b8:e9:4c:a4:6e: + e2:7a:c9:05:24:6d:70:db:d4:51:9e:e1:d6:4d:5a:38:40:98: + 63:af:35:22:b4:ae:a2:ed:b8:8b:56:07:7a:ee:55:99:b2:a1: + f0:68:03:37:6b:87:0a:26:49:e9:c5:71:04:fa:4a:a9:b6:10: + b3:c3:75:d5:49:8d:9c:e9:61:65:54:37:8e:c6:6e:5f:dd:28: + 0a:58:49:76:9b:ee:9b:0c:d0:a6:96:46:11:2e:5b:32:ad:23: + 9b:c6:ef:e7:03:f3:19:79:ea:93:e1:ff:87:15:89:8c:56:43: + 23:aa:9d:fc:96:70:6e:0b:7d:87:db:37:da:2b:95:53:66:f4: + 3c:03:12:d4:50:9d:10:42:c9:2c:17:b9:9b:7d:2e:95:0c:98: + 73:8b:07:5f:9f:58:32:29:f0:89:59:bc:33:2a:e2:32:ab:75: + 54:b8:6e:8a:5c:2e:e2:37:c4:b8:b5:ee:75:73:e5:5a:5f:cc: + 3c:06:7f:a3:e9:17:1d:b5:86:a0:0e:8f:9c:95:32:5e:58:6d: + 64:b2:6f:dd:1c:54:bb:b4:9e:21:83:c0:c2:88:d9:02:e8:ea: + c0:2f:46:92:ec:4d:06:7e:a9:d0:13:fd:6f:d5:bf:60:7a:fb: + d9:2f:c6:b1:7e:99:fd:fb:db:63:62:e3:de:cf:a4:21:ee:e7: + d0:c7:4b:b3:83:87:43:d4:45:29:0d:9a:bf:f7:fa:89:c4:d3: + 26:56:b0:f8:89:a0:b5:a0:07:5f:6e:fc:62:0c:24:c3:9b:07: + 0e:36:6f:4e:36:45:aa:a5:26:b8:ef:69:81:a0:af:f3:0e:b6: + 1d:9f:ca:9e:88:45:93:e6:9a:b4:db:21:24:63:c9:10:76:c3: + bf:0d:bb:4a:89:8e:0a:c3:28:f5:3d:2f:75:22:b9:7d:78:28: + 1a:1d:47:09:85:75:ee:67:e6:80:05:e0:df:58:cc:37:c7:31: + 75:cd:81:81:2a:ff:5a:d6:d8:50:23:8c:93:df:85:e6:da:3b: + 96:a9:39:7a:89:c7:04:b0:00:f8:d1:32:c2:6e:84:85:40:01: + 79:0a:14:aa:3a:c5:3c:51:45:92:59:70:14:14:92:9d:5b:e2: + 33:82:60:ea:7a:00:58:5b:a9:5e:cc:a5:5a:ea:fe:00:4e:32: + d1:af:e5:42:e7:16:5d:12:24:86:c6:ec:2e:eb:5b:27:06:43: + bc:29:bd:57:fd:47:70:d4:10:02:9e:a6:29:0d:9b:b5:56:98: + f5:d1:04:1a:e2:a5:88:f8:78:9c:c6:b2:fb:f6:9f:3a:ea:0d: + 93:a5:15:8f:05:b6:e8:22:d0:cf:7d:38:01:69:7c:85:6b:cc: + 1d:cd:11:1c:c3:c2:e9:34:87:76:07:d3:c9:87:ca:bc:28:d1: + e2:38:79:bf:65:9d:57:98:37:7d:d0:c9:a9:a8:5e:4c:2b:28: + c1:2d:73:7d:c6:22:23:9a:6f:9e:a0:c7:05:81:da:ba:d7:76: + 4c:da:ff:55:04:3a:df:b2:a9:d9:d7:77:02:de:2b:90:af:4f: + ea:a0:da:b1:05:f7:36:fb:c7:b1:d8:12:ee:67:05:90:92:67: + ef:4f:75:1a:58:1e:b6:44:cc:82:d7:b3:cd:1b:44:5d:e6:0b: + df:ed:fa:03:f7:e7:eb:93:2a:01:5b:eb:09:5d:ab:cc:49:89: + e8:28:31:4f:1c:a7:00:da:55:cb:d8:f6:3c:ce:79:7d:32:2e: + 77:29:09:4a:93:41:10:cd:ad:a9:e1:5f:e8:8c:bc:59:b4:80: + c2:8d:7f:3f:84:16:b2:ab:15:1a:4f:1d:91:6e:98:58:3a:5d: + 2e:b1:f4:b2:70:0e:31:6c:81:e5:29:a2:19:82:80:37:ac:1d: + bf:ac:c9:f8:02:8d:f4:46:83:15:e5:67:23:5e:b9:ff:e9:3d: + 46:79:40:33:fd:84:e3:cd:c2:3a:45:4c:33:9d:5f:15:9b:14: + ef:fb:66:a7:1c:9d:81:b6:7d:98:94:15:c5:2c:bd:d9:d0:18: + 26:b4:b0:8a:d4:70:d5:de:ae:e1:13:11:34:cb:ee:77:54:e2: + f0:79:dd:db:92:72:fa:5d:52:9f:68:39:dd:80:0d:86:82:70: + d3:01:f7:65:d1:bf:54:7e:9b:eb:c8:15:19:31:9f:aa:6f:6a: + 21:bf:a5:e1:5d:05:92:12:c7:5b:c4:80:f1:bc:5c:b9:bd:c1: + e9:8e:12:7e:e1:37:9a:ba:3e:91:27:b1:09:76:aa:c5:24:2d: + 05:23:9c:ca:80:84:68:9f:56:4e:09:c6:85:ee:80:9b:ec:bb: + c3:8e:b1:51:4e:b7:d6:e1:e4:67:76:dc:94:9f:ba:62:f1:51: + 4e:ce:d0:27:2e:39:05:3a:7c:b3:44:74:d3:9f:7b:83:ef:86: + c1:9c:37:9a:26:31:50:39:66:3f:d8:15:78:c8:ef:42:bb:46: + 5e:1c:ba:c2:b5:0a:21:34:4d:ab:ee:61:fe:3b:87:7b:cc:82: + 69:8f:b9:7c:0c:07:bc:25:bf:c8:57:d2:32:fe:32:0c:14:1a: + 09:f0:77:e8:bd:a1:1b:b7:2a:b2:42:ea:2c:ed:d8:69:83:a0: + 1c:92:85:ac:1d:4d:a2:88:75:d3:ca:1a:9b:e5:7a:2f:2c:63: + 86:9d:14:0d:d2:65:f7:08:02:63:d5:bd:d8:c2:e7:d8:38:92: + c1:6c:5c:b0:24:62:1f:63:70:89:c7:19:e9:71:14:80:be:bb: + a7:30:b6:0a:d8:18:8c:11:14:88:12:8e:55:da:e8:f3:b9:7a: + 5e:3c:d0:8d:dd:5d:ed:c4:c6:03:80:91:52:d7:99:fb:ee:a5: + bd:c2:f8:68:c2:7e:7d:dd:b5:c3:f6:21:ea:9b:bf:b2:0a:7f: + 8f:6a:27:e8:dd:5c:01:95:74:6f:4d:71:65:f2:a5:f0:09:6b: + f0:6d:64:78:d7:6d:e7:6a:97:66:d0:83:ac:8f:b6:28:f5:73: + f4:b4:84:03:b0:bc:60:98:69:37:d6:d5:75:e1:e0:c2:c9:31: + 80:2e:d8:ab:a0:80:cc:7e:70:48:20:89:c7:be:99:c8:cf:13: + 10:c0:fc:0c:5f:69:42:69:4b:ec:68:76:dc:91:16:2b:27:53: + b0:92:11:13:62:f1:a0:1e:ff:fc:a8:bc:a0:89:0a:f0:dd:e3: + 9e:8a:39:85:da:47:56:0a:73:7f:58:17:a7:b2:e7:87:3f:72: + b3:a5:69:0d:b9:4a:b7:0c:4b:e7:04:62:ff:44:7e:51:41:73: + d8:d1:22:05:db:5f:3e:f7:77:72:26:7f:cd:45:50:da:69:71: + b0:f2:dd:b5:13:10:ab:1f:b6:a4:63:55:c5:85:28:a7:6f:ae: + 49:f9:fa:21:28:0e:1d:51:85:75:f2:1f:90:38:7d:e2:08:56: + f5:ed:9e:85:e4:91:c9:43:2d:e4:3c:25:19:7e:01:b0:2d:fb: + 0e:da:61:d6:49:3c:e7:63:4c:c7:31:9d:74:55:c3:55:3b:e9: + 42:10:1a:01:d5:0e:e3:dd:36:19:fd:7d:6c:34:7b:4c:60:35: + 52:bd:f1:3b:37:33:6f:3e:a3:aa:a1:f7:5b:ac:ee:34:04:94: + d7:37:7c:e5:5e:d1:ef:68:9a:fa:a0:5a:23:de:c9:9d:f5:8a: + d2:a9:5f:00:db:67:02:f8:0e:83:c8:bd:99:dd:09:24:bf:a6: + e4:d2:15:73:72:b5:99:79:49:4e:da:0a:f9:52:b2:94:22:1d: + 66:28:f7:eb:59:fb:a4:9a:7a:f4:f0:7f:9a:5b:ac:60:b3:b0: + c3:fd:38:72:88:0f:31:02:d3:60:ff:20:27:a4:78:4e:7c:2a: + 19:65:b8:22:b5:a8:f6:02:cc:2a:8f:14:b1:f3:28:07:fd:4f: + 68:ef:d9:b2:29:72:1b:be:2b:eb:a7:a7:6b:4f:ec:4a:8b:b4: + 21:67:f8:84:e6:56:51:99:4b:d3:df:c3:7b:49:2a:d7:3e:2d: + ec:18:9c:0d:c6:d0:2f:bf:43:61:e9:c8:99:fc:74:d1:25:99: + 47:d7:7a:79:d5:b1:ae:f8:bf:22:4b:48:f0:e1:fa:9b:00:ba: + 8d:4f:62:f8:74:dd:ce:36:43:ca:3c:7a:10:54:75:14:33:da: + d1:e4:c8:97:aa:b5:7f:60:9c:54:42:a9:12:5e:e3:3c:66:18: + 66:f2:2d:86:e3:8f:55:78:50:a4:e5:b3:3f:e7:fb:5e:b6:4b: + b1:f1:9b:98:47:33:b7:f1:dd:b4:91:16:24:fa:1e:71:f0:ec: + c1:7e:6b:1d:f5:91:88:78:61:ed:96:41:f6:7e:85:c6:08:e4: + dc:31:37:41:e5:8d:b0:78:b8:66:c4:95:d7:80:29:f2:93:ce: + 5d:e1:de:4a:32:6f:a4:06:0a:8b:c3:d1:26:cd:29:cf:38:5d: + ac:6a:99:76:9c:8b:35:b3:bb:80:9b:a8:37:f4:3c:1c:e4:39: + 0f:20:b4:cf:2c:94:58:3c:ef:7a:e8:e2:86:a7:7a:5a:2f:19: + 93:8d:0a:b1:c8:01:00:db:64:63:f5:be:7e:37:4b:cf:67:8d: + b2:89:06:6d:0f:95:d7:9f:2d:b0:44:2b:95:58:83:8f:ff:c0: + b8:bc:b5:3d:d6:fb:79:68:7d:ba:da:f3:72:5f:d9:43:94:62: + 04:7a:87:cb:f5:fc:ae:cf:3b:bb:32:1f:2e:a4:b7:6e:5a:9f: + 76:0e:76:d7:52:83:de:33:4f:62:fd:23:bb:7b:b7:65:96:ca: + 32:ff:d4:92:79:11:0a:53:07:e5:37:33:19:0c:d3:e5:d5:90: + 8d:85:39:6d:74:6f:b5:f7:63:c3:d6:26:7d:d0:48:96:e2:07: + a2:64:08:0c:4d:c4:72:3a:50:1b:73:8f:b6:4b:fa:50:f7:cb: + a9:20:3d:a6:4d:bf:fe:36:09:6e:d1:82:61:13:19:bc:13:fe: + 1e:21:c7:3b:3b:cb:8e:64:c9:0a:83:b9:c6:2d:d8:23:4e:71: + 55:03:ef:f1:e8:06:4a:6a:89:31:44:70:e8:b9:ac:32:03:6f: + 93:8a:f9:d0:9f:8b:f8:7b:1d:b1:cc:e7:37:2c:1e:76:01:f7: + 03:c4:05:4e:55:0f:90:25:7d:61:4c:c2:ab:ee:e9:93:67:bd: + 89:5e:17:b6:53:82:c6:83:82:15:41:02:ba:16:c3:be:36:e0: + 0d:cc:90:d0:32:23:48:67:7b:ab:05:ef:3d:a8:a8:e6:b7:01: + ea:58:bd:3f:71:af:01:f4:cb:dc:3e:56:04:d9:8d:66:ee:86: + eb:bc:f6:cb:0f:3f:4d:3c:d9:45:73:06:12:d7:a9:9a:d4:06: + fd:5e:f9:07:14:3b:21:fb:bd:03:23:ae:c2:83:9d:61:1d:df: + 6c:53:d5:8e:7d:64:03:13:cf:20:60:30:0e:61:b2:d4:c5:24: + 92:cc:30:5e:3f:92:34:d9:63:7f:43:92:48:3a:75:43:c0:a4: + 40:d8:4e:39:eb:6b:fd:58:72:8f:38:bd:09:5b:67:64:3c:fe: + 9a:18:e4:0d:d5:ae:0c:a2:9c:31:ff:6f:d5:21:eb:e8:c0:76: + 28:b5:6e:47:12:86:60:1f:b6:22:9f:13:11:1e:9b:cf:8f:09: + 5e:e2:66:68:17:32:0a:cd:d5:25:9c:56:c4:43:c8:d8:cb:cf: + d9:99:0a:6c:7f:66:5b:1a:2d:b2:dc:c9:a4:24:c6:63:04:56: + c8:42:9e:02:2f:c8:05:40:aa:b4:07:d0:9f:bf:d6:2f:18:b8: + cf:71:4c:2d:ac:f5:94:96:bd:a5:8d:4f:36:e7:72:22:e6:0a: + 90:cc:78:c8:9a:27:99:a7:66:81:a0:75:e5:8c:f2:27:4f:a3: + db:94:ed:b8:2b:02:6f:4b:45:e3:c4:08:e6:16:38:4c:2c:94: + 6f:45:55:0b:f2:90:5a:9c:80:bf:5d:59:b2:54:90:82:5b:26: + 14:d9:ec:c7:c9:a5:1d:f3:88:08:b3:17:8c:52:6b:96:22:df: + ab:95:46:d5:e1:30:1c:b0:47:96:14:b1:d9:1a:63:1f:ae:db: + c9:f5:09:a9:64:a0:96:37:a2:29:2c:90:e8:1f:2f:77:6f:ad: + e8:6b:f0:9a:76:5a:48:cf:e6:25:a3:c9:e4:31:72:64:ce:6f: + d4:5d:9a:a3:51:88:d4:59:36:fd:45:1c:39:96:fb:8a:65:52: + ea:2b:cc:89:4c:c9:ad:e5:d5:fc:7c:31:cb:1f:c4:62:88:1e: + 0f:f6:53:07:95:c0:fe:71:23:0d:71:68:af:db:07:36:69:ef: + 44:d9:93:a4:f0:2f:f6:1f:e0:ce:5d:02:34:d2:4f:54:df:bd: + 9d:fd:38:67:f3:d9:03:fb:86:fb:2c:ec:1c:a5:78:ac:db:d5: + 54:63:19:3d:c1:11:a7:a5:ac:ca:75:1f:f1:b5:e9:bd:69:a5: + b2:31:c9:d5:5c:53:96:4b:96:cf:43:2d:76:43:a6:ea:bb:3b: + 0f:65:67:5a:66:f9:27:30:1d:ff:bb:17:32:f8:c9:0d:d2:56: + d8:5b:89:03:fe:7e:92:f3:97:73:24:14:12:4f:2f:45:e6:69: + 51:63:25:8e:11:d5:bc:be:7b:8b:6c:13:13:02:62:59:13:6a: + 51:92:32:76:5a:a4:7b:b0:e7:d1:de:0b:73:00:18:34:12:95: + bd:c5:96:b7:20:d5:d6:72:5e:4f:c9:b6:f5:4e:47:1a:0f:86: + 8b:5d:17:8b:2c:b3:f2:3c:3d:13:f2:a8:73:95:53:5c:6f:74: + 76:f6:7a:57:98:5c:25:14:c2:19:b3:fa:fe:13:f0:a7:6e:56: + 76:22:b5:d3:cb:14:6f:a6:52:0f:e3:59:ff:3d:27:53:95:20: + d6:05:a7:f4:2f:ed:ca:b1:ae:29:fa:6d:b7:a0:f4:d8:ba:fb: + 36:b4:70:75:72:7a:a2:69:c4:f6:bf:a1:96:60:80:38:83:8a: + 75:b6:9f:fc:69:ba:94:cd:72:54:3f:45:d4:5e:ff:01:66:16: + 33:c3:31:42:02:b8:85:0d:da:fc:db:00:78:8d:20:f6:bf:9b: + d7:e1:9f:0e:76:a9:c9:df:54:a4:ff:4e:d1:fa:b8:ed:5c:58: + 98:35:2d:c5:8e:9a:36:92:19:a4:b6:07:66:25:27:c2:f9:27: + f1:bb:69:2e:70:65:d5:e0:fe:57:ba:33:7a:2a:1f:e2:b1:a7: + 23:c5:63:a1:11:63:ad:4a:28:be:59:23:24:fd:8b:d3:2f:d5: + d7:2e:58:f1:e5:4c:a1:18:69:de:4e:9e:91:3c:48:90:c3:ef: + 4f:9e:06:3c:cc:c4:1a:6a:a1:31:aa:51:f0:13:e3:97:55:26: + a1:5e:97:01:b8:ac:06:d7:f4:94:e3:e1:3e:8f:4c:af:01:f5: + 41:6c:e4:71:3b:4f:de:d2:1a:58:13:6c:21:4e:60:b6:4d:59: + e6:b4:f8:7f:b0:94:bb:83:4a:70:d2:1f:ac:8d:f9:eb:6e:c8: + 3f:4a:f8:46:9f:8a:14:04:e4:a6:68:6b:ea:f4:72:e7:b7:96: + 26:6c:0d:cb:5a:95:c7:bc:b0:25:02:b9:1c:82:a0:26:e3:5c: + 58:58:a7:90:f0:24:f6:8a:2e:f1:17:c6:40:55:89:c7:31:e3: + 97:fd:b0:8a:3f:b2:7a:56:52:65:18:94:c9:f5:da:86:be:75: + 8c:86:47:4d:a4:9f:3e:3e:d7:ab:ca:f4:cd:09:35:28:22:37: + 9c:6f:bf:3a:c4:98:95:6f:56:8e:3d:b7:37:97:f2:86:8d:3d: + 27:63:98:a6:ae:3d:aa:89:fc:c5:0a:16:a2:b3:e2:1a:a6:e7: + 59:69:e9:78:e6:2d:0b:4c:d0:f5:d7:45:fb:c3:c0:16:c7:9a: + 02:7e:57:db:b4:ee:86:3e:37:06:34:05:43:a9:e5:20:4d:38: + 6e:6e:12:b7:c9:79:62:b3:11:9f:5d:84:a7:b9:00:68:c5:a4: + 3b:fc:88:e2:85:34:cb:4b:dd:8f:74:f4:bd:21:9a:0e:73:be: + ef:c3:c0:f7:62:25:6f:03:49:f5:3b:f0:e0:50:da:75:0d:10: + 1e:12:6a:5a:29:33:e2:44:ad:7b:b2:b4:2f:53:2a:54:78:cc: + 25:9d:b9:de:4e:41:7f:e7:99:b2:52:dc:f4:1c:6b:67:ee:d1: + 58:21:7d:95:21:41:59:15:17:c8:70:18:c1:9e:3b:ac:68:63: + bb:f7:94:ee:aa:cd:30:1b:31:54:b9:7e:57:94:3a:b7:11:6d: + 59:86:e6:13:86:28:1c:83:28:d4:2b:62:03:d4:b0:ea:6f:d0: + 5a:77:0f:70:50:e8:eb:97:68:26:8b:10:f8:1e:04:44:e3:b9: + 65:80:2d:b3:c6:37:db:4b:9f:b7:9b:bd:a0:e3:b5:a9:3c:6f: + b3:00:32:f5:9c:1d:b8:c5:27:0c:3f:a8:df:15:9c:75:27:8b: + d7:d2:60:59:ad:73:1f:99:b3:46:19:36:ec:82:7d:b1:87:43: + 35:ce:83:14:95:05:4b:49:0e:13:e9:d6:4e:79:fd:73:f7:dd: + 25:2d:2c:ea:8b:df:55:f8:0b:f0:81:21:b2:c4:ee:6b:9e:23: + a6:c4:c9:14:67:72:2a:8a:2d:73:a3:f8:bd:77:d7:70:7c:b8: + 24:0b:d3:bd:09:43:c6:d6:92:a1:67:00:5d:ee:e8:95:c9:55: + 9b:d6:a9:6d:93:0c:a7:f1:71:ce:a7:14:e2:d9:ff:a2:30:3e: + a8:a5:97:b2:ea:df:10:43:52:cf:c3:4e:7e:79:02:77:29:d6: + 28:f0:e3:89:71:77:30:1c:0a:f8:0d:c0:cb:2b:e5:5e:7e:21: + 3c:4f:ee:92:b8:13:26:d0:51:d0:72:da:8f:0f:c3:74:74:8a: + a8:d0:80:79:58:bb:73:ab:2a:d7:ce:74:90:35:31:96:25:72: + de:88:c9:07:aa:88:7b:68:f5:67:81:66:74:00:e9:1b:7b:76: + 9a:25:34:c7:f6:bf:7a:94:71:54:0d:8e:fd:af:81:3c:27:d7: + 7a:1b:44:3f:f4:f5:36:09:7f:2a:1f:a5:28:f8:b3:d8:7d:f4: + 7b:b1:0d:1f:d7:64:07:91:26:fc:62:fb:a3:67:17:7a:8d:03: + 1e:96:a9:e7:d2:ed:e5:be:61:51:31:53:d9:82:f3:0f:5d:dc: + a9:bb:ab:12:bb:78:4c:aa:0f:17:f3:8a:85:57:47:bc:b8:10: + 2c:27:5b:db:f1:c3:e4:8d:24:b5:64:5e:6f:0e:34:45:0c:78: + 2d:82:99:dd:b5:dd:00:36:67:8d:1a:88:47:a7:dd:55:9d:f2: + 88:2b:33:25:a8:2c:ea:70:b4:8b:b2:c3:29:db:25:59:9d:8d: + a7:d2:9f:22:d8:81:d3:c7:ba:12:c8:a1:c7:7e:22:76:e4:85: + c6:4c:02:d2:8e:7e:65:15:28:e1:cb:79:6f:0e:57:ee:22:b6: + df:7a:ba:84:10:5d:37:6b:ca:e8:61:f8:65:5c:f6:1d:cc:fb: + 2a:bd:2d:74:1b:46:51:5c:af:21:46:7b:7c:09:77:dc:ff:38: + 8e:94:89:b6:85:6b:22:f2:9b:e9:92:4d:e3:10:77:20:bd:e6: + f2:d9:18:57:f7:76:2f:4c:5b:b9:6b:0e:55:fb:be:13:87:de: + f2:ab:24:32:5b:97:7f:34:87:bd:5e:fd:4d:4c:d3:65:4a:60: + 04:b8:bf:f4:17:06:82:7b:76:ca:36:74:39:f8:45:89:2e:45: + d9:b1:9d:2f:72:36:1a:01:90:24:6a:5b:89:08:f0:6b:4e:6b: + 97:4c:04:af:12:67:01:7a:4c:a8:c4:8b:f1:85:42:8f:c2:25: + 78:09:03:da:ae:c7:22:84:ce:5a:44:58:80:f9:15:ca:2f:02: + ad:94:08:9c:95:b6:cf:55:a7:19:75:f3:85:c2:ff:d0:b2:1e: + fe:16:f2:78:e5:d8:db:38:76:af:02:13:ae:6d:47:20:c2:60: + 1f:72:2b:01:47:e8:8b:c8:f4:a6:c5:11:07:23:36:4a:19:c0: + d4:14:83:34:57:87:5d:72:8f:1c:d1:4f:ae:87:e4:55:ec:1a: + 22:0f:7e:96:3a:37:c2:7c:c9:8b:ae:d6:2f:a6:d6:df:25:71: + a9:a9:05:1f:9a:36:a4:f6:81:e0:e0:db:7f:7e:9a:c4:f3:db: + 75:a9:af:3b:57:d2:b8:c7:87:d7:c0:51:8b:3a:16:a8:7e:99: + ba:6f:66:58:4e:fc:78:3e:ad:49:ca:e4:c2:c0:b1:20:b0:3e: + 0c:e0:74:a1:08:62:ec:90:59:5a:9b:e7:1d:8b:af:d9:99:07: + 6a:cc:a6:35:32:7e:a0:1b:ea:d2:83:bf:0f:25:cb:73:c1:33: + 70:f8:b5:a7:0d:aa:8f:48:6d:c3:21:e0:5f:9f:a9:4d:04:3d: + d4:cb:f0:8f:f0:9a:e1:78:03:3c:a6:e7:df:d9:e6:63:9a:db: + e7:3b:c0:f9:e9:4e:22:e7:ee:2b:47:15:f3:90:96:3f:7d:23: + 96:c0:b2:e0:31:3b:37:c6:c1:f1:96:be:8e:0e:c2:d9:ea:80: + 65:25:44:be:70:6b:fd:f3:4b:8b:40:aa:10:05:aa:8c:3e:40: + a6:54:d2:7b:10:75:6c:e4:91:64:23:49:eb:42:fb:a5:e4:6f: + 5e:c8:dd:a3:f3:c5:ea:a9:6b:dd:37:4e:30:62:d7:f6:17:a7: + bd:24:e1:88:3b:5c:ec:ac:38:3d:f3:c1:14:b7:bc:5b:5a:a3: + 2c:fe:7f:9b:52:82:23:d9:c7:d8:61:56:3b:2c:7e:d5:65:15: + b1:a6:e1:2d:94:d6:7c:1a:35:c8:a4:8f:fc:69:f3:cd:6c:18: + 0f:74:ee:1e:68:9e:f0:fe:13:66:84:50:85:bd:66:45:ea:1c: + 7d:2d:bc:95:5b:15:e1:ac:ee:e4:b6:d0:81:0a:75:a8:d8:69: + c6:37:51:35:a1:02:a4:bd:52:5e:cf:3c:73:76:95:19:df:6f: + 9b:a1:e1:ea:dc:82:f0:a5:53:47:86:e9:49:88:01:be:f1:b0: + 02:58:48:85:e3:24:51:d5:ac:e4:b4:bf:6f:14:87:ca:7f:43: + e7:86:e0:c2:c0:b8:7d:76:d1:d1:3e:46:20:1b:e1:96:07:1f: + 7b:0f:20:e2:ad:67:9d:d1:a8:26:16:6f:0c:ab:21:18:b5:84: + 60:c9:54:08:85:8d:ea:7b:e7:57:d2:0b:a1:3d:fb:cc:39:5b: + 73:6f:f8:7c:a9:83:af:f0:39:6d:8f:50:9d:b5:08:28:08:53: + 4d:25:85:18:5c:38:4f:94:70:0d:0c:65:6a:c6:83:b4:15:06: + 60:75:4c:43:bf:61:8b:c0:04:52:1a:99:a3:7a:2e:0a:7b:96: + 17:c7:64:72:ce:53:14:a6:e4:c2:8b:6d:f9:6a:b3:55:30:11: + 1d:59:02:6f:8c:33:59:6b:1c:45:a2:5d:07:d4:b5:d9:95:3a: + 05:c2:17:5e:f4:75:c5:89:fd:d6:3d:24:f3:30:72:70:b3:6e: + c1:bc:71:29:f3:e3:3c:92:50:f6:48:eb:bd:f9:a2:d9:5a:57: + 3a:f2:4a:a0:8e:d8:81:ec:aa:c9:c7:8f:21:33:09:e7:ab:af: + 43:c4:af:20:ec:c6:17:7e:f0:04:e1:e5:e1:14:66:8f:b6:de: + d5:be:c2:f5:ff:a3:0e:bd:92:36:3d:f8:03:89:d2:c9:21:8f: + af:2c:76:a0:a1:f0:f9:42:ad:62:d6:f2:8c:6f:1d:d0:c2:94: + 57:1c:cd:f1:bf:bb:a5:39:2a:22:bb:66:ee:78:8f:2c:be:7d: + d7:d0:ce:8d:95:c0:3d:89:1a:8e:07:ea:38:f4:ec:f8:65:08: + 8d:bb:d3:91:5c:bf:4e:9f:e7:dd:22:4b:2f:54:34:61:57:f3: + 3f:e3:20:7d:2b:02:5e:f7:08:ca:2c:9c:cd:0f:0a:9f:65:b2: + 7a:ad:18:14:35:92:14:25:ed:4d:66:eb:5e:a8:44:69:51:66: + 5c:f7:79:7b:d4:1e:42:24:fa:ed:83:db:23:39:15:d5:83:42: + 42:f7:63:cb:c8:f3:2f:c1:d7:9c:6f:20:54:16:47:e4:79:f7: + ab:34:2b:5b:5d:4e:40:8f:1f:9e:e6:c6:0c:0b:c1:08:d8:46: + a1:6a:6e:65:23:b9:b6:f4:1e:71:89:56:2b:75:95:35:9e:a0: + 7a:6b:ad:86:7c:a7:e7:53:3a:5a:76:b9:84:b0:97:5c:cf:d4: + ef:dd:50:b0:fb:53:1d:29:13:90:2f:f1:d0:30:41:e2:c5:62: + 89:fb:b8:f5:9f:64:22:78:b1:5a:f4:ec:a1:00:7a:d2:16:ae: + 92:9f:69:71:c5:4f:5b:17:07:d7:ee:27:6c:eb:e5:d4:f6:73: + 4f:da:0b:3b:72:74:5a:23:a8:04:b6:69:eb:68:34:c5:bd:bb: + 3b:39:f3:62:cd:d6:08:41:a7:cf:32:a2: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----- +MIImJDCCB16gAwIBAgIBATALBglghkgBZQMEAxowgaMxCzAJBgNVBAYTAlVTMRAw +DgYDVQQIDAdNb250YW5hMRAwDgYDVQQHDAdCb3plbWFuMRgwFgYDVQQKDA93b2xm +U1NMX1NMSC1EU0ExGzAZBgNVBAsMElJvb3QtU0xILURTQS1zaGFrZTEYMBYGA1UE +AwwPd3d3LndvbGZzc2wuY29tMR8wHQYJKoZIhvcNAQkBFhBpbmZvQHdvbGZzc2wu +Y29tMB4XDTI2MDQyODA4MTAwNFoXDTI5MDEyMjA4MTAwNFowgb4xCzAJBgNVBAYT +AlVTMRAwDgYDVQQIDAdNb250YW5hMRAwDgYDVQQHDAdCb3plbWFuMRgwFgYDVQQK +DA93b2xmU1NMX1NMSC1EU0ExHTAbBgNVBAsMFFNlcnZlci1tbGRzYTQ0LXNoYWtl +MRgwFgYDVQQDDA93d3cud29sZnNzbC5jb20xHzAdBgkqhkiG9w0BCQEWEGluZm9A +d29sZnNzbC5jb20xFzAVBgoJkiaJk/IsZAEBDAd3b2xmU1NMMIIFMjALBglghkgB +ZQMEAxEDggUhABhSAaega5HUsoai6G/eXAfC1zWIKz9h4nyZdEvlx4g+2L3cEgg1 ++pPLkoHI+nuICy2IbtphA/xv85FpHquTRyek2ED9om+vjaYv3z2ovT91sUD/g8NA +B3UTku5LU3VFAnzQgSGqUZSoov4CKOUt80wj5/gaYO04E6RmrNicIXIpHXtpUgpQ +jM2J/3ytbMgQjePtBy6SmpP4Bf1rpd5U+nphTEXGzddPICZMz8MSZ+kzqkXhWjQb +vlAK7WL3pOqwFvN2i6zOWfvmwDGj/gc14DeV7qdbNyx6Pt/HfuGpI6RhJ+olXhcE +yjeQRJtoS6MGstMczs1go7E59ItAanFK8lo2Zwm3KmGBLzr3stgl/pgeilwe+UI6 +7RO4TrhZWnfUVxxpaD31e2ktI4UTzeS91kcVwcOBkszic9+K7h+P1dCWG07MbK53 +qpQqhQWU+Xb2XH3kITguNj/rgvhUHxOM6qs2/vXxuUaB3eVcR6vFT3KzxIMq7mZQ +7J6DNfmSI7OmUGV7T2D86P5M9qcbFkGOVTo/AYLShL3FchhHpP/FQ6fhEToe2Jit +gcdM9UD64TdR1GNGyzPyAZQ7T9xPoRNn1YDJG4gq28rV9lpzJ9GJvbq4PLaHpoXi +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 ++scABmqsDbG/LNk5I3vhoUe1b8SfYoXn +-----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/sphincs/bench_sphincs_fast_level1_key.der b/certs/sphincs/bench_sphincs_fast_level1_key.der deleted file mode 100644 index 2b343d4fdd..0000000000 Binary files a/certs/sphincs/bench_sphincs_fast_level1_key.der and /dev/null differ 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 cd691372ba..0000000000 Binary files a/certs/sphincs/bench_sphincs_fast_level3_key.der and /dev/null differ 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 19f4f4da07..0000000000 Binary files a/certs/sphincs/bench_sphincs_fast_level5_key.der and /dev/null differ 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 5133d7bca7..0000000000 Binary files a/certs/sphincs/bench_sphincs_small_level1_key.der and /dev/null differ 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 691d52e5e3..0000000000 Binary files a/certs/sphincs/bench_sphincs_small_level3_key.der and /dev/null differ 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 c90cdf68b3..0000000000 Binary files a/certs/sphincs/bench_sphincs_small_level5_key.der and /dev/null differ 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 1a5442ddfd..a485ebc5e9 100644 --- a/cmake/functions.cmake +++ b/cmake/functions.cmake @@ -213,11 +213,8 @@ 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_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) @@ -348,6 +345,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() @@ -1029,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) @@ -1070,10 +1066,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) @@ -1209,6 +1201,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/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 69f8501f04..786514eea3 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" @@ -1288,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 @@ -1638,6 +1649,30 @@ 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_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)])], @@ -1651,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 @@ -1706,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: @@ -1828,41 +1880,7 @@ 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], [AS_HELP_STRING([--enable-xmss],[Enable stateful XMSS/XMSS^MT signatures (default: disabled)])], [ ENABLED_XMSS=$enableval ], @@ -1888,73 +1906,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=""] -) - -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], [AS_HELP_STRING([--enable-lms],[Enable stateful LMS/HSS signatures (default: disabled)])], [ ENABLED_LMS=$enableval ], @@ -1980,93 +1932,15 @@ 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;; 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" - ] -) - -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 +1995,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 +4422,16 @@ 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 + fi +fi + # SHAKE256 AC_ARG_ENABLE([shake256], [AS_HELP_STRING([--enable-shake256],[Enable wolfSSL SHAKE256 support (default: disabled)])], @@ -4564,6 +4439,16 @@ 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 + fi +fi + # SHA512 AC_ARG_ENABLE([sha512], [AS_HELP_STRING([--enable-sha512],[Enable wolfSSL SHA-512 support (default: enabled)])], @@ -4589,6 +4474,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], @@ -4928,8 +4832,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 @@ -6132,12 +6035,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,7 +6156,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 + # 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 "$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 "$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"], + [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 not in-boundary in FIPS v6. AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NOSHA512_224 -DWOLFSSL_NOSHA512_256" # Shake128 because we're testing SHAKE256 @@ -6447,6 +6591,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"]) @@ -6457,7 +6609,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" @@ -6577,11 +6729,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"]) @@ -6819,18 +6966,15 @@ 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 -ENABLED_WC_MLKEM=no ENABLED_ML_KEM=unset ENABLED_MLKEM_MAKE_KEY=no ENABLED_MLKEM_ENCAPSULATE=no @@ -6897,99 +7041,10 @@ 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"], + [ENABLED_SHA512_DRBG=no]) AS_IF([test "x$ENABLED_AESXTS" = "xyes"], [AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_AES_XTS -DWOLFSSL_AES_DIRECT"]) @@ -7096,6 +7151,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" +then + ENABLED_SHA3=yes + ENABLED_SHAKE128=yes + ENABLED_SHAKE256=yes +fi +if test "$ENABLED_DILITHIUM" != "no" +then + ENABLED_SHA3=yes + ENABLED_SHAKE128=yes + ENABLED_SHAKE256=yes +fi + # Set SHA-3 flags if test "$ENABLED_SHA3" != "no" then @@ -7134,6 +7204,291 @@ 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" + AM_CCASFLAGS="$AM_CCASFLAGS -DWOLFSSL_HAVE_MLKEM" + + 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 + + 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], + [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 + # 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], + [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" + AM_CCASFLAGS="$AM_CCASFLAGS -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 + + test "$enable_sha3" = "" && enable_sha3=yes + test "$enable_shake128" = "" && enable_shake128=yes + test "$enable_shake256" = "" && enable_shake256=yes + + 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" +fi + +# LMS CFLAG processing (after FIPS section for sandwich pattern) +if test "$ENABLED_LMS" != "no" +then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_LMS" +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 @@ -7222,27 +7577,87 @@ then AM_CFLAGS="$AM_CFLAGS -DHAVE_ASCON" fi -# Hash DRBG +# 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 (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 "$ENABLED_HASHDRBG" != "yes" && test "$ENABLED_FIPS" = "yes" && + test "$FIPS_VERSION" != "dev" && test "$ENABLED_KCAPI" = "no" +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 @@ -7709,18 +8124,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 @@ -10422,9 +10837,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 (note: each index reserves one pointer per object, so large values increase memory use)]) ;; esac @@ -10834,6 +11250,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.])]) @@ -11571,10 +11992,10 @@ 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_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"]) @@ -11599,6 +12020,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"]) @@ -11610,6 +12033,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"]) @@ -11620,8 +12044,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"]) @@ -12088,6 +12510,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" @@ -12121,15 +12545,9 @@ 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" echo " * DILITHIUM: $ENABLED_DILITHIUM" echo " * ECCSI $ENABLED_ECCSI" echo " * SAKKE $ENABLED_SAKKE" @@ -12187,9 +12605,8 @@ 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 " * Falcon (via liboqs): $ENABLED_FALCON" echo " * Whitewood netRandom: $ENABLED_WNR" echo " * Server Name Indication: $ENABLED_SNI" echo " * ALPN: $ENABLED_ALPN" @@ -12276,6 +12693,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/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/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/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/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/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/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..5a7d7aaac0 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 */ @@ -105,7 +104,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 +120,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_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..363a8d8099 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 */ @@ -131,7 +130,6 @@ extern "C" { #if 1 /* LMS */ #define WOLFSSL_HAVE_LMS - #define WOLFSSL_WC_LMS #ifndef LMS_LEVELS #define LMS_LEVELS 1 #endif @@ -145,7 +143,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/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..9b0f746784 100755 --- a/gencertbuf.pl +++ b/gencertbuf.pl @@ -147,23 +147,12 @@ 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 -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/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 diff --git a/linuxkm/Makefile b/linuxkm/Makefile index b91d4c0b1b..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_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_reloc_tab_length = (unsigned int)(sizeof wc_linuxkm_pie_reloc_tab / sizeof wc_linuxkm_pie_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 57a2f02be0..1018d30c15 100755 --- a/linuxkm/linuxkm-fips-hash-wrapper.sh +++ b/linuxkm/linuxkm-fips-hash-wrapper.sh @@ -48,15 +48,19 @@ 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["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"; 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["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 fc53a1619f..ff327f0ceb 100644 --- a/linuxkm/linuxkm-fips-hash.c +++ b/linuxkm/linuxkm-fips-hash.c @@ -104,10 +104,14 @@ 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(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), @@ -228,10 +232,14 @@ 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.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) || @@ -267,12 +275,23 @@ 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); + } + + 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); @@ -291,10 +310,15 @@ 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.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; diff --git a/linuxkm/linuxkm_memory.c b/linuxkm/linuxkm_memory.c index 3448cc6de8..27814207e6 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->reloc_tab_start; - const word32 reloc_tab_len = *(const word32 *)seg_map->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 */ @@ -553,16 +585,28 @@ 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; + } + 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->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; + } + 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; @@ -575,8 +619,10 @@ 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->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) || @@ -594,8 +640,10 @@ 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->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) || @@ -614,10 +662,14 @@ 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->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) || @@ -631,15 +683,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 +701,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 +719,64 @@ 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; + } + } + + 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; @@ -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,61 @@ 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, + (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); + + if (ret) + goto out; } - 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); @@ -801,6 +950,8 @@ int wc_fips_generate_hash( 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/linuxkm_memory.h b/linuxkm/linuxkm_memory.h index 695a82aafa..76e681da80 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, \ @@ -167,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 { @@ -200,14 +208,18 @@ struct wc_reloc_counts { #if defined(WC_SYM_RELOC_TABLES) || defined(WC_SYM_RELOC_TABLES_SUPPORT) -#ifndef WOLFSSL_TEXT_SEGMENT_CANONICALIZER_BUFSIZ - #define WOLFSSL_TEXT_SEGMENT_CANONICALIZER_BUFSIZ 8192 +#ifndef WOLFSSL_SEGMENT_CANONICALIZER_BUFSIZ + #define WOLFSSL_SEGMENT_CANONICALIZER_BUFSIZ 8192 #endif -WOLFSSL_API ssize_t wc_reloc_normalize_text( - const byte *text_in, - size_t text_in_len, - byte *text_out, +#ifndef WOLFSSL_TEXT_SEGMENT_CANONICALIZER_BUFSIZ + #define WOLFSSL_TEXT_SEGMENT_CANONICALIZER_BUFSIZ WOLFSSL_SEGMENT_CANONICALIZER_BUFSIZ +#endif + +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/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_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; } 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 4edf50a06f..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; } @@ -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); @@ -1598,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. @@ -1656,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; } @@ -1669,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; } @@ -1702,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; } @@ -1729,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; } @@ -1765,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; } @@ -1779,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; } @@ -1848,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); } } @@ -1878,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; } @@ -1887,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; } @@ -1923,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; } @@ -1932,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; } } @@ -1942,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; @@ -1954,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) && \ @@ -1974,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 @@ -1987,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); @@ -2027,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; } } @@ -2059,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; } @@ -2082,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"); @@ -2115,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 */ @@ -2124,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; } } @@ -2133,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; } @@ -2150,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_exports.c.template b/linuxkm/module_exports.c.template index ad2f07cac9..f37eea1e49 100644 --- a/linuxkm/module_exports.c.template +++ b/linuxkm/module_exports.c.template @@ -152,27 +152,14 @@ #endif #ifdef WOLFSSL_HAVE_MLKEM - #include -#ifdef WOLFSSL_WC_MLKEM #include #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/linuxkm/module_hooks.c b/linuxkm/module_hooks.c index 90fc3123b2..1cbde5a6ee 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. @@ -711,28 +711,32 @@ 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); - ssize_t cur_reloc_index = -1; + u8 *canon_buf = malloc(WOLFSSL_SEGMENT_CANONICALIZER_BUFSIZ); + 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; + 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; } 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)); 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 +744,33 @@ 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. */ + 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)); + 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; @@ -751,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", @@ -1090,7 +1118,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(); @@ -1118,17 +1146,23 @@ 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; +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, .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, + .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 +1195,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 +1209,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 +1283,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 @@ -1717,7 +1775,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; } @@ -1790,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) { - pr_err_once("ERROR: register_kprobe(&kallsyms_lookup_name_kp) failed: %d", ret); +#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) { - pr_err_once("ERROR: kallsyms_lookup_name_kp.addr is null."); +#ifdef WOLFSSL_LINUXKM_VERBOSE_DEBUG + pr_err_once("ERROR: kallsyms_lookup_name_kp.addr is null.\n"); +#endif return 0; } } @@ -1825,7 +1887,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(); @@ -1836,7 +1898,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; } @@ -1855,7 +1917,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; } diff --git a/rpm/spec.in b/rpm/spec.in index a2ed090c71..3d74515ac0 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 @@ -76,6 +77,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.* @@ -92,6 +94,7 @@ fi %{_includedir}/wolfssl/openssl/*.h %{_libdir}/pkgconfig/wolfssl.pc %{_libdir}/libwolfssl@LIBSUFFIX@.so +%{_libdir}/cmake/wolfssl %changelog * Mon Oct 17 2022 Juliusz Sosinowicz @@ -100,8 +103,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 8c5200d2d3..b67fa26036 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,20 +294,26 @@ 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 ); 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 }, @@ -326,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); @@ -1122,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 }, ); @@ -1149,6 +1176,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 +1189,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/scripts/openssl.test b/scripts/openssl.test index 2bd049ae13..26ed1546e9 100755 --- a/scripts/openssl.test +++ b/scripts/openssl.test @@ -270,9 +270,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/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/src/crl.c b/src/crl.c index 630a678ccd..3adc15889f 100644 --- a/src/crl.c +++ b/src/crl.c @@ -1678,6 +1678,7 @@ static int SwapLists(WOLFSSL_CRL* crl) #include #include #include +#include #ifdef __MACH__ #define XEVENT_MODE O_EVTONLY @@ -1686,6 +1687,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 @@ -1729,6 +1731,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); @@ -1743,7 +1746,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); @@ -1753,7 +1756,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) @@ -1820,7 +1823,8 @@ static THREAD_RETURN WOLFSSL_THREAD DoMonitor(void* arg) #include #include #include - +#include +#include #ifndef max static WC_INLINE int max(int a, int b) @@ -1855,14 +1859,32 @@ static THREAD_RETURN WOLFSSL_THREAD DoMonitor(void* arg) WOLFSSL_ENTER("DoMonitor"); +#ifdef EFD_CLOEXEC + crl->mfd = eventfd(0, EFD_CLOEXEC); /* our custom shutdown event */ + 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"); 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/include.am b/src/include.am index c4f6b8a673..dd2527f084 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 @@ -1372,6 +1755,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 @@ -1397,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 @@ -1447,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 @@ -1587,20 +1978,9 @@ 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 -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/src/internal.c b/src/internal.c index 2ba6cabc15..6dc0cbe2d1 100644 --- a/src/internal.c +++ b/src/internal.c @@ -8976,6 +8976,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) { @@ -9339,6 +9344,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); @@ -10602,7 +10611,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 */ @@ -13947,9 +13957,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); } @@ -19779,8 +19810,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) { @@ -20673,9 +20704,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 @@ -20762,8 +20794,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); @@ -21907,6 +21940,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 */ @@ -25967,6 +26017,10 @@ int SendCertificateStatus(WOLFSSL* ssl) if (idx > chain->length) break; + if ((i + 1) >= (1 + MAX_CHAIN_DEPTH)) { + ret = MAX_CERT_EXTENSIONS_ERR; + break; + } ret = CreateOcspRequest(ssl, request, cert, der.buffer, der.length, &ctxOwnsRequest); if (ret == 0) { @@ -25995,6 +26049,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); @@ -27616,6 +27675,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"; @@ -28837,6 +28899,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 */ } @@ -30759,9 +30822,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/keys.c b/src/keys.c index 7f70a733c1..74b094fc59 100644 --- a/src/keys.c +++ b/src/keys.c @@ -3592,6 +3592,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/src/pk.c b/src/pk.c index 1aaf40d065..e4cfe897d9 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; } @@ -2104,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; } @@ -2116,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; } @@ -2131,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; @@ -2141,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); @@ -5501,6 +5511,60 @@ 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"); + +#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) { + 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; + } +#endif + + 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) { + WOLFSSL_ENTER("wolfSSL_ED25519_free"); + #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 */ + /******************************************************************************* * END OF ED25519 API ******************************************************************************/ @@ -5954,6 +6018,61 @@ 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"); + +#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"); + } + 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; + } +#endif + + 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) { + WOLFSSL_ENTER("wolfSSL_ED448_free"); + #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 */ + /******************************************************************************* * END OF ED448 API ******************************************************************************/ @@ -6262,6 +6381,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 +6538,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; @@ -7107,6 +7246,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. */ @@ -7139,9 +7279,11 @@ 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 { @@ -7198,6 +7340,20 @@ static int pem_write_mem_pkcs8privatekey(byte** pem, int* pemSz, } } + /* 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. */ return (res == 0) ? 0 : ret; diff --git a/src/pk_ec.c b/src/pk_ec.c index 66647c9eb7..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; } @@ -4095,6 +4098,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; } diff --git a/src/pk_rsa.c b/src/pk_rsa.c index c102f4ec21..682b1d2808 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; } @@ -779,6 +782,7 @@ static int wolfSSL_RSA_To_Der_ex(WOLFSSL_RSA* rsa, byte** outBuf, int publicKey, { int ret = 1; int derSz = 0; + word32 derAllocSz = 0; byte* derBuf = NULL; WOLFSSL_ENTER("wolfSSL_RSA_To_Der"); @@ -830,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)) { @@ -863,6 +870,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) && (derAllocSz > 0)) { + ForceZero(derBuf, derAllocSz); + } XFREE(derBuf, heap, DYNAMIC_TYPE_TMP_BUFFER); } WOLFSSL_LEAVE("wolfSSL_RSA_To_Der", ret); diff --git a/src/sniffer.c b/src/sniffer.c index e8664721b1..9f63a038c7 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,7 +4231,13 @@ static int ProcessClientHello(const byte* input, int* sslBytes, #ifdef WOLFSSL_TLS13 case EXT_KEY_SHARE: { - word16 ksLen = (word16)((input[0] << 8) | input[1]); + word16 ksLen = 0; + if (extLen < OPAQUE16_LEN) { + SetError(BUFFER_ERROR_STR, error, session, FATAL_ERROR_STATE); + return BUFFER_ERROR; + } + + 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; @@ -4252,6 +4261,11 @@ static int ProcessClientHello(const byte* input, int* sslBytes, word32 ticketAge; const byte *identity, *binders; + 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) { SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); @@ -7242,12 +7256,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; diff --git a/src/ssl.c b/src/ssl.c index f9b82ac4d0..e5ca3ca9c2 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 @@ -3231,26 +3228,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 +3252,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; @@ -10072,6 +10065,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) { @@ -10888,7 +10885,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) { @@ -10935,7 +10932,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"; @@ -10992,37 +10988,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"; @@ -11055,32 +11022,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 */ } } @@ -14571,8 +14512,14 @@ 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)); + 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) { if ((desc = oid_translate_num_to_str(buf))) { @@ -17197,7 +17144,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}, @@ -17224,7 +17171,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, @@ -17525,7 +17472,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); @@ -17579,7 +17526,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. @@ -17774,6 +17721,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; @@ -17792,6 +17747,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; @@ -18150,6 +18113,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; @@ -18172,6 +18143,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; @@ -18692,6 +18671,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 @@ -19648,7 +19628,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/ssl_api_cert.c b/src/ssl_api_cert.c index f54edcd8e4..ed471be105 100644 --- a/src/ssl_api_cert.c +++ b/src/ssl_api_cert.c @@ -1536,6 +1536,17 @@ 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. */ + if (X509StorePushCertsToCM(str) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("wolfSSL_CTX_set_cert_store: failed to push some " + "certs to CertManager"); + } +#endif } } 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/src/ssl_ech.c b/src/ssl_ech.c index eb9b9a6a5a..1f864bc15b 100644 --- a/src/ssl_ech.c +++ b/src/ssl_ech.c @@ -547,8 +547,9 @@ int SetEchConfigsEx(WOLFSSL_EchConfig** outputConfigs, void* heap, ato16(echConfig, &hpkePubkeyLen); echConfig += 2; - /* hpke public_key */ - if (hpkePubkeyLen > HPKE_Npk_MAX || hpkePubkeyLen == 0) { + /* 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/ssl_load.c b/src/ssl_load.c index 5c83e88c5a..2841f22e8e 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)) { @@ -4159,6 +4189,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 +4261,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 +4308,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; } @@ -4280,7 +4320,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; @@ -4561,6 +4601,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 +4673,13 @@ int wolfSSL_use_PrivateKey_Id_ex(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 +4722,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; } @@ -4689,7 +4739,7 @@ int wolfSSL_use_AltPrivateKey_Id(WOLFSSL* ssl, const unsigned char* id, long sz, } } 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) { @@ -5256,6 +5306,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; @@ -5365,6 +5427,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; } @@ -5662,9 +5727,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/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/src/ssl_sess.c b/src/ssl_sess.c index a2d97399f2..ec79057505 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/tls.c b/src/tls.c index e7912b815d..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) @@ -2816,6 +2810,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; @@ -3627,6 +3624,14 @@ int ProcessChainOCSPRequest(WOLFSSL* ssl) if (chain && chain->buffer) { while (ret == 0 && pos + OPAQUE24_LEN < chain->length) { + if (i >= MAX_CERT_EXTENSIONS) { + 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; + break; + } + c24to32(chain->buffer + pos, &der.length); pos += OPAQUE24_LEN; der.buffer = chain->buffer + pos; @@ -4567,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. @@ -4688,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: @@ -4739,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: @@ -4806,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: @@ -6493,7 +6410,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), @@ -6514,7 +6431,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); @@ -8620,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. */ @@ -8881,7 +8797,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 @@ -9964,7 +9882,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 @@ -9973,8 +9893,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; @@ -11358,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) @@ -13800,7 +13717,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; @@ -14195,6 +14112,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 */ @@ -14259,7 +14179,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; } @@ -14373,6 +14293,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) { @@ -14489,7 +14410,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. */ @@ -14863,9 +14785,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; @@ -14949,23 +14889,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 @@ -14977,22 +14925,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 @@ -15045,12 +15001,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; } @@ -15061,10 +15031,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; @@ -15077,6 +15057,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; @@ -15180,7 +15164,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 */ @@ -15188,20 +15174,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 @@ -15215,28 +15207,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 @@ -15292,16 +15292,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. */ @@ -15310,9 +15320,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 made no progress"); + 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 + offset > WOLFSSL_MAX_16BIT) { + WOLFSSL_MSG("TLSX_Write total extensions length exceeds word16"); + return BUFFER_E; + } + *pOffset += (word16)offset; + } return ret; } @@ -15870,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; @@ -15887,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 { @@ -16416,6 +16426,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. */ @@ -16619,6 +16636,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 */ @@ -17206,6 +17229,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 116c0cab82..65378db744 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 >= sizeof(ssl->encrypt.sanityCheck)) { 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 >= 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; @@ -3277,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) { @@ -3805,6 +3811,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; } @@ -3815,6 +3822,7 @@ int EchConfigGetSupportedCipherSuite(WOLFSSL_EchConfig* config) } } + WOLFSSL_MSG("ECH config: KDF or AEAD not supported"); return WOLFSSL_FATAL_ERROR; } @@ -3937,10 +3945,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 */ @@ -3980,6 +3992,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 */ @@ -4765,15 +4780,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 = (word16)(args->length + - args->ech->paddingLen + args->ech->hpke->Nt); + 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; } @@ -4915,8 +4933,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, @@ -4939,8 +4959,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); @@ -4949,10 +4971,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 @@ -5707,6 +5729,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 = @@ -8426,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 @@ -8556,7 +8582,10 @@ static WC_INLINE int DecodeTls13SigAlg(byte* input, byte* hashAlgo, break; #endif case NEW_SA_MAJOR: - *hashAlgo = 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 && @@ -8815,6 +8844,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; @@ -9049,7 +9080,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) @@ -9064,6 +9095,9 @@ static int WriteCSRToBuffer(WOLFSSL* ssl, DerBuffer** certExts, word32 extIdx; DerBuffer* der; + if (extSz_num > MAX_CERT_EXTENSIONS) + return MAX_CERT_EXTENSIONS_ERR; + ext = TLSX_Find(ssl->extensions, TLSX_STATUS_REQUEST); csr = ext ? (CertificateStatusRequest*)ext->data : NULL; @@ -9315,8 +9349,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 ((1 + ssl->buffers.certChainCnt) > MAX_CERT_EXTENSIONS) + 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); if (ret < 0) return ret; totalextSz += ret; diff --git a/src/wolfio.c b/src/wolfio.c index c6ffe7da11..fbea87f71d 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 (int)wc_accept_cloexec((int)sockfd, peer_addr, peer_len); } #endif /* HAVE_SOCKADDR */ @@ -3286,7 +3287,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 < 0 || sz > (int)WOLFSSL_MAX_16BIT) { + 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/src/x509.c b/src/x509.c index 8541f999e9..ae044624bc 100644 --- a/src/x509.c +++ b/src/x509.c @@ -3279,8 +3279,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; } @@ -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/src/x509_str.c b/src/x509_str.c index 294a5a2eb2..02a12c7032 100644 --- a/src/x509_str.c +++ b/src/x509_str.c @@ -1690,6 +1690,72 @@ 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; + } + + if (anyFail) { + return WOLFSSL_FATAL_ERROR; + } + return 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.c b/tests/api.c index ae3585568b..b3193c5ad0 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) @@ -10277,6 +10276,43 @@ 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); + long support; + + ExpectNotNull(ctx); + ExpectNotNull(ssl); + + ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_UseSecureRenegotiation(ssl)); + ExpectNotNull(ssl->secure_renegotiation); + if (EXPECT_SUCCESS()) { + if (ssl->secure_renegotiation != NULL) + ssl->secure_renegotiation->enabled = 1; + } + + 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); + } + + 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) { @@ -10545,6 +10581,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 @@ -11451,6 +11625,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() */ @@ -21620,6 +21878,335 @@ 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); + + /* 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); + wc_ecc_free(&rootKey); + wc_FreeRng(&rng); +#endif + 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; +#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; @@ -27739,8 +28326,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 }, @@ -35037,11 +35622,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" @@ -35094,7 +35677,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. @@ -35103,8 +35686,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"; @@ -35153,8 +35735,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; @@ -35325,7 +35906,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; @@ -35539,11 +36120,711 @@ 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(); +} + +/* 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) { 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; @@ -35807,11 +37088,15 @@ 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_PathLenSelfIssuedAllowed), + TEST_DECL(test_PathLenNoKeyUsage), TEST_DECL(test_MakeCertWith0Ser), TEST_DECL(test_MakeCertWithCaFalse), #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), @@ -36304,9 +37589,11 @@ 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), + 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) @@ -36477,6 +37764,13 @@ 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_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_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) 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/tests/api/test_evp_pkey.c b/tests/api/test_evp_pkey.c index adf381dcad..d1b7b28cc9 100644 --- a/tests/api/test_evp_pkey.c +++ b/tests/api/test_evp_pkey.c @@ -2429,3 +2429,145 @@ 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; + + /* 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] = { + 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, + 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() + * 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 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; + + { + 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; + + /* 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] = { + 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, + 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. */ + 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; + + /* 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; +#endif + return EXPECT_RESULT(); +} + diff --git a/tests/api/test_evp_pkey.h b/tests/api/test_evp_pkey.h index 7062e922a2..cd6d6fba09 100644 --- a/tests/api/test_evp_pkey.h +++ b/tests/api/test_evp_pkey.h @@ -61,6 +61,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), \ @@ -100,6 +103,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/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..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) || \ @@ -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) @@ -694,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) @@ -767,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; @@ -808,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; @@ -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); @@ -971,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; @@ -1203,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; @@ -1303,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; @@ -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); @@ -1426,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 @@ -2929,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; @@ -2973,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 @@ -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); @@ -3183,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 @@ -7651,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 @@ -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 @@ -12465,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; @@ -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,9 +16715,10 @@ 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 */ +#endif /* HAVE_DILITHIUM && !WOLFSSL_DILITHIUM_NO_SIGN */ return EXPECT_RESULT(); } @@ -16704,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; @@ -20242,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(); } @@ -20250,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; @@ -24522,8 +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_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_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(HAVE_DILITHIUM) && \ !defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) && \ !defined(WOLFSSL_DILITHIUM_NO_ASN1) && defined(WOLFSSL_ASN_TEMPLATE) static struct { @@ -24591,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) @@ -24609,6 +29715,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 +29783,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(); @@ -24684,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) && \ @@ -24872,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)) @@ -24984,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_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..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 @@ -1451,6 +1448,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 +1487,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(); @@ -1496,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 @@ -2470,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 @@ -3845,6 +3846,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 +3870,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(); @@ -3881,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) @@ -3937,8 +3942,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); @@ -3956,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) @@ -3993,22 +4000,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_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/tests/api/test_ossl_bn.c b/tests/api/test_ossl_bn.c index 3d9db919f2..c4872120f2 100644 --- a/tests/api/test_ossl_bn.c +++ b/tests/api/test_ossl_bn.c @@ -323,6 +323,42 @@ 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); + /* 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)); ExpectNotNull(BN_hex2bn(&b, str)); ExpectIntEQ(BN_cmp(a, b), 0); 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/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. */ diff --git a/tests/api/test_ossl_x509_str.c b/tests/api/test_ossl_x509_str.c index b0756f8bbb..aab2515372 100644 --- a/tests/api/test_ossl_x509_str.c +++ b/tests/api/test_ossl_x509_str.c @@ -1974,3 +1974,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) && !defined(NO_TLS) + 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/tests/api/test_pkcs7.c b/tests/api/test_pkcs7.c index 3c8b59fb8e..6d033b15d0 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() */ @@ -2397,7 +2620,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 +2654,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; @@ -2486,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 */ @@ -2501,6 +2792,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) { @@ -2520,12 +2813,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; @@ -2551,7 +2845,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, @@ -2560,9 +2861,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; } @@ -2579,7 +2886,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 @@ -2761,6 +3068,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, @@ -2784,7 +3096,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 +3262,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 +4297,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 +4489,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 +4504,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 +4549,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) { @@ -4269,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); @@ -4280,7 +4592,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/tests/api/test_pkcs7.h b/tests/api/test_pkcs7.h index 084744d43c..f4aed161da 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); @@ -57,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); @@ -82,6 +91,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 +121,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), \ @@ -108,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/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/tests/api/test_slhdsa.c b/tests/api/test_slhdsa.c index fc40bed9c7..646123f472 100644 --- a/tests/api/test_slhdsa.c +++ b/tests/api/test_slhdsa.c @@ -32,10 +32,93 @@ #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. */ @@ -43,46 +126,102 @@ int test_wc_slhdsa(void) { EXPECT_DECLS; #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 */ return EXPECT_RESULT(); @@ -95,7 +234,10 @@ int test_wc_slhdsa_sizes(void) { EXPECT_DECLS; #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,6 +367,128 @@ int test_wc_slhdsa_sizes(void) WC_SLHDSA_SHAKE256F_SIG_LEN); #endif +#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/api/test_tls13.c b/tests/api/test_tls13.c index 88af4ad05d..ba12b7e368 100644 --- a/tests/api/test_tls13.c +++ b/tests/api/test_tls13.c @@ -3726,6 +3726,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; @@ -4481,6 +4583,177 @@ 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 = 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 + * (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; + 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); + + 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)); + } + + /* 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. */ + 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. */ + 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; + 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); + + 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); + } + + if (EXPECT_SUCCESS()) { + int emptyBefore = WOLFSSL_MAX_EMPTY_RECORDS - 1; + int emptyAfter = WOLFSSL_MAX_EMPTY_RECORDS - 1; + int dataRecSz = 0; + byte dataRec[128]; + byte payload[1] = { 'a' }; + int totalSz = 0; + + 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); + } + + /* 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); + } + + 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. */ + 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); + 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 2047f153a0..c8b42fc56c 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); int test_tls13_early_data_0rtt_replay(void); int test_tls13_corrupted_finished(void); @@ -72,6 +74,7 @@ int test_tls13_cert_with_extern_psk_sh_confirms_resumption(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), \ @@ -79,6 +82,7 @@ int test_tls13_cert_with_extern_psk_sh_confirms_resumption(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_early_data_0rtt_replay), \ TEST_DECL_GROUP("tls13", test_tls13_unknown_ext_rejected), \ 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 dabc1f2756..3192e5070c 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])); @@ -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 5d8e8efb89..8f421542fd 100644 --- a/wolfcrypt/benchmark/benchmark.c +++ b/wolfcrypt/benchmark/benchmark.c @@ -169,29 +169,13 @@ #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 - #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 @@ -209,9 +193,6 @@ #if defined(HAVE_DILITHIUM) #include #endif -#if defined(HAVE_SPHINCS) - #include -#endif #ifdef WOLF_CRYPTO_CB #include @@ -945,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 @@ -976,16 +950,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)) @@ -1026,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. */ @@ -1293,6 +1286,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 +1345,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} @@ -1349,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 { @@ -1388,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 @@ -1574,16 +1569,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)); @@ -2058,12 +2067,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 +2081,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 +3205,108 @@ 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; + +#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 */ +#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 +3944,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 +4512,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; @@ -4586,19 +4727,15 @@ 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); + +#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: @@ -4625,7 +4762,6 @@ exit: (void)bench_asym_algs; (void)bench_other_algs; (void)bench_pq_asym_algs; - (void)bench_pq_asym_algs2; return NULL; } @@ -4733,6 +4869,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 +5096,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 +5119,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 +5154,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 +11208,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 +11226,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 +11719,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 +11749,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: @@ -11419,10 +11836,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); @@ -11443,9 +11858,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 @@ -11564,7 +11976,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); @@ -11573,8 +11985,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); @@ -11586,7 +11997,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); @@ -11594,17 +12005,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 @@ -11612,7 +12022,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); @@ -11621,8 +12031,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); @@ -11634,7 +12043,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); @@ -11642,17 +12051,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 @@ -11733,13 +12141,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) { @@ -12172,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; @@ -12201,15 +12602,26 @@ 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; - XMEMCPY(name, "SLH-DSA-S", 10); - if ((param & 1) == 1) { - name[8] = 'F'; + if (SLHDSA_IS_SHA2((enum SlhDsaParam)param)) { + XMEMCPY(name, "SLH-DSA-SHA2-S", 15); + if ((param & 1) == 1) { + name[13] = 'F'; + } + } + else { + /* 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[14] = 'F'; + } } bench_stats_start(&count, &start); @@ -12227,6 +12639,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 +12655,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); @@ -12250,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; } @@ -12274,6 +12688,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) @@ -14387,19 +14873,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); } } @@ -15663,6 +16150,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 +16169,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; @@ -15825,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) @@ -16627,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++) @@ -16932,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)) { @@ -16941,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 dc97fe6837..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); @@ -130,13 +128,19 @@ 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); 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/aes.c b/wolfcrypt/src/aes.c index 02a6e1d424..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__) @@ -10062,8 +10068,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; @@ -16849,6 +16858,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, @@ -17140,7 +17154,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 +17212,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 > WC_AES_BLOCK_SIZE + || authInSz < WOLFSSL_MIN_AUTH_TAG_SZ) { return BAD_FUNC_ARG; } 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/asn.c b/wolfcrypt/src/asn.c index 088eb47ea5..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 @@ -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 */ @@ -4571,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 @@ -4604,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 @@ -4659,11 +4666,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 @@ -4692,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 @@ -5339,6 +5589,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; @@ -5547,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; } @@ -5672,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; } @@ -7244,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 @@ -7257,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; @@ -7288,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. */ @@ -8577,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; @@ -9109,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; } @@ -9609,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) { @@ -12148,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. @@ -12447,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 @@ -13052,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; @@ -15541,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 ); } @@ -15882,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) */ @@ -16078,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 @@ -16259,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 } @@ -16728,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; @@ -17086,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) */ @@ -17296,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) */ @@ -18996,6 +19193,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. @@ -20218,6 +20448,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; @@ -22491,16 +22729,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"); @@ -22510,7 +22756,43 @@ 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->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"); + 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); } } @@ -23244,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-----"); @@ -23426,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; @@ -25188,6 +25517,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 */ @@ -25218,6 +25550,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 */ @@ -26298,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; @@ -26310,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 @@ -26372,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; @@ -26448,6 +26791,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 }, @@ -26506,6 +26855,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, @@ -26561,6 +26915,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 }; @@ -26816,6 +27174,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 @@ -27126,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; @@ -27158,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; @@ -27171,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; @@ -27256,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; @@ -27412,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); @@ -27425,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); @@ -27485,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; } @@ -27559,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) { @@ -27746,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. */ @@ -27790,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; @@ -27820,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 */ @@ -27912,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; @@ -27924,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); @@ -27984,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; } @@ -28032,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) { @@ -28152,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)) { @@ -28185,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; @@ -28215,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 @@ -28384,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; @@ -28430,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 @@ -28480,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; @@ -28523,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; @@ -28568,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 @@ -28627,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; @@ -28655,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, @@ -28825,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; @@ -28833,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; @@ -28878,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 @@ -28922,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; @@ -28950,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); } @@ -28983,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; @@ -29011,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); } @@ -29251,6 +29562,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 @@ -30968,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, @@ -31328,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 d6568aa5d1..3abc341798 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) @@ -5956,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; @@ -5966,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; } @@ -6072,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; @@ -6340,6 +6374,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 +6486,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 + @@ -6519,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); @@ -6571,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; @@ -6598,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; @@ -6774,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; @@ -6783,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; } @@ -6897,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 @@ -7157,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); @@ -7206,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; @@ -7233,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/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/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/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..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 @@ -138,16 +136,17 @@ #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 #if defined(HAVE_DILITHIUM) -#ifdef HAVE_LIBOQS -#include -#endif - #include #include #include @@ -172,8 +171,6 @@ #endif #endif -#ifdef WOLFSSL_WC_DILITHIUM - #if defined(USE_INTEL_SPEEDUP) static cpuid_flags_t cpuid_flags = WC_CPUID_INITIALIZER; #endif @@ -814,6 +811,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 +9526,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 +9985,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 +10029,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,189 +10091,13 @@ 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; } #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) { @@ -10295,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; @@ -10304,12 +10133,47 @@ 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 + /* 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; } @@ -10323,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; @@ -10332,12 +10195,11 @@ 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 + * function and has the RNG parameter needed for signing. */ + return ret; } #endif @@ -10392,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; @@ -10446,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; @@ -10505,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; @@ -10551,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; @@ -10591,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; @@ -10627,7 +10461,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)) { @@ -10636,16 +10471,51 @@ 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; +} + +/* 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) +{ + 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; @@ -10703,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; @@ -10757,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; @@ -10816,16 +10678,43 @@ 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; +} + +/* 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) +{ + 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; @@ -10923,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 @@ -11017,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); } @@ -11042,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) { @@ -11109,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 @@ -11127,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); @@ -11378,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; @@ -11504,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 */ @@ -12274,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); } @@ -12509,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/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; diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 573a690140..684a7d4c0d 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(); @@ -11226,7 +11232,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 diff --git a/wolfcrypt/src/ed448.c b/wolfcrypt/src/ed448.c index 6ded8265e1..a3f931f5c5 100644 --- a/wolfcrypt/src/ed448.c +++ b/wolfcrypt/src/ed448.c @@ -1001,6 +1001,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/wolfcrypt/src/error.c b/wolfcrypt/src/error.c index 4e02795e89..8826d9b198 100644 --- a/wolfcrypt/src/error.c +++ b/wolfcrypt/src/error.c @@ -668,9 +668,51 @@ 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"; + 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/evp.c b/wolfcrypt/src/evp.c index 40bca5578f..8ea053427f 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; @@ -5809,8 +5815,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 +5825,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 +10773,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 +10882,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 +11040,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 +11051,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 +11202,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 +11212,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 @@ -11734,6 +11750,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 7767cb92f4..719548ffe4 100644 --- a/wolfcrypt/src/evp_pk.c +++ b/wolfcrypt/src/evp_pk.c @@ -231,6 +231,316 @@ 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 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) +{ + ed25519_key* edKey = NULL; + word32 keyIdx = 0; + int isEdKey; + int ret = 1; + void* heap = NULL; + + if (*out != NULL) { + heap = (*out)->heap; + } + + edKey = wolfSSL_ED25519_new(heap, INVALID_DEVID); + if (edKey == NULL) { + return 0; + } + + /* 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); + } + else { + isEdKey = (wc_Ed25519PublicKeyDecode(mem, &keyIdx, edKey, + (word32)memSz) == 0); + } + + if (!isEdKey) { + wolfSSL_ED25519_free(edKey); + return WOLFSSL_FATAL_ERROR; + } + + /* 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); + } + if (ret == 1) { + (*out)->ownEd25519 = 1; + (*out)->ed25519 = edKey; + } + else { + wolfSSL_ED25519_free(edKey); + } + + 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 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) +{ + ed448_key* edKey = NULL; + word32 keyIdx = 0; + int isEdKey; + int ret = 1; + void* heap = NULL; + + if (*out != NULL) { + heap = (*out)->heap; + } + + edKey = wolfSSL_ED448_new(heap, INVALID_DEVID); + if (edKey == NULL) { + return 0; + } + + /* 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); + } + else { + isEdKey = (wc_Ed448PublicKeyDecode(mem, &keyIdx, edKey, + (word32)memSz) == 0); + } + + if (!isEdKey) { + wolfSSL_ED448_free(edKey); + return WOLFSSL_FATAL_ERROR; + } + + /* 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); + } + if (ret == 1) { + (*out)->ownEd448 = 1; + (*out)->ed448 = edKey; + } + else { + wolfSSL_ED448_free(edKey); + } + + return ret; +} +#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. @@ -389,7 +699,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; @@ -398,13 +708,15 @@ 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) { - ret = 0; + 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; + } } if (ret == 1) { /* DH key has data and is external to DH object. */ @@ -412,7 +724,7 @@ static int d2iTryAltDhKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, if (priv) { elements |= ELEMENT_PRV; } - if (SetDhExternal_ex(dhObj, elements) != WOLFSSL_SUCCESS ) { + if (SetDhExternal_ex(dhObj, elements) != WOLFSSL_SUCCESS) { ret = 0; } } @@ -421,11 +733,11 @@ static int d2iTryAltDhKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, 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; } - if (ret == 0) { + else if (dhObj != NULL) { wolfSSL_DH_free(dhObj); } @@ -448,8 +760,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); } /** @@ -692,6 +1006,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) { ; @@ -923,7 +1249,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; } @@ -1028,6 +1361,26 @@ 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: + /* 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; + } + break; +#endif /* HAVE_ED25519 */ +#ifdef HAVE_ED448 + case WC_EVP_PKEY_ED448: + /* See WC_EVP_PKEY_ED25519 case above. */ + if (d2iTryEd448Key(&local, p, local->pkey_sz, priv) != 1) { + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + break; +#endif /* HAVE_ED448 */ default: WOLFSSL_MSG("Unsupported key type"); wolfSSL_EVP_PKEY_free(local); diff --git a/wolfcrypt/src/ext_lms.c b/wolfcrypt/src/ext_lms.c deleted file mode 100644 index c953abcfb3..0000000000 --- a/wolfcrypt/src/ext_lms.c +++ /dev/null @@ -1,1083 +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"; - 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); - 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_mlkem.c b/wolfcrypt/src/ext_mlkem.c deleted file mode 100644 index 91634f494f..0000000000 --- a/wolfcrypt/src/ext_mlkem.c +++ /dev/null @@ -1,762 +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) -#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/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/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/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; } } 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/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 8e8ad3ff3e..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 @@ -1395,7 +1541,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; } @@ -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/hpke.c b/wolfcrypt/src/hpke.c index 8f16f66f70..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,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; } diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index 36b817ed51..729c17f091 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 @@ -94,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; }; @@ -109,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; @@ -207,10 +222,15 @@ 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); 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; @@ -265,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; @@ -2197,7 +2227,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 +2249,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) || @@ -2253,10 +2280,10 @@ 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); + (int)idx); atrIdx += idx; } else { esd->signedAttribsCount = 0; @@ -4284,6 +4311,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 */ @@ -4363,6 +4478,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"); @@ -4473,6 +4613,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); @@ -4638,6 +4796,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"); @@ -5351,11 +5525,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; @@ -5398,6 +5577,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; + } } } @@ -7043,6 +7228,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; @@ -7735,6 +7923,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))) && \ @@ -7770,6 +7961,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; } @@ -7782,7 +7974,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 +7996,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 +8009,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; } @@ -9620,7 +9814,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); @@ -9761,6 +9955,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; @@ -9772,6 +9967,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; @@ -9796,6 +9992,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; @@ -9827,6 +10024,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; @@ -9852,6 +10050,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; @@ -9889,7 +10088,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); @@ -10594,6 +10793,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, @@ -10610,7 +10884,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 @@ -10769,15 +11045,17 @@ 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 is within buffer */ + if ((word32)length > pkiMsgSz - (*idx)) return BUFFER_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; } - (*idx) += (word32)keyIdSize; + (*idx) += (word32)length; } if (GetAlgoId(pkiMsg, idx, &encOID, oidKeyType, pkiMsgSz) < 0) @@ -10917,8 +11195,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"); @@ -10932,9 +11210,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 } @@ -10949,30 +11227,153 @@ 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); #ifndef WC_NO_RSA_OAEP if (encOID == RSAESOAEPk) { if (outKey) { + ForceZero(outKey, outKeySz); XFREE(outKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); } } @@ -11054,6 +11455,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 +11942,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 +12135,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 +12160,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); @@ -11754,6 +12188,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; @@ -11766,7 +12201,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; } @@ -11775,7 +12212,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; } @@ -11784,7 +12223,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 */ @@ -11818,7 +12259,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 +12285,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 +12300,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,13 +12311,15 @@ 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); + /* 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) { @@ -11876,7 +12328,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 +12357,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 @@ -12658,6 +13114,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; @@ -12813,6 +13285,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; @@ -13032,6 +13509,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; @@ -13047,10 +13532,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) @@ -13242,6 +13735,13 @@ int wc_PKCS7_DecodeEnvelopedData(wc_PKCS7* pkcs7, byte* in, } wc_PKCS7_DecryptContentFree(pkcs7, encOID, pkcs7->heap); } else { + word32 tmpSum; + if (!WC_SAFE_SUM_WORD32(idx, (word32)encryptedContentTotalSz, tmpSum) || + tmpSum > pkiMsgSz) { + ret = BUFFER_E; + break; + } + pkcs7->cachedEncryptedContentSz = (word32)encryptedContentTotalSz; pkcs7->totalEncryptedContentSz = @@ -13326,8 +13826,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); @@ -13340,6 +13845,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) { @@ -13350,6 +13865,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); @@ -14110,6 +14628,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; @@ -14245,6 +14767,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) { @@ -14262,6 +14789,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; @@ -14387,9 +14954,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; @@ -14405,7 +14980,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); @@ -15273,6 +15857,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 @@ -15310,7 +15900,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; } @@ -15323,16 +15914,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); } 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/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/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/caam/wolfcaam_qnx.c b/wolfcrypt/src/port/caam/wolfcaam_qnx.c index 71d5cbfb61..fff951b56d 100644 --- a/wolfcrypt/src/port/caam/wolfcaam_qnx.c +++ b/wolfcrypt/src/port/caam/wolfcaam_qnx.c @@ -33,9 +33,9 @@ #include #include #include - #include + /* for devctl use */ int caamFd = -1; static wolfSSL_Mutex caamMutex; @@ -48,7 +48,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/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/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/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/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/src/random.c b/wolfcrypt/src/random.c index e15c9ce9b1..efc9eaf59a 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 @@ -204,8 +209,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 */ @@ -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,459 @@ 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 +#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) { + 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 + +#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; +} + +/* 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 +1615,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 +1755,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 +1855,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 +2039,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 +2073,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 +2283,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 +2392,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 +2505,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 +2519,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 +2593,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 +2633,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 +2655,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 +2702,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 +2718,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 +2771,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 +3083,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 */ @@ -3843,7 +5392,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 */ @@ -3851,7 +5400,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 */ @@ -3869,7 +5418,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 */ @@ -3877,7 +5426,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 */ @@ -3958,7 +5507,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/rng_bank.c b/wolfcrypt/src/rng_bank.c index 3cea1c7520..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, @@ -52,7 +97,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, @@ -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/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/sha512.c b/wolfcrypt/src/sha512.c index 35fcf08ce2..425ad745c2 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; } @@ -331,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; @@ -386,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; @@ -443,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; @@ -1950,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; @@ -2387,6 +2408,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; } @@ -2530,6 +2554,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; } diff --git a/wolfcrypt/src/sphincs.c b/wolfcrypt/src/sphincs.c deleted file mode 100644 index 587b99375e..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_PQC) && 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_PQC && HAVE_SPHINCS */ 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); diff --git a/wolfcrypt/src/wc_lms.c b/wolfcrypt/src/wc_lms.c index 402b2f3c5a..99a3e19e81 100644 --- a/wolfcrypt/src/wc_lms.c +++ b/wolfcrypt/src/wc_lms.c @@ -21,7 +21,12 @@ #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 */ + #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,191 @@ 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 */ + + /* 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 */ }; /* Number of parameter sets supported. */ #define WC_LMS_MAP_LEN ((int)(sizeof(wc_lms_map) / sizeof(*wc_lms_map))) @@ -483,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. @@ -1159,7 +1397,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. */ @@ -1291,7 +1530,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)); @@ -1358,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 44191dbb33..2759804b36 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 @@ -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; @@ -2165,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); @@ -2304,6 +2559,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 +2581,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 +2592,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 +2604,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 +2615,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 +2631,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 +2672,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 +2687,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 +2708,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 +2723,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 +2772,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 +2782,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 +2809,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 +2892,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 +2920,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 +2931,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 +2977,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); } @@ -2855,6 +3211,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; } @@ -3684,13 +4041,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); @@ -3698,6 +4067,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) { @@ -3709,26 +4079,36 @@ 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; } -#endif /* WOLFSSL_HAVE_LMS && WOLFSSL_WC_LMS */ +#endif /* WOLFSSL_HAVE_LMS */ 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 74c4260a1c..ccdd671256 100644 --- a/wolfcrypt/src/wc_mlkem.c +++ b/wolfcrypt/src/wc_mlkem.c @@ -78,7 +78,11 @@ #undef WOLFSSL_RISCV_ASM #endif -#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 #include #include @@ -116,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); @@ -636,6 +640,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 +916,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 */ @@ -2515,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/src/wc_port.c b/wolfcrypt/src/wc_port.c index ba740423ea..e84c385744 100644 --- a/wolfcrypt/src/wc_port.c +++ b/wolfcrypt/src/wc_port.c @@ -19,6 +19,15 @@ * 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 +#elif defined(__FreeBSD__) + /* for __FreeBSD_version */ + #include +#endif + /* wolfCrypt Porting Build Options: @@ -106,6 +115,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 @@ -215,7 +227,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 @@ -334,6 +346,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 +663,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 @@ -4088,7 +4116,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 +4148,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 @@ -5130,6 +5158,78 @@ char* wolfSSL_strnstr(const char* s1, const char* s2, size_t 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(__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) + 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/wolfcrypt/src/wc_slhdsa.c b/wolfcrypt/src/wc_slhdsa.c index 65926a4334..3909bbb653 100644 --- a/wolfcrypt/src/wc_slhdsa.c +++ b/wolfcrypt/src/wc_slhdsa.c @@ -21,10 +21,16 @@ #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 +#include #include #include #ifdef NO_INLINE @@ -35,6 +41,11 @@ #endif #include #include +#ifdef WOLFSSL_SLHDSA_SHA2 + #include + #include + #include +#endif #if defined(USE_INTEL_SPEEDUP) /* CPU information for Intel. */ @@ -370,6 +381,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 +629,811 @@ 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]; + int copy_succeeded = 0; + + (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) { + copy_succeeded = 1; + /* 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); + } + if (copy_succeeded) { + wc_Sha256Free(&key->hash.sha2.sha256); + } + + return ret; +} + +#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY +/* 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]; + 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); + } + 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); + } + 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); + } + 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); + } + if (copy_succeeded) { + wc_Sha512Free(&key->hash.sha2.sha512); + } + } + + return ret; +} +#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ + +/* 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]; + 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); + } + 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); + } + 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); + } + 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); + } + if (copy_succeeded) { + wc_Sha512Free(&key->hash.sha2.sha512); + } + } + + return ret; +} + +#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY +/* 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]; + int copy_succeeded = 0; + + (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) { + copy_succeeded = 1; + 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); + } + if (copy_succeeded) { + wc_Sha256Free(&key->hash.sha2.sha256); + } + + return ret; +} +#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ + +/* 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; +} + +/* 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. + * 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; + 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) { + ret = wc_Sha256Update(&key->hash.sha2.sha256_2, cBuf, 4); + } + 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; + } + } + 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; + 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) { + ret = wc_Sha512Update(&key->hash.sha2.sha512_2, cBuf, 4); + } + 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; + } + } + counter++; + } + + return ret; +} + +#ifndef WOLFSSL_SLHDSA_VERIFY_ONLY +/* 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; +} +#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ + +/* 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]; + 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) { + 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); + } + if (sha_inited) { + wc_Sha256Free(&key->hash.sha2.sha256_2); + } + + /* 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]; + 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) { + 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); + } + if (sha_inited) { + wc_Sha512Free(&key->hash.sha2.sha512_2); + } + + /* 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 +} + +#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) +{ +#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 +} +#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) +{ + return slhdsakey_hash_shake_4(&key->hash.shk.shake, pk_seed, n, adrs, m1, + 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) +{ +#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 +} +#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ + +#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 +1443,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 +1452,78 @@ 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)) + +#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) \ + 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) + +#define HASH_T_FREE(k) \ + slhdsakey_hash_free(&(k)->hash.shk.shake2) + +#endif /* WOLFSSL_SLHDSA_SHA2 */ /* Start hashing with SHAKE-256. * @@ -835,6 +1622,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 ******************************************************************************/ @@ -925,13 +1721,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; } @@ -1229,7 +2025,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. * @@ -1264,7 +2060,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. * @@ -1308,7 +2104,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. * @@ -1650,7 +2446,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. @@ -2139,7 +2935,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 +3003,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 +3071,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 +3118,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 +3192,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 +3209,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 +3220,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 +3233,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; } @@ -2474,6 +3270,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; @@ -2482,17 +3279,21 @@ 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; + 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); /* 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 +3307,11 @@ 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); + } + + if (hash_t_started) { + HASH_T_FREE(key); } return ret; @@ -2798,7 +3603,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); } @@ -2864,7 +3669,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; @@ -2895,7 +3700,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 +3715,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; } @@ -3183,20 +3990,20 @@ 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; 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); #if !defined(WOLFSSL_SLHDSA_PARAM_NO_128) - if ((ret == 0) && (n == 16)) { - ii = 0; + if ((ret == 0) && (n == WC_SLHDSA_N_128)) { + 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) { @@ -3223,7 +4030,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) { @@ -3250,7 +4060,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) { @@ -3275,20 +4088,29 @@ 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); - 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); + hash_t_started = 1; + 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); + } + if (hash_t_started) { + HASH_T_FREE(key); } WC_FREE_VAR_EX(nodes, key->heap, DYNAMIC_TYPE_SLHDSA); @@ -3331,6 +4153,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); @@ -3354,15 +4177,19 @@ 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) { + hash_t_started = 1; /* 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); + } + if (hash_t_started) { + HASH_T_FREE(key); } WC_FREE_VAR_EX(nodes, key->heap, DYNAMIC_TYPE_SLHDSA); @@ -3403,13 +4230,15 @@ 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); 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) { + 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. */ @@ -3421,7 +4250,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 +4260,10 @@ 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); + } + if (hash_t_started) { + HASH_T_FREE(key); } return ret; @@ -3491,7 +4323,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 +4421,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 +4442,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 +4513,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); } } @@ -3717,7 +4551,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; @@ -3752,7 +4586,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. * @@ -3829,11 +4663,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; @@ -3946,7 +4780,7 @@ static int slhdsakey_ht_sign(SlhDsaKey* key, const byte* pk_fors, return ret; } -#endif +#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ /* Verify hypertree signature. * @@ -4076,7 +4910,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 +5131,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 +5183,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 +5195,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 +5203,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 +5314,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 +5330,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 +5426,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 +5442,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 +5559,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 +5588,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 +5605,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 +5624,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 +5681,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 +5701,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); } } @@ -4905,7 +5739,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; @@ -4928,7 +5762,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++) { @@ -4973,7 +5809,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. @@ -5275,7 +6111,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 +6132,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 +6153,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 +6230,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 +6251,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 +6272,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 +6341,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 +6362,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 +6378,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; @@ -5586,6 +6422,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); @@ -5595,11 +6432,16 @@ 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); + + 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) && 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 +6456,11 @@ 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); + } + + if (hash_t_started) { + HASH_T_FREE(key); } return ret; @@ -5664,15 +6510,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 +6518,26 @@ 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) && (key->params->n > 16)) { + ret = wc_InitSha512(&key->hash.sha2.sha512); + } + } + 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 +6559,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 +6764,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 +6849,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 +6965,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 +7005,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,7 +7199,52 @@ int wc_SlhDsaKey_Sign(SlhDsaKey* key, const byte* ctx, byte ctxSz, return ret; } -#endif + +/* 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 /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ /* Verify SLH-DSA signature. * @@ -6337,34 +7355,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 +7401,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 +7516,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 +7625,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 +7778,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 */ @@ -6825,7 +7989,7 @@ int wc_SlhDsaKey_SignHash(SlhDsaKey* key, const byte* ctx, byte ctxSz, return ret; } -#endif +#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ /* Verify SLH-DSA signature. * @@ -6919,37 +8083,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,11 +8167,16 @@ 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; } -#endif +#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ /* Import public key from data. * @@ -7019,7 +8202,12 @@ 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); + } +#endif } return ret; @@ -7101,7 +8289,7 @@ int wc_SlhDsaKey_ExportPrivate(SlhDsaKey* key, byte* priv, word32* privLen) return ret; } -#endif +#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ /* Export the public key. * @@ -7159,7 +8347,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. * @@ -7235,6 +8423,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; @@ -7242,7 +8450,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. * @@ -7273,6 +8481,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 +8538,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; @@ -7317,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/src/wc_xmss.c b/wolfcrypt/src/wc_xmss.c index ef7248d209..2a80deb217 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 @@ -834,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/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 befb652b01..361f16d631 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -389,33 +389,17 @@ 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 #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 @@ -437,6 +421,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,13 +876,20 @@ 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 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 @@ -968,11 +962,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); @@ -1255,6 +1247,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); /* NOLINT(concurrency-mt-unsafe) */ +#endif } #ifdef REALLY_LONG_DRBG_CONTINUOUS_TEST only_run_cb_once = 0; @@ -1267,9 +1268,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; @@ -1327,9 +1332,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; @@ -1385,9 +1390,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. @@ -2940,6 +2945,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) @@ -3114,17 +3126,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) @@ -3144,14 +3160,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) @@ -4026,8 +4040,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 } }; @@ -8042,17 +8054,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); @@ -19505,6 +19520,115 @@ 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. */ + { + 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, + vectors[0].iv, (word32)vectors[0].iv_length, + vectors[0].aad, + (word32)vectors[0].aad_length); + if (ret != 0) { + 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); + WC_FREE_VAR(eax, HEAP_HINT); + 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); + WC_FREE_VAR(eax, HEAP_HINT); + 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); + WC_FREE_VAR(eax, HEAP_HINT); + return WC_TEST_RET_ENC_EC(ret); + } + + wc_AesEaxFree(eax); + WC_FREE_VAR(eax, HEAP_HINT); + } + } +#endif /* WOLFSSL_MIN_AUTH_TAG_SZ > 0 */ + return 0; } @@ -20537,6 +20661,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) { @@ -20951,14 +21297,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 @@ -21209,6 +21591,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, @@ -21257,11 +21645,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) @@ -21278,6 +21668,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) @@ -21435,8 +21972,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)); @@ -21518,8 +22064,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); } @@ -32620,18 +33178,24 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t x963kdf_test(void) defined(HAVE_CURVE448)) && \ defined(HAVE_AESGCM) -static wc_test_ret_t hpke_test_single(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; @@ -32640,20 +33204,62 @@ static wc_test_ret_t hpke_test_single(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); } #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); @@ -32667,6 +33273,85 @@ static wc_test_ret_t hpke_test_single(Hpke* hpke) 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, @@ -32678,6 +33363,36 @@ static wc_test_ret_t hpke_test_single(Hpke* hpke) 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); @@ -32685,6 +33400,149 @@ static wc_test_ret_t hpke_test_single(Hpke* hpke) 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, 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), + (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; + } + + /* 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*)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; + } + /* tampered ciphertext */ + if (ret == 0) { + ciphertext[0] ^= 0xFF; + 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); + ciphertext[0] ^= 0xFF; + if (ret == 0) + ret = WC_TEST_RET_ENC_NC; + else + ret = 0; + } + /* wrong receiver key */ + if (ret == 0) + ret = wc_HpkeGenerateKeyPair(hpke, &wrongKey, rng); + if (ret == 0) { + 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 */ if (ret == 0) { ret = wc_HpkeOpenBase(hpke, receiverKey, pubKey, pubKeySz, @@ -32702,34 +33560,8 @@ 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); - if (receiverKey != NULL) wc_HpkeFreeKey(hpke, hpke->kem, receiverKey, hpke->heap); @@ -32741,6 +33573,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; @@ -32753,91 +33589,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 */ + 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; } @@ -32850,11 +34006,8 @@ 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 */ - 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); @@ -32865,11 +34018,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); @@ -32881,11 +34031,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); @@ -32896,11 +34043,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); @@ -32911,11 +34055,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); @@ -32926,11 +34067,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); @@ -32941,15 +34079,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)) @@ -33701,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: @@ -34271,7 +35404,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) @@ -43349,7 +44482,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) { @@ -47730,7 +48862,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) { @@ -47771,8 +48902,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; @@ -47960,7 +49090,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); @@ -47971,7 +49101,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) @@ -47987,7 +49116,6 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t mlkem_test(void) if (ret != 0) goto out; #endif -#endif /* WOLFSSL_WC_MLKEM */ out: @@ -51526,13 +52654,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) @@ -51540,13 +52666,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) @@ -51554,13 +52678,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) @@ -52312,10 +53434,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"); @@ -52374,7 +53494,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); @@ -52401,7 +53520,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); } @@ -52512,9 +53630,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. * @@ -52858,10 +53975,80 @@ 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) + +#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) { @@ -52904,8 +54091,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); } @@ -52930,14 +54119,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); } @@ -52965,11 +54197,31 @@ 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) { -#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 @@ -54033,7 +55285,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); } @@ -54075,8 +55329,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); } @@ -54084,14 +55340,609 @@ 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 #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 + #ifdef WOLFSSL_SLHDSA_PARAM_128S ret = slhdsa_test_param(SLHDSA_SHAKE128S); if (ret != 0) { @@ -54134,10 +55985,56 @@ 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 -out: +#endif /* !WOLFSSL_SLHDSA_VERIFY_ONLY */ +#ifdef SLHDSA_TEST_HAVE_ANY_PARAM +out: +#endif + +#ifdef WOLFSSL_SLHDSA_PARAM_128S #ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC if (key_vfy) #endif @@ -54145,6 +56042,9 @@ out: wc_SlhDsaKey_Free(key_vfy); } WC_FREE_VAR_EX(key_vfy, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + /* 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) @@ -54157,6 +56057,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; } @@ -57053,6 +58954,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; } @@ -57066,6 +58970,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; } @@ -57079,6 +58986,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; @@ -66205,7 +68115,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)++; @@ -66473,43 +68383,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, @@ -66518,27 +68418,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, @@ -66547,10 +68441,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 */ @@ -67274,10 +69166,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; @@ -68727,7 +70617,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/wolfcrypt/test/test.h b/wolfcrypt/test/test.h index 72b9ff586d..016ca6553a 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 @@ -310,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-VS2022.vcxproj b/wolfssl-VS2022.vcxproj index d5e13a3964..a2c001ca8a 100644 --- a/wolfssl-VS2022.vcxproj +++ b/wolfssl-VS2022.vcxproj @@ -428,7 +428,6 @@ - @@ -460,7 +459,6 @@ - @@ -470,6 +468,7 @@ + diff --git a/wolfssl.vcproj b/wolfssl.vcproj index 02554722d2..1bcc024863 100644 --- a/wolfssl.vcproj +++ b/wolfssl.vcproj @@ -263,10 +263,6 @@ RelativePath=".\wolfcrypt\src\error.c" > - - @@ -375,10 +371,6 @@ RelativePath=".\wolfcrypt\src\sha512.c" > - - @@ -419,6 +411,10 @@ RelativePath=".\wolfcrypt\src\wc_port.c" > + + diff --git a/wolfssl.vcxproj b/wolfssl.vcxproj index 58410b144a..acc663d6a2 100644 --- a/wolfssl.vcxproj +++ b/wolfssl.vcxproj @@ -427,7 +427,6 @@ - @@ -460,7 +459,6 @@ - @@ -470,6 +468,7 @@ + diff --git a/wolfssl/certs_test.h b/wolfssl/certs_test.h index efd4c1bd28..42b849f4ca 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)) @@ -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/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 7ef18d6c7f..6eaefa8939 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1442,6 +1442,15 @@ enum { */ #define AEAD_SM4_CCM_LIMIT w64From32(0, (1 << 10) - 1) +#ifndef WOLFSSL_COOKIE_LEN +/* Maximum size for a DTLS cookie */ +#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 @@ -1569,7 +1578,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 = 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 */ @@ -1767,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. */ @@ -2738,6 +2747,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 */ @@ -3141,9 +3151,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; @@ -3189,9 +3199,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 +3611,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 */ @@ -5237,6 +5256,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/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/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 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/openssl/evp.h b/wolfssl/openssl/evp.h index 2117d0be7f..c1f60e6ca3 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, @@ -517,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 @@ -979,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); @@ -1388,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 diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 236515157b..3f5411c5f5 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -603,6 +603,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; @@ -628,6 +634,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 }; @@ -1037,7 +1049,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 @@ -2120,6 +2132,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); @@ -4766,7 +4779,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. @@ -4816,7 +4829,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/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; 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/asn.h b/wolfssl/wolfcrypt/asn.h index b3028c9c99..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 @@ -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 */ @@ -1538,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 { @@ -1591,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 @@ -1852,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; @@ -2107,7 +2112,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; @@ -2680,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 */ @@ -3123,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, @@ -3140,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 3d4a78b598..bb85d51b0e 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" { @@ -78,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 { @@ -140,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, @@ -469,6 +478,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 +635,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/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 07eee8c6a4..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 @@ -856,6 +749,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 +770,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/ed448.h b/wolfssl/wolfcrypt/ed448.h index e255fdacae..0890198874 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 #ifdef HAVE_ED448_KEY_IMPORT WOLFSSL_API diff --git a/wolfssl/wolfcrypt/error-crypt.h b/wolfssl/wolfcrypt/error-crypt.h index 40962ee084..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,10 +314,22 @@ 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 */ - 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 */ + + 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/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_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/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/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/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/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 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 diff --git a/wolfssl/wolfcrypt/include.am b/wolfssl/wolfcrypt/include.am index 1c23469d20..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 \ @@ -77,19 +76,14 @@ 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 \ - 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 noinst_HEADERS+= \ diff --git a/wolfssl/wolfcrypt/lms.h b/wolfssl/wolfcrypt/lms.h deleted file mode 100644 index 8ba69d98a3..0000000000 --- a/wolfssl/wolfcrypt/lms.h +++ /dev/null @@ -1,202 +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, -#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, -#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/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 e1fbee5f44..8df91a8546 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 */ @@ -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 */ @@ -233,10 +245,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 */ @@ -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 }; @@ -412,6 +436,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 */ @@ -469,6 +497,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 */ @@ -1556,10 +1588,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 */ @@ -1572,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 */ @@ -1637,10 +1681,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 */ @@ -1653,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 }; @@ -1690,7 +1746,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 */ @@ -1713,8 +1769,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/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/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 */ diff --git a/wolfssl/wolfcrypt/random.h b/wolfssl/wolfcrypt/random.h index db7d58a97e..102f05d6b5 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 d01ab3cd46..e02620e7a4 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 @@ -505,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 @@ -550,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) @@ -920,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: */ @@ -2185,10 +2197,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 @@ -2209,7 +2221,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 @@ -2254,6 +2267,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) @@ -3280,7 +3295,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 @@ -3290,7 +3305,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 @@ -3946,6 +3961,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 @@ -4033,6 +4049,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) && \ @@ -4143,6 +4167,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) && \ @@ -4542,61 +4576,39 @@ 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) || \ - defined(HAVE_LIBXMSS) || \ - defined(HAVE_LIBLMS) || \ defined(WOLFSSL_DUAL_ALG_CERTS) || \ defined(HAVE_ASCON)) && \ !defined(WOLFSSL_EXPERIMENTAL_SETTINGS) #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 " \ @@ -4631,15 +4643,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 @@ -4685,7 +4697,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 deleted file mode 100644 index a14252278e..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_PQC) && 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_PQC && HAVE_SPHINCS */ -#endif /* WOLF_CRYPT_SPHINCS_H */ diff --git a/wolfssl/wolfcrypt/types.h b/wolfssl/wolfcrypt/types.h index e8c24855be..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, @@ -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 @@ -2089,7 +2087,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") @@ -2316,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, @@ -2369,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_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 diff --git a/wolfssl/wolfcrypt/wc_lms.h b/wolfssl/wolfcrypt/wc_lms.h index 914ffa1371..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,10 +94,13 @@ #include -#if defined(WOLFSSL_HAVE_LMS) && defined(WOLFSSL_WC_LMS) +#ifdef WOLFSSL_HAVE_LMS -#include +#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. */ @@ -101,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 @@ -122,10 +315,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 +505,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 +548,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 +647,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 { @@ -466,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 @@ -495,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); @@ -504,9 +815,14 @@ 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 */ +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* WOLFSSL_HAVE_LMS */ #endif /* WC_LMS_H */ 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/wolfssl/wolfcrypt/wc_port.h b/wolfssl/wolfcrypt/wc_port.h index 9c595f2b0c..d722ea8d10 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 @@ -1861,6 +1863,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 diff --git a/wolfssl/wolfcrypt/wc_slhdsa.h b/wolfssl/wolfcrypt/wc_slhdsa.h index 19ee86fbb2..715b9af80b 100644 --- a/wolfssl/wolfcrypt/wc_slhdsa.h +++ b/wolfssl/wolfcrypt/wc_slhdsa.h @@ -23,10 +23,33 @@ #define WOLF_CRYPT_WC_SLHDSA_H #include + +#if FIPS_VERSION3_GE(7,0,0) + #include +#endif + +#ifdef WOLFSSL_HAVE_SLHDSA + #include #include -#ifdef WOLFSSL_HAVE_SLHDSA +#ifdef WOLFSSL_SLHDSA_SHA2 + #include + #include + #include +#endif + +/* ======== 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 @@ -60,6 +83,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) @@ -155,12 +180,169 @@ #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 + +/* 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 + +#else /* !WOLFSSL_SLHDSA_SHA2 */ + + #define WOLFSSL_SLHDSA_NO_SHA2 + +#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 +398,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 @@ -247,26 +497,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 @@ -279,8 +553,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 +606,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 +654,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); @@ -375,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/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 */ 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..391b5c9eb9 100644 --- a/wrapper/CSharp/wolfssl.vcxproj +++ b/wrapper/CSharp/wolfssl.vcxproj @@ -308,7 +308,6 @@ - @@ -342,7 +341,6 @@ - @@ -352,6 +350,7 @@ + diff --git a/wrapper/rust/wolfssl-wolfcrypt/Cargo.lock b/wrapper/rust/wolfssl-wolfcrypt/Cargo.lock index 9fe8a69681..ea88736bdf 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" @@ -284,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" @@ -391,8 +423,10 @@ dependencies = [ "aead", "bindgen", "cipher", + "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 08ee5ac62b..9defa79fee 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/Cargo.toml +++ b/wrapper/rust/wolfssl-wolfcrypt/Cargo.toml @@ -15,16 +15,22 @@ std = [] 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 37dc9a8579..51dc4c801e 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,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/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/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/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 729c7cff96..ec817dcf4c 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,7 +61,11 @@ 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")] +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 { 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..40314f9548 --- /dev/null +++ b/wrapper/rust/wolfssl-wolfcrypt/src/rsa_pkcs1v15.rs @@ -0,0 +1,351 @@ +/* + * 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)) + } +} + +/// 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. +/// +/// 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}"); + } + if (n_len as usize) != N || e_len == 0 || (e_len as usize) > MAX_E_LEN { + panic!("wc_RsaFlattenPublicKey returned unexpected lengths: e_len: {e_len}, n_len: {n_len}"); + } + VerifyingKey { + n, + e, + e_len: e_len as u8, + _hash: PhantomData, + } + } +} 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_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 // --------------------------------------------------------------------------- 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"); +} 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, + ); +} diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index 35b8a76565..7332865b75 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) @@ -112,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) @@ -123,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) 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..13c689da6d 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 @@ -337,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