diff --git a/.github/workflows/tinytls13.yml b/.github/workflows/tinytls13.yml new file mode 100644 index 00000000000..f8b51ce4aa9 --- /dev/null +++ b/.github/workflows/tinytls13.yml @@ -0,0 +1,154 @@ +name: Tiny TLS 1.3 Tests + +# START OF COMMON SECTION +on: + push: + branches: [ 'release/**' ] + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + branches: [ '*' ] + schedule: + - cron: '42 10 * * 1-5' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +# END OF COMMON SECTION + +permissions: + contents: read + +jobs: + # Build + make check every --enable-tinytls13 spelling on one runner via + # .github/scripts/parallel-make-check.py (see psk.yml for the pattern). + make_check: + name: make check + if: ${{ (github.repository_owner == 'wolfssl') && (github.event_name != 'pull_request' || github.event.pull_request.draft == false) }} + runs-on: ubuntu-24.04 + timeout-minutes: 10 + steps: + - uses: actions/checkout@v5 + name: Checkout wolfSSL + + - name: Install dependencies + uses: ./.github/actions/install-apt-deps + with: + packages: autoconf automake libtool build-essential bubblewrap + ghcr-debs-tag: ubuntu-24.04-minimal + + - name: Set up ccache + uses: ./.github/actions/ccache-setup + with: + workflow-id: tinytls13 + read-only: ${{ github.event_name == 'pull_request' }} + max-size: 100M + + - name: Allow unprivileged user namespaces (for bwrap) + run: sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 || true + + # Every tiny TLS 1.3 profile/adder spelling, so each is proven to build + # and pass make check (which runs the TLS handshake test suite) out of + # the box. Server is enabled where a config needs the server-side tests. + # The psk-p256 and cert-rsaverify configs strip to combinations + # (ECDHE-only ECC without certs, RSA verify only) that the OpenSSL-compat + # API unit suite (coupled to examples via BUILD_TESTS) does not gate for. + # Rather than carry test-harness edits for those, they build static with + # --disable-examples, skip make check ("check": false), and instead run + # wolfcrypt/test/testwolfcrypt plus examples/tls13/tls13_memio.c + # (a self-contained in-memory TLS 1.3 handshake) for real crypto and + # handshake verification. + - name: Build and test all tinytls13 configs + run: | + cat > "$RUNNER_TEMP/tinytls13-configs.json" <<'EOF' + [ + {"name": "tinytls13-psk-x25519", "minutes": 1, + "configure": ["--enable-tinytls13=psk,server", "--disable-mlkem"]}, + {"name": "tinytls13-psk-p256", "minutes": 1, "check": false, + "configure": ["--enable-tinytls13=psk,p256,server", "--enable-static", "--disable-shared", "--disable-examples", "--disable-mlkem"], + "run": [["make", "wolfcrypt/test/testwolfcrypt"], ["./wolfcrypt/test/testwolfcrypt"], + ["cc", "-I.", "-I..", "../examples/tls13/tls13_memio.c", "src/.libs/libwolfssl.a", "-lm", "-o", "tls13_memio"], + ["./tls13_memio"]]}, + {"name": "tinytls13-psk-staticmem", "minutes": 1, + "configure": ["--enable-tinytls13=psk,server,staticmem", "--disable-mlkem"]}, + {"name": "tinytls13-psk-mldsa", "minutes": 1, + "configure": ["--enable-tinytls13=psk,server,mldsa", "--disable-mlkem"]}, + {"name": "tinytls13-psk-sha384", "minutes": 1, + "configure": ["--enable-tinytls13=psk,server,sha384", "--disable-mlkem"]}, + {"name": "tinytls13-cert", "minutes": 1, + "configure": ["--enable-tinytls13=cert,server", "--disable-mlkem"]}, + {"name": "tinytls13-cert-sha384", "minutes": 1, + "configure": ["--enable-tinytls13=cert,server,sha384", "--disable-mlkem"]}, + {"name": "tinytls13-cert-mutualauth", "minutes": 1, + "configure": ["--enable-tinytls13=cert,mutualauth,server", "--disable-mlkem"]}, + {"name": "tinytls13-cert-rsaverify", "minutes": 1, "check": false, + "configure": ["--enable-tinytls13=cert,server,rsaverify", "--enable-static", "--disable-shared", "--disable-examples", "--disable-mlkem"], + "run": [["make", "wolfcrypt/test/testwolfcrypt"], ["./wolfcrypt/test/testwolfcrypt"], + ["cc", "-I.", "-I..", "../examples/tls13/tls13_memio.c", "src/.libs/libwolfssl.a", "-lm", "-o", "tls13_memio"], + ["./tls13_memio"]]}, + {"name": "tinytls13-cert-mldsa", "minutes": 1, + "configure": ["--enable-tinytls13=cert,server,mldsa", "--enable-static", "--disable-mlkem"], + "run": [["cc", "-I.", "-I..", "../examples/tls13/tls13_memio.c", "src/.libs/libwolfssl.a", "-lm", "-o", "tls13_memio"], + ["./tls13_memio"]]}, + {"name": "tinytls13-psk-client-only", "minutes": 1, + "configure": ["--enable-tinytls13=psk", "--disable-mlkem"]}, + {"name": "tinytls13-cert-client-only", "minutes": 1, + "configure": ["--enable-tinytls13=cert", "--disable-mlkem"]}, + {"name": "tinytls13-psk-asm", "minutes": 1, + "configure": ["--enable-tinytls13=psk,server,asm", "--disable-mlkem"]}, + {"name": "tinytls13-cert-asm", "minutes": 1, + "configure": ["--enable-tinytls13=cert,server,asm", "--disable-mlkem"]}, + {"name": "tinytls13-cert-chacha", "minutes": 1, "check": false, + "configure": ["--enable-tinytls13=cert,server", "--enable-static", "--disable-shared", "--disable-examples", "--disable-mlkem"], + "cflags": "-DHAVE_CHACHA -DHAVE_POLY1305", + "run": [["cc", "-I.", "-I..", "../examples/tls13/tls13_memio.c", "src/.libs/libwolfssl.a", "-lm", "-o", "tls13_memio"], + ["./tls13_memio", "TLS13-CHACHA20-POLY1305-SHA256"]]}, + {"name": "tinytls13-cert-aes256", "minutes": 1, "check": false, + "configure": ["--enable-tinytls13=cert,server,sha384", "--enable-static", "--disable-shared", "--disable-examples", "--disable-mlkem"], + "cflags": "-DWOLFSSL_AES_256", + "run": [["cc", "-I.", "-I..", "../examples/tls13/tls13_memio.c", "src/.libs/libwolfssl.a", "-lm", "-o", "tls13_memio"], + ["./tls13_memio", "TLS13-AES256-GCM-SHA384"]]}, + {"name": "tinytls13-psk-mlkem", "minutes": 1, + "configure": ["--enable-tinytls13=psk,server", "--enable-static"], + "run": [["cc", "-I.", "-I..", "../examples/tls13/tls13_memio.c", "src/.libs/libwolfssl.a", "-lm", "-o", "tls13_memio"], + ["./tls13_memio", "-", "mlkem"]]}, + {"name": "tinytls13-cert-staticmem", "minutes": 1, "check": false, + "configure": ["--enable-tinytls13=cert,server,staticmem", "--enable-static", "--disable-shared", "--disable-examples", "--disable-mlkem"], + "run": [["make", "wolfcrypt/test/testwolfcrypt"], ["./wolfcrypt/test/testwolfcrypt"], + ["cc", "-I.", "-I..", "../examples/tls13/tls13_memio.c", "src/.libs/libwolfssl.a", "-lm", "-o", "tls13_memio"], + ["./tls13_memio"]]}, + {"name": "tinytls13-nomalloc", "minutes": 1, "check": false, + "configure": ["--enable-tinytls13=psk,server,staticmem", "--enable-static", "--disable-shared", "--disable-examples", "--disable-crypttests", "--disable-mlkem"], + "cflags": "-DWOLFSSL_NO_MALLOC"}, + {"name": "tinytls13-combo-cert-mutualauth-sha384", "minutes": 1, + "configure": ["--enable-tinytls13=cert,mutualauth,server,sha384", "--disable-mlkem"]}, + {"name": "tinytls13-combo-cert-mldsa-sha384", "minutes": 1, + "configure": ["--enable-tinytls13=cert,server,mldsa,sha384", "--enable-static", "--disable-mlkem"], + "run": [["cc", "-I.", "-I..", "../examples/tls13/tls13_memio.c", "src/.libs/libwolfssl.a", "-lm", "-o", "tls13_memio"], + ["./tls13_memio"]]}, + {"name": "tinytls13-bare", "minutes": 1, + "configure": ["--enable-tinytls13", "--disable-mlkem"]}, + {"name": "tinytls13-usersettings", "minutes": 1, "check": false, + "user_settings": "examples/configs/user_settings_tinytls13.h", + "configure": ["--enable-usersettings", "--enable-static", "--disable-shared", "--disable-examples", "--disable-crypttests"]} + ] + EOF + .github/scripts/parallel-make-check.py \ + ${{ github.event_name == 'schedule' && '--build-only' || '' }} \ + --private-dir=certs \ + "$RUNNER_TEMP/tinytls13-configs.json" + + - name: ccache stats + if: always() + run: ccache -s || true + + - name: Upload logs on failure + if: failure() + uses: actions/upload-artifact@v6 + with: + retention-days: 7 + name: tinytls13-logs + path: | + build-*/make-check.log + build-*/test-suite.log + build-*/config.log + if-no-files-found: ignore diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 101ebf2fa88..c287b1ba4eb 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -948,6 +948,7 @@ WOLFSSL_TICKET_ENC_CBC_HMAC WOLFSSL_TICKET_ENC_CHACHA20_POLY1305 WOLFSSL_TICKET_ENC_HMAC_SHA384 WOLFSSL_TICKET_ENC_HMAC_SHA512 +WOLFSSL_TINY_TLS13_NO_DEFAULT_CURVE WOLFSSL_TI_CURRTIME WOLFSSL_TLS13_DRAFT WOLFSSL_TLS13_IGNORE_AEAD_LIMITS diff --git a/certs/mldsa/ecc-leaf-mldsa44.pem b/certs/mldsa/ecc-leaf-mldsa44.pem new file mode 100644 index 00000000000..601e1cb6a7f --- /dev/null +++ b/certs/mldsa/ecc-leaf-mldsa44.pem @@ -0,0 +1,61 @@ +-----BEGIN CERTIFICATE----- +MIIK4zCCAVmgAwIBAgIUWxTZmWEP7xd/6kP8yG6lrPoDI0EwCwYJYIZIAWUDBAMR +MFoxCzAJBgNVBAYTAlVTMRAwDgYDVQQIDAdNb250YW5hMRAwDgYDVQQHDAdCb3pl +bWFuMRAwDgYDVQQKDAd3b2xmU1NMMRUwEwYDVQQDDAxUZXN0IG1sZHNhNDQwHhcN +MjYwNjI5MjA0MjExWhcNMzYwNjI2MjA0MjExWjAUMRIwEAYDVQQDDAlsb2NhbGhv +c3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAS7M6xMJ1BKxkqlBMM83p8223It +zpTqK/rLIAk5LBboYQLpr03TApOaMVuXkiF/8M8Y2pERAjSG6CBYMwuANInYo0Iw +QDAdBgNVHQ4EFgQUXV0m76x+NvmbdhUrSiUCI++yiTAwHwYDVR0jBBgwFoAUswU7 +xg6AYh+iTpNtmT4TaDnG/DIwCwYJYIZIAWUDBAMRA4IJdQBRjK3IylTYl8c3Xr5o +BPVm8ERo5JxgRVYWclOVjuTlVYjnBg1ldXnyhXDjrq9cWDzYAbsjDD8AF6n2KlWK +YtQ+PDGt9owu4tYuHKHSE3KTsUEXLrZV0sUr1gR6SDGhbKaGTa3mHs+/qTOyh/5U +e2uKuGCr6mVa6QNJnvomq31KcPh52RaBEtpP04zJ3PfR+XEToXLKDS8/q6tLtuAI +5WBUiLMz2f5LW3/ShM5g4ANQNUjp2GgOZp5zx/en/1GyqVep7QJgdY//fj9LSRqP +jkyVSVRf+kOdG5FK1du8pysnZRy5+hj7QVRcuFIcaXfs9ak2xd7A2tti486WzUIF +vVDAhkxNRc6Kk5o0dm7uO+EyiPvtvPw94TOuXp6aPZJfBaYc+DeN2L+yNHDBJu22 +wR+1f4vKsRCcZE82J93RfWp86PO9OWFMdghX/GRHC+GF6bR9gvXjXLnYpl5rIQ6q +Y68CNM1oWp6jCNW273X505pvijAoG3m/9JL8XkRbGuhXli/1fKWuo03Plbha9sbe +zPpc/I6Srq3LUcvmbajt+rDzuFRPpweLimAToqtji6eqx/RGusdtROGROd1/e9PI +PEWd9DxfQxttyo+maJ9+o4jB+MIRwCdVp+GYiEDalBXdUd5GmqY2Y64UnzxaATq7 +scLJWX3UKN0DPhAfJOQgXnExlkCTg7as3jQ7M3xmfEO1L+v91dRW4PT+yBQxfVm0 +1NCmQ058PT0udeqkuMdrEgkdxoRRPN4uoDj08U/0hCaJOLbE2WkgEekdCaIjrJz7 +rTpnOrJ9ey3KIUBJLm6uGkqc81na6kRlELU4/1g54O73plpn6+85NUU8sCSs9WqL +uYHDyYskyL+1FbplOtpubCk8hAxQ+cls/uM7mkEms0bjFEej428HlGkVjp9iJP4v +bYdjctEOSbebnujWHT8RnmkIhV68bAQWiNDEoHxvI8GBY4lDrllfXBhxCDVs2mJa +MfTLBRI8ZyiBiDatT04aghySMMuJG2GSu3AoSNTilhpziMVrIYP62aopjSdmoUcH +XLMcUrjtjx4ssINqzEqZXqeW+knaSNdeDtPk1ECiBG5amPpB18GOAAhBYrS+8SNZ +gmyKs5S9l9qLhQZ/ZHWF4BT1BC29gQ863fobxrUd6XSu/WJSoOMCmY+tRFbeQ74U +Q0lTJK995Mru7L7YZEsbYaZsa/pwK7lnaOD+XDmq5P9RV0KTI//zTrQHhnBonViW +gbIoa21eJCvTbax0Jcczd7FvjbFf8zfYzKNq532ZTdzMiZ9Z15ic1EfSArQwy1BC +lsuX8yQIVHt1SdbZFjW0JQycrbDdYC6A4UFA/Ce8SAOf3qMViIw8eGU2aNtwOf/Q +YWfJ+dfhfE6QeQe3sj87j00Hp4k9DG/20zb4W2kMl043xsTa6DzMujSE7Af82zgt +6x5rXhdDph63KQ1E35tiuPekoALnmgEZV5Jg/Ze459ugXlseGNeXIA+6he3iKO3J +gqVLOQQSTXP6nUX4R4E/eI7FnaWFXk+wVWuOgBzLmvyZrjecC1vgnl2j0mvsXbVN +cvIaezO0vB9WcudUs6d4RsnH/yGIvx05FfYWa5iVBhSbugGsn5QfeMBr6UQwQOoh +MAqgSMrgB4UAgiR/zxai/Uyd82rpFaCHNa61j4G/TFHFYyTVCyl2Ru4fhTINF2wD +IM4ZV1qX9Lt65G+/I80I2KZLs2j5huFqMhWApBFdJ2Mxhqg0T+zDgWtK64RxExKH +bzcsiFjBaKBQV6HNxdfmL5K29vR59q4R/FxXmxtqZaZAEMY3rg1mdMNqmea6qO6Z +LBaWytwugs5cSiJJjoyUEoBVGyxDj6kG0qyHCdZ376ryqDAimR/SZDLjfyr9WQdt +/dZ462aaywPjvb+6D9NZHkronNqcOsEyct6O+n15E8j7c1lXc7G5SWGYz2bfgYvs +1VSn+KNsYth9xp67Sx+x2WsGEB3jbR12HybkOBD4EGVIsNgnRW3N2SkJQP2i6UjW +WCHWL0qJwdx/Umv08zo0ACApemUr3u5UWW+5twNiEjzk+oymsQ2Z8fbzA58qBuK4 +Yp3eepqozA3ELg9fizfo/+itibHVEHlepjttxbCVfLpAb2psRD/733ZAhV1hLrV8 +2Nvou8LqoJY2L01q06OPPgFYpb+e6AdtEv6n2pF0JMK4BVHTAIJIgBCaAoagkQtX +4Nhk+90oA3WKkYkxRKI7dbExMa2wPo2EqS04D1GjFuvnvEhF+KXYUJlIlnyrLnpw +UAJc8jN1v6U3yPwnOS2VMD1bEs/Dc1v97rgqk7lTNjJNJBub7jkLf4kc9wXsuGld +YZPqpb51vgkG9+k/f31LMQ4uFNvPPg/TodUi//4smlTYkTiC20eIgp9hXU9YbRJ0 +aH2DcnADL1Zd+L5BUhSmgTSyaViIRUdUOO1G/cRV7MnRx72ufgyTv5yJHcRqS1Qb +W98tnQPDKNb8RsYbvdRnOSpuxEIcfKv7zigdvXuIg4I+XJeBeuICjcLYWcvwJSLa +ouilseTBoMhxFQsPSc/rRuRWWa9quwVwuhippKrXnadjcBD4d14nez6+ipiTlW4+ +Hu5JjqHTkBdzdgZCZ223eIobuzul3YNnHoYp15rL1Puphmefpw6ySJDWWLfMm3Wz +4IlpnLoj7MdYRTnb6UP3Y/9uRxfb7LzTuvVKBXsZxLjKhxTL+uFyA0E7glPGypFs +sDl2CErC+yfY7dCGFJIHr+JbegqKZyliIX/Zf1ZRNHg5eGtPrQrATIh96QoOKWKO +T0eD1OWf/V3ySUhD5bW+2DHRLWp9vjxAGHI656nGJEfDaOyOpSkhTBBLPZM7n+0+ +Cu+dU/VZgaX+uVGmJLKlcQJUi+G90XGYysHzvjwWE4p04f2vOn1JvZGepOwDk+hA +n1mMN1eHSyXf560GCh0uCzBqW26Faotfq6JNNGa6t5AGAtxaoL/gxLuH1aevaYJY +fcb6hbfpVI35UqIwCqeNQz8afvBYN0zg1xoByfmHwcoOoPX4lAogW3jbAGWoLw52 +GTUqbdT76LW8hvTUYYzOA+o4vi9CXtIQl1YUS9cunynNgmrNlPtzOisWu1RvaXgW +Fa3pAXLiYRAfAkIRwmElXIbnfxEXaJCWsrbn9/3+Bh4kKDNkb3a7y9Lf4/YJJ11s +b4SPpMXO2N7o6/T4BxI1OkBKUVRspcXI1OPn6uzu9f7/AAAAAAAAAAAAAAAAAAAA +AAAACxkpPg== +-----END CERTIFICATE----- diff --git a/certs/mldsa/include.am b/certs/mldsa/include.am index 1d6588ee053..405a0859502 100644 --- a/certs/mldsa/include.am +++ b/certs/mldsa/include.am @@ -28,6 +28,7 @@ EXTRA_DIST += \ certs/mldsa/mldsa44-key.pem \ certs/mldsa/mldsa44-cert.pem \ certs/mldsa/mldsa44-cert.der \ + certs/mldsa/ecc-leaf-mldsa44.pem \ certs/mldsa/mldsa65-key.pem \ certs/mldsa/mldsa65-cert.pem \ certs/mldsa/mldsa65-cert.der \ diff --git a/certs/renewcerts.sh b/certs/renewcerts.sh index 397b989d44b..7011ff3ffa3 100755 --- a/certs/renewcerts.sh +++ b/certs/renewcerts.sh @@ -1109,6 +1109,26 @@ EOF echo "End of ML-DSA-${level} section" done + + # ECC P-256 leaf signed by the ML-DSA-44 CA; used by + # examples/tls13/tls13_memio.c to drive ML-DSA cert verify. + echo "Generating ecc-leaf-mldsa44.pem (P-256 leaf signed by ML-DSA-44 CA)..." + cat > mldsa/ecc-leaf.ext < ecc-leaf.ext <@], + [Enable tiny TLS 1.3 footprint build. LIST is comma-separated from: + psk cert server mutualauth staticmem asm p256 sha384 mldsa rsaverify + (default: disabled; bare flag = psk). NOTE: the cert profile is a + reduced-security verify (no name constraints, relaxed ASN, no CRL) + meant for a known or pinned CA, not public-internet PKI.])], + [ ENABLED_TINYTLS13=$enableval ], + [ ENABLED_TINYTLS13=no ] + ) + +if test "$ENABLED_TINYTLS13" != "no" +then + if test "$FIPS_VERSION" != "none" + then + AC_MSG_ERROR([--enable-tinytls13 is a non-FIPS footprint profile and cannot be combined with FIPS.]) + fi + + # Feature switches were aligned early (MATH LIBRARY SELECTION section); + # here we only emit the umbrella + adder macros (settings.h does the rest). + tinytls13_base=psk + tinytls13_mldsa=no + for v in `echo $ENABLED_TINYTLS13 | tr ',' ' '` + do + case $v in + yes|psk) ;; + cert) tinytls13_base=cert ;; + mutualauth) tinytls13_base=cert + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_TINY_TLS13_MUTUAL_AUTH" ;; + server) AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_TINY_TLS13_SERVER" ;; + staticmem) AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_TINY_TLS13_STATIC_MEM" ;; + asm) AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_TINY_TLS13_ASM" ;; + p256) AM_CFLAGS="$AM_CFLAGS -DHAVE_ECC -DECC_USER_CURVES" ;; + rsaverify) AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_TINY_TLS13_RSA_VERIFY" ;; + sha384) AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SHA384" ;; + mldsa) tinytls13_mldsa=yes + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_MLDSA -DWOLFSSL_MLDSA_VERIFY_ONLY -DWOLFSSL_MLDSA_VERIFY_SMALL_MEM -DWOLFSSL_NO_ML_DSA_65 -DWOLFSSL_NO_ML_DSA_87" ;; + no) ;; + *) AC_MSG_ERROR([Invalid --enable-tinytls13 value: $v. Valid: psk cert server mutualauth staticmem asm p256 sha384 mldsa rsaverify.]) ;; + esac + done + + # ML-DSA on the PSK floor never parses a certificate, so drop the ASN.1/ + # X.509 surface for footprint. The cert profile needs it to decode and + # verify ML-DSA certificates, so keep ASN.1 there. + if test "$tinytls13_mldsa" = "yes" && test "$tinytls13_base" != "cert" + then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_MLDSA_NO_ASN1" + fi + + if test "$tinytls13_base" = "cert" + then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_TINY_TLS13_CERT" + AC_MSG_NOTICE([tiny TLS 1.3 cert profile is a reduced-security verify: no name constraints, relaxed ASN, no CRL. For a known or pinned CA, not public-internet PKI.]) + else + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_TINY_TLS13" + fi +fi + # low resource options to reduce flash and memory use AC_ARG_ENABLE([lowresource], @@ -12908,6 +13040,7 @@ echo " * TLS v1.0 (Old): $ENABLED_TLSV10" echo " * TLS v1.1 (Old): $ENABLED_OLD_TLS" echo " * TLS v1.2: $ENABLED_TLSV12" echo " * TLS v1.3: $ENABLED_TLS13" +echo " * Tiny TLS 1.3: $ENABLED_TINYTLS13" echo " * RPK: $ENABLED_RPK" echo " * Post-handshake Auth: $ENABLED_TLS13_POST_AUTH" echo " * Early Data: $ENABLED_TLS13_EARLY_DATA" diff --git a/examples/configs/README.md b/examples/configs/README.md index 0a2f3193fa3..90358249af6 100644 --- a/examples/configs/README.md +++ b/examples/configs/README.md @@ -18,6 +18,7 @@ Example wolfSSL configuration file templates for use when autoconf is not availa * `user_settings_stm32.h`: Example configuration file generated from the wolfSSL STM32 Cube pack. * `user_settings_tls12.h`: Example for TLS v1.2 client only, ECC only, AES-GCM only, SHA2-256 only. * `user_settings_tls13.h`: TLS 1.3 only configuration (no TLS 1.2). Modern cipher suites with X25519/X448 key exchange. +* `user_settings_tinytls13.h`: Smallest TLS 1.3 only footprint profile. PSK + ECDHE floor (no X.509) with opt-in adders: `cert` (minimal X.509 verify), `server`, `mutualauth`, `staticmem`, `asm`, `p256`, `sha384`, `mldsa`, `rsaverify`. Pairs with `--enable-tinytls13`. See `examples/tls13/tls13_memio.c` for the self-contained in-memory handshake check used by `--disable-examples` builds. * `user_settings_dtls13.h`: DTLS 1.3 for IoT and embedded. Includes connection ID support and smaller MTU options. * `user_settings_pq.h`: Post-quantum TLS with ML-KEM (Kyber) key exchange and ML-DSA (Dilithium) certificates. * `user_settings_openssl_compat.h`: OpenSSL compatibility layer for drop-in replacement. Enables OPENSSL_ALL and related APIs. diff --git a/examples/configs/include.am b/examples/configs/include.am index 9def0850c80..4ea3e15fbb9 100644 --- a/examples/configs/include.am +++ b/examples/configs/include.am @@ -23,6 +23,7 @@ EXTRA_DIST += examples/configs/user_settings_stm32.h EXTRA_DIST += examples/configs/user_settings_template.h EXTRA_DIST += examples/configs/user_settings_tls12.h EXTRA_DIST += examples/configs/user_settings_tls13.h +EXTRA_DIST += examples/configs/user_settings_tinytls13.h EXTRA_DIST += examples/configs/user_settings_wolfboot_keytools.h EXTRA_DIST += examples/configs/user_settings_wolfssh.h EXTRA_DIST += examples/configs/user_settings_wolftpm.h diff --git a/examples/configs/user_settings_tinytls13.h b/examples/configs/user_settings_tinytls13.h new file mode 100644 index 00000000000..e2de2706f18 --- /dev/null +++ b/examples/configs/user_settings_tinytls13.h @@ -0,0 +1,155 @@ +/* user_settings_tinytls13.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 + */ + +/* Tiny TLS 1.3 footprint profile. + * + * A TLS 1.3-only build that strips to a PSK + ECDHE floor (no X.509), with + * X.509 cert verify, mTLS, server role, zero-heap, and PQC as opt-in adders. + * The WOLFSSL_TINY_TLS13 umbrella in settings.h expands these into the + * underlying wolfSSL macros; this file just selects the profile and options. + * + * Smallest footprint comes from a dead-code-eliminated, LTO link of a single + * client/server: + * cp ./examples/configs/user_settings_tinytls13.h user_settings.h + * ./configure --enable-usersettings --enable-static --disable-shared \ + * --disable-examples --disable-crypttests + * make + * # link your app: -Os -flto -ffunction-sections -fdata-sections \ + * # -Wl,--gc-sections (use gcc-ar/gcc-ranlib for LTO archives) + */ + +#ifndef WOLFSSL_USER_SETTINGS_H +#define WOLFSSL_USER_SETTINGS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* ===== PROFILE ========================================================== */ +#if 1 /* Profile A: PSK + ECDHE floor, no X.509 (smallest) */ + #define WOLFSSL_TINY_TLS13 +#endif +#if 0 /* Profile B: + minimal X.509 cert verify (ECDSA P-256). Implies core. + * Reduced-security verify: no name constraints, relaxed ASN, no CRL. + * For a known or pinned CA, not general public-internet PKI. */ + #define WOLFSSL_TINY_TLS13_CERT +#endif + +/* ===== ROLE / AUTH ADDERS =============================================== */ +#if 0 /* add TLS 1.3 server role (default is client only) */ + #define WOLFSSL_TINY_TLS13_SERVER +#endif +#if 0 /* mutual TLS (X.509 client auth, adds ECDSA sign). Implies cert. */ + #define WOLFSSL_TINY_TLS13_MUTUAL_AUTH +#endif +#if 0 /* add RSA-PSS cert verify (cert profile is ECDSA-only by default) */ + #define WOLFSSL_TINY_TLS13_RSA_VERIFY +#endif + +/* ===== MEMORY MODEL ===================================================== */ +#if 0 /* static memory pool for TLS allocations (deterministic RAM, no + * fragmentation). App provides the pool via + * wolfSSL_CTX_load_static_memory(). Keeps the malloc fallback. */ + #define WOLFSSL_TINY_TLS13_STATIC_MEM +#endif +#if 0 /* true zero-heap: forbid all system malloc. Opt-in because it removes + * the allocator the standard test suite relies on. Pair with the + * static memory pool above. */ + #define WOLFSSL_NO_MALLOC +#endif +#if 0 /* Static-memory pool buckets for a tinytls13 PSK handshake, measured with + * wolfSSL's memory-bucket-optimizer. The distribution sets the minimum + * pool size (~320 KB for client+server, ~half a single role), so enable + * these only once your buffer matches; re-run the optimizer for your own + * role/adders. Left out of the floor because forcing a large distribution + * breaks consumers that load a smaller buffer. */ + #define WOLFMEM_BUCKETS 64,96,160,288,816,3408,5088,6176,10784 + #define WOLFMEM_DIST 92,34,36,421,63,20,3,1,2 + #define WOLFMEM_DEF_BUCKETS 9 +#endif + +/* ===== SPEED ============================================================ */ +#if 0 /* tiny+fast: assembly crypto instead of small-C (size up, speed up) */ + #define WOLFSSL_TINY_TLS13_ASM +#endif + +/* ===== CURVE (Profile A) =============================================== */ +/* Default curve is X25519. For P-256 ECDHE instead, enable the next block. + * (Profile B uses P-256 automatically for both ECDHE and ECDSA verify.) */ +#if 0 + #define HAVE_ECC + #define ECC_USER_CURVES +#endif + +/* ===== AEAD / HASH ADDERS (floor is AES-128-GCM + SHA-256) ============= */ +#if 0 /* ChaCha20-Poly1305 */ + #define HAVE_CHACHA + #define HAVE_POLY1305 +#endif +#if 0 /* AES-256-GCM (floor is AES-128 only) */ + #undef NO_AES_256 + #define WOLFSSL_AES_256 +#endif +#if 0 /* SHA-384 (for AES-256-GCM-SHA384 etc.) */ + #define WOLFSSL_SHA384 +#endif + +/* ===== PQC ADDERS (valid on either profile; SHA-3/SHAKE pulled in auto) = */ +#if 0 /* ML-DSA-44 verify-only. Use with the cert profile (Profile B) for TLS + * auth: the PSK floor has no certificate to verify, so on Profile A + * this only confirms the umbrella builds. ML-DSA-44 is the right tier + * for a tiny stack paired with X25519/P-256 + AES-128; higher levels + * add no security against that classical floor. */ + #define WOLFSSL_HAVE_MLDSA + #define WOLFSSL_MLDSA_VERIFY_ONLY + #define WOLFSSL_MLDSA_VERIFY_SMALL_MEM + #ifndef WOLFSSL_TINY_TLS13_CERT + /* PSK floor never parses a cert; the cert profile needs ML-DSA ASN.1 + * to decode and verify ML-DSA certificates, so keep it there. */ + #define WOLFSSL_MLDSA_NO_ASN1 + #endif + #define WOLFSSL_NO_ML_DSA_65 + #define WOLFSSL_NO_ML_DSA_87 +#endif +#if 0 /* ML-KEM-768 + X25519MLKEM768 hybrid (768 is the widely-adopted tier; + * disable 512/1024) */ + #define WOLFSSL_HAVE_MLKEM + #define WOLFSSL_NO_ML_KEM_512 + #define WOLFSSL_NO_ML_KEM_1024 + #define WOLFSSL_MLKEM_DYNAMIC_KEYS +#endif + +/* ===== PLATFORM (bare-metal defaults; adjust for your target) ========== */ +#if 1 + #define WOLFSSL_USER_IO /* provide your own send/recv callbacks */ + #define NO_FILESYSTEM + #define WOLFSSL_NO_SOCK + #define NO_WRITEV + #define WOLFSSL_NO_GETPID +#endif +/* Provide a hardware RNG seed for bare metal: + * #define CUSTOM_RAND_GENERATE_SEED my_hw_seed (int f(byte*, word32)) */ + +#ifdef __cplusplus +} +#endif + +#endif /* WOLFSSL_USER_SETTINGS_H */ diff --git a/examples/echoclient/echoclient.c b/examples/echoclient/echoclient.c index 3b99e58db9e..b35fd3c2c43 100644 --- a/examples/echoclient/echoclient.c +++ b/examples/echoclient/echoclient.c @@ -121,8 +121,8 @@ void echoclient_test(void* args) #ifdef WOLFSSL_LEANPSK doPSK = 1; #endif -#if defined(NO_RSA) && !defined(HAVE_ECC) && !defined(HAVE_ED25519) && \ - !defined(HAVE_ED448) +#if defined(NO_CERTS) || (defined(NO_RSA) && !defined(HAVE_ECC) && \ + !defined(HAVE_ED25519) && !defined(HAVE_ED448)) doPSK = 1; #endif (void)doPSK; @@ -146,7 +146,7 @@ void echoclient_test(void* args) #endif ctx = SSL_CTX_new(method); -#ifndef NO_FILESYSTEM +#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) #ifndef NO_RSA if (SSL_CTX_load_verify_locations(ctx, caCertFile, 0) != WOLFSSL_SUCCESS) err_sys("can't load ca file, Please run from wolfSSL home dir"); diff --git a/examples/echoserver/echoserver.c b/examples/echoserver/echoserver.c index baa2ed5bed4..c6e368033e1 100644 --- a/examples/echoserver/echoserver.c +++ b/examples/echoserver/echoserver.c @@ -123,8 +123,9 @@ THREAD_RETURN WOLFSSL_THREAD echoserver_test(void* args) ((func_args*)args)->return_code = -1; /* error state */ -#if (defined(NO_RSA) && !defined(HAVE_ECC) && !defined(HAVE_ED25519) && \ - !defined(HAVE_ED448)) || defined(WOLFSSL_LEANPSK) +#if defined(NO_CERTS) || defined(WOLFSSL_LEANPSK) || \ + (defined(NO_RSA) && !defined(HAVE_ECC) && !defined(HAVE_ED25519) && \ + !defined(HAVE_ED448)) doPSK = 1; #else doPSK = 0; @@ -178,7 +179,7 @@ THREAD_RETURN WOLFSSL_THREAD echoserver_test(void* args) #ifndef NO_FILESYSTEM if (doPSK == 0) { - #if defined(HAVE_ECC) && !defined(WOLFSSL_SNIFFER) + #if defined(HAVE_ECC) && !defined(NO_CERTS) && !defined(WOLFSSL_SNIFFER) /* ecc */ if (wolfSSL_CTX_use_certificate_file(ctx, eccCertFile, CERT_FILETYPE) != WOLFSSL_SUCCESS) @@ -189,7 +190,7 @@ THREAD_RETURN WOLFSSL_THREAD echoserver_test(void* args) != WOLFSSL_SUCCESS) err_sys("can't load server key file, " "Please run from wolfSSL home dir"); - #elif defined(HAVE_ED25519) && !defined(WOLFSSL_SNIFFER) + #elif defined(HAVE_ED25519) && !defined(NO_CERTS) && !defined(WOLFSSL_SNIFFER) /* ed25519 */ if (wolfSSL_CTX_use_certificate_chain_file(ctx, edCertFile) != WOLFSSL_SUCCESS) @@ -200,7 +201,7 @@ THREAD_RETURN WOLFSSL_THREAD echoserver_test(void* args) != WOLFSSL_SUCCESS) err_sys("can't load server key file, " "Please run from wolfSSL home dir"); - #elif defined(HAVE_ED448) && !defined(WOLFSSL_SNIFFER) + #elif defined(HAVE_ED448) && !defined(NO_CERTS) && !defined(WOLFSSL_SNIFFER) /* ed448 */ if (wolfSSL_CTX_use_certificate_chain_file(ctx, ed448CertFile) != WOLFSSL_SUCCESS) diff --git a/examples/include.am b/examples/include.am index 6235d147f83..2a779bc07f9 100644 --- a/examples/include.am +++ b/examples/include.am @@ -12,4 +12,5 @@ include examples/configs/include.am include examples/asn1/include.am include examples/pem/include.am include examples/ocsp_responder/include.am +include examples/tls13/include.am EXTRA_DIST += examples/README.md diff --git a/examples/server/server.c b/examples/server/server.c index 2ac169dce57..8ea1fcf6b4b 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -3110,7 +3110,7 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) #endif -#ifdef HAVE_ECC +#if defined(HAVE_ECC) && !defined(NO_CERTS) /* Use ECDHE key size that matches long term key. * Zero means use ctx->privateKeySz. * Default ECDHE_SIZE is 32 bytes diff --git a/examples/tls13/include.am b/examples/tls13/include.am new file mode 100644 index 00000000000..3e6c3a89ef6 --- /dev/null +++ b/examples/tls13/include.am @@ -0,0 +1,4 @@ +# vim:ft=automake +# All paths should be given relative to the root + +EXTRA_DIST += examples/tls13/tls13_memio.c diff --git a/examples/tls13/tls13_memio.c b/examples/tls13/tls13_memio.c new file mode 100644 index 00000000000..1ca912748c6 --- /dev/null +++ b/examples/tls13/tls13_memio.c @@ -0,0 +1,257 @@ +/* tls13_memio.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 + */ + +/* Self-contained TLS 1.3 handshake over an in-memory transport. + * + * Single process, no sockets, no threads (SINGLE_THREADED safe): the client + * and server WOLFSSL objects are wired together through two in-memory byte + * queues, and the handshake is driven to completion in one loop. It exercises + * the real TLS 1.3 handshake state machine for builds where the example/unit + * test harness is not available, e.g. a minimal --disable-examples build. + * + * By default it runs the minimal PSK + ECDHE handshake (no X.509). On a cert + * build (WOLFSSL_TINY_TLS13_CERT) it runs a certificate handshake instead: the + * server presents an ECDSA P-256 certificate and the client validates it, + * driving the Certificate / CertificateVerify path. Cert files default to + * ../certs (the layout used by parallel-make-check.py builds); override the + * CERT_DIR macro at build time to point elsewhere. + * + * Build against a static build and run: + * cc -I -I tls13_memio.c /src/.libs/libwolfssl.a -lm \ + * -o tls13_memio && ./tls13_memio + */ + +#ifndef WOLFSSL_USER_SETTINGS + #include +#endif +#include + +#include +#include + +/* In-memory transport buffer; must hold one handshake flight. Build-time override. */ +#ifndef MEM_BUF_SZ +#define MEM_BUF_SZ 32768 +#endif + +/* Max connect/accept round trips to drive the handshake. Build-time override. */ +#ifndef HS_MAX_ITERS +#define HS_MAX_ITERS 50 +#endif + +#ifndef WOLFSSL_TINY_TLS13_CERT +/* Example-only fixed test PSK and identity shared by both endpoints; not a + * real secret. Provision your own for anything beyond this smoke test. */ +static const unsigned char psk_key[16] = { + 0x1a, 0x2b, 0x3c, 0x4d, 0x5e, 0x6f, 0x70, 0x81, + 0x92, 0xa3, 0xb4, 0xc5, 0xd6, 0xe7, 0xf8, 0x09 +}; +static const char psk_identity[] = "tinytls13-client"; +#endif /* !WOLFSSL_TINY_TLS13_CERT */ + +typedef struct membuf { + unsigned char data[MEM_BUF_SZ]; + int len; +} membuf; + +/* recv: drain from the queue this endpoint reads from */ +static int mem_recv(WOLFSSL* ssl, char* buf, int sz, void* ctx) +{ + membuf* mb = (membuf*)ctx; + int n; + + (void)ssl; + if (mb->len == 0) + return WOLFSSL_CBIO_ERR_WANT_READ; + n = (sz < mb->len) ? sz : mb->len; + XMEMCPY(buf, mb->data, (size_t)n); + XMEMMOVE(mb->data, mb->data + n, (size_t)(mb->len - n)); + mb->len -= n; + return n; +} + +/* send: append to the queue the peer reads from */ +static int mem_send(WOLFSSL* ssl, char* buf, int sz, void* ctx) +{ + membuf* mb = (membuf*)ctx; + + (void)ssl; + if (sz < 0 || mb->len > MEM_BUF_SZ - sz) + return WOLFSSL_CBIO_ERR_WANT_WRITE; + XMEMCPY(mb->data + mb->len, buf, (size_t)sz); + mb->len += sz; + return sz; +} + +#ifndef WOLFSSL_TINY_TLS13_CERT +static unsigned int psk_client_cb(WOLFSSL* ssl, const char* hint, + char* identity, unsigned int id_max, unsigned char* key, + unsigned int key_max) +{ + (void)ssl; + (void)hint; + if (id_max < sizeof(psk_identity) || key_max < sizeof(psk_key)) + return 0; + XMEMCPY(identity, psk_identity, sizeof(psk_identity)); + XMEMCPY(key, psk_key, sizeof(psk_key)); + return (unsigned int)sizeof(psk_key); +} + +static unsigned int psk_server_cb(WOLFSSL* ssl, const char* identity, + unsigned char* key, unsigned int key_max) +{ + (void)ssl; + (void)identity; + if (key_max < sizeof(psk_key)) + return 0; + XMEMCPY(key, psk_key, sizeof(psk_key)); + return (unsigned int)sizeof(psk_key); +} +#endif /* !WOLFSSL_TINY_TLS13_CERT */ + +#ifdef WOLFSSL_TINY_TLS13_CERT +/* Build-time override to point at a different certs tree. */ +#ifndef CERT_DIR +#define CERT_DIR "../certs" +#endif +#if defined(WOLFSSL_HAVE_MLDSA) + #define SERVER_CERT_FILE CERT_DIR "/mldsa/ecc-leaf-mldsa44.pem" + #define CLIENT_CA_FILE CERT_DIR "/mldsa/mldsa44-cert.pem" +#elif defined(WOLFSSL_TINY_TLS13_RSA_VERIFY) + #define SERVER_CERT_FILE CERT_DIR "/rsapss/ecc-leaf-rsapss.pem" + #define CLIENT_CA_FILE CERT_DIR "/rsapss/ca-rsapss.pem" +#else + #define SERVER_CERT_FILE CERT_DIR "/server-ecc.pem" + #define CLIENT_CA_FILE CERT_DIR "/ca-ecc-cert.pem" +#endif +#define SERVER_KEY_FILE CERT_DIR "/ecc-key.pem" +#endif /* WOLFSSL_TINY_TLS13_CERT */ + +int main(int argc, char** argv) +{ + WOLFSSL_CTX* cctx = NULL; + WOLFSSL_CTX* sctx = NULL; + WOLFSSL* c = NULL; + WOLFSSL* s = NULL; + membuf c2s; /* client writes, server reads */ + membuf s2c; /* server writes, client reads */ + int i, cdone = 0, sdone = 0, ret = 1; + int cret = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR); + int sret = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR); + const char* cipher = (argc > 1) ? argv[1] : "-"; + const char* group = (argc > 2) ? argv[2] : "-"; + int mlkemGroup[1]; + + XMEMSET(&c2s, 0, sizeof(c2s)); + XMEMSET(&s2c, 0, sizeof(s2c)); + + wolfSSL_Init(); + + cctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()); + sctx = wolfSSL_CTX_new(wolfTLSv1_3_server_method()); + if (cctx == NULL || sctx == NULL) { + printf("smoke: CTX_new failed\n"); + goto done; + } + + /* Force a specific suite when asked, so an adder config proves its cipher + * negotiates: a single-suite list means a completed handshake used it. */ + if (cipher[0] != '\0' && cipher[0] != '-') { + wolfSSL_CTX_set_cipher_list(cctx, cipher); + wolfSSL_CTX_set_cipher_list(sctx, cipher); + } + +#ifdef WOLFSSL_TINY_TLS13_CERT + /* Server presents an ECDSA leaf signed by the CA whose algorithm this + * profile verifies (ECDSA, ML-DSA-44, or RSA-PSS); a completed handshake + * drives that verify path. */ + if (wolfSSL_CTX_use_certificate_file(sctx, SERVER_CERT_FILE, + WOLFSSL_FILETYPE_PEM) != WOLFSSL_SUCCESS || + wolfSSL_CTX_use_PrivateKey_file(sctx, SERVER_KEY_FILE, + WOLFSSL_FILETYPE_PEM) != WOLFSSL_SUCCESS || + wolfSSL_CTX_load_verify_locations(cctx, CLIENT_CA_FILE, NULL) + != WOLFSSL_SUCCESS) { + printf("smoke: cert load failed (dir=%s)\n", CERT_DIR); + goto done; + } +#else + wolfSSL_CTX_set_psk_client_callback(cctx, psk_client_cb); + wolfSSL_CTX_set_psk_server_callback(sctx, psk_server_cb); +#endif + + wolfSSL_CTX_SetIORecv(cctx, mem_recv); + wolfSSL_CTX_SetIOSend(cctx, mem_send); + wolfSSL_CTX_SetIORecv(sctx, mem_recv); + wolfSSL_CTX_SetIOSend(sctx, mem_send); + + c = wolfSSL_new(cctx); + s = wolfSSL_new(sctx); + if (c == NULL || s == NULL) { + printf("smoke: SSL_new failed\n"); + goto done; + } + + /* Restrict to the ML-KEM hybrid key share when asked, so a completed + * handshake proves the hybrid KEX was negotiated. */ + if (XSTRCMP(group, "mlkem") == 0) { + mlkemGroup[0] = WOLFSSL_X25519MLKEM768; + wolfSSL_set_groups(c, mlkemGroup, 1); + wolfSSL_set_groups(s, mlkemGroup, 1); + } + + /* client reads s2c, writes c2s; server reads c2s, writes s2c */ + wolfSSL_SetIOReadCtx(c, &s2c); + wolfSSL_SetIOWriteCtx(c, &c2s); + wolfSSL_SetIOReadCtx(s, &c2s); + wolfSSL_SetIOWriteCtx(s, &s2c); + + for (i = 0; i < HS_MAX_ITERS && !(cdone && sdone); i++) { + if (!cdone) { + cret = wolfSSL_connect(c); + if (cret == WOLFSSL_SUCCESS) + cdone = 1; + } + if (!sdone) { + sret = wolfSSL_accept(s); + if (sret == WOLFSSL_SUCCESS) + sdone = 1; + } + } + + if (cdone && sdone && + XSTRCMP(wolfSSL_get_version(c), "TLSv1.3") == 0) { + printf("tls13_memio handshake OK: %s %s\n", + wolfSSL_get_version(c), wolfSSL_get_cipher(c)); + ret = 0; + } + else { + printf("tls13_memio handshake FAILED (client err %d, server err %d)\n", + wolfSSL_get_error(c, cret), wolfSSL_get_error(s, sret)); + } + +done: + wolfSSL_free(c); + wolfSSL_free(s); + wolfSSL_CTX_free(cctx); + wolfSSL_CTX_free(sctx); + wolfSSL_Cleanup(); + return ret; +} diff --git a/src/internal.c b/src/internal.c index fed9d370dea..6aff3582af6 100644 --- a/src/internal.c +++ b/src/internal.c @@ -3367,7 +3367,7 @@ void InitCipherSpecs(CipherSpecs* cs) } #if defined(USE_ECDSA_KEYSZ_HASH_ALGO) || (defined(WOLFSSL_TLS13) && \ - defined(HAVE_ECC)) + defined(HAVE_ECC) && !defined(NO_CERTS)) static int GetMacDigestSize(byte macAlgo) { switch (macAlgo) { @@ -7177,7 +7177,8 @@ int SetSSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup) ssl->eccTempKeySz = ctx->eccTempKeySz; ssl->ecdhCurveOID = ctx->ecdhCurveOID; #endif -#if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) +#if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) || \ + defined(HAVE_FALCON) || defined(WOLFSSL_HAVE_MLDSA) ssl->pkCurveOID = ctx->pkCurveOID; #endif @@ -8683,9 +8684,10 @@ int AllocKey(WOLFSSL* ssl, int type, void** pKey) return ret; } -#if !defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519) || \ - defined(HAVE_CURVE25519) || defined(HAVE_ED448) || \ - defined(HAVE_CURVE448) || defined(HAVE_FALCON) || defined(WOLFSSL_HAVE_MLDSA) +#if (!defined(NO_CERTS) || !defined(WOLFSSL_NO_TLS12)) && \ + (!defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519) || \ + defined(HAVE_CURVE25519) || defined(HAVE_ED448) || \ + defined(HAVE_CURVE448) || defined(HAVE_FALCON) || defined(WOLFSSL_HAVE_MLDSA)) static int ReuseKey(WOLFSSL* ssl, int type, void* pKey) { int ret = 0; @@ -30501,7 +30503,8 @@ static int MatchSigAlgo(WOLFSSL* ssl, int sigAlgo) } #if defined(HAVE_ECC) && \ - (defined(WOLFSSL_TLS13) || defined(USE_ECDSA_KEYSZ_HASH_ALGO)) + ((defined(WOLFSSL_TLS13) && !defined(NO_CERTS)) || \ + defined(USE_ECDSA_KEYSZ_HASH_ALGO)) static int CmpEccStrength(int hashAlgo, int curveSz) { int dgstSz = GetMacDigestSize((byte)hashAlgo); @@ -30675,7 +30678,7 @@ int PickHashSigAlgo(WOLFSSL* ssl, const byte* hashSigAlgo, word32 hashSigAlgoSz, "be used together" #endif - #if defined(HAVE_ECC) && (defined(WOLFSSL_TLS13) || \ + #if defined(HAVE_ECC) && !defined(NO_CERTS) && (defined(WOLFSSL_TLS13) || \ defined(WOLFSSL_ECDSA_MATCH_HASH)) #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) if (sigAlgo == sm2_sa_algo && hashAlgo == sm3_mac diff --git a/src/ssl_load.c b/src/ssl_load.c index 9831518005e..6d04e09ea10 100644 --- a/src/ssl_load.c +++ b/src/ssl_load.c @@ -1590,7 +1590,8 @@ static void ProcessBufferCertSetHave(WOLFSSL_CTX* ctx, WOLFSSL* ssl, #if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) || \ defined(HAVE_FALCON) || defined(WOLFSSL_HAVE_MLDSA) || !defined(NO_RSA) - #if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) + #if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) || \ + defined(HAVE_FALCON) || defined(WOLFSSL_HAVE_MLDSA) /* Set the private key curve OID. */ if (ssl != NULL) { ssl->pkCurveOID = cert->pkCurveOID; diff --git a/src/tls13.c b/src/tls13.c index ecfd5946dd8..11a4c927e89 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -10802,8 +10802,9 @@ static int DoTls13Certificate(WOLFSSL* ssl, byte* input, word32* inOutIdx, } #endif -#if !defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519) || \ - defined(HAVE_ED448) +#if (!defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519) || \ + defined(HAVE_ED448) || defined(HAVE_FALCON) || \ + defined(WOLFSSL_HAVE_MLDSA)) && !defined(NO_CERTS) typedef struct Dcv13Args { byte* output; /* not allocated */ @@ -13844,8 +13845,9 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, break; #endif -#if !defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519) || \ - defined(HAVE_ED448) || defined(HAVE_FALCON) || defined(WOLFSSL_HAVE_MLDSA) +#if (!defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519) || \ + defined(HAVE_ED448) || defined(HAVE_FALCON) || \ + defined(WOLFSSL_HAVE_MLDSA)) && !defined(NO_CERTS) case certificate_verify: WOLFSSL_MSG("processing certificate verify"); ret = DoTls13CertificateVerify(ssl, input, inOutIdx, size); diff --git a/tests/api/test_curve25519.c b/tests/api/test_curve25519.c index 33c51253f7e..9e920196d68 100644 --- a/tests/api/test_curve25519.c +++ b/tests/api/test_curve25519.c @@ -754,7 +754,7 @@ int test_wc_Curve25519KeyToDer_oneasymkey_version(void) { EXPECT_DECLS; #if defined(HAVE_CURVE25519) && defined(HAVE_CURVE25519_KEY_EXPORT) && \ - defined(HAVE_CURVE25519_KEY_IMPORT) + defined(HAVE_CURVE25519_KEY_IMPORT) && !defined(NO_ASN) curve25519_key key; curve25519_key key2; WC_RNG rng; diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 3cd37c739bd..8d19650b263 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -4152,7 +4152,8 @@ struct WOLFSSL_CTX { #ifdef HAVE_ECC word16 eccTempKeySz; /* in octets 20 - 66 */ #endif -#if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) +#if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) || \ + defined(HAVE_FALCON) || defined(WOLFSSL_HAVE_MLDSA) word32 pkCurveOID; /* curve Ecc_Sum */ #endif #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) @@ -6267,7 +6268,8 @@ struct WOLFSSL { byte peerEccDsaKeyPresent; #endif #if defined(HAVE_ECC) || defined(HAVE_ED25519) || \ - defined(HAVE_CURVE448) || defined(HAVE_ED448) + defined(HAVE_CURVE448) || defined(HAVE_ED448) || \ + defined(HAVE_FALCON) || defined(WOLFSSL_HAVE_MLDSA) word32 pkCurveOID; /* curve Ecc_Sum */ #endif #ifdef HAVE_ED25519 @@ -6963,7 +6965,6 @@ WOLFSSL_LOCAL WC_RNG* WOLFSSL_RSA_GetRNG(WOLFSSL_RSA *rsa, WC_RNG **tmpRNG, int *initTmpRng); #endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ -#ifndef NO_CERTS #ifndef NO_RSA #ifdef WC_RSA_PSS WOLFSSL_LOCAL int CheckRsaPssPadding(const byte* plain, word32 plainSz, @@ -7020,7 +7021,7 @@ WOLFSSL_LOCAL WC_RNG* WOLFSSL_RSA_GetRNG(WOLFSSL_RSA *rsa, WC_RNG **tmpRNG, buffer* keyBufInfo); #endif /* HAVE_ED448 */ - +#ifndef NO_CERTS #ifdef WOLFSSL_TRUST_PEER_CERT /* options for searching hash table for a matching trusted peer cert */ diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 9f699145847..9d53d875c48 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -1912,6 +1912,244 @@ #define TFM_TIMING_RESISTANT #endif +/* tiny TLS 1.3 profile: TLS1.3-only footprint build expressed purely in + * standard macros (translation layer). WOLFSSL_TINY_TLS13 = PSK+ECDHE floor + * (no X.509); WOLFSSL_TINY_TLS13_CERT adds minimal X.509 verify (implies core). */ +/* mTLS (X.509 client auth) needs the cert profile. */ +#ifdef WOLFSSL_TINY_TLS13_MUTUAL_AUTH + #undef WOLFSSL_TINY_TLS13_CERT + #define WOLFSSL_TINY_TLS13_CERT +#endif +#ifdef WOLFSSL_TINY_TLS13_CERT + #undef WOLFSSL_TINY_TLS13 + #define WOLFSSL_TINY_TLS13 +#endif + +#ifdef WOLFSSL_TINY_TLS13 + #undef WOLFSSL_TLS13 + #define WOLFSSL_TLS13 + #undef WOLFSSL_NO_TLS12 + #define WOLFSSL_NO_TLS12 + #undef NO_OLD_TLS + #define NO_OLD_TLS + #undef HAVE_TLS_EXTENSIONS + #define HAVE_TLS_EXTENSIONS + #undef HAVE_SUPPORTED_CURVES + #define HAVE_SUPPORTED_CURVES + #undef HAVE_HKDF + #define HAVE_HKDF + + /* Default curve: X25519 for the PSK floor; P-256 for the cert profile + * (P-256 serves both ECDHE and ECDSA cert verify). Override by selecting a + * curve beforehand or with WOLFSSL_TINY_TLS13_NO_DEFAULT_CURVE. */ + #if !defined(HAVE_CURVE25519) && !defined(HAVE_ECC) && \ + !defined(WOLFSSL_TINY_TLS13_NO_DEFAULT_CURVE) + #ifdef WOLFSSL_TINY_TLS13_CERT + #undef HAVE_ECC + #define HAVE_ECC + #undef ECC_USER_CURVES + #define ECC_USER_CURVES + #else + #undef HAVE_CURVE25519 + #define HAVE_CURVE25519 + #undef CURVE25519_SMALL + #define CURVE25519_SMALL + #endif + #endif + + /* SP math drives the ECC asm; small C at the headline, asm via *_ASM. + * Respect an SP variant already chosen by configure (avoids clashing with + * WOLFSSL_SP_MATH_ALL); only provide one for the user_settings path. */ + #ifdef HAVE_ECC + #if !defined(WOLFSSL_SP_MATH) && !defined(WOLFSSL_SP_MATH_ALL) + #define WOLFSSL_SP_MATH + #endif + #undef WOLFSSL_HAVE_SP_ECC + #define WOLFSSL_HAVE_SP_ECC + #undef ECC_TIMING_RESISTANT + #define ECC_TIMING_RESISTANT + #ifndef WOLFSSL_TINY_TLS13_ASM + #undef WOLFSSL_SP_SMALL + #define WOLFSSL_SP_SMALL + #endif + #endif + + /* AEAD + hash floor: AES-128-GCM + SHA-256. */ + #undef HAVE_AESGCM + #define HAVE_AESGCM + #undef WOLFSSL_AES_128 + #define WOLFSSL_AES_128 + /* Floor is AES-128 only, but let a user adder (WOLFSSL_AES_192 / + * WOLFSSL_AES_256) opt back in; user_settings.h is processed before this. */ + #ifndef WOLFSSL_AES_192 + #undef NO_AES_192 + #define NO_AES_192 + #endif + #ifndef WOLFSSL_AES_256 + #undef NO_AES_256 + #define NO_AES_256 + #endif + #undef GCM_SMALL + #define GCM_SMALL + /* Small AES tables at the size-first headline; fast AES with the asm toggle. */ + #ifndef WOLFSSL_TINY_TLS13_ASM + #undef WOLFSSL_AES_SMALL_TABLES + #define WOLFSSL_AES_SMALL_TABLES + #undef WOLFSSL_AES_NO_UNROLL + #define WOLFSSL_AES_NO_UNROLL + #endif + #undef WOLFSSL_NOSHA512_224 + #define WOLFSSL_NOSHA512_224 + #undef WOLFSSL_NOSHA512_256 + #define WOLFSSL_NOSHA512_256 + /* Floor is SHA-256. SHA-384/512 share the large SHA-512 core; keep them out + * unless asked (the sha384 adder defines WOLFSSL_SHA384). This matches the + * configure path so both build methods give the same SHA-256 floor. */ + #if !defined(WOLFSSL_SHA384) && !defined(WOLFSSL_SHA512) + #undef NO_SHA512 + #define NO_SHA512 + #endif + + /* Strip legacy / unused algorithms. */ + #undef NO_DSA + #define NO_DSA + #undef NO_DH + #define NO_DH + #undef NO_DES3 + #define NO_DES3 + #undef NO_RC4 + #define NO_RC4 + #undef NO_MD4 + #define NO_MD4 + #undef NO_MD5 + #define NO_MD5 + #undef NO_SHA + #define NO_SHA + #undef NO_PWDBASED + #define NO_PWDBASED + + /* Footprint hygiene. NO_FILESYSTEM stays template-only so examples link. */ + #undef NO_ERROR_STRINGS + #define NO_ERROR_STRINGS + #undef WOLFSSL_SMALL_STACK + #define WOLFSSL_SMALL_STACK + #undef NO_SESSION_CACHE + #define NO_SESSION_CACHE + #undef NO_CLIENT_CACHE + #define NO_CLIENT_CACHE + #undef NO_HANDSHAKE_DONE_CB + #define NO_HANDSHAKE_DONE_CB + #undef NO_SIG_WRAPPER + #define NO_SIG_WRAPPER + #undef SINGLE_THREADED + #define SINGLE_THREADED + + /* Client by default; server is an opt-in adder. */ + #ifndef WOLFSSL_TINY_TLS13_SERVER + #undef NO_WOLFSSL_SERVER + #define NO_WOLFSSL_SERVER + #endif + + /* Optional static memory: serve TLS allocations from a caller-provided + * static pool (deterministic RAM, no fragmentation). Requires + * wolfSSL_CTX_load_static_memory() at runtime. For a true zero-heap build + * (no system malloc at all), also define WOLFSSL_NO_MALLOC in your + * user_settings; that is left opt-in because it removes the allocator the + * standard test suite relies on. */ + #ifdef WOLFSSL_TINY_TLS13_STATIC_MEM + #undef WOLFSSL_STATIC_MEMORY + #define WOLFSSL_STATIC_MEMORY + /* Size a tiny WOLFMEM_* pool with the memory-bucket-optimizer; see the + * measured starting point in user_settings_tinytls13.h. */ + #endif + + /* Profile A: no X.509 at all (the cert variant keeps ASN/certs). */ + #ifndef WOLFSSL_TINY_TLS13_CERT + #undef NO_RSA + #define NO_RSA + #undef NO_CERTS + #define NO_CERTS + #undef NO_ASN + #define NO_ASN + #endif +#endif /* WOLFSSL_TINY_TLS13 */ + +/* Profile B delta: minimal X.509 chain verify on top of the core. Curve/SP + * (P-256) come from the cert-aware default above; this adds the ASN/verify + * surface, trimmed to chain-verify essentials. NOTE: a reduced-security verify + * (no name constraints, relaxed ASN); intended for a known/pinned CA, not + * general public-internet PKI. ECDSA-only by default; RSA verify is an adder. */ +#ifdef WOLFSSL_TINY_TLS13_CERT + #undef WOLFSSL_ASN_TEMPLATE + #define WOLFSSL_ASN_TEMPLATE + #undef WOLFSSL_SMALL_CERT_VERIFY + #define WOLFSSL_SMALL_CERT_VERIFY + #undef IGNORE_NAME_CONSTRAINTS + #define IGNORE_NAME_CONSTRAINTS + #undef WOLFSSL_NO_ASN_STRICT + #define WOLFSSL_NO_ASN_STRICT + #undef NO_CRL + #define NO_CRL + + #ifdef WOLFSSL_TINY_TLS13_RSA_VERIFY + #undef WOLFSSL_RSA_VERIFY_ONLY + #define WOLFSSL_RSA_VERIFY_ONLY + #undef WC_RSA_PSS + #define WC_RSA_PSS + #else + #undef NO_RSA + #define NO_RSA + #endif +#endif /* WOLFSSL_TINY_TLS13_CERT */ + +/* PQC adders need SHA-3/SHAKE, which the floor otherwise leaves out. Pull it in + * automatically so ML-DSA / ML-KEM "just work" as adders on the tiny profile. */ +#if defined(WOLFSSL_TINY_TLS13) && \ + (defined(WOLFSSL_HAVE_MLDSA) || defined(WOLFSSL_HAVE_MLKEM) || \ + defined(HAVE_DILITHIUM) || defined(WOLFSSL_HAVE_KYBER)) + #undef WOLFSSL_SHA3 + #define WOLFSSL_SHA3 + #undef WOLFSSL_SHAKE128 + #define WOLFSSL_SHAKE128 + #undef WOLFSSL_SHAKE256 + #define WOLFSSL_SHAKE256 +#endif + +/* tiny TLS 1.3 sanity checks: catch incompatible selections early. */ +#ifdef WOLFSSL_TINY_TLS13 + #if !defined(WOLFSSL_TLS13) || !defined(WOLFSSL_NO_TLS12) || \ + !defined(NO_OLD_TLS) + #error "tiny TLS 1.3 must be TLS 1.3 only (WOLFSSL_TLS13, WOLFSSL_NO_TLS12, NO_OLD_TLS)" + #endif + #if !defined(HAVE_CURVE25519) && !defined(HAVE_ECC) + #error "tiny TLS 1.3 needs an ECDHE curve (HAVE_CURVE25519 or HAVE_ECC)" + #endif + #if !defined(HAVE_AESGCM) && !defined(HAVE_CHACHA) + #error "tiny TLS 1.3 needs an AEAD (HAVE_AESGCM or ChaCha20-Poly1305)" + #endif + #if defined(NO_SHA256) + #error "tiny TLS 1.3 needs SHA-256" + #endif + #if !defined(HAVE_HKDF) + #error "tiny TLS 1.3 needs HKDF" + #endif + #ifndef WOLFSSL_TINY_TLS13_CERT + #if defined(NO_PSK) + #error "tiny-psk profile needs PSK (do not define NO_PSK; use the cert profile for X.509)" + #endif + #if !defined(NO_CERTS) + #error "tiny-psk profile expects NO_CERTS (use WOLFSSL_TINY_TLS13_CERT for X.509)" + #endif + #else + #if defined(NO_CERTS) || defined(NO_ASN) + #error "tiny-cert profile must not disable certs/ASN" + #endif + #if !defined(HAVE_ECC) && defined(NO_RSA) && !defined(WOLFSSL_HAVE_MLDSA) + #error "tiny-cert profile needs a verify alg (ECDSA, RSA verify, or ML-DSA)" + #endif + #endif +#endif /* WOLFSSL_TINY_TLS13 */ + /* To support storing some of the large constant tables in flash memory rather than SRAM. Useful for processors that have limited SRAM, such as the AVR family of microtrollers. */ #ifdef WOLFSSL_USE_FLASHMEM